1/****************************************************************************
2**
3** Copyright (C) 2019 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#ifndef QQMLPROPERTYDATA_P_H
41#define QQMLPROPERTYDATA_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <private/qobject_p.h>
55#include <QtCore/qglobal.h>
56
57QT_BEGIN_NAMESPACE
58
59class QQmlPropertyCacheMethodArguments;
60class QQmlPropertyData
61{
62public:
63 enum WriteFlag {
64 BypassInterceptor = 0x01,
65 DontRemoveBinding = 0x02,
66 RemoveBindingOnAliasWrite = 0x04
67 };
68 Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
69
70 typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
71
72 struct Flags {
73 friend class QQmlPropertyData;
74 enum Types {
75 OtherType = 0,
76 FunctionType = 1, // Is an invokable
77 QObjectDerivedType = 2, // Property type is a QObject* derived type
78 EnumType = 3, // Property type is an enum
79 QListType = 4, // Property type is a QML list
80 QmlBindingType = 5, // Property type is a QQmlBinding*
81 QJSValueType = 6, // Property type is a QScriptValue
82 // Gap, used to be V4HandleType
83 VarPropertyType = 8, // Property type is a "var" property of VMEMO
84 QVariantType = 9 // Property is a QVariant
85 };
86
87 // Members of the form aORb can only be a when type is not FunctionType, and only be
88 // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
89 // overloaded, and the accessor functions are used to get the correct value
90 //
91 // Moreover, isSignalHandler, isOverload and isCloned and isConstructor make only sense
92 // for functions, too (and could at a later point be reused for flags that only make sense
93 // for non-functions)
94 //
95 // Lastly, isDirect and isOverridden apply to both functions and non-functions
96 private:
97 quint16 isConstantORisVMEFunction : 1; // Has CONST flag OR Function was added by QML
98 quint16 isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
99 quint16 isResettableORisSignal : 1; // Has RESET function OR Function is a signal
100 quint16 isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
101 quint16 isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
102 quint16 isSignalHandler : 1; // Function is a signal handler
103 quint16 isOverload : 1; // Function is an overload of another function
104 quint16 isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
105 quint16 isConstructor : 1; // The function was marked is a constructor
106 quint16 isDirect : 1; // Exists on a C++ QMetaObject
107 quint16 isOverridden : 1; // Is overridden by a extension property
108 public:
109 quint16 type : 4; // stores an entry of Types
110
111 // Apply only to IsFunctions
112
113 // Internal QQmlPropertyCache flags
114 quint16 overrideIndexIsProperty: 1;
115
116 inline Flags();
117 inline bool operator==(const Flags &other) const;
118 inline void copyPropertyTypeFlags(Flags from);
119
120 void setIsConstant(bool b) {
121 Q_ASSERT(type != FunctionType);
122 isConstantORisVMEFunction = b;
123 }
124
125 void setIsWritable(bool b) {
126 Q_ASSERT(type != FunctionType);
127 isWritableORhasArguments = b;
128 }
129
130 void setIsResettable(bool b) {
131 Q_ASSERT(type != FunctionType);
132 isResettableORisSignal = b;
133 }
134
135 void setIsAlias(bool b) {
136 Q_ASSERT(type != FunctionType);
137 isAliasORisVMESignal = b;
138 }
139
140 void setIsFinal(bool b) {
141 Q_ASSERT(type != FunctionType);
142 isFinalORisV4Function = b;
143 }
144
145 void setIsOverridden(bool b) {
146 isOverridden = b;
147 }
148
149 void setIsDirect(bool b) {
150 isDirect = b;
151 }
152
153 void setIsRequired(bool b) {
154 Q_ASSERT(type != FunctionType);
155 isRequiredORisCloned = b;
156 }
157
158 void setIsVMEFunction(bool b) {
159 Q_ASSERT(type == FunctionType);
160 isConstantORisVMEFunction = b;
161 }
162 void setHasArguments(bool b) {
163 Q_ASSERT(type == FunctionType);
164 isWritableORhasArguments = b;
165 }
166 void setIsSignal(bool b) {
167 Q_ASSERT(type == FunctionType);
168 isResettableORisSignal = b;
169 }
170 void setIsVMESignal(bool b) {
171 Q_ASSERT(type == FunctionType);
172 isAliasORisVMESignal = b;
173 }
174
175 void setIsV4Function(bool b) {
176 Q_ASSERT(type == FunctionType);
177 isFinalORisV4Function = b;
178 }
179
180 void setIsSignalHandler(bool b) {
181 Q_ASSERT(type == FunctionType);
182 isSignalHandler = b;
183 }
184
185 void setIsOverload(bool b) {
186 Q_ASSERT(type == FunctionType);
187 isOverload = b;
188 }
189
190 void setIsCloned(bool b) {
191 Q_ASSERT(type == FunctionType);
192 isRequiredORisCloned = b;
193 }
194
195 void setIsConstructor(bool b) {
196 Q_ASSERT(type == FunctionType);
197 isConstructor = b;
198 }
199
200 };
201
202 Q_STATIC_ASSERT(sizeof(Flags) == sizeof(quint16));
203
204 inline bool operator==(const QQmlPropertyData &) const;
205
206 Flags flags() const { return m_flags; }
207 void setFlags(Flags f) { m_flags = f; }
208
209 bool isValid() const { return coreIndex() != -1; }
210
211 bool isConstant() const { return !isFunction() && m_flags.isConstantORisVMEFunction; }
212 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
213 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
214 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
215 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
216 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
217 bool isOverridden() const { return m_flags.isOverridden; }
218 bool isDirect() const { return m_flags.isDirect; }
219 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
220 bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
221 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
222 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
223 bool isEnum() const { return m_flags.type == Flags::EnumType; }
224 bool isQList() const { return m_flags.type == Flags::QListType; }
225 bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
226 bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
227 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
228 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
229 bool isVMEFunction() const { return isFunction() && m_flags.isConstantORisVMEFunction; }
230 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
231 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
232 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
233 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
234 bool isSignalHandler() const { return m_flags.isSignalHandler; }
235 bool isOverload() const { return m_flags.isOverload; }
236 void setOverload(bool onoff) { m_flags.isOverload = onoff; }
237 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
238 bool isConstructor() const { return m_flags.isConstructor; }
239
240 bool hasOverride() const { return overrideIndex() >= 0; }
241 bool hasRevision() const { return revision() != 0; }
242
243 // This is unsafe in the general case. The property might be in the process of getting
244 // resolved. Only use it if this case has been taken into account.
245 bool isResolved() const { return m_propTypeAndRelativePropIndex != 0; }
246
247 int propType() const
248 {
249 const quint32 type = m_propTypeAndRelativePropIndex & PropTypeMask;
250 Q_ASSERT(type > 0); // Property has to be fully resolved.
251 return type == PropTypeUnknown ? 0 : type;
252 }
253
254 void setPropType(int pt)
255 {
256 // You can only directly set the property type if you own the QQmlPropertyData.
257 // It must not be exposed to other threads before setting the type!
258 Q_ASSERT(pt >= 0);
259 Q_ASSERT(uint(pt) < PropTypeUnknown);
260 m_propTypeAndRelativePropIndex
261 = (m_propTypeAndRelativePropIndex & RelativePropIndexMask)
262 | (pt == 0 ? PropTypeUnknown : quint32(pt));
263 }
264
265 int notifyIndex() const { return m_notifyIndex; }
266 void setNotifyIndex(int idx)
267 {
268 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
269 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
270 m_notifyIndex = qint16(idx);
271 }
272
273 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
274 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
275
276 int overrideIndex() const { return m_overrideIndex; }
277 void setOverrideIndex(int idx)
278 {
279 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
280 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
281 m_overrideIndex = qint16(idx);
282 }
283
284 int coreIndex() const { return m_coreIndex; }
285 void setCoreIndex(int idx)
286 {
287 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
288 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
289 m_coreIndex = qint16(idx);
290 }
291
292 quint8 revision() const { return m_revision; }
293 void setRevision(quint8 rev)
294 {
295 Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
296 m_revision = quint8(rev);
297 }
298
299 /* If a property is a C++ type, then we store the minor
300 * version of this type.
301 * This is required to resolve property or signal revisions
302 * if this property is used as a grouped property.
303 *
304 * Test.qml
305 * property TextEdit someTextEdit: TextEdit {}
306 *
307 * Test {
308 * someTextEdit.preeditText: "test" //revision 7
309 * someTextEdit.onEditingFinished: console.log("test") //revision 6
310 * }
311 *
312 * To determine if these properties with revisions are available we need
313 * the minor version of TextEdit as imported in Test.qml.
314 *
315 */
316
317 quint8 typeMinorVersion() const { return m_typeMinorVersion; }
318 void setTypeMinorVersion(quint8 rev)
319 {
320 Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
321 m_typeMinorVersion = quint8(rev);
322 }
323
324 QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
325 bool setArguments(QQmlPropertyCacheMethodArguments *args)
326 {
327 return m_arguments.testAndSetRelease(expectedValue: nullptr, newValue: args);
328 }
329
330 int metaObjectOffset() const { return m_metaObjectOffset; }
331 void setMetaObjectOffset(int off)
332 {
333 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
334 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
335 m_metaObjectOffset = qint16(off);
336 }
337
338 StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
339 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
340 {
341 if (relativePropertyIndex > std::numeric_limits<quint16>::max())
342 return;
343
344 const quint16 propType = m_propTypeAndRelativePropIndex & PropTypeMask;
345 if (propType > 0) {
346 // We can do this because we know that resolve() has run at this point
347 // and we don't need to synchronize anymore. If we get a 0, that means it hasn't
348 // run or is currently in progress. We don't want to interfer and just go through
349 // the meta object.
350 m_propTypeAndRelativePropIndex
351 = propType | (relativePropertyIndex << RelativePropIndexShift);
352 m_staticMetaCallFunction = f;
353 }
354 }
355
356 quint16 relativePropertyIndex() const
357 {
358 Q_ASSERT(hasStaticMetaCallFunction());
359 return m_propTypeAndRelativePropIndex >> 16;
360 }
361
362 static Flags flagsForProperty(const QMetaProperty &);
363 void load(const QMetaProperty &);
364 void load(const QMetaMethod &);
365 QString name(QObject *) const;
366 QString name(const QMetaObject *) const;
367
368 void markAsOverrideOf(QQmlPropertyData *predecessor);
369
370 inline void readProperty(QObject *target, void *property) const
371 {
372 void *args[] = { property, nullptr };
373 readPropertyWithArgs(target, args);
374 }
375
376 inline void readPropertyWithArgs(QObject *target, void *args[]) const
377 {
378 if (hasStaticMetaCallFunction())
379 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
380 else if (isDirect())
381 target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
382 else
383 QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
384 }
385
386 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
387 {
388 int status = -1;
389 void *argv[] = { value, nullptr, &status, &flags };
390 if (flags.testFlag(flag: BypassInterceptor) && hasStaticMetaCallFunction())
391 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
392 else if (flags.testFlag(flag: BypassInterceptor) && isDirect())
393 target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
394 else
395 QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
396 return true;
397 }
398
399 static Flags defaultSignalFlags()
400 {
401 Flags f;
402 f.type = Flags::FunctionType;
403 f.setIsSignal(true);
404 f.setIsVMESignal(true);
405 return f;
406 }
407
408 static Flags defaultSlotFlags()
409 {
410 Flags f;
411 f.type = Flags::FunctionType;
412 f.setIsVMEFunction(true);
413 return f;
414 }
415
416private:
417 friend class QQmlPropertyCache;
418 void lazyLoad(const QMetaProperty &);
419 void lazyLoad(const QMetaMethod &);
420
421 enum {
422 PropTypeMask = 0x0000ffff,
423 RelativePropIndexMask = 0xffff0000,
424 RelativePropIndexShift = 16,
425 PropTypeUnknown = std::numeric_limits<quint16>::max(),
426 };
427 QAtomicInteger<quint32> m_propTypeAndRelativePropIndex;
428
429 Flags m_flags;
430 qint16 m_coreIndex = -1;
431
432 // The notify index is in the range returned by QObjectPrivate::signalIndex().
433 // This is different from QMetaMethod::methodIndex().
434 qint16 m_notifyIndex = -1;
435 qint16 m_overrideIndex = -1;
436
437 quint8 m_revision = 0;
438 quint8 m_typeMinorVersion = 0;
439 qint16 m_metaObjectOffset = -1;
440
441 QAtomicPointer<QQmlPropertyCacheMethodArguments> m_arguments;
442 StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
443};
444
445#if QT_POINTER_SIZE == 4
446 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
447#else // QT_POINTER_SIZE == 8
448 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
449#endif
450
451bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
452{
453 return flags() == other.flags() &&
454 propType() == other.propType() &&
455 coreIndex() == other.coreIndex() &&
456 notifyIndex() == other.notifyIndex() &&
457 revision() == other.revision();
458}
459
460QQmlPropertyData::Flags::Flags()
461 : isConstantORisVMEFunction(false)
462 , isWritableORhasArguments(false)
463 , isResettableORisSignal(false)
464 , isAliasORisVMESignal(false)
465 , isFinalORisV4Function(false)
466 , isSignalHandler(false)
467 , isOverload(false)
468 , isRequiredORisCloned(false)
469 , isConstructor(false)
470 , isDirect(false)
471 , isOverridden(false)
472 , type(OtherType)
473 , overrideIndexIsProperty(false)
474{}
475
476bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
477{
478 return isConstantORisVMEFunction == other.isConstantORisVMEFunction &&
479 isWritableORhasArguments == other.isWritableORhasArguments &&
480 isResettableORisSignal == other.isResettableORisSignal &&
481 isAliasORisVMESignal == other.isAliasORisVMESignal &&
482 isFinalORisV4Function == other.isFinalORisV4Function &&
483 isOverridden == other.isOverridden &&
484 isSignalHandler == other.isSignalHandler &&
485 isRequiredORisCloned == other.isRequiredORisCloned &&
486 type == other.type &&
487 isConstructor == other.isConstructor &&
488 overrideIndexIsProperty == other.overrideIndexIsProperty;
489}
490
491void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
492{
493 switch (from.type) {
494 case QObjectDerivedType:
495 case EnumType:
496 case QListType:
497 case QmlBindingType:
498 case QJSValueType:
499 case QVariantType:
500 type = from.type;
501 }
502}
503
504Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
505
506QT_END_NAMESPACE
507
508#endif // QQMLPROPERTYDATA_P_H
509

source code of qtdeclarative/src/qml/qml/qqmlpropertydata_p.h