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 | |
56 | QT_BEGIN_NAMESPACE |
57 | |
58 | class QQmlPropertyCacheMethodArguments; |
59 | class QQmlPropertyData |
60 | { |
61 | public: |
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 | |
311 | private: |
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 | |
340 | bool 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 | |
349 | QQmlPropertyData::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 | |
372 | bool 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 | |
394 | void 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 | |
407 | Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags) |
408 | |
409 | QT_END_NAMESPACE |
410 | |
411 | #endif // QQMLPROPERTYDATA_P_H |
412 | |