1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qqmltypewrapper_p.h"
41
42 #include <private/qqmlengine_p.h>
43 #include <private/qqmlcontext_p.h>
44 #include <private/qqmlmetaobject_p.h>
45 #include <private/qqmltypedata_p.h>
46
47 #include <private/qjsvalue_p.h>
48 #include <private/qv4functionobject_p.h>
49 #include <private/qv4objectproto_p.h>
50 #include <private/qv4qobjectwrapper_p.h>
51 #include <private/qv4identifiertable_p.h>
52 #include <private/qv4lookup_p.h>
53
54 QT_BEGIN_NAMESPACE
55
56 using namespace QV4;
57
58 DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
59 DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
60
init()61 void Heap::QQmlTypeWrapper::init()
62 {
63 Object::init();
64 mode = IncludeEnums;
65 object.init();
66 }
67
destroy()68 void Heap::QQmlTypeWrapper::destroy()
69 {
70 QQmlType::derefHandle(typePrivate);
71 typePrivate = nullptr;
72 if (typeNamespace)
73 typeNamespace->release();
74 object.destroy();
75 Object::destroy();
76 }
77
type() const78 QQmlType Heap::QQmlTypeWrapper::type() const
79 {
80 return QQmlType(typePrivate);
81 }
82
isSingleton() const83 bool QQmlTypeWrapper::isSingleton() const
84 {
85 return d()->type().isSingleton();
86 }
87
singletonObject() const88 QObject* QQmlTypeWrapper::singletonObject() const
89 {
90 if (!isSingleton())
91 return nullptr;
92
93 QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
94 return e->singletonInstance<QObject*>(d()->type());
95 }
96
toVariant() const97 QVariant QQmlTypeWrapper::toVariant() const
98 {
99 if (!isSingleton())
100 return QVariant::fromValue<QObject *>(d()->object);
101
102 QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
103 const QQmlType type = d()->type();
104 if (type.isQJSValueSingleton())
105 return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
106
107 return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
108 }
109
110
111 // Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
create(QV4::ExecutionEngine * engine,QObject * o,const QQmlType & t,Heap::QQmlTypeWrapper::TypeNameMode mode)112 ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
113 Heap::QQmlTypeWrapper::TypeNameMode mode)
114 {
115 Q_ASSERT(t.isValid());
116 Scope scope(engine);
117
118 Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
119 w->d()->mode = mode; w->d()->object = o;
120 w->d()->typePrivate = t.priv();
121 QQmlType::refHandle(w->d()->typePrivate);
122 return w.asReturnedValue();
123 }
124
125 // Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
126 // namespace.
create(QV4::ExecutionEngine * engine,QObject * o,const QQmlRefPointer<QQmlTypeNameCache> & t,const QQmlImportRef * importNamespace,Heap::QQmlTypeWrapper::TypeNameMode mode)127 ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t, const QQmlImportRef *importNamespace,
128 Heap::QQmlTypeWrapper::TypeNameMode mode)
129 {
130 Q_ASSERT(t);
131 Q_ASSERT(importNamespace);
132 Scope scope(engine);
133
134 Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
135 w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t.data(); w->d()->importNamespace = importNamespace;
136 t->addref();
137 return w.asReturnedValue();
138 }
139
enumForSingleton(QV4::ExecutionEngine * v4,String * name,QObject * qobjectSingleton,const QQmlType & type,bool * ok)140 static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
141 const QQmlType &type, bool *ok)
142 {
143 Q_ASSERT(ok != nullptr);
144 int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok);
145 if (*ok)
146 return value;
147
148 // ### Optimize
149 QByteArray enumName = name->toQString().toUtf8();
150 const QMetaObject *metaObject = qobjectSingleton->metaObject();
151 for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
152 QMetaEnum e = metaObject->enumerator(ii);
153 value = e.keyToValue(enumName.constData(), ok);
154 if (*ok)
155 return value;
156 }
157 *ok = false;
158 return -1;
159 }
160
throwLowercaseEnumError(QV4::ExecutionEngine * v4,String * name,const QQmlType & type)161 static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, const QQmlType &type)
162 {
163 const QString message =
164 QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.")
165 .arg(name->toQString()).arg(QLatin1String(type.typeName()));
166 return v4->throwTypeError(message);
167 }
168
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)169 ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
170 {
171 // Keep this code in sync with ::virtualResolveLookupGetter
172 Q_ASSERT(m->as<QQmlTypeWrapper>());
173
174 if (!id.isString())
175 return Object::virtualGet(m, id, receiver, hasProperty);
176
177 QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
178 QV4::Scope scope(v4);
179 ScopedString name(scope, id.asStringOrSymbol());
180
181 Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(m));
182
183 if (hasProperty)
184 *hasProperty = true;
185
186 QQmlContextData *context = v4->callingQmlContext();
187
188 QObject *object = w->d()->object;
189 QQmlType type = w->d()->type();
190
191 if (type.isValid()) {
192
193 // singleton types are handled differently to other types.
194 if (type.isSingleton()) {
195 QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
196 QJSValue scriptSingleton;
197 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
198 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
199 // check for enum value
200 const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
201 if (includeEnums && name->startsWithUpper()) {
202 bool ok = false;
203 int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
204 if (ok)
205 return QV4::Value::fromInt32(value).asReturnedValue();
206
207 value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
208 if (ok) {
209 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
210 enumWrapper->d()->typePrivate = type.priv();
211 QQmlType::refHandle(enumWrapper->d()->typePrivate);
212 enumWrapper->d()->scopeEnumIndex = value;
213 return enumWrapper.asReturnedValue();
214 }
215 }
216
217 // check for property.
218 bool ok;
219 const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
220 if (hasProperty)
221 *hasProperty = ok;
222
223 // Warn when attempting to access a lowercased enum value, singleton case
224 if (!ok && includeEnums && !name->startsWithUpper()) {
225 enumForSingleton(v4, name, qobjectSingleton, type, &ok);
226 if (ok)
227 return throwLowercaseEnumError(v4, name, type);
228 }
229
230 return result;
231 }
232 } else if (type.isQJSValueSingleton()) {
233 QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
234 if (!scriptSingleton.isUndefined()) {
235 // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
236 QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton));
237 if (!!o)
238 return o->get(name);
239 }
240 }
241
242 // Fall through to base implementation
243
244 } else {
245
246 if (name->startsWithUpper()) {
247 bool ok = false;
248 int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
249 if (ok)
250 return QV4::Value::fromInt32(value).asReturnedValue();
251
252 value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
253 if (ok) {
254 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
255 enumWrapper->d()->typePrivate = type.priv();
256 QQmlType::refHandle(enumWrapper->d()->typePrivate);
257 enumWrapper->d()->scopeEnumIndex = value;
258 return enumWrapper.asReturnedValue();
259 }
260
261 // Fall through to base implementation
262
263 } else if (w->d()->object) {
264 QObject *ao = qmlAttachedPropertiesObject(
265 object,
266 type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine())));
267 if (ao)
268 return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
269
270 // Fall through to base implementation
271 }
272
273 // Fall through to base implementation
274 }
275
276 // Fall through to base implementation
277
278 } else if (w->d()->typeNamespace) {
279 Q_ASSERT(w->d()->importNamespace);
280 QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace);
281
282 if (r.isValid()) {
283 if (r.type.isValid()) {
284 return create(scope.engine, object, r.type, w->d()->mode);
285 } else if (r.scriptIndex != -1) {
286 QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
287 return scripts->get(r.scriptIndex);
288 } else if (r.importNamespace) {
289 return create(scope.engine, object, context->imports, r.importNamespace);
290 }
291
292 return QV4::Encode::undefined();
293
294 }
295
296 // Fall through to base implementation
297
298 } else {
299 Q_ASSERT(!"Unreachable");
300 }
301
302 bool ok = false;
303 const ReturnedValue result = Object::virtualGet(m, id, receiver, &ok);
304 if (hasProperty)
305 *hasProperty = ok;
306
307 // Warn when attempting to access a lowercased enum value, non-singleton case
308 if (!ok && type.isValid() && !type.isSingleton() && !name->startsWithUpper()) {
309 bool enumOk = false;
310 type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk);
311 if (enumOk)
312 return throwLowercaseEnumError(v4, name, type);
313 }
314
315 return result;
316 }
317
318
virtualPut(Managed * m,PropertyKey id,const Value & value,Value * receiver)319 bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
320 {
321 if (!id.isString())
322 return Object::virtualPut(m, id, value, receiver);
323
324
325 Q_ASSERT(m->as<QQmlTypeWrapper>());
326 QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
327 QV4::Scope scope(w);
328 if (scope.engine->hasException)
329 return false;
330
331 ScopedString name(scope, id.asStringOrSymbol());
332 QQmlContextData *context = scope.engine->callingQmlContext();
333
334 QQmlType type = w->d()->type();
335 if (type.isValid() && !type.isSingleton() && w->d()->object) {
336 QObject *object = w->d()->object;
337 QQmlEngine *e = scope.engine->qmlEngine();
338 QObject *ao = qmlAttachedPropertiesObject(
339 object, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e)));
340 if (ao)
341 return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
342 return false;
343 } else if (type.isSingleton()) {
344 QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
345 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
346 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
347 return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
348
349 } else {
350 QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
351 if (!scriptSingleton.isUndefined()) {
352 QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
353 if (!apiprivate) {
354 QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
355 scope.engine->throwError(error);
356 return false;
357 } else {
358 return apiprivate->put(name, value);
359 }
360 }
361 }
362 }
363
364 return false;
365 }
366
virtualGetOwnProperty(const Managed * m,PropertyKey id,Property * p)367 PropertyAttributes QQmlTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
368 {
369 if (id.isString()) {
370 Scope scope(m);
371 ScopedString n(scope, id.asStringOrSymbol());
372 // ### Implement more efficiently.
373 bool hasProperty = false;
374 static_cast<const Object *>(m)->get(n, &hasProperty);
375 return hasProperty ? Attr_Data : Attr_Invalid;
376 }
377
378 return QV4::Object::virtualGetOwnProperty(m, id, p);
379 }
380
virtualIsEqualTo(Managed * a,Managed * b)381 bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
382 {
383 Q_ASSERT(a->as<QV4::QQmlTypeWrapper>());
384 QV4::QQmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QQmlTypeWrapper *>(a);
385 if (QV4::QQmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QQmlTypeWrapper>())
386 return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant();
387 else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>())
388 return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object();
389
390 return false;
391 }
392
virtualInstanceOf(const Object * typeObject,const Value & var)393 ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
394 {
395 Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
396 const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
397 QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
398 QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
399
400 // can only compare a QObject* against a QML type
401 const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
402 if (!wrapper)
403 return QV4::Encode(false);
404
405 // in case the wrapper outlived the QObject*
406 const QObject *wrapperObject = wrapper->object();
407 if (!wrapperObject)
408 return engine->throwTypeError();
409
410 const int myTypeId = typeWrapper->d()->type().typeId();
411 QQmlMetaObject myQmlType;
412 if (myTypeId == 0) {
413 // we're a composite type; a composite type cannot be equal to a
414 // non-composite object instance (Rectangle{} is never an instance of
415 // CustomRectangle)
416 QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false);
417 Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
418 if (!theirDData->compilationUnit)
419 return Encode(false);
420
421 QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
422 ExecutableCompilationUnit *cu = td->compilationUnit();
423 myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
424 } else {
425 myQmlType = qenginepriv->metaObjectForType(myTypeId);
426 }
427
428 const QMetaObject *theirType = wrapperObject->metaObject();
429
430 return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
431 }
432
virtualResolveLookupGetter(const Object * object,ExecutionEngine * engine,Lookup * lookup)433 ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
434 {
435 // Keep this code in sync with ::virtualGet
436 PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
437 if (!id.isString())
438 return Object::virtualResolveLookupGetter(object, engine, lookup);
439 Scope scope(engine);
440
441 const QQmlTypeWrapper *This = static_cast<const QQmlTypeWrapper *>(object);
442 ScopedString name(scope, id.asStringOrSymbol());
443 QQmlContextData *qmlContext = engine->callingQmlContext();
444
445 Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(This));
446 QQmlType type = w->d()->type();
447
448 if (type.isValid()) {
449
450 if (type.isSingleton()) {
451 QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
452 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
453 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
454 const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
455 if (!includeEnums || !name->startsWithUpper()) {
456 QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
457 if (ddata && ddata->propertyCache) {
458 QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
459 if (property) {
460 ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
461 lookup->qobjectLookup.qmlTypeIc = This->internalClass();
462 lookup->qobjectLookup.ic = val->objectValue()->internalClass();
463 lookup->qobjectLookup.propertyCache = ddata->propertyCache;
464 lookup->qobjectLookup.propertyCache->addref();
465 lookup->qobjectLookup.propertyData = property;
466 lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
467 return lookup->getter(lookup, engine, *object);
468 }
469 // Fall through to base implementation
470 }
471 // Fall through to base implementation
472 }
473 // Fall through to base implementation
474 }
475 // Fall through to base implementation
476 }
477 // Fall through to base implementation
478 }
479
480 if (name->startsWithUpper()) {
481 bool ok = false;
482 int value = type.enumValue(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
483 if (ok) {
484 lookup->qmlEnumValueLookup.ic = This->internalClass();
485 lookup->qmlEnumValueLookup.encodedEnumValue
486 = QV4::Value::fromInt32(value).asReturnedValue();
487 lookup->getter = QQmlTypeWrapper::lookupEnumValue;
488 return lookup->getter(lookup, engine, *object);
489 }
490
491 value = type.scopedEnumIndex(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
492 if (ok) {
493 Scoped<QQmlScopedEnumWrapper> enumWrapper(
494 scope, engine->memoryManager->allocate<QQmlScopedEnumWrapper>());
495 enumWrapper->d()->typePrivate = type.priv();
496 QQmlType::refHandle(enumWrapper->d()->typePrivate);
497 enumWrapper->d()->scopeEnumIndex = value;
498
499 lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
500 lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
501 = static_cast<Heap::Object*>(enumWrapper->heapObject());
502 lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
503 return enumWrapper.asReturnedValue();
504 }
505 // Fall through to base implementation
506 }
507 // Fall through to base implementation
508 }
509 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
510 }
511
virtualResolveLookupSetter(Object * object,ExecutionEngine * engine,Lookup * lookup,const Value & value)512 bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
513 {
514 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
515 }
516
lookupSingletonProperty(Lookup * l,ExecutionEngine * engine,const Value & object)517 ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
518 {
519 const auto revertLookup = [l, engine, &object]() {
520 l->qobjectLookup.propertyCache->release();
521 l->qobjectLookup.propertyCache = nullptr;
522 l->getter = Lookup::getterGeneric;
523 return Lookup::getterGeneric(l, engine, object);
524 };
525
526 // we can safely cast to a QV4::Object here. If object is something else,
527 // the internal class won't match
528 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
529 if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
530 return revertLookup();
531
532 Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o);
533
534 QQmlType type = This->type();
535 if (!type.isValid())
536 return revertLookup();
537
538 if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
539 return revertLookup();
540
541 QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
542 QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
543 Q_ASSERT(qobjectSingleton);
544
545 Scope scope(engine);
546 ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
547 return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
548 }
549
lookupEnumValue(Lookup * l,ExecutionEngine * engine,const Value & base)550 ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
551 {
552 auto *o = static_cast<Heap::Object *>(base.heapObject());
553 if (!o || o->internalClass != l->qmlEnumValueLookup.ic) {
554 l->getter = Lookup::getterGeneric;
555 return Lookup::getterGeneric(l, engine, base);
556 }
557
558 return l->qmlEnumValueLookup.encodedEnumValue;
559 }
560
lookupScopedEnum(Lookup * l,ExecutionEngine * engine,const Value & base)561 ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base)
562 {
563 Scope scope(engine);
564 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
565 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
566
567 auto *o = static_cast<Heap::Object *>(base.heapObject());
568 if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
569 QQmlType::derefHandle(enumWrapper->d()->typePrivate);
570 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
571 l->getter = Lookup::getterGeneric;
572 return Lookup::getterGeneric(l, engine, base);
573 }
574
575 return enumWrapper.asReturnedValue();
576 }
577
destroy()578 void Heap::QQmlScopedEnumWrapper::destroy()
579 {
580 QQmlType::derefHandle(typePrivate);
581 typePrivate = nullptr;
582 Object::destroy();
583 }
584
type() const585 QQmlType Heap::QQmlScopedEnumWrapper::type() const
586 {
587 return QQmlType(typePrivate);
588 }
589
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)590 ReturnedValue QQmlScopedEnumWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
591 {
592 Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
593 if (!id.isString())
594 return Object::virtualGet(m, id, receiver, hasProperty);
595
596 const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
597 QV4::ExecutionEngine *v4 = resource->engine();
598 QV4::Scope scope(v4);
599 ScopedString name(scope, id.asStringOrSymbol());
600
601 QQmlType type = resource->d()->type();
602 int index = resource->d()->scopeEnumIndex;
603
604 bool ok = false;
605 int value = type.scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok);
606 if (hasProperty)
607 *hasProperty = ok;
608 if (ok)
609 return QV4::Value::fromInt32(value).asReturnedValue();
610
611 return Encode::undefined();
612 }
613
614 QT_END_NAMESPACE
615