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 "qqmlvaluetype_p.h"
41
42#include <QtCore/qmutex.h>
43#include <private/qqmlglobal_p.h>
44#include <QtCore/qdebug.h>
45#include <private/qqmlengine_p.h>
46#include <private/qmetaobjectbuilder_p.h>
47#if QT_CONFIG(qml_itemmodel)
48#include <private/qqmlmodelindexvaluetype_p.h>
49#endif
50
51Q_DECLARE_METATYPE(QQmlProperty)
52
53QT_BEGIN_NAMESPACE
54
55namespace {
56
57struct QQmlValueTypeFactoryImpl
58{
59 QQmlValueTypeFactoryImpl();
60 ~QQmlValueTypeFactoryImpl();
61
62 bool isValueType(int idx);
63
64 const QMetaObject *metaObjectForMetaType(int);
65 QQmlValueType *valueType(int);
66
67 QQmlValueType *valueTypes[QMetaType::User];
68 QHash<int, QQmlValueType *> userTypes;
69 QMutex mutex;
70
71 QQmlValueType invalidValueType;
72};
73
74QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
75{
76 std::fill_n(valueTypes, int(QMetaType::User), &invalidValueType);
77
78#if QT_CONFIG(qml_itemmodel)
79 // See types wrapped in qqmlmodelindexvaluetype_p.h
80 qRegisterMetaType<QItemSelectionRange>();
81#endif
82}
83
84QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
85{
86 for (QQmlValueType *type : valueTypes) {
87 if (type != &invalidValueType)
88 delete type;
89 }
90 qDeleteAll(c: userTypes);
91}
92
93bool isInternalType(int idx)
94{
95 // Qt internal types
96 switch (idx) {
97 case QMetaType::UnknownType:
98 case QMetaType::QStringList:
99 case QMetaType::QObjectStar:
100 case QMetaType::VoidStar:
101 case QMetaType::Nullptr:
102 case QMetaType::QVariant:
103 case QMetaType::QLocale:
104 case QMetaType::QImage: // scarce type, keep as QVariant
105 case QMetaType::QPixmap: // scarce type, keep as QVariant
106 return true;
107 default:
108 return false;
109 }
110}
111
112bool QQmlValueTypeFactoryImpl::isValueType(int idx)
113{
114 if (idx < 0 || isInternalType(idx))
115 return false;
116
117 return valueType(idx) != nullptr;
118}
119
120const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
121{
122 switch (t) {
123 case QMetaType::QPoint:
124 return &QQmlPointValueType::staticMetaObject;
125 case QMetaType::QPointF:
126 return &QQmlPointFValueType::staticMetaObject;
127 case QMetaType::QSize:
128 return &QQmlSizeValueType::staticMetaObject;
129 case QMetaType::QSizeF:
130 return &QQmlSizeFValueType::staticMetaObject;
131 case QMetaType::QRect:
132 return &QQmlRectValueType::staticMetaObject;
133 case QMetaType::QRectF:
134 return &QQmlRectFValueType::staticMetaObject;
135 case QMetaType::QEasingCurve:
136 return &QQmlEasingValueType::staticMetaObject;
137#if QT_CONFIG(qml_itemmodel)
138 case QMetaType::QModelIndex:
139 return &QQmlModelIndexValueType::staticMetaObject;
140 case QMetaType::QPersistentModelIndex:
141 return &QQmlPersistentModelIndexValueType::staticMetaObject;
142#endif
143 default:
144#if QT_CONFIG(qml_itemmodel)
145 if (t == qMetaTypeId<QItemSelectionRange>())
146 return &QQmlItemSelectionRangeValueType::staticMetaObject;
147#endif
148 if (t == qMetaTypeId<QQmlProperty>())
149 return &QQmlPropertyValueType::staticMetaObject;
150 if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
151 return mo;
152 break;
153 }
154
155 QMetaType metaType(t);
156 if (metaType.flags() & QMetaType::IsGadget)
157 return metaType.metaObject();
158 return nullptr;
159}
160
161QQmlValueType *QQmlValueTypeFactoryImpl::valueType(int idx)
162{
163 if (idx >= (int)QMetaType::User) {
164 // Protect the hash with a mutex
165 mutex.lock();
166
167 QHash<int, QQmlValueType *>::iterator it = userTypes.find(key: idx);
168 if (it == userTypes.end()) {
169 QQmlValueType *vt = nullptr;
170 if (const QMetaObject *mo = metaObjectForMetaType(t: idx))
171 vt = new QQmlValueType(idx, mo);
172 it = userTypes.insert(key: idx, value: vt);
173 }
174
175 mutex.unlock();
176 return *it;
177 }
178
179 QQmlValueType *rv = valueTypes[idx];
180 if (rv == &invalidValueType) {
181 // No need for mutex protection - the most we can lose is a valueType instance
182
183 // TODO: Investigate the performance/memory characteristics of
184 // removing the preallocated array
185 if (isInternalType(idx))
186 rv = valueTypes[idx] = nullptr;
187 else if (const QMetaObject *mo = metaObjectForMetaType(t: idx))
188 rv = valueTypes[idx] = new QQmlValueType(idx, mo);
189 else
190 rv = valueTypes[idx] = nullptr;
191 }
192
193 return rv;
194}
195
196}
197
198Q_GLOBAL_STATIC(QQmlValueTypeFactoryImpl, factoryImpl);
199
200bool QQmlValueTypeFactory::isValueType(int idx)
201{
202 return factoryImpl()->isValueType(idx);
203}
204
205QQmlValueType *QQmlValueTypeFactory::valueType(int idx)
206{
207 return factoryImpl()->valueType(idx);
208}
209
210const QMetaObject *QQmlValueTypeFactory::metaObjectForMetaType(int type)
211{
212 return factoryImpl()->metaObjectForMetaType(t: type);
213}
214
215void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, int versionMinor)
216{
217 qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, qmlName: "Easing");
218}
219
220QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
221 : metaType(typeId)
222{
223 QMetaObjectBuilder builder(gadgetMetaObject);
224 dynamicMetaObject = builder.toMetaObject();
225 *static_cast<QMetaObject*>(this) = *dynamicMetaObject;
226}
227
228QQmlValueType::~QQmlValueType()
229{
230 ::free(ptr: dynamicMetaObject);
231}
232
233QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, int index)
234{
235 return engine ? QQmlEnginePrivate::get(e: engine)->valueTypeInstance(typeIndex: index) : nullptr;
236}
237
238QQmlGadgetPtrWrapper::QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent)
239 : QObject(parent), m_gadgetPtr(valueType->create())
240{
241 QObjectPrivate *d = QObjectPrivate::get(o: this);
242 Q_ASSERT(!d->metaObject);
243 d->metaObject = valueType;
244}
245
246QQmlGadgetPtrWrapper::~QQmlGadgetPtrWrapper()
247{
248 QObjectPrivate *d = QObjectPrivate::get(o: this);
249 static_cast<const QQmlValueType *>(d->metaObject)->destroy(gadgetPtr: m_gadgetPtr);
250 d->metaObject = nullptr;
251}
252
253void QQmlGadgetPtrWrapper::read(QObject *obj, int idx)
254{
255 Q_ASSERT(m_gadgetPtr);
256 void *a[] = { m_gadgetPtr, nullptr };
257 QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
258}
259
260void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
261{
262 Q_ASSERT(m_gadgetPtr);
263 int status = -1;
264 void *a[] = { m_gadgetPtr, nullptr, &status, &flags };
265 QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
266}
267
268QVariant QQmlGadgetPtrWrapper::value()
269{
270 Q_ASSERT(m_gadgetPtr);
271 return QVariant(metaTypeId(), m_gadgetPtr);
272}
273
274void QQmlGadgetPtrWrapper::setValue(const QVariant &value)
275{
276 Q_ASSERT(m_gadgetPtr);
277 Q_ASSERT(metaTypeId() == value.userType());
278 const QQmlValueType *type = valueType();
279 type->destruct(gadgetPtr: m_gadgetPtr);
280 type->construct(gadgetPtr: m_gadgetPtr, copy: value.constData());
281}
282
283int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv)
284{
285 Q_ASSERT(m_gadgetPtr);
286 const QMetaObject *metaObject = valueType();
287 QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, metaObject: &metaObject, index: &id);
288 metaObject->d.static_metacall(static_cast<QObject *>(m_gadgetPtr), type, id, argv);
289 return id;
290}
291
292const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const
293{
294 const QObjectPrivate *d = QObjectPrivate::get(o: this);
295 return static_cast<const QQmlValueType *>(d->metaObject);
296}
297
298QAbstractDynamicMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
299{
300 return this;
301}
302
303void QQmlValueType::objectDestroyed(QObject *)
304{
305}
306
307int QQmlValueType::metaCall(QObject *object, QMetaObject::Call type, int _id, void **argv)
308{
309 return static_cast<QQmlGadgetPtrWrapper *>(object)->metaCall(type, id: _id, argv);
310}
311
312QString QQmlPointFValueType::toString() const
313{
314 return QString::asprintf(format: "QPointF(%g, %g)", v.x(), v.y());
315}
316
317qreal QQmlPointFValueType::x() const
318{
319 return v.x();
320}
321
322qreal QQmlPointFValueType::y() const
323{
324 return v.y();
325}
326
327void QQmlPointFValueType::setX(qreal x)
328{
329 v.setX(x);
330}
331
332void QQmlPointFValueType::setY(qreal y)
333{
334 v.setY(y);
335}
336
337
338int QQmlPointValueType::x() const
339{
340 return v.x();
341}
342
343int QQmlPointValueType::y() const
344{
345 return v.y();
346}
347
348void QQmlPointValueType::setX(int x)
349{
350 v.setX(x);
351}
352
353void QQmlPointValueType::setY(int y)
354{
355 v.setY(y);
356}
357
358
359QString QQmlSizeFValueType::toString() const
360{
361 return QString::asprintf(format: "QSizeF(%g, %g)", v.width(), v.height());
362}
363
364qreal QQmlSizeFValueType::width() const
365{
366 return v.width();
367}
368
369qreal QQmlSizeFValueType::height() const
370{
371 return v.height();
372}
373
374void QQmlSizeFValueType::setWidth(qreal w)
375{
376 v.setWidth(w);
377}
378
379void QQmlSizeFValueType::setHeight(qreal h)
380{
381 v.setHeight(h);
382}
383
384
385int QQmlSizeValueType::width() const
386{
387 return v.width();
388}
389
390int QQmlSizeValueType::height() const
391{
392 return v.height();
393}
394
395void QQmlSizeValueType::setWidth(int w)
396{
397 v.setWidth(w);
398}
399
400void QQmlSizeValueType::setHeight(int h)
401{
402 v.setHeight(h);
403}
404
405QString QQmlRectFValueType::toString() const
406{
407 return QString::asprintf(format: "QRectF(%g, %g, %g, %g)", v.x(), v.y(), v.width(), v.height());
408}
409
410qreal QQmlRectFValueType::x() const
411{
412 return v.x();
413}
414
415qreal QQmlRectFValueType::y() const
416{
417 return v.y();
418}
419
420void QQmlRectFValueType::setX(qreal x)
421{
422 v.moveLeft(pos: x);
423}
424
425void QQmlRectFValueType::setY(qreal y)
426{
427 v.moveTop(pos: y);
428}
429
430qreal QQmlRectFValueType::width() const
431{
432 return v.width();
433}
434
435qreal QQmlRectFValueType::height() const
436{
437 return v.height();
438}
439
440void QQmlRectFValueType::setWidth(qreal w)
441{
442 v.setWidth(w);
443}
444
445void QQmlRectFValueType::setHeight(qreal h)
446{
447 v.setHeight(h);
448}
449
450qreal QQmlRectFValueType::left() const
451{
452 return v.left();
453}
454
455qreal QQmlRectFValueType::right() const
456{
457 return v.right();
458}
459
460qreal QQmlRectFValueType::top() const
461{
462 return v.top();
463}
464
465qreal QQmlRectFValueType::bottom() const
466{
467 return v.bottom();
468}
469
470int QQmlRectValueType::x() const
471{
472 return v.x();
473}
474
475int QQmlRectValueType::y() const
476{
477 return v.y();
478}
479
480void QQmlRectValueType::setX(int x)
481{
482 v.moveLeft(pos: x);
483}
484
485void QQmlRectValueType::setY(int y)
486{
487 v.moveTop(pos: y);
488}
489
490int QQmlRectValueType::width() const
491{
492 return v.width();
493}
494
495int QQmlRectValueType::height() const
496{
497 return v.height();
498}
499
500void QQmlRectValueType::setWidth(int w)
501{
502 v.setWidth(w);
503}
504
505void QQmlRectValueType::setHeight(int h)
506{
507 v.setHeight(h);
508}
509
510int QQmlRectValueType::left() const
511{
512 return v.left();
513}
514
515int QQmlRectValueType::right() const
516{
517 return v.right();
518}
519
520int QQmlRectValueType::top() const
521{
522 return v.top();
523}
524
525int QQmlRectValueType::bottom() const
526{
527 return v.bottom();
528}
529
530QQmlEasingValueType::Type QQmlEasingValueType::type() const
531{
532 return (QQmlEasingValueType::Type)v.type();
533}
534
535qreal QQmlEasingValueType::amplitude() const
536{
537 return v.amplitude();
538}
539
540qreal QQmlEasingValueType::overshoot() const
541{
542 return v.overshoot();
543}
544
545qreal QQmlEasingValueType::period() const
546{
547 return v.period();
548}
549
550void QQmlEasingValueType::setType(QQmlEasingValueType::Type type)
551{
552 v.setType((QEasingCurve::Type)type);
553}
554
555void QQmlEasingValueType::setAmplitude(qreal amplitude)
556{
557 v.setAmplitude(amplitude);
558}
559
560void QQmlEasingValueType::setOvershoot(qreal overshoot)
561{
562 v.setOvershoot(overshoot);
563}
564
565void QQmlEasingValueType::setPeriod(qreal period)
566{
567 v.setPeriod(period);
568}
569
570void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant)
571{
572 if (customCurveVariant.isEmpty())
573 return;
574
575 if ((customCurveVariant.count() % 6) != 0)
576 return;
577
578 auto convert = [](const QVariant &v, qreal &r) {
579 bool ok;
580 r = v.toReal(ok: &ok);
581 return ok;
582 };
583
584 QEasingCurve newEasingCurve(QEasingCurve::BezierSpline);
585 for (int i = 0, ei = customCurveVariant.size(); i < ei; i += 6) {
586 qreal c1x, c1y, c2x, c2y, c3x, c3y;
587 if (!convert(customCurveVariant.at(i ), c1x)) return;
588 if (!convert(customCurveVariant.at(i: i + 1), c1y)) return;
589 if (!convert(customCurveVariant.at(i: i + 2), c2x)) return;
590 if (!convert(customCurveVariant.at(i: i + 3), c2y)) return;
591 if (!convert(customCurveVariant.at(i: i + 4), c3x)) return;
592 if (!convert(customCurveVariant.at(i: i + 5), c3y)) return;
593
594 const QPointF c1(c1x, c1y);
595 const QPointF c2(c2x, c2y);
596 const QPointF c3(c3x, c3y);
597
598 newEasingCurve.addCubicBezierSegment(c1, c2, endPoint: c3);
599 }
600
601 v = newEasingCurve;
602}
603
604QObject *QQmlPropertyValueType::object() const
605{
606 return v.object();
607}
608
609QString QQmlPropertyValueType::name() const
610{
611 return v.name();
612}
613
614QVariantList QQmlEasingValueType::bezierCurve() const
615{
616 QVariantList rv;
617 const QVector<QPointF> points = v.toCubicSpline();
618 rv.reserve(size: points.size() * 2);
619 for (const auto &point : points)
620 rv << QVariant(point.x()) << QVariant(point.y());
621 return rv;
622}
623
624QT_END_NAMESPACE
625
626#include "moc_qqmlvaluetype_p.cpp"
627

source code of qtdeclarative/src/qml/qml/qqmlvaluetype.cpp