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