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
56QT_BEGIN_NAMESPACE
57
58class QQmlPropertyCacheMethodArguments;
59class QQmlPropertyData
60{
61public:
62 enum WriteFlag {
63 BypassInterceptor = 0x01,
64 DontRemoveBinding = 0x02,
65 RemoveBindingOnAliasWrite = 0x04
66 };
67 Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
68
69 typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
70
71 struct Flags {
72 enum Types {
73 OtherType = 0,
74 FunctionType = 1, // Is an invokable
75 QObjectDerivedType = 2, // Property type is a QObject* derived type
76 EnumType = 3, // Property type is an enum
77 QListType = 4, // Property type is a QML list
78 QmlBindingType = 5, // Property type is a QQmlBinding*
79 QJSValueType = 6, // Property type is a QScriptValue
80 // Gap, used to be V4HandleType
81 VarPropertyType = 8, // Property type is a "var" property of VMEMO
82 QVariantType = 9 // Property is a QVariant
83 };
84
85 // The _otherBits (which "pad" the Flags struct to align it nicely) are used
86 // to store the relative property index. It will only get used when said index fits. See
87 // trySetStaticMetaCallFunction for details.
88 // (Note: this padding is done here, because certain compilers have surprising behavior
89 // when an enum is declared in-between two bit fields.)
90 enum { BitsLeftInFlags = 10 };
91 unsigned otherBits : BitsLeftInFlags; // align to 32 bits
92
93 // Can apply to all properties, except IsFunction
94 unsigned isConstant : 1; // Has CONST flag
95 unsigned isWritable : 1; // Has WRITE function
96 unsigned isResettable : 1; // Has RESET function
97 unsigned isAlias : 1; // Is a QML alias to another property
98 unsigned isFinal : 1; // Has FINAL flag
99 unsigned isOverridden : 1; // Is overridden by a extension property
100 unsigned isDirect : 1; // Exists on a C++ QMetaObject
101
102 unsigned type : 4; // stores an entry of Types
103
104 // Apply only to IsFunctions
105 unsigned isVMEFunction : 1; // Function was added by QML
106 unsigned hasArguments : 1; // Function takes arguments
107 unsigned isSignal : 1; // Function is a signal
108 unsigned isVMESignal : 1; // Signal was added by QML
109 unsigned isV4Function : 1; // 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 isCloned : 1; // The function was marked as cloned
113 unsigned isConstructor : 1; // The function was marked is a constructor
114
115 // Internal QQmlPropertyCache flags
116 unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
117 unsigned overrideIndexIsProperty: 1;
118
119 inline Flags();
120 inline bool operator==(const Flags &other) const;
121 inline void copyPropertyTypeFlags(Flags from);
122 };
123
124 inline bool operator==(const QQmlPropertyData &) const;
125
126 Flags flags() const { return m_flags; }
127 void setFlags(Flags f)
128 {
129 unsigned otherBits = m_flags.otherBits;
130 m_flags = f;
131 m_flags.otherBits = otherBits;
132 }
133
134 bool isValid() const { return coreIndex() != -1; }
135
136 bool isConstant() const { return m_flags.isConstant; }
137 bool isWritable() const { return m_flags.isWritable; }
138 void setWritable(bool onoff) { m_flags.isWritable = onoff; }
139 bool isResettable() const { return m_flags.isResettable; }
140 bool isAlias() const { return m_flags.isAlias; }
141 bool isFinal() const { return m_flags.isFinal; }
142 bool isOverridden() const { return m_flags.isOverridden; }
143 bool isDirect() const { return m_flags.isDirect; }
144 bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
145 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
146 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
147 bool isEnum() const { return m_flags.type == Flags::EnumType; }
148 bool isQList() const { return m_flags.type == Flags::QListType; }
149 bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
150 bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
151 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
152 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
153 bool isVMEFunction() const { return m_flags.isVMEFunction; }
154 bool hasArguments() const { return m_flags.hasArguments; }
155 bool isSignal() const { return m_flags.isSignal; }
156 bool isVMESignal() const { return m_flags.isVMESignal; }
157 bool isV4Function() const { return m_flags.isV4Function; }
158 bool isSignalHandler() const { return m_flags.isSignalHandler; }
159 bool isOverload() const { return m_flags.isOverload; }
160 void setOverload(bool onoff) { m_flags.isOverload = onoff; }
161 bool isCloned() const { return m_flags.isCloned; }
162 bool isConstructor() const { return m_flags.isConstructor; }
163
164 bool hasOverride() const { return overrideIndex() >= 0; }
165 bool hasRevision() const { return revision() != 0; }
166
167 bool isFullyResolved() const { return !m_flags.notFullyResolved; }
168
169 int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; }
170 void setPropType(int pt)
171 {
172 Q_ASSERT(pt >= 0);
173 Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
174 m_propType = quint16(pt);
175 }
176
177 int notifyIndex() const { return m_notifyIndex; }
178 void setNotifyIndex(int idx)
179 {
180 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
181 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
182 m_notifyIndex = qint16(idx);
183 }
184
185 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
186 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
187
188 int overrideIndex() const { return m_overrideIndex; }
189 void setOverrideIndex(int idx)
190 {
191 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
192 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
193 m_overrideIndex = qint16(idx);
194 }
195
196 int coreIndex() const { return m_coreIndex; }
197 void setCoreIndex(int idx)
198 {
199 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
200 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
201 m_coreIndex = qint16(idx);
202 }
203
204 quint8 revision() const { return m_revision; }
205 void setRevision(quint8 rev)
206 {
207 Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
208 m_revision = quint8(rev);
209 }
210
211 /* If a property is a C++ type, then we store the minor
212 * version of this type.
213 * This is required to resolve property or signal revisions
214 * if this property is used as a grouped property.
215 *
216 * Test.qml
217 * property TextEdit someTextEdit: TextEdit {}
218 *
219 * Test {
220 * someTextEdit.preeditText: "test" //revision 7
221 * someTextEdit.onEditingFinished: console.log("test") //revision 6
222 * }
223 *
224 * To determine if these properties with revisions are available we need
225 * the minor version of TextEdit as imported in Test.qml.
226 *
227 */
228
229 quint8 typeMinorVersion() const { return m_typeMinorVersion; }
230 void setTypeMinorVersion(quint8 rev)
231 {
232 Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
233 m_typeMinorVersion = quint8(rev);
234 }
235
236 QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
237 void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
238
239 int metaObjectOffset() const { return m_metaObjectOffset; }
240 void setMetaObjectOffset(int off)
241 {
242 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
243 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
244 m_metaObjectOffset = qint16(off);
245 }
246
247 StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
248 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
249 {
250 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
251 m_flags.otherBits = relativePropertyIndex;
252 m_staticMetaCallFunction = f;
253 }
254 }
255 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
256
257 static Flags flagsForProperty(const QMetaProperty &);
258 void load(const QMetaProperty &);
259 void load(const QMetaMethod &);
260 QString name(QObject *) const;
261 QString name(const QMetaObject *) const;
262
263 void markAsOverrideOf(QQmlPropertyData *predecessor);
264
265 inline void readProperty(QObject *target, void *property) const
266 {
267 void *args[] = { property, nullptr };
268 readPropertyWithArgs(target, args);
269 }
270
271 inline void readPropertyWithArgs(QObject *target, void *args[]) const
272 {
273 if (hasStaticMetaCallFunction())
274 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
275 else if (isDirect())
276 target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
277 else
278 QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
279 }
280
281 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
282 {
283 int status = -1;
284 void *argv[] = { value, nullptr, &status, &flags };
285 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
286 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
287 else if (flags.testFlag(BypassInterceptor) && isDirect())
288 target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
289 else
290 QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
291 return true;
292 }
293
294 static Flags defaultSignalFlags()
295 {
296 Flags f;
297 f.isSignal = true;
298 f.type = Flags::FunctionType;
299 f.isVMESignal = true;
300 return f;
301 }
302
303 static Flags defaultSlotFlags()
304 {
305 Flags f;
306 f.type = Flags::FunctionType;
307 f.isVMEFunction = true;
308 return f;
309 }
310
311private:
312 friend class QQmlPropertyCache;
313 void lazyLoad(const QMetaProperty &);
314 void lazyLoad(const QMetaMethod &);
315 bool notFullyResolved() const { return m_flags.notFullyResolved; }
316
317 Flags m_flags;
318 qint16 m_coreIndex = -1;
319 quint16 m_propType = 0;
320
321 // The notify index is in the range returned by QObjectPrivate::signalIndex().
322 // This is different from QMetaMethod::methodIndex().
323 qint16 m_notifyIndex = -1;
324 qint16 m_overrideIndex = -1;
325
326 quint8 m_revision = 0;
327 quint8 m_typeMinorVersion = 0;
328 qint16 m_metaObjectOffset = -1;
329
330 QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
331 StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
332};
333
334#if QT_POINTER_SIZE == 4
335 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
336#else // QT_POINTER_SIZE == 8
337 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
338#endif
339
340bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
341{
342 return flags() == other.flags() &&
343 propType() == other.propType() &&
344 coreIndex() == other.coreIndex() &&
345 notifyIndex() == other.notifyIndex() &&
346 revision() == other.revision();
347}
348
349QQmlPropertyData::Flags::Flags()
350 : otherBits(0)
351 , isConstant(false)
352 , isWritable(false)
353 , isResettable(false)
354 , isAlias(false)
355 , isFinal(false)
356 , isOverridden(false)
357 , isDirect(false)
358 , type(OtherType)
359 , isVMEFunction(false)
360 , hasArguments(false)
361 , isSignal(false)
362 , isVMESignal(false)
363 , isV4Function(false)
364 , isSignalHandler(false)
365 , isOverload(false)
366 , isCloned(false)
367 , isConstructor(false)
368 , notFullyResolved(false)
369 , overrideIndexIsProperty(false)
370{}
371
372bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
373{
374 return isConstant == other.isConstant &&
375 isWritable == other.isWritable &&
376 isResettable == other.isResettable &&
377 isAlias == other.isAlias &&
378 isFinal == other.isFinal &&
379 isOverridden == other.isOverridden &&
380 type == other.type &&
381 isVMEFunction == other.isVMEFunction &&
382 hasArguments == other.hasArguments &&
383 isSignal == other.isSignal &&
384 isVMESignal == other.isVMESignal &&
385 isV4Function == other.isV4Function &&
386 isSignalHandler == other.isSignalHandler &&
387 isOverload == other.isOverload &&
388 isCloned == other.isCloned &&
389 isConstructor == other.isConstructor &&
390 notFullyResolved == other.notFullyResolved &&
391 overrideIndexIsProperty == other.overrideIndexIsProperty;
392}
393
394void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
395{
396 switch (from.type) {
397 case QObjectDerivedType:
398 case EnumType:
399 case QListType:
400 case QmlBindingType:
401 case QJSValueType:
402 case QVariantType:
403 type = from.type;
404 }
405}
406
407Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
408
409QT_END_NAMESPACE
410
411#endif // QQMLPROPERTYDATA_P_H
412