aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/v4/qv4bindings.cpp74
-rw-r--r--src/declarative/qml/v4/qv4compiler.cpp67
-rw-r--r--src/declarative/qml/v4/qv4instruction.cpp12
-rw-r--r--src/declarative/qml/v4/qv4instruction_p.h4
-rw-r--r--src/declarative/qml/v4/qv4ir.cpp24
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/urlProperty.1.qml10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.h12
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp16
8 files changed, 207 insertions, 12 deletions
diff --git a/src/declarative/qml/v4/qv4bindings.cpp b/src/declarative/qml/v4/qv4bindings.cpp
index 04c410c15d..0ccf25cebd 100644
--- a/src/declarative/qml/v4/qv4bindings.cpp
+++ b/src/declarative/qml/v4/qv4bindings.cpp
@@ -999,6 +999,80 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertStringToReal, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QString tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.geturlptr()) QUrl(tmp);
+ URL_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setbool(!tmp.isEmpty());
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.getstringptr()) QString(tmp.toString());
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToString, unaryop)
+
+ QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ *output.geturlptr() = context->resolvedUrl(tmp);
+ } else {
+ new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
+ URL_REGISTER(instr->unaryop.output);
+ }
+ }
+ }
+ QML_V4_END_INSTR(ResolveUrl, unaryop)
+
QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
{
const Register &src = registers[instr->unaryop.src];
diff --git a/src/declarative/qml/v4/qv4compiler.cpp b/src/declarative/qml/v4/qv4compiler.cpp
index e091ce2731..5d732d5603 100644
--- a/src/declarative/qml/v4/qv4compiler.cpp
+++ b/src/declarative/qml/v4/qv4compiler.cpp
@@ -340,6 +340,9 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
case QMetaType::QString:
regType = QStringType;
break;
+ case QMetaType::QUrl:
+ regType = QUrlType;
+ break;
default:
if (propTy == qMetaTypeId<QDeclarative1AnchorLine>()) {
@@ -848,15 +851,40 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
traceExpression(s->source, dest);
V4Instr::Type opcode = V4Instr::Noop;
- if (target->type == IR::BoolType) {
- switch (s->source->type) {
+ IR::Type targetTy = s->target->type;
+ IR::Type sourceTy = s->source->type;
+
+ if (sourceTy == IR::UrlType) {
+ switch (targetTy) {
+ case IR::BoolType:
+ case IR::StringType:
+ // nothing to do. V4 will generate optimized
+ // url-to-xxx conversions.
+ break;
+ default: {
+ // generate a UrlToString conversion and fix
+ // the type of the source expression.
+ V4Instr conv;
+ conv.unaryop.output = V4Instr::ConvertUrlToString;
+ conv.unaryop.src = src;
+ gen(opcode, conv);
+
+ sourceTy = IR::StringType;
+ break;
+ }
+ } // switch
+ }
+
+ if (targetTy == IR::BoolType) {
+ switch (sourceTy) {
case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
default: break;
} // switch
- } else if (target->type == IR::IntType) {
- switch (s->source->type) {
+ } else if (targetTy == IR::IntType) {
+ switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
case IR::RealType: {
if (s->isMoveForReturn)
@@ -868,26 +896,49 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
default: break;
} // switch
- } else if (target->type == IR::RealType) {
- switch (s->source->type) {
+ } else if (targetTy == IR::RealType) {
+ switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
default: break;
} // switch
- } else if (target->type == IR::StringType) {
- switch (s->source->type) {
+ } else if (targetTy == IR::StringType) {
+ switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
+ default: break;
+ } // switch
+ } else if (targetTy == IR::UrlType) {
+ V4Instr convToString;
+ convToString.unaryop.output = dest;
+ convToString.unaryop.src = src;
+
+ // try to convert the source expression to a string.
+ switch (sourceTy) {
+ case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
+ case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break;
+ case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break;
default: break;
} // switch
+
+ if (sourceTy == IR::StringType)
+ opcode = V4Instr::ConvertStringToUrl;
}
if (opcode != V4Instr::Noop) {
V4Instr conv;
conv.unaryop.output = dest;
conv.unaryop.src = src;
gen(opcode, conv);
+
+ if (s->isMoveForReturn && opcode == V4Instr::ConvertStringToUrl) {
+ V4Instr resolveUrl;
+ resolveUrl.unaryop.output = dest;
+ resolveUrl.unaryop.src = dest;
+ gen(V4Instr::ResolveUrl, resolveUrl);
+ }
} else {
discard();
}
diff --git a/src/declarative/qml/v4/qv4instruction.cpp b/src/declarative/qml/v4/qv4instruction.cpp
index ccf91d567b..18b2a24c1b 100644
--- a/src/declarative/qml/v4/qv4instruction.cpp
+++ b/src/declarative/qml/v4/qv4instruction.cpp
@@ -168,6 +168,18 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertStringToReal:
INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
+ case V4Instr::ConvertStringToUrl:
+ INSTR_DUMP << "\t" << "ConvertStringToUrl" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertUrlToBool:
+ INSTR_DUMP << "\t" << "ConvertUrlToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertUrlToString:
+ INSTR_DUMP << "\t" << "ConvertUrlToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ResolveUrl:
+ INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
case V4Instr::MathSinReal:
INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
diff --git a/src/declarative/qml/v4/qv4instruction_p.h b/src/declarative/qml/v4/qv4instruction_p.h
index 6f90117c7c..f1966bb875 100644
--- a/src/declarative/qml/v4/qv4instruction_p.h
+++ b/src/declarative/qml/v4/qv4instruction_p.h
@@ -91,6 +91,10 @@ QT_BEGIN_NAMESPACE
F(ConvertStringToBool, unaryop) \
F(ConvertStringToInt, unaryop) \
F(ConvertStringToReal, unaryop) \
+ F(ConvertStringToUrl, unaryop) \
+ F(ConvertUrlToBool, unaryop) \
+ F(ConvertUrlToString, unaryop) \
+ F(ResolveUrl, unaryop) \
F(MathSinReal, unaryop) \
F(MathCosReal, unaryop) \
F(MathRoundReal, unaryop) \
diff --git a/src/declarative/qml/v4/qv4ir.cpp b/src/declarative/qml/v4/qv4ir.cpp
index 48d6c9b81c..0a0228b894 100644
--- a/src/declarative/qml/v4/qv4ir.cpp
+++ b/src/declarative/qml/v4/qv4ir.cpp
@@ -71,14 +71,30 @@ inline const char *typeName(Type t)
}
}
+inline bool isNumberType(IR::Type ty)
+{
+ return ty >= IR::FirstNumberType;
+}
+
+inline bool isStringType(IR::Type ty)
+{
+ return ty == IR::StringType || ty == IR::UrlType;
+}
+
IR::Type maxType(IR::Type left, IR::Type right)
{
- if (left == right)
+ if (isStringType(left) && isStringType(right)) {
+ // String promotions (url to string) are more specific than
+ // identity conversions (AKA left == right). That's because
+ // we want to ensure we convert urls to strings in binary
+ // expressions.
+ return IR::StringType;
+ } else if (left == right)
return left;
- else if (left >= IR::FirstNumberType && right >= IR::FirstNumberType)
+ else if (isNumberType(left) && isNumberType(right))
return qMax(left, right);
- else if ((left >= IR::FirstNumberType && right == IR::StringType) ||
- (right >= IR::FirstNumberType && left == IR::StringType))
+ else if ((isNumberType(left) && isStringType(right)) ||
+ (isNumberType(right) && isStringType(left)))
return IR::StringType;
else
return IR::InvalidType;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/urlProperty.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/urlProperty.1.qml
new file mode 100644
index 0000000000..451cb03206
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/urlProperty.1.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool result
+ urlProperty: stringProperty + "/index.html"
+ intProperty: if (urlProperty) 123; else 321
+ value: urlProperty == stringProperty + "/index.html"
+ result: urlProperty == urlProperty
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
index cd5bac5253..2f1d3f9414 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
@@ -93,6 +93,7 @@ class MyQmlObject : public QObject
Q_PROPERTY(int value READ value WRITE setValue)
Q_PROPERTY(int console READ console CONSTANT)
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
+ Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlChanged)
Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged)
Q_PROPERTY(QDeclarativeListProperty<QObject> objectListProperty READ objectListProperty CONSTANT)
Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
@@ -118,6 +119,15 @@ public:
emit stringChanged();
}
+ QUrl urlProperty() const { return m_url; }
+ void setUrlProperty(const QUrl &url)
+ {
+ if (url == m_url)
+ return;
+ m_url = url;
+ emit urlChanged();
+ }
+
QObject *objectProperty() const { return m_object; }
void setObjectProperty(QObject *obj) {
if (obj == m_object)
@@ -171,6 +181,7 @@ signals:
void basicSignal();
void argumentSignal(int a, QString b, qreal c, MyEnum2 d, Qt::MouseButtons e);
void stringChanged();
+ void urlChanged();
void objectChanged();
void anotherBasicSignal();
void thirdBasicSignal();
@@ -196,6 +207,7 @@ private:
QObject *m_object;
QString m_string;
+ QUrl m_url;
QList<QObject *> m_objectQList;
int m_value;
int m_resetProperty;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index a01c80b7e3..f3d810ed9d 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -220,6 +220,7 @@ private slots:
void aliasWritesOverrideBindings();
void aliasToCompositeElement();
void realToInt();
+ void urlProperty();
void dynamicString();
void include();
void signalHandlers();
@@ -5462,6 +5463,21 @@ void tst_qdeclarativeecmascript::realToInt()
QMetaObject::invokeMethod(object, "test2");
QCOMPARE(object->value(), int(8));
}
+
+void tst_qdeclarativeecmascript::urlProperty()
+{
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("urlProperty.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ object->setStringProperty("http://qt-project.org");
+ QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
+ QCOMPARE(object->intProperty(), 123);
+ QCOMPARE(object->value(), 1);
+ QCOMPARE(object->property("result").toBool(), true);
+ }
+}
+
void tst_qdeclarativeecmascript::dynamicString()
{
QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));