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
57 QT_BEGIN_NAMESPACE
58
59 class QQmlPropertyCacheMethodArguments;
60 class QQmlPropertyData
61 {
62 public:
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 // The _otherBits (which "pad" the Flags struct to align it nicely) are used
88 // to store the relative property index. It will only get used when said index fits. See
89 // trySetStaticMetaCallFunction for details.
90 // (Note: this padding is done here, because certain compilers have surprising behavior
91 // when an enum is declared in-between two bit fields.)
92 enum { BitsLeftInFlags = 15 };
93 unsigned otherBits : BitsLeftInFlags; // align to 32 bits
94
95 // Members of the form aORb can only be a when type is not FunctionType, and only be
96 // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
97 // overloaded, and the accessor functions are used to get the correct value
98 //
99 // Moreover, isSignalHandler, isOverload and isCloned and isConstructor make only sense
100 // for functions, too (and could at a later point be reused for flags that only make sense
101 // for non-functions)
102 //
103 // Lastly, isDirect and isOverridden apply to both functions and non-functions
104 private:
105 unsigned isConstantORisVMEFunction : 1; // Has CONST flag OR Function was added by QML
106 unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
107 unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
108 unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
109 unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
110 unsigned isSignalHandler : 1; // Function is a signal handler
111 unsigned isOverload : 1; // Function is an overload of another function
112 unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
113 unsigned isConstructor : 1; // The function was marked is a constructor
114 unsigned isDirect : 1; // Exists on a C++ QMetaObject
115 unsigned isOverridden : 1; // Is overridden by a extension property
116 public:
117 unsigned type : 4; // stores an entry of Types
118
119 // Apply only to IsFunctions
120
121 // Internal QQmlPropertyCache flags
122 unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
123 unsigned overrideIndexIsProperty: 1;
124
125 inline Flags();
126 inline bool operator==(const Flags &other) const;
127 inline void copyPropertyTypeFlags(Flags from);
128
setIsConstantFlags129 void setIsConstant(bool b) {
130 Q_ASSERT(type != FunctionType);
131 isConstantORisVMEFunction = b;
132 }
133
setIsWritableFlags134 void setIsWritable(bool b) {
135 Q_ASSERT(type != FunctionType);
136 isWritableORhasArguments = b;
137 }
138
setIsResettableFlags139 void setIsResettable(bool b) {
140 Q_ASSERT(type != FunctionType);
141 isResettableORisSignal = b;
142 }
143
setIsAliasFlags144 void setIsAlias(bool b) {
145 Q_ASSERT(type != FunctionType);
146 isAliasORisVMESignal = b;
147 }
148
setIsFinalFlags149 void setIsFinal(bool b) {
150 Q_ASSERT(type != FunctionType);
151 isFinalORisV4Function = b;
152 }
153
setIsOverriddenFlags154 void setIsOverridden(bool b) {
155 isOverridden = b;
156 }
157
setIsDirectFlags158 void setIsDirect(bool b) {
159 isDirect = b;
160 }
161
setIsRequiredFlags162 void setIsRequired(bool b) {
163 Q_ASSERT(type != FunctionType);
164 isRequiredORisCloned = b;
165 }
166
setIsVMEFunctionFlags167 void setIsVMEFunction(bool b) {
168 Q_ASSERT(type == FunctionType);
169 isConstantORisVMEFunction = b;
170 }
setHasArgumentsFlags171 void setHasArguments(bool b) {
172 Q_ASSERT(type == FunctionType);
173 isWritableORhasArguments = b;
174 }
setIsSignalFlags175 void setIsSignal(bool b) {
176 Q_ASSERT(type == FunctionType);
177 isResettableORisSignal = b;
178 }
setIsVMESignalFlags179 void setIsVMESignal(bool b) {
180 Q_ASSERT(type == FunctionType);
181 isAliasORisVMESignal = b;
182 }
183
setIsV4FunctionFlags184 void setIsV4Function(bool b) {
185 Q_ASSERT(type == FunctionType);
186 isFinalORisV4Function = b;
187 }
188
setIsSignalHandlerFlags189 void setIsSignalHandler(bool b) {
190 Q_ASSERT(type == FunctionType);
191 isSignalHandler = b;
192 }
193
setIsOverloadFlags194 void setIsOverload(bool b) {
195 Q_ASSERT(type == FunctionType);
196 isOverload = b;
197 }
198
setIsClonedFlags199 void setIsCloned(bool b) {
200 Q_ASSERT(type == FunctionType);
201 isRequiredORisCloned = b;
202 }
203
setIsConstructorFlags204 void setIsConstructor(bool b) {
205 Q_ASSERT(type == FunctionType);
206 isConstructor = b;
207 }
208
209 };
210
211
212 inline bool operator==(const QQmlPropertyData &) const;
213
flags()214 Flags flags() const { return m_flags; }
setFlags(Flags f)215 void setFlags(Flags f)
216 {
217 unsigned otherBits = m_flags.otherBits;
218 m_flags = f;
219 m_flags.otherBits = otherBits;
220 }
221
isValid()222 bool isValid() const { return coreIndex() != -1; }
223
isConstant()224 bool isConstant() const { return !isFunction() && m_flags.isConstantORisVMEFunction; }
isWritable()225 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
setWritable(bool onoff)226 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
isResettable()227 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
isAlias()228 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
isFinal()229 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
isOverridden()230 bool isOverridden() const { return m_flags.isOverridden; }
isDirect()231 bool isDirect() const { return m_flags.isDirect; }
isRequired()232 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
hasStaticMetaCallFunction()233 bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
isFunction()234 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
isQObject()235 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
isEnum()236 bool isEnum() const { return m_flags.type == Flags::EnumType; }
isQList()237 bool isQList() const { return m_flags.type == Flags::QListType; }
isQmlBinding()238 bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
isQJSValue()239 bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
isVarProperty()240 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
isQVariant()241 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
isVMEFunction()242 bool isVMEFunction() const { return isFunction() && m_flags.isConstantORisVMEFunction; }
hasArguments()243 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
isSignal()244 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
isVMESignal()245 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
isV4Function()246 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
isSignalHandler()247 bool isSignalHandler() const { return m_flags.isSignalHandler; }
isOverload()248 bool isOverload() const { return m_flags.isOverload; }
setOverload(bool onoff)249 void setOverload(bool onoff) { m_flags.isOverload = onoff; }
isCloned()250 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
isConstructor()251 bool isConstructor() const { return m_flags.isConstructor; }
252
hasOverride()253 bool hasOverride() const { return overrideIndex() >= 0; }
hasRevision()254 bool hasRevision() const { return revision() != 0; }
255
isFullyResolved()256 bool isFullyResolved() const { return !m_flags.notFullyResolved; }
257
propType()258 int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; }
setPropType(int pt)259 void setPropType(int pt)
260 {
261 Q_ASSERT(pt >= 0);
262 Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
263 m_propType = quint16(pt);
264 }
265
notifyIndex()266 int notifyIndex() const { return m_notifyIndex; }
setNotifyIndex(int idx)267 void setNotifyIndex(int idx)
268 {
269 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
270 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
271 m_notifyIndex = qint16(idx);
272 }
273
overrideIndexIsProperty()274 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
setOverrideIndexIsProperty(bool onoff)275 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
276
overrideIndex()277 int overrideIndex() const { return m_overrideIndex; }
setOverrideIndex(int idx)278 void setOverrideIndex(int idx)
279 {
280 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
281 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
282 m_overrideIndex = qint16(idx);
283 }
284
coreIndex()285 int coreIndex() const { return m_coreIndex; }
setCoreIndex(int idx)286 void setCoreIndex(int idx)
287 {
288 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
289 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
290 m_coreIndex = qint16(idx);
291 }
292
revision()293 quint8 revision() const { return m_revision; }
setRevision(quint8 rev)294 void setRevision(quint8 rev)
295 {
296 Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
297 m_revision = quint8(rev);
298 }
299
300 /* If a property is a C++ type, then we store the minor
301 * version of this type.
302 * This is required to resolve property or signal revisions
303 * if this property is used as a grouped property.
304 *
305 * Test.qml
306 * property TextEdit someTextEdit: TextEdit {}
307 *
308 * Test {
309 * someTextEdit.preeditText: "test" //revision 7
310 * someTextEdit.onEditingFinished: console.log("test") //revision 6
311 * }
312 *
313 * To determine if these properties with revisions are available we need
314 * the minor version of TextEdit as imported in Test.qml.
315 *
316 */
317
typeMinorVersion()318 quint8 typeMinorVersion() const { return m_typeMinorVersion; }
setTypeMinorVersion(quint8 rev)319 void setTypeMinorVersion(quint8 rev)
320 {
321 Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
322 m_typeMinorVersion = quint8(rev);
323 }
324
arguments()325 QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
setArguments(QQmlPropertyCacheMethodArguments * args)326 void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
327
metaObjectOffset()328 int metaObjectOffset() const { return m_metaObjectOffset; }
setMetaObjectOffset(int off)329 void setMetaObjectOffset(int off)
330 {
331 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
332 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
333 m_metaObjectOffset = qint16(off);
334 }
335
staticMetaCallFunction()336 StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
trySetStaticMetaCallFunction(StaticMetaCallFunction f,unsigned relativePropertyIndex)337 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
338 {
339 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
340 m_flags.otherBits = relativePropertyIndex;
341 m_staticMetaCallFunction = f;
342 }
343 }
relativePropertyIndex()344 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
345
346 static Flags flagsForProperty(const QMetaProperty &);
347 void load(const QMetaProperty &);
348 void load(const QMetaMethod &);
349 QString name(QObject *) const;
350 QString name(const QMetaObject *) const;
351
352 void markAsOverrideOf(QQmlPropertyData *predecessor);
353
readProperty(QObject * target,void * property)354 inline void readProperty(QObject *target, void *property) const
355 {
356 void *args[] = { property, nullptr };
357 readPropertyWithArgs(target, args);
358 }
359
readPropertyWithArgs(QObject * target,void * args[])360 inline void readPropertyWithArgs(QObject *target, void *args[]) const
361 {
362 if (hasStaticMetaCallFunction())
363 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
364 else if (isDirect())
365 target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
366 else
367 QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
368 }
369
writeProperty(QObject * target,void * value,WriteFlags flags)370 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
371 {
372 int status = -1;
373 void *argv[] = { value, nullptr, &status, &flags };
374 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
375 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
376 else if (flags.testFlag(BypassInterceptor) && isDirect())
377 target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
378 else
379 QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
380 return true;
381 }
382
defaultSignalFlags()383 static Flags defaultSignalFlags()
384 {
385 Flags f;
386 f.type = Flags::FunctionType;
387 f.setIsSignal(true);
388 f.setIsVMESignal(true);
389 return f;
390 }
391
defaultSlotFlags()392 static Flags defaultSlotFlags()
393 {
394 Flags f;
395 f.type = Flags::FunctionType;
396 f.setIsVMEFunction(true);
397 return f;
398 }
399
400 private:
401 friend class QQmlPropertyCache;
402 void lazyLoad(const QMetaProperty &);
403 void lazyLoad(const QMetaMethod &);
notFullyResolved()404 bool notFullyResolved() const { return m_flags.notFullyResolved; }
405
406 Flags m_flags;
407 qint16 m_coreIndex = -1;
408 quint16 m_propType = 0;
409
410 // The notify index is in the range returned by QObjectPrivate::signalIndex().
411 // This is different from QMetaMethod::methodIndex().
412 qint16 m_notifyIndex = -1;
413 qint16 m_overrideIndex = -1;
414
415 quint8 m_revision = 0;
416 quint8 m_typeMinorVersion = 0;
417 qint16 m_metaObjectOffset = -1;
418
419 QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
420 StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
421 };
422
423 #if QT_POINTER_SIZE == 4
424 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
425 #else // QT_POINTER_SIZE == 8
426 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
427 #endif
428
429 bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
430 {
431 return flags() == other.flags() &&
432 propType() == other.propType() &&
433 coreIndex() == other.coreIndex() &&
434 notifyIndex() == other.notifyIndex() &&
435 revision() == other.revision();
436 }
437
Flags()438 QQmlPropertyData::Flags::Flags()
439 : otherBits(0)
440 , isConstantORisVMEFunction(false)
441 , isWritableORhasArguments(false)
442 , isResettableORisSignal(false)
443 , isAliasORisVMESignal(false)
444 , isFinalORisV4Function(false)
445 , isSignalHandler(false)
446 , isOverload(false)
447 , isRequiredORisCloned(false)
448 , isConstructor(false)
449 , isDirect(false)
450 , isOverridden(false)
451 , type(OtherType)
452 , notFullyResolved(false)
453 , overrideIndexIsProperty(false)
454 {}
455
456 bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
457 {
458 return isConstantORisVMEFunction == other.isConstantORisVMEFunction &&
459 isWritableORhasArguments == other.isWritableORhasArguments &&
460 isResettableORisSignal == other.isResettableORisSignal &&
461 isAliasORisVMESignal == other.isAliasORisVMESignal &&
462 isFinalORisV4Function == other.isFinalORisV4Function &&
463 isOverridden == other.isOverridden &&
464 isSignalHandler == other.isSignalHandler &&
465 isRequiredORisCloned == other.isRequiredORisCloned &&
466 type == other.type &&
467 isConstructor == other.isConstructor &&
468 notFullyResolved == other.notFullyResolved &&
469 overrideIndexIsProperty == other.overrideIndexIsProperty;
470 }
471
copyPropertyTypeFlags(QQmlPropertyData::Flags from)472 void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
473 {
474 switch (from.type) {
475 case QObjectDerivedType:
476 case EnumType:
477 case QListType:
478 case QmlBindingType:
479 case QJSValueType:
480 case QVariantType:
481 type = from.type;
482 }
483 }
484
485 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
486
487 QT_END_NAMESPACE
488
489 #endif // QQMLPROPERTYDATA_P_H
490