52
51
#include <private/qqmlboundsignal_p.h>
53
52
#include <private/qqmltrace_p.h>
54
53
#include <private/qqmlcomponentattached_p.h>
55
#include <QQmlComponent>
56
54
#include <private/qqmlcomponent_p.h>
57
#include <private/qqmlcodegenerator_p.h>
55
#include <private/qqmlcustomparser_p.h>
56
#include <private/qqmlscriptstring_p.h>
57
#include <private/qqmlpropertyvalueinterceptor_p.h>
58
#include <private/qqmlvaluetypeproxybinding_p.h>
62
63
struct ActiveOCRestorer
64
ActiveOCRestorer(QmlObjectCreator *creator, QQmlEnginePrivate *ep)
65
ActiveOCRestorer(QQmlObjectCreator *creator, QQmlEnginePrivate *ep)
65
66
: ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
66
67
~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
68
69
QQmlEnginePrivate *ep;
69
QmlObjectCreator *oldCreator;
70
QQmlObjectCreator *oldCreator;
73
QQmlCompilePass::QQmlCompilePass(const QUrl &url, const QV4::CompiledData::QmlUnit *unit)
79
void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description)
83
error.setLine(location.line);
84
error.setColumn(location.column);
85
error.setDescription(description);
89
#define COMPILE_EXCEPTION(token, desc) \
91
recordError((token)->location, desc); \
95
static QAtomicInt classIndexCounter(0);
97
QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit, const QUrl &url, const QQmlImports *imports,
98
QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes)
99
: QQmlCompilePass(url, unit)
100
, enginePrivate(enginePrivate)
102
, resolvedTypes(resolvedTypes)
106
bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **resultCache, QByteArray *vmeMetaObjectData)
108
Q_ASSERT(!stringAt(obj->inheritedTypeNameIndex).isEmpty());
110
QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex);
111
QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
112
Q_ASSERT(baseTypeCache);
113
if (obj->nProperties == 0 && obj->nSignals == 0 && obj->nFunctions == 0) {
114
*resultCache = baseTypeCache;
115
vmeMetaObjectData->clear();
119
QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate),
121
obj->nFunctions + obj->nProperties + obj->nSignals,
122
obj->nSignals + obj->nProperties);
123
*resultCache = cache;
125
vmeMetaObjectData->clear();
128
QV4::CompiledData::Property::Type dtype;
131
{ QV4::CompiledData::Property::Var, QMetaType::QVariant },
132
{ QV4::CompiledData::Property::Variant, QMetaType::QVariant },
133
{ QV4::CompiledData::Property::Int, QMetaType::Int },
134
{ QV4::CompiledData::Property::Bool, QMetaType::Bool },
135
{ QV4::CompiledData::Property::Real, QMetaType::Double },
136
{ QV4::CompiledData::Property::String, QMetaType::QString },
137
{ QV4::CompiledData::Property::Url, QMetaType::QUrl },
138
{ QV4::CompiledData::Property::Color, QMetaType::QColor },
139
{ QV4::CompiledData::Property::Font, QMetaType::QFont },
140
{ QV4::CompiledData::Property::Time, QMetaType::QTime },
141
{ QV4::CompiledData::Property::Date, QMetaType::QDate },
142
{ QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
143
{ QV4::CompiledData::Property::Rect, QMetaType::QRectF },
144
{ QV4::CompiledData::Property::Point, QMetaType::QPointF },
145
{ QV4::CompiledData::Property::Size, QMetaType::QSizeF },
146
{ QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
147
{ QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
148
{ QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
149
{ QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
150
{ QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
152
static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
154
QByteArray newClassName;
156
if (false /* ### compileState->root == obj && !compileState->nested*/) {
158
QString path = output->url.path();
159
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
160
if (lastSlash > -1) {
161
QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
162
if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
163
newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
164
QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
168
if (newClassName.isEmpty()) {
169
newClassName = QQmlMetaObject(baseTypeCache).className();
170
newClassName.append("_QML_");
171
newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
174
cache->_dynamicClassName = newClassName;
177
int varPropCount = 0;
179
const QV4::CompiledData::Property *p = obj->propertyTable();
180
for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
182
if (p->type == QV4::CompiledData::Property::Alias)
184
else if (p->type == QV4::CompiledData::Property::Var)
187
#if 0 // ### Do this elsewhere
188
// No point doing this for both the alias and non alias cases
189
QQmlPropertyData *d = property(obj, p->name);
190
if (d && d->isFinal())
191
COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
195
typedef QQmlVMEMetaData VMD;
197
QByteArray &dynamicData = *vmeMetaObjectData = QByteArray(sizeof(QQmlVMEMetaData)
198
+ obj->nProperties * sizeof(VMD::PropertyData)
199
+ obj->nFunctions * sizeof(VMD::MethodData)
200
+ aliasCount * sizeof(VMD::AliasData), 0);
202
int effectivePropertyIndex = cache->propertyIndexCacheStart;
203
int effectiveMethodIndex = cache->methodIndexCacheStart;
205
// For property change signal override detection.
206
// We prepopulate a set of signal names which already exist in the object,
207
// and throw an error if there is a signal/method defined as an override.
208
QSet<QString> seenSignals;
209
seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
210
QQmlPropertyCache *parentCache = cache;
211
while ((parentCache = parentCache->parent())) {
212
if (int pSigCount = parentCache->signalCount()) {
213
int pSigOffset = parentCache->signalOffset();
214
for (int i = pSigOffset; i < pSigCount; ++i) {
215
QQmlPropertyData *currPSig = parentCache->signal(i);
216
// XXX TODO: find a better way to get signal name from the property data :-/
217
for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
218
iter != parentCache->stringCache.end(); ++iter) {
219
if (currPSig == (*iter).second) {
220
seenSignals.insert(iter.key());
228
// First set up notify signals for properties - first normal, then var, then alias
229
enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
230
for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
232
if (ii == NSS_Var && varPropCount == 0) continue;
233
else if (ii == NSS_Alias && aliasCount == 0) continue;
235
const QV4::CompiledData::Property *p = obj->propertyTable();
236
for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
237
if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias ||
238
p->type == QV4::CompiledData::Property::Var)) ||
239
((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) ||
240
((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias)))
243
quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
244
QQmlPropertyData::IsVMESignal;
246
QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
247
seenSignals.insert(changedSigName);
249
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
254
for (uint i = 0; i < obj->nSignals; ++i) {
255
const QV4::CompiledData::Signal *s = obj->signalAt(i);
256
const int paramCount = s->nParameters;
258
QList<QByteArray> names;
259
QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
262
paramTypes[0] = paramCount;
264
for (int i = 0; i < paramCount; ++i) {
265
const QV4::CompiledData::Parameter *param = s->parameterAt(i);
266
names.append(stringAt(param->nameIndex).toUtf8());
267
if (param->type < builtinTypeCount) {
269
paramTypes[i + 1] = builtinTypes[param->type].metaType;
271
// lazily resolved type
272
Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
273
const QString customTypeName = stringAt(param->customTypeNameIndex);
274
QQmlType *qmltype = 0;
275
if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0))
276
COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(customTypeName));
278
if (qmltype->isComposite()) {
279
QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
281
Q_ASSERT(tdata->isComplete());
283
QQmlCompiledData *data = tdata->compiledData();
285
paramTypes[i + 1] = data->metaTypeId;
289
paramTypes[i + 1] = qmltype->typeId();
295
((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
297
quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
298
QQmlPropertyData::IsVMESignal;
300
flags |= QQmlPropertyData::HasArguments;
302
QString signalName = stringAt(s->nameIndex);
303
if (seenSignals.contains(signalName))
304
COMPILE_EXCEPTION(s, tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
305
seenSignals.insert(signalName);
307
cache->appendSignal(signalName, flags, effectiveMethodIndex++,
308
paramCount?paramTypes.constData():0, names);
313
const quint32 *functionIndex = obj->functionOffsetTable();
314
for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) {
315
const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex);
316
int paramCount = s->nFormals;
318
quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
321
flags |= QQmlPropertyData::HasArguments;
323
QString slotName = stringAt(s->nameIndex);
324
if (seenSignals.contains(slotName))
325
COMPILE_EXCEPTION(s, tr("Duplicate method name: invalid override of property change signal or superclass signal"));
326
// Note: we don't append slotName to the seenSignals list, since we don't
327
// protect against overriding change signals or methods with properties.
329
const quint32 *formalsIndices = s->formalsTable();
330
QList<QByteArray> parameterNames;
331
parameterNames.reserve(paramCount);
332
for (int i = 0; i < paramCount; ++i)
333
parameterNames << stringAt(formalsIndices[i]).toUtf8();
335
cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
339
// Dynamic properties (except var and aliases)
340
int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
341
/* const QV4::CompiledData::Property* */ p = obj->propertyTable();
342
for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
344
if (p->type == QV4::CompiledData::Property::Alias ||
345
p->type == QV4::CompiledData::Property::Var)
348
int propertyType = 0;
349
int vmePropertyType = 0;
350
quint32 propertyFlags = 0;
352
if (p->type < builtinTypeCount) {
353
propertyType = builtinTypes[p->type].metaType;
354
vmePropertyType = propertyType;
356
if (p->type == QV4::CompiledData::Property::Variant)
357
propertyFlags |= QQmlPropertyData::IsQVariant;
359
Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
360
p->type == QV4::CompiledData::Property::Custom);
362
QQmlType *qmltype = 0;
363
if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) {
364
COMPILE_EXCEPTION(p, tr("Invalid property type"));
368
if (qmltype->isComposite()) {
369
QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
371
Q_ASSERT(tdata->isComplete());
373
QQmlCompiledData *data = tdata->compiledData();
375
if (p->type == QV4::CompiledData::Property::Custom) {
376
propertyType = data->metaTypeId;
377
vmePropertyType = QMetaType::QObjectStar;
379
propertyType = data->listMetaTypeId;
380
vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
385
if (p->type == QV4::CompiledData::Property::Custom) {
386
propertyType = qmltype->typeId();
387
vmePropertyType = QMetaType::QObjectStar;
389
propertyType = qmltype->qListTypeId();
390
vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
394
if (p->type == QV4::CompiledData::Property::Custom)
395
propertyFlags |= QQmlPropertyData::IsQObjectDerived;
397
propertyFlags |= QQmlPropertyData::IsQList;
400
if ((!p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
401
propertyFlags |= QQmlPropertyData::IsWritable;
404
QString propertyName = stringAt(p->nameIndex);
405
if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
406
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
407
propertyType, effectiveSignalIndex);
409
effectiveSignalIndex++;
411
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
412
(vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
413
vmd->propertyCount++;
416
// Now do var properties
417
/* const QV4::CompiledData::Property* */ p = obj->propertyTable();
418
for (quint32 i = 0; i < obj->nProperties; ++i, ++p) {
420
if (p->type != QV4::CompiledData::Property::Var)
423
quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
424
if (!p->flags & QV4::CompiledData::Property::IsReadOnly)
425
propertyFlags |= QQmlPropertyData::IsWritable;
427
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
428
(vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
429
vmd->propertyCount++;
430
((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
432
QString propertyName = stringAt(p->nameIndex);
433
if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
434
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
435
QMetaType::QVariant, effectiveSignalIndex);
437
effectiveSignalIndex++;
440
// Alias property count. Actual data is setup in buildDynamicMetaAliases
441
((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
443
// Dynamic slot data - comes after the property data
444
/*const quint32* */functionIndex = obj->functionOffsetTable();
445
for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) {
446
const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex);
448
VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ###
450
/* s->location.start.line */0 }; // ###
452
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
453
VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
461
74
static void removeBindingOnProperty(QObject *o, int index)
463
76
int coreIndex = index & 0x0000FFFF;
606
361
case QVariant::String: {
607
if (binding->type == QV4::CompiledData::Binding::Type_String) {
608
QString value = binding->valueAsString(&qmlUnit->header);
610
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
612
recordError(binding->location, tr("Invalid property assignment: string expected"));
362
Q_ASSERT(binding->evaluatesToString());
363
QString value = binding->valueAsString(&qmlUnit->header);
365
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
616
368
case QVariant::StringList: {
617
if (binding->type == QV4::CompiledData::Binding::Type_String) {
618
QStringList value(binding->valueAsString(&qmlUnit->header));
620
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
622
recordError(binding->location, tr("Invalid property assignment: string or string list expected"));
369
Q_ASSERT(binding->evaluatesToString());
370
QStringList value(binding->valueAsString(&qmlUnit->header));
372
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
626
375
case QVariant::ByteArray: {
627
if (binding->type == QV4::CompiledData::Binding::Type_String) {
628
QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
630
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
632
recordError(binding->location, tr("Invalid property assignment: byte array expected"));
376
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
377
QByteArray value(binding->valueAsString(&qmlUnit->header).toUtf8());
379
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
636
382
case QVariant::Url: {
637
if (binding->type == QV4::CompiledData::Binding::Type_String) {
638
QString string = binding->valueAsString(&qmlUnit->header);
639
// Encoded dir-separators defeat QUrl processing - decode them first
640
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
641
QUrl value = string.isEmpty() ? QUrl() : this->url.resolved(QUrl(string));
642
// Apply URL interceptor
643
if (engine->urlInterceptor())
644
value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
646
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
648
recordError(binding->location, tr("Invalid property assignment: url expected"));
383
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
384
QString string = binding->valueAsString(&qmlUnit->header);
385
// Encoded dir-separators defeat QUrl processing - decode them first
386
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
387
QUrl value = string.isEmpty() ? QUrl() : compiledData->url.resolved(QUrl(string));
388
// Apply URL interceptor
389
if (engine->urlInterceptor())
390
value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
392
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
652
395
case QVariant::UInt: {
653
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
654
double d = binding->valueAsNumber();
655
if (double(uint(d)) == d) {
656
uint value = uint(d);
658
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
662
recordError(binding->location, tr("Invalid property assignment: unsigned int expected"));
396
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
397
double d = binding->valueAsNumber();
398
uint value = uint(d);
400
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
665
404
case QVariant::Int: {
666
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
667
double d = binding->valueAsNumber();
668
if (double(int(d)) == d) {
671
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
675
recordError(binding->location, tr("Invalid property assignment: int expected"));
405
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
406
double d = binding->valueAsNumber();
409
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
678
413
case QMetaType::Float: {
679
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
680
float value = float(binding->valueAsNumber());
682
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
684
recordError(binding->location, tr("Invalid property assignment: number expected"));
414
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
415
float value = float(binding->valueAsNumber());
417
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
688
420
case QVariant::Double: {
689
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
690
double value = binding->valueAsNumber();
692
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
694
recordError(binding->location, tr("Invalid property assignment: number expected"));
421
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
422
double value = binding->valueAsNumber();
424
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
698
427
case QVariant::Color: {
700
429
uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(&qmlUnit->header), &ok);
703
struct { void *data[4]; } buffer;
704
if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
705
argv[0] = reinterpret_cast<void *>(&buffer);
706
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
709
recordError(binding->location, tr("Invalid property assignment: color expected"));
431
struct { void *data[4]; } buffer;
432
if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) {
433
argv[0] = reinterpret_cast<void *>(&buffer);
434
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
714
439
case QVariant::Date: {
716
441
QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(&qmlUnit->header), &ok);
719
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
721
recordError(binding->location, tr("Invalid property assignment: date expected"));
444
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
725
447
case QVariant::Time: {
727
449
QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(&qmlUnit->header), &ok);
730
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
732
recordError(binding->location, tr("Invalid property assignment: time expected"));
452
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
736
455
case QVariant::DateTime: {
738
457
QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(&qmlUnit->header), &ok);
741
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
743
recordError(binding->location, tr("Invalid property assignment: datetime expected"));
458
// ### VME compatibility :(
460
const qint64 date = value.date().toJulianDay();
461
const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay();
462
value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
466
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
747
469
#endif // QT_NO_DATESTRING
748
470
case QVariant::Point: {
750
472
QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
753
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
755
recordError(binding->location, tr("Invalid property assignment: point expected"));
475
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
759
478
case QVariant::PointF: {
761
480
QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
764
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
766
recordError(binding->location, tr("Invalid property assignment: point expected"));
483
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
770
486
case QVariant::Size: {
772
488
QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
775
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
777
recordError(binding->location, tr("Invalid property assignment: size expected"));
491
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
781
494
case QVariant::SizeF: {
783
496
QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
786
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
788
recordError(binding->location, tr("Invalid property assignment: size expected"));
499
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
792
502
case QVariant::Rect: {
794
504
QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
797
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
799
recordError(binding->location, tr("Invalid property assignment: point expected"));
507
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
803
510
case QVariant::RectF: {
805
512
QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
808
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
810
recordError(binding->location, tr("Invalid property assignment: point expected"));
515
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
814
518
case QVariant::Bool: {
815
if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
816
bool value = binding->valueAsBoolean();
818
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
820
recordError(binding->location, tr("Invalid property assignment: boolean expected"));
519
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
520
bool value = binding->valueAsBoolean();
522
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
824
525
case QVariant::Vector3D: {
845
if (QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec))) {
846
argv[0] = reinterpret_cast<void *>(&vec);
847
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
849
recordError(binding->location, tr("Invalid property assignment: 4D vector expected"));
545
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(&qmlUnit->header), &vec, sizeof(vec));
548
argv[0] = reinterpret_cast<void *>(&vec);
549
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
853
552
case QVariant::RegExp:
854
recordError(binding->location, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
553
Q_ASSERT(!"not possible");
857
556
// generate single literal value assignment to a list property if required
858
557
if (property->propType == qMetaTypeId<QList<qreal> >()) {
859
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
861
value.append(binding->valueAsNumber());
862
argv[0] = reinterpret_cast<void *>(&value);
863
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
865
recordError(binding->location, tr("Invalid property assignment: real or array of reals expected"));
558
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
560
value.append(binding->valueAsNumber());
561
argv[0] = reinterpret_cast<void *>(&value);
562
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
868
564
} else if (property->propType == qMetaTypeId<QList<int> >()) {
869
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
870
double n = binding->valueAsNumber();
871
if (double(int(n)) == n) {
873
value.append(int(n));
874
argv[0] = reinterpret_cast<void *>(&value);
875
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
878
recordError(binding->location, tr("Invalid property assignment: int or array of ints expected"));
565
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
566
double n = binding->valueAsNumber();
568
value.append(int(n));
569
argv[0] = reinterpret_cast<void *>(&value);
570
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
882
572
} else if (property->propType == qMetaTypeId<QList<bool> >()) {
883
if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
885
value.append(binding->valueAsBoolean());
886
argv[0] = reinterpret_cast<void *>(&value);
887
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
889
recordError(binding->location, tr("Invalid property assignment: bool or array of bools expected"));
573
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
575
value.append(binding->valueAsBoolean());
576
argv[0] = reinterpret_cast<void *>(&value);
577
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
892
579
} else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
893
if (binding->type == QV4::CompiledData::Binding::Type_String) {
894
QString urlString = binding->valueAsString(&qmlUnit->header);
895
QUrl u = urlString.isEmpty() ? QUrl() : this->url.resolved(QUrl(urlString));
898
argv[0] = reinterpret_cast<void *>(&value);
899
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
901
recordError(binding->location, tr("Invalid property assignment: url or array of urls expected"));
580
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
581
QString urlString = binding->valueAsString(&qmlUnit->header);
582
QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url.resolved(QUrl(urlString));
585
argv[0] = reinterpret_cast<void *>(&value);
586
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
904
588
} else if (property->propType == qMetaTypeId<QList<QString> >()) {
905
if (binding->type == QV4::CompiledData::Binding::Type_String) {
906
QList<QString> value;
907
value.append(binding->valueAsString(&qmlUnit->header));
908
argv[0] = reinterpret_cast<void *>(&value);
909
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
911
recordError(binding->location, tr("Invalid property assignment: string or array of strings expected"));
589
Q_ASSERT(binding->evaluatesToString());
590
QList<QString> value;
591
value.append(binding->valueAsString(&qmlUnit->header));
592
argv[0] = reinterpret_cast<void *>(&value);
593
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv);
914
595
} else if (property->propType == qMetaTypeId<QJSValue>()) {
1202
void QmlObjectCreator::setupFunctions()
987
void QQmlObjectCreator::setupFunctions()
1204
989
QV4::Scope scope(_qmlContext);
1205
990
QV4::ScopedValue function(scope);
1206
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(_qobject);
1208
992
const quint32 *functionIdx = _compiledObject->functionOffsetTable();
1209
993
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
1210
QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[*functionIdx];
1211
const QString name = runtimeFunction->name->toQString();
994
QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[*functionIdx];
995
const QString name = runtimeFunction->name()->toQString();
1213
997
QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
1214
998
if (!property->isVMEFunction())
1217
function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction);
1218
vme->setVmeMethod(property->coreIndex, function);
1001
function = QV4::FunctionObject::createScriptFunction(_qmlContext, runtimeFunction);
1002
_vmeMetaObject->setVmeMethod(property->coreIndex, function);
1222
QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
1006
void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
1009
error.setUrl(compiledData->url);
1010
error.setLine(location.line);
1011
error.setColumn(location.column);
1012
error.setDescription(description);
1016
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
1018
QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler);
1224
1019
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
1226
1021
bool isComponent = false;
1227
1022
QObject *instance = 0;
1023
QQmlData *ddata = 0;
1024
QQmlCustomParser *customParser = 0;
1025
QQmlParserStatus *parserStatus = 0;
1026
bool installPropertyCache = true;
1028
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
1229
1029
if (compiledData->isComponent(index)) {
1230
1030
isComponent = true;
1231
1031
QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
1032
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"),
1033
context->url, obj->location.line, obj->location.column));
1232
1034
QQmlComponentPrivate::get(component)->creationContext = context;
1233
1035
instance = component;
1036
ddata = QQmlData::get(instance, /*create*/true);
1235
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
1237
QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
1238
QQmlType *type = typeRef.type;
1038
QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
1040
installPropertyCache = !typeRef->isFullyDynamicType;
1041
QQmlType *type = typeRef->type;
1043
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(),
1044
context->url, obj->location.line, obj->location.column));
1240
1045
instance = type->create();
1241
1046
if (!instance) {
1242
1047
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
1051
const int parserStatusCast = type->parserStatusCast();
1052
if (parserStatusCast != -1)
1053
parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
1055
customParser = type->customParser();
1057
if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation) {
1058
QQmlData *ddata = QQmlData::get(instance, /*create*/true);
1059
ddata->rootObjectInCreation = true;
1060
sharedState->rootContext->isRootObjectInCreation = false;
1063
sharedState->allCreatedObjects.push(instance);
1246
Q_ASSERT(typeRef.component);
1247
if (typeRef.component->qmlUnit->isSingleton())
1065
Q_ASSERT(typeRef->component);
1066
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->name,
1067
context->url, obj->location.line, obj->location.column));
1068
if (typeRef->component->qmlUnit->isSingleton())
1249
1070
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
1252
QmlObjectCreator subCreator(context, typeRef.component);
1074
QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data());
1253
1075
instance = subCreator.create();
1254
1076
if (!instance) {
1255
1077
errors += subCreator.errors;
1258
if (subCreator.componentAttached)
1259
subCreator.componentAttached->add(&componentAttached);
1260
allCreatedBindings << subCreator.allCreatedBindings;
1262
// ### use no-event variant
1264
instance->setParent(parent);
1082
QQml_setParent_noEvent(instance, parent);
1084
ddata = QQmlData::get(instance, /*create*/true);
1085
ddata->lineNumber = obj->location.line;
1086
ddata->columnNumber = obj->location.column;
1267
QQmlData *ddata = QQmlData::get(instance, /*create*/true);
1268
if (static_cast<quint32>(index) == qmlUnit->indexOfRootObject) {
1089
ddata->setImplicitDestructible();
1090
if (static_cast<quint32>(index) == qmlUnit->indexOfRootObject || ddata->rootObjectInCreation) {
1269
1091
if (ddata->context) {
1270
1092
Q_ASSERT(ddata->context != context);
1271
1093
Q_ASSERT(ddata->outerContext);
1282
1104
ddata->outerContext = context;
1107
parserStatus->classBegin();
1108
// push() the profiler state here, together with the parserStatus, as we'll pop() them
1110
Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler));
1111
sharedState->allParserStatusCallbacks.push(parserStatus);
1112
parserStatus->d = &sharedState->allParserStatusCallbacks.top();
1284
1115
QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
1285
1116
if (idEntry != objectIndexToId.constEnd())
1286
1117
context->setIdProperty(idEntry.value(), instance);
1289
QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index);
1290
Q_ASSERT(!cache.isNull());
1292
if (!populateInstance(index, instance, cache, instance, /*value type property*/0))
1119
// Register the context object in the context early on in order for pending binding
1120
// initialization to find it available.
1121
if (isContextObject)
1122
context->contextObject = instance;
1124
QBitArray bindingsToSkip;
1126
QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index);
1127
if (entry != compiledData->customParserData.constEnd()) {
1128
customParser->setCustomData(instance, entry->compilationArtifact, compiledData);
1129
bindingsToSkip = entry->bindings;
1136
QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index);
1137
Q_ASSERT(!cache.isNull());
1138
if (installPropertyCache) {
1139
if (ddata->propertyCache)
1140
ddata->propertyCache->release();;
1141
ddata->propertyCache = cache;
1142
ddata->propertyCache->addref();
1145
QObject *scopeObject = instance;
1146
qSwap(_scopeObject, scopeObject);
1148
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
1149
QV4::Scope valueScope(v4);
1150
QV4::ScopedValue scopeObjectProtector(valueScope, ddata ? ddata->jsWrapper.value() : 0);
1151
Q_UNUSED(scopeObjectProtector);
1152
QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
1153
QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope));
1154
QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
1156
qSwap(_qmlContext, qmlContext);
1158
bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip);
1160
qSwap(_qmlContext, qmlContext);
1161
qSwap(_scopeObject, scopeObject);
1163
return result ? instance : 0;
1299
void QmlObjectCreator::finalize()
1166
QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
1168
Q_ASSERT(phase == ObjectsCreated || phase == Finalizing);
1171
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher(sharedState.data());
1172
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
1302
1175
QQmlTrace trace("VME Binding Enable");
1303
1176
trace.event("begin binding eval");
1305
Q_ASSERT(allCreatedBindings.isEmpty() || allCreatedBindings.isDetached());
1307
for (QLinkedList<QVector<QQmlAbstractBinding*> >::Iterator it = allCreatedBindings.begin(), end = allCreatedBindings.end();
1309
const QVector<QQmlAbstractBinding *> &bindings = *it;
1310
for (int i = 0; i < bindings.count(); ++i) {
1311
QQmlAbstractBinding *b = bindings.at(i);
1315
QQmlData *data = QQmlData::get(b->object());
1317
data->clearPendingBindingBit(b->propertyIndex());
1318
b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
1319
QQmlPropertyPrivate::DontRemoveBinding);
1178
while (!sharedState->allCreatedBindings.isEmpty()) {
1179
QQmlAbstractBinding *b = sharedState->allCreatedBindings.pop();
1183
QQmlData *data = QQmlData::get(b->object());
1185
data->clearPendingBindingBit(b->propertyIndex());
1186
b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
1187
QQmlPropertyPrivate::DontRemoveBinding);
1189
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1194
if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
1195
QQmlTrace trace("VME Component Complete");
1196
while (!sharedState->allParserStatusCallbacks.isEmpty()) {
1197
QQmlObjectCompletionProfiler profiler(&sharedState->profiler);
1198
QQmlParserStatus *status = sharedState->allParserStatusCallbacks.pop();
1200
if (status && status->d) {
1202
status->componentComplete();
1205
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1211
QQmlTrace trace("VME Finalize Callbacks");
1212
for (int ii = 0; ii < sharedState->finalizeCallbacks.count(); ++ii) {
1213
QQmlEnginePrivate::FinalizeCallback callback = sharedState->finalizeCallbacks.at(ii);
1214
QObject *obj = callback.first;
1216
void *args[] = { 0 };
1217
QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
1219
if (watcher.hasRecursed())
1222
sharedState->finalizeCallbacks.clear();
1325
1226
QQmlTrace trace("VME Component.onCompleted Callbacks");
1326
while (componentAttached) {
1327
QQmlComponentAttached *a = componentAttached;
1227
while (sharedState->componentAttached) {
1228
QQmlComponentAttached *a = sharedState->componentAttached;
1329
1230
QQmlData *d = QQmlData::get(a->parent());
1331
1232
Q_ASSERT(d->context);
1332
1233
a->add(&d->context->componentAttached);
1333
// ### designer if (componentCompleteEnabled())
1234
if (QQmlVME::componentCompleteEnabled())
1334
1235
emit a->completed();
1337
1237
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1344
bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache,
1345
QObject *scopeObjectForBindings, QQmlPropertyData *valueTypeProperty)
1244
return sharedState->rootContext;
1247
void QQmlObjectCreator::clear()
1249
if (phase == Done || phase == Finalizing || phase == Startup)
1251
Q_ASSERT(phase != Startup);
1253
while (!sharedState->allCreatedObjects.isEmpty())
1254
delete sharedState->allCreatedObjects.pop();
1259
bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip)
1347
1261
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
1349
Q_ASSERT(scopeObjectForBindings);
1351
1263
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
1353
qSwap(_propertyCache, cache);
1354
1265
qSwap(_qobject, instance);
1355
qSwap(_qobjectForBindings, scopeObjectForBindings);
1356
1266
qSwap(_valueTypeProperty, valueTypeProperty);
1357
1267
qSwap(_compiledObject, obj);
1358
1268
qSwap(_ddata, declarativeData);
1269
qSwap(_bindingTarget, bindingTarget);
1271
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
1272
QV4::Scope valueScope(v4);
1273
QV4::ScopedValue scopeObjectProtector(valueScope);
1275
QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index);
1360
1277
QQmlVMEMetaObject *vmeMetaObject = 0;
1361
1278
const QByteArray data = vmeMetaObjectData.value(index);
1362
1279
if (!data.isEmpty()) {
1280
Q_ASSERT(!cache.isNull());
1363
1281
// install on _object
1364
vmeMetaObject = new QQmlVMEMetaObject(_qobjectForBindings, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
1282
vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
1365
1283
if (_ddata->propertyCache)
1366
1284
_ddata->propertyCache->release();
1367
_ddata->propertyCache = _propertyCache;
1285
_ddata->propertyCache = cache;
1368
1286
_ddata->propertyCache->addref();
1287
scopeObjectProtector = _ddata->jsWrapper.value();
1370
vmeMetaObject = QQmlVMEMetaObject::get(_qobjectForBindings);
1289
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
1373
_ddata->lineNumber = _compiledObject->location.line;
1374
_ddata->columnNumber = _compiledObject->location.column;
1291
qSwap(_propertyCache, cache);
1376
1292
qSwap(_vmeMetaObject, vmeMetaObject);
1378
QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
1379
qSwap(_createdBindings, createdBindings);
1381
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
1382
QV4::Scope valueScope(v4);
1383
QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _qobjectForBindings));
1384
QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject));
1385
QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
1387
qSwap(_qmlContext, qmlContext);
1294
QBitArray bindingSkipList = bindingsToSkip;
1296
QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.find(index);
1297
if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) {
1298
if (bindingSkipList.isEmpty())
1299
bindingSkipList.resize(deferredBindings->count());
1301
for (int i = 0; i < deferredBindings->count(); ++i)
1302
if (deferredBindings->testBit(i))
1303
bindingSkipList.setBit(i);
1304
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
1305
deferData->deferredIdx = index;
1306
deferData->compiledData = compiledData;
1307
deferData->compiledData->addref();
1308
deferData->context = context;
1309
_ddata->deferredData = deferData;
1390
1313
setupFunctions();
1392
allCreatedBindings.append(_createdBindings);
1394
qSwap(_qmlContext, qmlContext);
1396
qSwap(_createdBindings, createdBindings);
1314
setupBindings(bindingSkipList);
1397
1316
qSwap(_vmeMetaObject, vmeMetaObject);
1398
qSwap(_propertyCache, cache);
1317
qSwap(_bindingTarget, bindingTarget);
1399
1318
qSwap(_ddata, declarativeData);
1400
1319
qSwap(_compiledObject, obj);
1401
1320
qSwap(_valueTypeProperty, valueTypeProperty);
1402
qSwap(_qobjectForBindings, scopeObjectForBindings);
1403
1321
qSwap(_qobject, instance);
1405
return errors.isEmpty();
1409
QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
1410
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
1411
const QList<QQmlPropertyCache *> &propertyCaches, QList<QByteArray> *vmeMetaObjectData,
1412
QHash<int, int> *objectIndexToIdForRoot,
1413
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent)
1414
: QQmlCompilePass(url, qmlUnit)
1415
, _componentIndex(-1)
1416
, _objectIndexToIdInScope(0)
1417
, resolvedTypes(resolvedTypes)
1418
, propertyCaches(propertyCaches)
1419
, vmeMetaObjectData(vmeMetaObjectData)
1420
, objectIndexToIdForRoot(objectIndexToIdForRoot)
1421
, objectIndexToIdPerComponent(objectIndexToIdPerComponent)
1425
bool QQmlComponentAndAliasResolver::resolve()
1427
Q_ASSERT(componentRoots.isEmpty());
1429
// Find objects that are Components. This is missing an extra pass
1430
// that finds implicitly defined components, i.e.
1431
// someProperty: Item { ... }
1432
// when someProperty _is_ a QQmlComponent. In that case the Item {}
1433
// should be implicitly surrounded by Component {}
1435
for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
1436
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
1437
if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
1440
QQmlCompiledData::TypeReference tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
1443
if (tref.type->metaObject() != &QQmlComponent::staticMetaObject)
1446
componentRoots.append(i);
1447
// Sanity checks: There can be only an (optional) id property and
1448
// a default property, that defines the component tree.
1451
std::sort(componentRoots.begin(), componentRoots.end());
1453
// For each component's tree, remember to which component the children
1455
for (int i = 0; i < componentRoots.count(); ++i) {
1456
const QV4::CompiledData::Object *component = qmlUnit->objectAt(componentRoots.at(i));
1458
if (component->nFunctions > 0)
1459
COMPILE_EXCEPTION(component, tr("Component objects cannot declare new functions."));
1460
if (component->nProperties > 0)
1461
COMPILE_EXCEPTION(component, tr("Component objects cannot declare new properties."));
1462
if (component->nSignals > 0)
1463
COMPILE_EXCEPTION(component, tr("Component objects cannot declare new signals."));
1465
if (component->nBindings == 0)
1466
COMPILE_EXCEPTION(component, tr("Cannot create empty component specification"));
1468
const QV4::CompiledData::Binding *rootBinding = component->bindingTable();
1469
if (component->nBindings > 1 || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
1470
COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
1472
_componentIndex = i;
1473
_idToObjectIndex.clear();
1475
_objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)];
1477
_objectsWithAliases.clear();
1479
if (!collectIdsAndAliases(rootBinding->value.objectIndex))
1482
if (!resolveAliases())
1486
// Collect ids and aliases for root
1487
_componentIndex = -1;
1488
_idToObjectIndex.clear();
1489
_objectIndexToIdInScope = objectIndexToIdForRoot;
1490
_objectsWithAliases.clear();
1492
collectIdsAndAliases(qmlUnit->indexOfRootObject);
1496
return errors.isEmpty();
1499
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
1501
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
1503
// Only include creatable types. Everything else is synthetic, such as group property
1505
if (_componentIndex != -1 && !stringAt(obj->inheritedTypeNameIndex).isEmpty())
1506
objectIndexToComponentIndex.insert(objectIndex, _componentIndex);
1508
QString id = stringAt(obj->idIndex);
1509
if (!id.isEmpty()) {
1510
if (_idToObjectIndex.contains(obj->idIndex)) {
1511
recordError(obj->locationOfIdProperty, tr("id is not unique"));
1514
_idToObjectIndex.insert(obj->idIndex, objectIndex);
1515
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
1518
const QV4::CompiledData::Property *property = obj->propertyTable();
1519
for (quint32 i = 0; i < obj->nProperties; ++i, ++property)
1520
if (property->type == QV4::CompiledData::Property::Alias) {
1521
_objectsWithAliases.append(objectIndex);
1525
const QV4::CompiledData::Binding *binding = obj->bindingTable();
1526
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
1527
if (binding->type != QV4::CompiledData::Binding::Type_Object
1528
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
1529
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
1532
// Stop at Component boundary
1533
if (std::binary_search(componentRoots.constBegin(), componentRoots.constEnd(), binding->value.objectIndex))
1536
if (!collectIdsAndAliases(binding->value.objectIndex))
1543
bool QQmlComponentAndAliasResolver::resolveAliases()
1545
foreach (int objectIndex, _objectsWithAliases) {
1546
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
1548
QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex);
1549
Q_ASSERT(propertyCache);
1551
int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
1552
int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
1553
int effectiveAliasIndex = 0;
1555
const QV4::CompiledData::Property *p = obj->propertyTable();
1556
for (quint32 propertyIndex = 0; propertyIndex < obj->nProperties; ++propertyIndex, ++p) {
1557
if (p->type != QV4::CompiledData::Property::Alias)
1560
const int idIndex = p->aliasIdValueIndex;
1561
const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
1562
if (targetObjectIndex == -1) {
1563
recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
1566
const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1);
1567
Q_ASSERT(targetId != -1);
1569
const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex);
1571
QStringRef property;
1572
QStringRef subProperty;
1574
const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
1575
if (propertySeparator != -1) {
1576
property = aliasPropertyValue.leftRef(propertySeparator);
1577
subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
1579
property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
1583
int notifySignal = -1;
1586
bool writable = false;
1587
bool resettable = false;
1589
quint32 propertyFlags = QQmlPropertyData::IsAlias;
1591
if (property.isEmpty()) {
1592
const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(targetObjectIndex);
1593
QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex);
1596
type = typeRef.type->typeId();
1598
type = typeRef.component->metaTypeId;
1600
flags |= QML_ALIAS_FLAG_PTR;
1601
propertyFlags |= QQmlPropertyData::IsQObjectDerived;
1603
QQmlPropertyCache *targetCache = propertyCaches.value(targetObjectIndex);
1604
Q_ASSERT(targetCache);
1605
QtQml::PropertyResolver resolver(targetCache);
1607
QQmlPropertyData *targetProperty = resolver.property(property.toString());
1608
if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
1609
recordError(p->aliasLocation, tr("Invalid alias location"));
1613
propIdx = targetProperty->coreIndex;
1614
type = targetProperty->propType;
1616
writable = targetProperty->isWritable();
1617
resettable = targetProperty->isResettable();
1618
notifySignal = targetProperty->notifyIndex;
1620
if (!subProperty.isEmpty()) {
1621
QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
1623
recordError(p->aliasLocation, tr("Invalid alias location"));
1629
int valueTypeIndex =
1630
valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData());
1631
if (valueTypeIndex == -1) {
1632
recordError(p->aliasLocation, tr("Invalid alias location"));
1635
Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
1637
propIdx |= (valueTypeIndex << 16);
1638
if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
1639
type = QVariant::Int;
1641
type = valueType->metaObject()->property(valueTypeIndex).userType();
1644
if (targetProperty->isEnum()) {
1645
type = QVariant::Int;
1648
propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask;
1650
if (targetProperty->isVarProperty())
1651
propertyFlags |= QQmlPropertyData::IsQVariant;
1653
if (targetProperty->isQObject())
1654
flags |= QML_ALIAS_FLAG_PTR;
1659
QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal };
1661
typedef QQmlVMEMetaData VMD;
1662
QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex];
1663
Q_ASSERT(!dynamicData.isEmpty());
1664
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
1665
*(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
1667
Q_ASSERT(dynamicData.isDetached());
1669
if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
1670
propertyFlags |= QQmlPropertyData::IsWritable;
1672
propertyFlags &= ~QQmlPropertyData::IsWritable;
1675
propertyFlags |= QQmlPropertyData::IsResettable;
1677
propertyFlags &= ~QQmlPropertyData::IsResettable;
1679
QString propertyName = stringAt(p->nameIndex);
1680
if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName;
1681
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
1682
type, effectiveSignalIndex++);
1690
QQmlPropertyValidator::QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
1691
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
1692
const QList<QQmlPropertyCache *> &propertyCaches, const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent)
1693
: QQmlCompilePass(url, qmlUnit)
1694
, resolvedTypes(resolvedTypes)
1695
, propertyCaches(propertyCaches)
1696
, objectIndexToIdPerComponent(objectIndexToIdPerComponent)
1700
bool QQmlPropertyValidator::validate()
1702
for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
1703
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
1704
if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
1710
QQmlPropertyCache *propertyCache = propertyCaches.value(i);
1711
Q_ASSERT(propertyCache);
1713
if (!validateObject(obj, i, propertyCache))
1719
bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache)
1721
PropertyResolver propertyResolver(propertyCache);
1723
QQmlPropertyData *defaultProperty = propertyCache->defaultProperty();
1725
const QV4::CompiledData::Binding *binding = obj->bindingTable();
1726
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
1727
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
1728
|| binding->type == QV4::CompiledData::Binding::Type_GroupProperty)
1731
const QString name = stringAt(binding->propertyNameIndex);
1733
bool bindingToDefaultProperty = false;
1735
bool notInRevision = false;
1736
QQmlPropertyData *pd = 0;
1737
if (!name.isEmpty()) {
1738
pd = propertyResolver.property(name, ¬InRevision);
1740
if (notInRevision) {
1741
QString typeName = stringAt(obj->inheritedTypeNameIndex);
1742
QQmlCompiledData::TypeReference type = resolvedTypes.value(objectIndex);
1744
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1746
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
1750
pd = defaultProperty;
1751
bindingToDefaultProperty = true;
1755
if (bindingToDefaultProperty) {
1756
COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
1758
COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
1322
qSwap(_propertyCache, cache);
1324
return errors.isEmpty();