aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-04-20 10:43:11 +0200
committerUlf Hermann <ulf.hermann@qt.io>2021-04-22 22:15:36 +0200
commit3c9339f3c817c985f9ff3410f1f0ef864554687a (patch)
tree05305a6a503b35f9627456435cc2523f5c9909ed
parente44a949f9028df1d4750dad2925b074c9c59efcc (diff)
Support native transformation between UrlObject and QVariant/QUrl
URL has become a builtin type. We should support it on the same level as QString/String and QDateTime/Date. In order to continue support for comparing URL properties with the JavaScript equality operators, we still pass URLs as variants when using them in JavaScript. However, we now create proper URL objects for QJSValue and QJSManagedValue, and we allow transforming the URL-carrying variant objects back into QUrls. Change-Id: I78cb2d7d51ac720877217d2d4b4d0ab17cdd2a4b Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qml/jsapi/qjsvalue.cpp10
-rw-r--r--src/qml/jsapi/qjsvalue.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp24
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h28
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp14
-rw-r--r--tests/auto/qml/qjsmanagedvalue/tst_qjsmanagedvalue.cpp1
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp3
9 files changed, 76 insertions, 17 deletions
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 0cff55ac9d..03cd1e9aa9 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -56,6 +56,7 @@
#include <private/qv4mm_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4urlobject_p.h>
/*!
\since 5.0
@@ -371,6 +372,15 @@ bool QJSValue::isError() const
}
/*!
+ Returns true if this QJSValue is an object of the URL class;
+ otherwise returns false.
+*/
+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."
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index 9bbc8c9f88..97a93798c0 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -126,6 +126,7 @@ public:
bool isRegExp() const;
bool isArray() const;
bool isError() const;
+ bool isUrl() const;
QString toString() const;
double toNumber() const;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 34fbd19a78..69db5efd05 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -94,6 +94,7 @@
#include "qv4atomics_p.h"
#include "qv4urlobject_p.h"
#include "qv4jscall_p.h"
+#include "qv4variantobject_p.h"
#if QT_CONFIG(qml_sequence_object)
#include "qv4sequenceobject_p.h"
@@ -1083,6 +1084,14 @@ Heap::UrlObject *ExecutionEngine::newUrlObject()
return memoryManager->allocate<UrlObject>();
}
+Heap::UrlObject *ExecutionEngine::newUrlObject(const QUrl &url)
+{
+ Scope scope(this);
+ Scoped<UrlObject> urlObject(scope, newUrlObject());
+ urlObject->setUrl(url);
+ return urlObject->d();
+}
+
Heap::UrlSearchParamsObject *ExecutionEngine::newUrlSearchParamsObject()
{
return memoryManager->allocate<UrlSearchParamsObject>();
@@ -1628,6 +1637,8 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMet
#endif
if (const QV4::DateObject *d = value.as<DateObject>())
return d->toQDateTime();
+ if (const QV4::UrlObject *d = value.as<UrlObject>())
+ return d->toQUrl();
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
return d->asByteArray();
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
@@ -1949,6 +1960,9 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(QMetaType type, const void *dat
// unwrap it: this is tested in QJSEngine, and makes the most sense for
// end-user code too.
return fromVariant(*reinterpret_cast<const QVariant*>(data));
+ } else if (type == QMetaType::fromType<QUrl>()) {
+ // Create a proper URL object here, rather than a variant.
+ return newUrlObject(*reinterpret_cast<const QUrl *>(data))->asReturnedValue();
}
return fromData(type, data);
@@ -2296,7 +2310,15 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
} else if (const QV4::UrlObject *d = value.as<UrlObject>()) {
*reinterpret_cast<QUrl *>(data) = d->toQUrl();
return true;
- } break;
+ } else if (const QV4::VariantObject *d = value.as<VariantObject>()) {
+ const QVariant *variant = &d->d()->data();
+ if (variant->metaType() == QMetaType::fromType<QUrl>()) {
+ *reinterpret_cast<QUrl *>(data)
+ = *reinterpret_cast<const QUrl *>(variant->constData());
+ return true;
+ }
+ }
+ break;
#if QT_CONFIG(regularexpression)
case QMetaType::QRegularExpression:
if (const QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) {
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 96aad5ee72..e3e0a481cf 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -601,6 +601,7 @@ public:
#endif
Heap::UrlObject *newUrlObject();
+ Heap::UrlObject *newUrlObject(const QUrl &url);
Heap::UrlSearchParamsObject *newUrlSearchParamsObject();
Heap::Object *newErrorObject(const Value &value);
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index b933945a7c..c63e71ea46 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -149,11 +149,16 @@ bool UrlObject::setHost(QString hostname)
bool UrlObject::setHref(QString href)
{
- QUrl url(href);
-
+ const QUrl url(href);
if (!url.isValid() || url.isRelative())
return false;
+ setUrl(url);
+ return true;
+}
+
+void UrlObject::setUrl(const QUrl &url)
+{
d()->hash.set(engine(), engine()->newString(url.fragment()));
d()->hostname.set(engine(), engine()->newString(url.host()));
d()->href.set(engine(), engine()->newString(url.toString()));
@@ -168,8 +173,6 @@ bool UrlObject::setHref(QString href)
updateOrigin();
updateHost();
-
- return true;
}
bool UrlObject::setPassword(QString password)
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
index 8ac3d72a4f..0b64066f34 100644
--- a/src/qml/jsruntime/qv4urlobject_p.h
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -111,41 +111,47 @@ struct UrlObject : Object
Q_MANAGED_TYPE(UrlObject)
V4_PROTOTYPE(urlPrototype)
- QString hash() const { return QLatin1String("#") + d()->hash->toQString(); }
+ QString hash() const { return QLatin1String("#") + toQString(d()->hash); }
bool setHash(QString hash);
- QString host() const { return d()->host->toQString(); }
+ QString host() const { return toQString(d()->host); }
bool setHost(QString host);
- QString hostname() const { return d()->hostname->toQString(); }
+ QString hostname() const { return toQString(d()->hostname); }
bool setHostname(QString hostname);
- QString href() const { return d()->href->toQString(); }
+ QString href() const { return toQString(d()->href); }
bool setHref(QString href);
- QString origin() const { return d()->origin->toQString(); }
+ QString origin() const { return toQString(d()->origin); }
- QString password() const { return d()->password->toQString(); }
+ QString password() const { return toQString(d()->password); }
bool setPassword(QString password);
- QString pathname() const { return d()->pathname->toQString(); }
+ QString pathname() const { return toQString(d()->pathname); }
bool setPathname(QString pathname);
- QString port() const { return d()->port->toQString(); }
+ QString port() const { return toQString(d()->port); }
bool setPort(QString port);
- QString protocol() const { return d()->protocol->toQString(); }
+ QString protocol() const { return toQString(d()->protocol); }
bool setProtocol(QString protocol);
- QString search() const { return QLatin1String("?") + d()->search->toQString(); }
+ QString search() const { return QLatin1String("?") + toQString(d()->search); }
bool setSearch(QString search);
- QString username() const { return d()->username->toQString(); }
+ QString username() const { return toQString(d()->username); }
bool setUsername(QString username);
QUrl toQUrl() const;
+ void setUrl(const QUrl &url);
private:
+ static QString toQString(const Heap::String *string)
+ {
+ return string ? string->toQString() : QString();
+ }
+
void updateOrigin();
void updateHost();
};
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 11c81dbdf2..c8ceaf7680 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -5328,6 +5328,20 @@ void tst_QJSEngine::urlObject()
engine.catchError();
}
+ QVariant urlVariant(url);
+ QV4::Scope scope(engine.handle());
+ QV4::ScopedValue urlValue(scope, scope.engine->fromVariant(urlVariant));
+ QVERIFY(urlValue->isObject());
+
+ QUrl result1;
+ QVERIFY(scope.engine->metaTypeFromJS(urlValue, QMetaType::fromType<QUrl>(), &result1));
+ QCOMPARE(result1, url);
+
+ QV4::ScopedValue urlVariantValue(scope, scope.engine->newVariantObject(urlVariant));
+ QVERIFY(urlVariantValue->isObject());
+ QUrl result2;
+ QVERIFY(scope.engine->metaTypeFromJS(urlVariantValue, QMetaType::fromType<QUrl>(), &result2));
+ QCOMPARE(result2, url);
}
QTEST_MAIN(tst_QJSEngine)
diff --git a/tests/auto/qml/qjsmanagedvalue/tst_qjsmanagedvalue.cpp b/tests/auto/qml/qjsmanagedvalue/tst_qjsmanagedvalue.cpp
index ce9164aa96..6233f38c9a 100644
--- a/tests/auto/qml/qjsmanagedvalue/tst_qjsmanagedvalue.cpp
+++ b/tests/auto/qml/qjsmanagedvalue/tst_qjsmanagedvalue.cpp
@@ -1731,6 +1731,7 @@ void tst_QJSManagedValue::stringAndUrl()
const QUrl url(string);
const QJSManagedValue urlValue(engine.toManagedValue(url));
+ QVERIFY(urlValue.isUrl());
QCOMPARE(urlValue.toString(), string);
QCOMPARE(engine.fromManagedValue<QUrl>(urlValue), url);
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 2b91ca0019..8ee31b8509 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -396,7 +396,8 @@ void tst_QJSValue::toString()
QVERIFY(!variant.isVariant());
QCOMPARE(variant.toString(), QString::fromLatin1("QPoint(10, 20)"));
variant = eng.toScriptValue(QUrl());
- QVERIFY(variant.isVariant());
+ QVERIFY(!variant.isVariant());
+ QVERIFY(variant.isUrl());
QVERIFY(variant.toString().isEmpty());
{