aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGlenn Watson <glenn.watson@nokia.com>2012-07-18 13:20:00 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-08 00:34:22 +0200
commitec519529087cc3005d55242569dcbca3dcee91bf (patch)
tree9fb83a2396c62e5231b11aaff013e94ed7f239dc /src
parent8bb5677f45935a03f1ed439e8a01ca71e9f1152c (diff)
Support JS Array.sort() function for sequence wrappers.
The V8 natve sort implementation calls some functions that are incompatible with the way sequence wrappers work. In particular, it calls an internal length() function which does not pass through the length accessor provided by sequence wrappers, so the sort function always thinks the array is zero length. Instead, clone the array prototype and override the sort function with one that is specific to sequence wrappers. Task-number: QTBUG-25269 Change-Id: Ic83b9ee0bd3a0707e512f28057f0f99b432fded4 Reviewed-by: Matthew Vogt <matthew.vogt@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper.cpp44
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p.h5
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p_p.h20
3 files changed, 67 insertions, 2 deletions
diff --git a/src/qml/qml/v8/qv8sequencewrapper.cpp b/src/qml/qml/v8/qv8sequencewrapper.cpp
index 883ed1b60c..6bd72387b5 100644
--- a/src/qml/qml/v8/qv8sequencewrapper.cpp
+++ b/src/qml/qml/v8/qv8sequencewrapper.cpp
@@ -64,6 +64,22 @@ void QV8SequenceWrapper::init(QV8Engine *engine)
m_engine = engine;
m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
+
+ QString defaultSortString = QLatin1String(
+ "(function compare(x,y) {"
+ " if (x === y) return 0;"
+ " x = x.toString();"
+ " y = y.toString();"
+ " if (x == y) return 0;"
+ " else return x < y ? -1 : 1;"
+ "})");
+
+ m_sort = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Sort)->GetFunction());
+ m_arrayPrototype = qPersistentNew<v8::Object>(v8::Array::New(1)->GetPrototype()->ToObject()->Clone());
+ m_arrayPrototype->Set(v8::String::New("sort"), m_sort);
+ v8::Local<v8::Script> defaultSortCompareScript = v8::Script::Compile(engine->toString(defaultSortString));
+ m_defaultSortComparer = qPersistentNew<v8::Function>(v8::Handle<v8::Function>(v8::Function::Cast(*defaultSortCompareScript->Run())));
+
v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter, IndexedSetter, 0, IndexedDeleter, IndexedEnumerator);
@@ -84,6 +100,9 @@ void QV8SequenceWrapper::init(QV8Engine *engine)
void QV8SequenceWrapper::destroy()
{
+ qPersistentDispose(m_defaultSortComparer);
+ qPersistentDispose(m_sort);
+ qPersistentDispose(m_arrayPrototype);
qPersistentDispose(m_toString);
qPersistentDispose(m_valueOf);
qPersistentDispose(m_constructor);
@@ -122,7 +141,7 @@ v8::Local<v8::Object> QV8SequenceWrapper::newSequence(int sequenceType, QObject
v8::Local<v8::Object> rv = m_constructor->NewInstance();
rv->SetExternalResource(r);
- rv->SetPrototype(v8::Array::New(1)->GetPrototype());
+ rv->SetPrototype(m_arrayPrototype);
return rv;
}
#undef NEW_REFERENCE_SEQUENCE
@@ -145,7 +164,7 @@ v8::Local<v8::Object> QV8SequenceWrapper::fromVariant(const QVariant& v, bool *s
v8::Local<v8::Object> rv = m_constructor->NewInstance();
rv->SetExternalResource(r);
- rv->SetPrototype(v8::Array::New(1)->GetPrototype());
+ rv->SetPrototype(m_arrayPrototype);
return rv;
}
#undef NEW_COPY_SEQUENCE
@@ -227,6 +246,27 @@ v8::Handle<v8::Value> QV8SequenceWrapper::ValueOfGetter(v8::Local<v8::String> pr
return info.Data();
}
+v8::Handle<v8::Value> QV8SequenceWrapper::Sort(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+
+ if (argCount < 2) {
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
+ Q_ASSERT(sr);
+
+ qint32 length = sr->lengthGetter();
+ if (length > 1) {
+ v8::Handle<v8::Function> jsCompareFn = sr->engine->sequenceWrapper()->m_defaultSortComparer;
+ if (argCount == 1 && args[0]->IsFunction())
+ jsCompareFn = v8::Handle<v8::Function>(v8::Function::Cast(*args[0]));
+
+ sr->sort(jsCompareFn);
+ }
+ }
+
+ return args.This();
+}
+
v8::Handle<v8::Value> QV8SequenceWrapper::ToString(const v8::Arguments &args)
{
QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
diff --git a/src/qml/qml/v8/qv8sequencewrapper_p.h b/src/qml/qml/v8/qv8sequencewrapper_p.h
index 104135ff76..08bc6146f7 100644
--- a/src/qml/qml/v8/qv8sequencewrapper_p.h
+++ b/src/qml/qml/v8/qv8sequencewrapper_p.h
@@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE
class QV8Engine;
class QV8ObjectResource;
+
class QV8SequenceWrapper
{
public:
@@ -85,6 +86,9 @@ private:
v8::Persistent<v8::Function> m_constructor;
v8::Persistent<v8::Function> m_toString;
v8::Persistent<v8::Function> m_valueOf;
+ v8::Persistent<v8::Function> m_sort;
+ v8::Persistent<v8::Object> m_arrayPrototype;
+ v8::Persistent<v8::Function> m_defaultSortComparer;
static v8::Handle<v8::Value> IndexedGetter(quint32 index, const v8::AccessorInfo &info);
static v8::Handle<v8::Value> IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
@@ -98,6 +102,7 @@ private:
static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args);
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Sort(const v8::Arguments &args);
};
diff --git a/src/qml/qml/v8/qv8sequencewrapper_p_p.h b/src/qml/qml/v8/qv8sequencewrapper_p_p.h
index cf20aa39fd..e74a5849cc 100644
--- a/src/qml/qml/v8/qv8sequencewrapper_p_p.h
+++ b/src/qml/qml/v8/qv8sequencewrapper_p_p.h
@@ -88,6 +88,7 @@ public:
virtual v8::Handle<v8::Boolean> indexedDeleter(quint32 index) = 0;
virtual v8::Handle<v8::Array> indexedEnumerator() = 0;
virtual v8::Handle<v8::Value> toString() = 0;
+ virtual void sort(v8::Handle<v8::Function> comparer) = 0;
ObjectType objectType;
QByteArray typeName;
@@ -474,6 +475,25 @@ static QString convertUrlToString(QV8Engine *, const QUrl &v)
void *a[] = { &c, 0, &status, &flags }; \
QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
} \
+ class CompareFunctor \
+ { \
+ public: \
+ CompareFunctor(QV8Engine *engine, v8::Handle<v8::Function> f) : jsFn(f), eng(engine) {} \
+ bool operator()(SequenceElementType e0, SequenceElementType e1) \
+ { \
+ v8::Handle<v8::Value> argv[2] = { eng->fromVariant(e0), eng->fromVariant(e1) }; \
+ v8::Handle<v8::Value> compareValue = jsFn->Call(eng->global(), 2, argv); \
+ return compareValue->NumberValue() < 0; \
+ } \
+ private: \
+ v8::Handle<v8::Function> jsFn; \
+ QV8Engine *eng; \
+ }; \
+ void sort(v8::Handle<v8::Function> jsCompareFunction) \
+ { \
+ CompareFunctor cf(engine, jsCompareFunction); \
+ qSort(c.begin(), c.end(), cf); \
+ } \
private: \
QQmlGuard<QObject> object; \
int propertyIndex; \