aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsapi/qjsvalue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsapi/qjsvalue.cpp')
-rw-r--r--src/qml/jsapi/qjsvalue.cpp238
1 files changed, 130 insertions, 108 deletions
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 6d70c72722..5d320809dd 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qstring.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdatetime.h>
-#include "qjsengine.h"
#include "qjsvalue.h"
#include "qjsprimitivevalue.h"
#include "qjsmanagedvalue.h"
@@ -56,6 +19,8 @@
#include <private/qv4mm_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4urlobject_p.h>
+#include <private/qqmlbuiltins_p.h>
/*!
\since 5.0
@@ -141,6 +106,16 @@
integers.append(jsArray.property(i).toInt());
}
\endcode
+
+ \section2 Converting to JSON
+
+ It's possible to convert a QJSValue to a JSON type. For example,
+ to convert to an array, use \l QJSEngine::fromScriptValue():
+
+ \code
+ const QJsonValue jsonValue = engine.fromScriptValue<QJsonValue>(jsValue);
+ const QJsonArray jsonArray = jsonValue.toArray();
+ \endcode
*/
/*!
@@ -189,10 +164,11 @@
/*!
\enum QJSValue::ObjectConversionBehavior
- This enum is used to specify how JavaScript objects without an equivalent
+ This enum is used to specify how JavaScript objects and symbols without an equivalent
native Qt type should be treated when converting to QVariant.
\value ConvertJSObjects A best-effort, possibly lossy, conversion is attempted.
+ Symbols are converted to QString.
\value RetainJSObjects The value is retained as QJSValue wrapped in QVariant.
*/
@@ -204,61 +180,59 @@ using namespace QV4;
/*!
Constructs a new QJSValue with a boolean \a value.
*/
-QJSValue::QJSValue(bool value) : d(QV4::Encode(value))
+QJSValue::QJSValue(bool value) : d(QJSValuePrivate::encode(value))
{
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(int value) : d(QV4::Encode(value))
+QJSValue::QJSValue(int value) : d(QJSValuePrivate::encode(value))
{
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(uint value) : d(QV4::Encode(value))
+QJSValue::QJSValue(uint value) : d(QJSValuePrivate::encode(value))
{
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(double value) : d(QV4::Encode(value))
+QJSValue::QJSValue(double value) : d(QJSValuePrivate::encode(value))
{
}
/*!
Constructs a new QJSValue with a string \a value.
*/
-QJSValue::QJSValue(const QString& value)
+QJSValue::QJSValue(const QString &value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setString(this, QString(value));
}
/*!
Constructs a new QJSValue with a special \a value.
*/
-QJSValue::QJSValue(SpecialValue value) : d(value == NullValue ? QV4::Encode::null() : 0)
+QJSValue::QJSValue(SpecialValue value)
+ : d(value == NullValue ? QJSValuePrivate::encodeNull() : QJSValuePrivate::encodeUndefined())
{
}
/*!
Constructs a new QJSValue with a string \a value.
*/
-QJSValue::QJSValue(const QLatin1String &value)
+QJSValue::QJSValue(const QLatin1String &value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setString(this, QString(value));
}
/*!
Constructs a new QJSValue with a string \a value.
*/
#ifndef QT_NO_CAST_FROM_ASCII
-QJSValue::QJSValue(const char *value)
+QJSValue::QJSValue(const char *value) : d(QJSValuePrivate::encode(QString::fromUtf8(value)))
{
- QJSValuePrivate::setString(this, QString(QString::fromUtf8(value)));
}
#endif
@@ -269,12 +243,24 @@ QJSValue::QJSValue(const char *value)
true), then only a reference to the underlying object is copied into
the new script value (i.e., the object itself is not copied).
*/
-QJSValue::QJSValue(const QJSValue &other) : d(0)
+QJSValue::QJSValue(const QJSValue &other) : d(other.d)
{
- if (const QString *string = QJSValuePrivate::asQString(&other))
- QJSValuePrivate::setString(this, *string);
- else
- QJSValuePrivate::setValue(this, QJSValuePrivate::asReturnedValue(&other));
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::Undefined:
+ case QJSValuePrivate::Kind::Null:
+ case QJSValuePrivate::Kind::IntValue:
+ case QJSValuePrivate::Kind::BoolValue:
+ return;
+ case QJSValuePrivate::Kind::DoublePtr:
+ d = QJSValuePrivate::encode(*QJSValuePrivate::doublePtr(d));
+ return;
+ case QJSValuePrivate::Kind::QV4ValuePtr:
+ d = QJSValuePrivate::encode(*QJSValuePrivate::qv4ValuePtr(d));
+ return;
+ case QJSValuePrivate::Kind::QStringPtr:
+ d = QJSValuePrivate::encode(*QJSValuePrivate::qStringPtr(d));
+ break;
+ }
}
/*!
@@ -305,7 +291,7 @@ QJSValue::~QJSValue()
*/
bool QJSValue::isBool() const
{
- return QV4::Value::fromReturnedValue(d).isBoolean();
+ return QJSValuePrivate::tag(d) == QJSValuePrivate::Kind::BoolValue;
}
/*!
@@ -316,7 +302,15 @@ bool QJSValue::isBool() const
*/
bool QJSValue::isNumber() const
{
- return QV4::Value::fromReturnedValue(d).isNumber();
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::IntValue:
+ case QJSValuePrivate::Kind::DoublePtr:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
}
/*!
@@ -325,7 +319,7 @@ bool QJSValue::isNumber() const
*/
bool QJSValue::isNull() const
{
- return QV4::Value::fromReturnedValue(d).isNull();
+ return QJSValuePrivate::tag(d) == QJSValuePrivate::Kind::Null;
}
/*!
@@ -336,11 +330,17 @@ bool QJSValue::isNull() const
*/
bool QJSValue::isString() const
{
- if (QJSValuePrivate::asQString(this))
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::QStringPtr:
return true;
+ case QJSValuePrivate::Kind::QV4ValuePtr: {
+ return QJSValuePrivate::qv4ValuePtr(d)->isString();
+ }
+ default:
+ break;
+ }
- // String is managed
- return QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)).isString();
+ return false;
}
/*!
@@ -349,14 +349,16 @@ bool QJSValue::isString() const
*/
bool QJSValue::isUndefined() const
{
- if (QJSValuePrivate::asQString(this))
- return false;
- QV4::Value v = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this));
- if (v.isUndefined())
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::Undefined:
return true;
- if (!v.isManaged())
- return false;
- return v.managed() == nullptr;
+ case QJSValuePrivate::Kind::QV4ValuePtr:
+ return QJSValuePrivate::qv4ValuePtr(d)->isUndefined();
+ default:
+ break;
+ }
+
+ return false;
}
/*!
@@ -371,6 +373,18 @@ bool QJSValue::isError() const
}
/*!
+ Returns true if this QJSValue is an object of the URL JavaScript class;
+ otherwise returns false.
+
+ \note For a QJSValue that contains a QUrl, this function returns false.
+ However, \c{toVariant().value<QUrl>()} works in both cases.
+*/
+bool QJSValue::isUrl() const
+{
+ return QJSValuePrivate::asManagedType<UrlObject>(this);
+}
+
+/*!
\since 5.12
Returns the error type this QJSValue represents if it is an Error object.
Otherwise, returns \c NoError."
@@ -398,8 +412,7 @@ QJSValue::ErrorType QJSValue::errorType() const
case QV4::Heap::ErrorObject::URIError:
return URIError;
}
- Q_UNREACHABLE();
- return NoError;
+ Q_UNREACHABLE_RETURN(NoError);
}
/*!
@@ -438,16 +451,32 @@ bool QJSValue::isCallable() const
return QJSValuePrivate::asManagedType<FunctionObject>(this);
}
+#if QT_DEPRECATED_SINCE(6, 9)
/*!
+ \deprecated [6.9]
Returns true if this QJSValue is a variant value;
otherwise returns false.
+ \warning This function is likely to give unexpected results.
+ A variant value is only constructed by the QJSEngine in a very
+ limited number of cases. This used to be different before Qt
+ 5.14, where \l{QJSEngine::toScriptValue} would have created
+ them for more types instead of corresponding ECMAScript types.
+ You can get a valid \l QVariant via \l toVariant for many values
+ for which \c{isVariant} returns false.
+
\sa toVariant()
*/
bool QJSValue::isVariant() const
{
- return QJSValuePrivate::asManagedType<QV4::VariantObject>(this);
+ if (QJSValuePrivate::asManagedType<QV4::VariantObject>(this))
+ return true;
+ if (auto vt = QJSValuePrivate::asManagedType<QV4::QQmlValueTypeWrapper>(this))
+ if (vt->metaObject() == &QQmlVarForeign::staticMetaObject)
+ return true;
+ return false;
}
+#endif
/*!
Returns the string value of this QJSValue, as defined in
@@ -516,7 +545,7 @@ double QJSValue::toNumber() const
bool QJSValue::toBool() const
{
if (const QString *string = QJSValuePrivate::asQString(this))
- return string->length() > 0;
+ return string->size() > 0;
return caughtResult<bool>(this, &QV4::Value::toBoolean);
}
@@ -625,8 +654,13 @@ QVariant QJSValue::toVariant(QJSValue::ObjectConversionBehavior behavior) const
if (val.isString())
return QVariant(val.toQString());
- if (QV4::Managed *m = val.as<QV4::Managed>())
- return m->engine()->toVariant(val, /*typeHint*/ -1, behavior == RetainJSObjects);
+ if (val.as<QV4::Managed>()) {
+ if (behavior == RetainJSObjects)
+ return QV4::ExecutionEngine::toVariant(
+ val, /*typeHint*/ QMetaType{}, /*createJSValueForObjectsAndSymbols=*/ true);
+ else
+ return QV4::ExecutionEngine::toVariantLossy(val);
+ }
Q_ASSERT(false);
return QVariant();
@@ -649,20 +683,7 @@ QJSPrimitiveValue QJSValue::toPrimitive() const
return *string;
const QV4::Value val = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this));
- if (val.isUndefined())
- return QJSPrimitiveUndefined();
- if (val.isNull())
- return QJSPrimitiveNull();
- if (val.isBoolean())
- return val.toBoolean();
- if (val.isInteger())
- return val.integerValue();
- if (val.isDouble())
- return val.doubleValue();
-
- bool ok;
- const QString result = val.toQString(&ok);
- return ok ? QJSPrimitiveValue(result) : QJSPrimitiveValue(QJSPrimitiveUndefined());
+ return QV4::ExecutionEngine::createPrimitive(&val);
}
/*!
@@ -690,20 +711,20 @@ QJSValue QJSValue::call(const QJSValueList &args) const
Q_ASSERT(engine);
Scope scope(engine);
- JSCallData jsCallData(scope, args.length());
- *jsCallData->thisObject = engine->globalObject;
+ JSCallArguments jsCallData(scope, args.size());
+ *jsCallData.thisObject = engine->globalObject;
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
+ jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
- if (engine->isInterrupted.loadAcquire())
+ if (engine->isInterrupted.loadRelaxed())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
@@ -744,20 +765,20 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
return QJSValue();
}
- JSCallData jsCallData(scope, args.size());
- *jsCallData->thisObject = QJSValuePrivate::convertToReturnedValue(engine, instance);
+ JSCallArguments jsCallData(scope, args.size());
+ *jsCallData.thisObject = QJSValuePrivate::convertToReturnedValue(engine, instance);
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
+ jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
- if (engine->isInterrupted.loadAcquire())
+ if (engine->isInterrupted.loadRelaxed())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
@@ -791,19 +812,19 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const
Q_ASSERT(engine);
Scope scope(engine);
- JSCallData jsCallData(scope, args.size());
+ JSCallArguments jsCallData(scope, args.size());
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
+ jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->callAsConstructor(jsCallData));
if (engine->hasException)
result = engine->catchException();
- if (engine->isInterrupted.loadAcquire())
+ if (engine->isInterrupted.loadRelaxed())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
@@ -896,22 +917,22 @@ QJSValue::QJSValue(QJSPrimitiveValue &&value)
{
switch (value.type()) {
case QJSPrimitiveValue::Undefined:
- d = QV4::Encode::undefined();
+ d = QJSValuePrivate::encodeUndefined();
return;
case QJSPrimitiveValue::Null:
- d = QV4::Encode::null();
+ d = QJSValuePrivate::encodeNull();
return;
case QJSPrimitiveValue::Boolean:
- d = QV4::Encode(value.asBoolean());
+ d = QJSValuePrivate::encode(value.asBoolean());
return;
case QJSPrimitiveValue::Integer:
- d = QV4::Encode(value.asInteger());
+ d = QJSValuePrivate::encode(value.asInteger());
return;
case QJSPrimitiveValue::Double:
- d = QV4::Encode(value.asDouble());
+ d = QJSValuePrivate::encode(value.asDouble());
return;
case QJSPrimitiveValue::String:
- QJSValuePrivate::setString(this, std::move(std::get<QString>(value.d)));
+ d = QJSValuePrivate::encode(value.asString());
return;
}
@@ -923,10 +944,11 @@ QJSValue::QJSValue(QJSManagedValue &&value)
if (!value.d) {
d = QV4::Encode::undefined();
} else if (value.d->isManaged()) {
- QJSValuePrivate::setRawValue(this, value.d);
+ // If it's managed, we can adopt the persistent value.
+ QJSValuePrivate::adoptPersistentValue(this, value.d);
value.d = nullptr;
} else {
- d = value.d->asReturnedValue();
+ d = QJSValuePrivate::encode(*value.d);
QV4::PersistentValueStorage::free(value.d);
value.d = nullptr;
}