1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4variantobject_p.h"
5#include "qv4functionobject_p.h"
6#include <private/qqmlvaluetypewrapper_p.h>
7#include <private/qv4qobjectwrapper_p.h>
8
9QT_BEGIN_NAMESPACE
10
11using namespace QV4;
12
13DEFINE_OBJECT_VTABLE(VariantObject);
14
15void Heap::VariantObject::init()
16{
17 Object::init();
18 scarceData = new ExecutionEngine::ScarceResourceData;
19}
20
21void Heap::VariantObject::init(const QMetaType type, const void *data)
22{
23 Object::init();
24 scarceData = new ExecutionEngine::ScarceResourceData(type, data);
25 if (isScarce())
26 removeVmePropertyReference();
27}
28
29bool VariantObject::Data::isScarce() const
30{
31 int t = data().userType();
32 return t == QMetaType::QPixmap || t == QMetaType::QImage;
33}
34
35bool VariantObject::virtualIsEqualTo(Managed *m, Managed *other)
36{
37 Q_ASSERT(m->as<QV4::VariantObject>());
38 QV4::VariantObject *lv = static_cast<QV4::VariantObject *>(m);
39
40 if (QV4::VariantObject *rv = other->as<QV4::VariantObject>())
41 return lv->d()->data() == rv->d()->data();
42
43 if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>())
44 return v->isEqual(value: lv->d()->data());
45
46 return false;
47}
48
49void VariantObject::addVmePropertyReference() const
50{
51 if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) {
52 // remove from the ep->scarceResources list
53 // since it is now no longer eligible to be
54 // released automatically by the engine.
55 d()->addVmePropertyReference();
56 }
57}
58
59void VariantObject::removeVmePropertyReference() const
60{
61 if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) {
62 // and add to the ep->scarceResources list
63 // since it is now eligible to be released
64 // automatically by the engine.
65 d()->removeVmePropertyReference();
66 }
67}
68
69
70void VariantPrototype::init()
71{
72 defineDefaultProperty(QStringLiteral("preserve"), code: method_preserve, argumentCount: 0);
73 defineDefaultProperty(QStringLiteral("destroy"), code: method_destroy, argumentCount: 0);
74 defineDefaultProperty(name: engine()->id_valueOf(), code: method_valueOf, argumentCount: 0);
75 defineDefaultProperty(name: engine()->id_toString(), code: method_toString, argumentCount: 0);
76}
77
78ReturnedValue VariantPrototype::method_preserve(const FunctionObject *, const Value *thisObject, const Value *, int)
79{
80 const VariantObject *o = thisObject->as<QV4::VariantObject>();
81 if (o && o->d()->isScarce())
82 o->d()->addVmePropertyReference();
83 RETURN_UNDEFINED();
84}
85
86ReturnedValue VariantPrototype::method_destroy(const FunctionObject *, const Value *thisObject, const Value *, int)
87{
88 const VariantObject *o = thisObject->as<QV4::VariantObject>();
89 if (o) {
90 if (o->d()->isScarce())
91 o->d()->addVmePropertyReference();
92 o->d()->data() = QVariant();
93 }
94 RETURN_UNDEFINED();
95}
96
97ReturnedValue VariantPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
98{
99 ExecutionEngine *v4 = b->engine();
100 const VariantObject *o = thisObject->as<QV4::VariantObject>();
101 if (!o)
102 RETURN_UNDEFINED();
103 const QVariant variant = o->d()->data();
104 QString result = variant.toString();
105 if (result.isEmpty() && !variant.canConvert(targetType: QMetaType(QMetaType::QString))) {
106 QDebug dbg(&result);
107 dbg << variant;
108 // QDebug appends a space, we're not interested in continuing the stream so we chop it off.
109 // Can't use nospace() because it would affect the debug-stream operator of the variant.
110 result.chop(n: 1);
111 }
112 return Encode(v4->newString(s: result));
113}
114
115ReturnedValue VariantPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
116{
117 const VariantObject *o = thisObject->as<QV4::VariantObject>();
118 if (o) {
119 QVariant v = o->d()->data();
120 switch (v.userType()) {
121 case QMetaType::UnknownType:
122 return Encode::undefined();
123 case QMetaType::QString:
124 return Encode(b->engine()->newString(s: v.toString()));
125 case QMetaType::Int:
126 return Encode(v.toInt());
127 case QMetaType::Double:
128 case QMetaType::UInt:
129 return Encode(v.toDouble());
130 case QMetaType::Bool:
131 return Encode(v.toBool());
132 default:
133 if (QMetaType(v.metaType()).flags() & QMetaType::IsEnumeration)
134 if (v.metaType().sizeOf() <= qsizetype(sizeof(int)))
135 return Encode(v.toInt());
136 if (v.canConvert<double>())
137 return Encode(v.toDouble());
138 if (v.canConvert<int>())
139 return Encode(v.toInt());
140 if (v.canConvert<uint>())
141 return Encode(v.toUInt());
142 if (v.canConvert<bool>())
143 return Encode(v.toBool());
144 if (v.canConvert<QString>())
145 return Encode(b->engine()->newString(s: v.toString()));
146 break;
147 }
148 }
149 return thisObject->asReturnedValue();
150}
151
152QT_END_NAMESPACE
153

source code of qtdeclarative/src/qml/jsruntime/qv4variantobject.cpp