Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsengine.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#ifndef QJSENGINE_H
6#define QJSENGINE_H
7
8#include <QtCore/qmetatype.h>
9
10#include <QtCore/qvariant.h>
11#include <QtCore/qsharedpointer.h>
12#include <QtCore/qobject.h>
13#include <QtCore/qtimezone.h>
14#include <QtQml/qjsvalue.h>
15#include <QtQml/qjsmanagedvalue.h>
16#include <QtQml/qqmldebug.h>
17
18QT_BEGIN_NAMESPACE
19
20
21template <typename T>
22inline T qjsvalue_cast(const QJSValue &);
23
24class QJSEnginePrivate;
25class Q_QML_EXPORT QJSEngine
26 : public QObject
27{
28 Q_OBJECT
29 Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage NOTIFY uiLanguageChanged)
30public:
31 QJSEngine();
32 explicit QJSEngine(QObject *parent);
33 ~QJSEngine() override;
34
35 QJSValue globalObject() const;
36
37 QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1, QStringList *exceptionStackTrace = nullptr);
38
39 QJSValue importModule(const QString &fileName);
40 bool registerModule(const QString &moduleName, const QJSValue &value);
41
42 QJSValue newObject();
43 QJSValue newSymbol(const QString &name);
44 QJSValue newArray(uint length = 0);
45
46 QJSValue newQObject(QObject *object);
47
48 QJSValue newQMetaObject(const QMetaObject* metaObject);
49
50 template <typename T>
51 QJSValue newQMetaObject()
52 {
53 return newQMetaObject(&T::staticMetaObject);
54 }
55
56 QJSValue newErrorObject(QJSValue::ErrorType errorType, const QString &message = QString());
57
58 template <typename T>
59 inline QJSValue toScriptValue(const T &value)
60 {
61 return create(QMetaType::fromType<T>(), &value);
62 }
63
64 template <typename T>
65 inline QJSManagedValue toManagedValue(const T &value)
66 {
67 return createManaged(QMetaType::fromType<T>(), &value);
68 }
69
70 template <typename T>
71 inline QJSPrimitiveValue toPrimitiveValue(const T &value)
72 {
73 // In the common case that the argument fits into QJSPrimitiveValue, use it.
74 if constexpr (std::disjunction_v<
75 std::is_same<T, int>,
76 std::is_same<T, bool>,
77 std::is_same<T, double>,
78 std::is_same<T, QString>>) {
79 return QJSPrimitiveValue(value);
80 } else {
81 return createPrimitive(QMetaType::fromType<T>(), &value);
82 }
83 }
84
85 template <typename T>
86 inline T fromScriptValue(const QJSValue &value)
87 {
88 return qjsvalue_cast<T>(value);
89 }
90
91 template <typename T>
92 inline T fromManagedValue(const QJSManagedValue &value)
93 {
94 return qjsvalue_cast<T>(value);
95 }
96
97 template <typename T>
98 inline T fromPrimitiveValue(const QJSPrimitiveValue &value)
99 {
100 if constexpr (std::is_same_v<T, int>)
101 return value.toInteger();
102 if constexpr (std::is_same_v<T, bool>)
103 return value.toBoolean();
104 if constexpr (std::is_same_v<T, double>)
105 return value.toDouble();
106 if constexpr (std::is_same_v<T, QString>)
107 return value.toString();
108 if constexpr (std::is_same_v<T, QVariant>)
109 return value.toVariant();
110 if constexpr (std::is_pointer_v<T>)
111 return nullptr;
112 return qjsvalue_cast<T>(value);
113 }
114
115 template <typename T>
116 inline T fromVariant(const QVariant &value)
117 {
118 if constexpr (std::is_same_v<T, QVariant>)
119 return value;
120
121 const QMetaType sourceType = value.metaType();
122 const QMetaType targetType = QMetaType::fromType<T>();
123 if (sourceType == targetType)
124 return *reinterpret_cast<const T *>(value.constData());
125
126 if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
127 using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
128 const QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
129 if (value.metaType() == nonConstTargetType)
130 return *reinterpret_cast<const nonConstT *>(value.constData());
131 }
132
133 if constexpr (std::is_same_v<T, QJSValue>)
134 return toScriptValue(value);
135
136 if constexpr (std::is_same_v<T, QJSManagedValue>)
137 return toManagedValue(value);
138
139 if constexpr (std::is_same_v<T, QJSPrimitiveValue>)
140 return toPrimitiveValue(value);
141
142 if constexpr (std::is_same_v<T, QString>) {
143 if (sourceType.flags() & QMetaType::PointerToQObject) {
144 return convertQObjectToString(
145 *reinterpret_cast<QObject *const *>(value.constData()));
146 }
147 }
148
149 if constexpr (std::is_same_v<T, double>) {
150 if (sourceType == QMetaType::fromType<int>())
151 return double(*static_cast<const int *>(value.constData()));
152 }
153
154 if constexpr (std::is_same_v<T, int>) {
155 if (sourceType == QMetaType::fromType<double>()) {
156 return QJSNumberCoercion::toInteger(
157 *static_cast<const double *>(value.constData()));
158 }
159 }
160
161 if constexpr (std::is_same_v<QObject, std::remove_const_t<std::remove_pointer_t<T>>>) {
162 if (sourceType.flags() & QMetaType::PointerToQObject) {
163 return *static_cast<QObject *const *>(value.constData());
164
165 // We should not access source->metaObject() here since that may trigger some
166 // rather involved code. convertVariant() can do this using property caches.
167 }
168 }
169
170 if (sourceType == QMetaType::fromType<QJSValue>())
171 return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData()));
172
173 if (sourceType == QMetaType::fromType<QJSManagedValue>()) {
174 return fromManagedValue<T>(
175 *reinterpret_cast<const QJSManagedValue *>(value.constData()));
176 }
177
178 if (sourceType == QMetaType::fromType<QJSPrimitiveValue>()) {
179 return fromPrimitiveValue<T>(
180 *reinterpret_cast<const QJSPrimitiveValue *>(value.constData()));
181 }
182
183 return [&] {
184 T t{};
185 if (value.metaType() == QMetaType::fromType<QString>()) {
186 if (convertString(value.toString(), targetType, &t))
187 return t;
188 } else if (convertVariant(value, targetType, &t)) {
189 return t;
190 }
191
192 QMetaType::convert(value.metaType(), value.constData(), targetType, &t);
193 return t;
194 }();
195 }
196
197 template<typename From, typename To>
198 inline To coerceValue(const From &from)
199 {
200 if constexpr (std::is_base_of_v<To, From>)
201 return from;
202
203 if constexpr (std::is_same_v<To, QJSValue>)
204 return toScriptValue(from);
205
206 if constexpr (std::is_same_v<From, QJSValue>)
207 return fromScriptValue<To>(from);
208
209 if constexpr (std::is_same_v<To, QJSManagedValue>)
210 return toManagedValue(from);
211
212 if constexpr (std::is_same_v<From, QJSManagedValue>)
213 return fromManagedValue<To>(from);
214
215 if constexpr (std::is_same_v<To, QJSPrimitiveValue>)
216 return toPrimitiveValue(from);
217
218 if constexpr (std::is_same_v<From, QJSPrimitiveValue>)
219 return fromPrimitiveValue<To>(from);
220
221 if constexpr (std::is_same_v<From, QVariant>)
222 return fromVariant<To>(from);
223
224 if constexpr (std::is_same_v<To, QVariant>)
225 return QVariant::fromValue(from);
226
227 if constexpr (std::is_same_v<To, QString>) {
228 if constexpr (std::is_base_of_v<QObject, std::remove_const_t<std::remove_pointer_t<From>>>)
229 return convertQObjectToString(from);
230 }
231
232 if constexpr (std::is_same_v<From, QDateTime>) {
233 if constexpr (std::is_same_v<To, QDate>)
234 return convertDateTimeToDate(from.toLocalTime());
235 if constexpr (std::is_same_v<To, QTime>)
236 return from.toLocalTime().time();
237 if constexpr (std::is_same_v<To, QString>)
238 return convertDateTimeToString(from.toLocalTime());
239 if constexpr (std::is_same_v<To, double>)
240 return convertDateTimeToNumber(from.toLocalTime());
241 }
242
243 if constexpr (std::is_same_v<From, QDate>) {
244 if constexpr (std::is_same_v<To, QDateTime>)
245 return from.startOfDay(QTimeZone::UTC);
246 if constexpr (std::is_same_v<To, QTime>) {
247 // This is the current time zone offset, for better or worse
248 return coerceValue<QDateTime, QTime>(coerceValue<QDate, QDateTime>(from));
249 }
250 if constexpr (std::is_same_v<To, QString>)
251 return convertDateTimeToString(coerceValue<QDate, QDateTime>(from));
252 if constexpr (std::is_same_v<To, double>)
253 return convertDateTimeToNumber(coerceValue<QDate, QDateTime>(from));
254 }
255
256 if constexpr (std::is_same_v<From, QTime>) {
257 if constexpr (std::is_same_v<To, QDate>) {
258 // Yes. April Fools' 1971. See qv4dateobject.cpp.
259 return from.isValid() ? QDate(1971, 4, 1) : QDate();
260 }
261
262 if constexpr (std::is_same_v<To, QDateTime>)
263 return QDateTime(coerceValue<QTime, QDate>(from), from, QTimeZone::LocalTime);
264 if constexpr (std::is_same_v<To, QString>)
265 return convertDateTimeToString(coerceValue<QTime, QDateTime>(from));
266 if constexpr (std::is_same_v<To, double>)
267 return convertDateTimeToNumber(coerceValue<QTime, QDateTime>(from));
268 }
269
270 if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) {
271 using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *;
272 if constexpr (std::is_same_v<From, nonConstTo>)
273 return from;
274 }
275
276 if constexpr (std::is_same_v<To, double>) {
277 if constexpr (std::is_same_v<From, int>)
278 return double(from);
279 }
280
281 if constexpr (std::is_same_v<To, int>) {
282 if constexpr (std::is_same_v<From, double>)
283 return QJSNumberCoercion::toInteger(from);
284 }
285
286 return [&] {
287 const QMetaType sourceType = QMetaType::fromType<From>();
288 const QMetaType targetType = QMetaType::fromType<To>();
289 To to{};
290 if constexpr (std::is_same_v<From, QString>) {
291 if (convertString(from, targetType, &to))
292 return to;
293 } else if (convertMetaType(sourceType, &from, targetType, &to)) {
294 return to;
295 }
296
297 QMetaType::convert(sourceType, &from, targetType, &to);
298 return to;
299 }();
300 }
301
302 void collectGarbage();
303
304 enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
305 static void setObjectOwnership(QObject *, ObjectOwnership);
306 static ObjectOwnership objectOwnership(QObject *);
307
308 enum Extension {
309 TranslationExtension = 0x1,
310 ConsoleExtension = 0x2,
311 GarbageCollectionExtension = 0x4,
312 AllExtensions = 0xffffffff
313 };
314 Q_DECLARE_FLAGS(Extensions, Extension)
315
316 void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
317
318 void setInterrupted(bool interrupted);
319 bool isInterrupted() const;
320
321 QV4::ExecutionEngine *handle() const { return m_v4Engine; }
322
323 void throwError(const QString &message);
324 void throwError(QJSValue::ErrorType errorType, const QString &message = QString());
325 void throwError(const QJSValue &error);
326 bool hasError() const;
327 QJSValue catchError();
328
329 QString uiLanguage() const;
330 void setUiLanguage(const QString &language);
331
332Q_SIGNALS:
333 void uiLanguageChanged();
334
335private:
336 QJSPrimitiveValue createPrimitive(QMetaType type, const void *ptr);
337 QJSManagedValue createManaged(QMetaType type, const void *ptr);
338 QJSValue create(QMetaType type, const void *ptr);
339#if QT_QML_REMOVED_SINCE(6, 5)
340 QJSValue create(int id, const void *ptr); // only there for BC reasons
341#endif
342
343 static bool convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr);
344 static bool convertManaged(const QJSManagedValue &value, int type, void *ptr);
345 static bool convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr);
346#if QT_QML_REMOVED_SINCE(6, 5)
347 static bool convertV2(const QJSValue &value, int type, void *ptr); // only there for BC reasons
348#endif
349 static bool convertV2(const QJSValue &value, QMetaType metaType, void *ptr);
350 static bool convertString(const QString &string, QMetaType metaType, void *ptr);
351
352 bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr);
353 bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to);
354
355 QString convertQObjectToString(QObject *object);
356 QString convertDateTimeToString(const QDateTime &dateTime);
357 double convertDateTimeToNumber(const QDateTime &dateTime);
358 static QDate convertDateTimeToDate(const QDateTime &dateTime);
359
360 template<typename T>
361 friend inline T qjsvalue_cast(const QJSValue &);
362
363 template<typename T>
364 friend inline T qjsvalue_cast(const QJSManagedValue &);
365
366 template<typename T>
367 friend inline T qjsvalue_cast(const QJSPrimitiveValue &);
368
369protected:
370 QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr);
371
372private:
373 QV4::ExecutionEngine *m_v4Engine;
374 Q_DISABLE_COPY(QJSEngine)
375 Q_DECLARE_PRIVATE(QJSEngine)
376};
377
378Q_DECLARE_OPERATORS_FOR_FLAGS(QJSEngine::Extensions)
379
380template<typename T>
381T qjsvalue_cast(const QJSValue &value)
382{
383 if (T t; QJSEngine::convertV2(value, QMetaType::fromType<T>(), &t))
384 return t;
385 return qvariant_cast<T>(value.toVariant());
386}
387
388template<typename T>
389T qjsvalue_cast(const QJSManagedValue &value)
390{
391 if (T t; QJSEngine::convertManaged(value, QMetaType::fromType<T>(), &t))
392 return t;
393
394 return qvariant_cast<T>(value.toVariant());
395}
396
397template<typename T>
398T qjsvalue_cast(const QJSPrimitiveValue &value)
399{
400 if (T t; QJSEngine::convertPrimitive(value, QMetaType::fromType<T>(), &t))
401 return t;
402
403 return qvariant_cast<T>(value.toVariant());
404}
405
406template <>
407inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
408{
409 return value.toVariant();
410}
411
412template <>
413inline QVariant qjsvalue_cast<QVariant>(const QJSManagedValue &value)
414{
415 return value.toVariant();
416}
417
418template <>
419inline QVariant qjsvalue_cast<QVariant>(const QJSPrimitiveValue &value)
420{
421 return value.toVariant();
422}
423
424Q_QML_EXPORT QJSEngine *qjsEngine(const QObject *);
425
426QT_END_NAMESPACE
427
428#endif // QJSENGINE_H
The QJSEngine class provides an environment for evaluating JavaScript code.
Definition qjsengine.h:27
QJSEngine * qjsEngine(const QObject *object)
T qjsvalue_cast(const QJSManagedValue &value)
Definition qjsengine.h:389