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 "qv4variantobject_p.h"
41 #include "qv4functionobject_p.h"
42 #include "qv4objectproto_p.h"
43 #include <private/qqmlvaluetypewrapper_p.h>
44 #include <private/qv4qobjectwrapper_p.h>
45
46 QT_BEGIN_NAMESPACE
47
48 using namespace QV4;
49
50 DEFINE_OBJECT_VTABLE(VariantObject);
51
init()52 void Heap::VariantObject::init()
53 {
54 Object::init();
55 scarceData = new ExecutionEngine::ScarceResourceData;
56 }
57
init(const QVariant & value)58 void Heap::VariantObject::init(const QVariant &value)
59 {
60 Object::init();
61 scarceData = new ExecutionEngine::ScarceResourceData(value);
62 if (isScarce())
63 removeVmePropertyReference();
64 }
65
isScarce() const66 bool VariantObject::Data::isScarce() const
67 {
68 int t = data().userType();
69 return t == QMetaType::QPixmap || t == QMetaType::QImage;
70 }
71
virtualIsEqualTo(Managed * m,Managed * other)72 bool VariantObject::virtualIsEqualTo(Managed *m, Managed *other)
73 {
74 Q_ASSERT(m->as<QV4::VariantObject>());
75 QV4::VariantObject *lv = static_cast<QV4::VariantObject *>(m);
76
77 if (QV4::VariantObject *rv = other->as<QV4::VariantObject>())
78 return lv->d()->data() == rv->d()->data();
79
80 if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>())
81 return v->isEqual(lv->d()->data());
82
83 return false;
84 }
85
addVmePropertyReference() const86 void VariantObject::addVmePropertyReference() const
87 {
88 if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) {
89 // remove from the ep->scarceResources list
90 // since it is now no longer eligible to be
91 // released automatically by the engine.
92 d()->addVmePropertyReference();
93 }
94 }
95
removeVmePropertyReference() const96 void VariantObject::removeVmePropertyReference() const
97 {
98 if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) {
99 // and add to the ep->scarceResources list
100 // since it is now eligible to be released
101 // automatically by the engine.
102 d()->removeVmePropertyReference();
103 }
104 }
105
106
init()107 void VariantPrototype::init()
108 {
109 defineDefaultProperty(QStringLiteral("preserve"), method_preserve, 0);
110 defineDefaultProperty(QStringLiteral("destroy"), method_destroy, 0);
111 defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0);
112 defineDefaultProperty(engine()->id_toString(), method_toString, 0);
113 }
114
method_preserve(const FunctionObject *,const Value * thisObject,const Value *,int)115 ReturnedValue VariantPrototype::method_preserve(const FunctionObject *, const Value *thisObject, const Value *, int)
116 {
117 const VariantObject *o = thisObject->as<QV4::VariantObject>();
118 if (o && o->d()->isScarce())
119 o->d()->addVmePropertyReference();
120 RETURN_UNDEFINED();
121 }
122
method_destroy(const FunctionObject *,const Value * thisObject,const Value *,int)123 ReturnedValue VariantPrototype::method_destroy(const FunctionObject *, const Value *thisObject, const Value *, int)
124 {
125 const VariantObject *o = thisObject->as<QV4::VariantObject>();
126 if (o) {
127 if (o->d()->isScarce())
128 o->d()->addVmePropertyReference();
129 o->d()->data() = QVariant();
130 }
131 RETURN_UNDEFINED();
132 }
133
method_toString(const FunctionObject * b,const Value * thisObject,const Value *,int)134 ReturnedValue VariantPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
135 {
136 ExecutionEngine *v4 = b->engine();
137 const VariantObject *o = thisObject->as<QV4::VariantObject>();
138 if (!o)
139 RETURN_UNDEFINED();
140 const QVariant variant = o->d()->data();
141 QString result = variant.toString();
142 if (result.isEmpty() && !variant.canConvert(QMetaType::QString)) {
143 QDebug dbg(&result);
144 dbg << variant;
145 // QDebug appends a space, we're not interested in continuing the stream so we chop it off.
146 // Can't use nospace() because it would affect the debug-stream operator of the variant.
147 result.chop(1);
148 }
149 return Encode(v4->newString(result));
150 }
151
method_valueOf(const FunctionObject * b,const Value * thisObject,const Value *,int)152 ReturnedValue VariantPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
153 {
154 const VariantObject *o = thisObject->as<QV4::VariantObject>();
155 if (o) {
156 QVariant v = o->d()->data();
157 switch (v.userType()) {
158 case QMetaType::UnknownType:
159 return Encode::undefined();
160 case QMetaType::QString:
161 return Encode(b->engine()->newString(v.toString()));
162 case QMetaType::Int:
163 return Encode(v.toInt());
164 case QMetaType::Double:
165 case QMetaType::UInt:
166 return Encode(v.toDouble());
167 case QMetaType::Bool:
168 return Encode(v.toBool());
169 default:
170 if (QMetaType::typeFlags(v.userType()) & QMetaType::IsEnumeration)
171 RETURN_RESULT(Encode(v.toInt()));
172 break;
173 }
174 }
175 return thisObject->asReturnedValue();
176 }
177
178 QT_END_NAMESPACE
179