diff options
author | Glenn Watson <glenn.watson@nokia.com> | 2012-07-18 13:20:00 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-08 00:34:22 +0200 |
commit | ec519529087cc3005d55242569dcbca3dcee91bf (patch) | |
tree | 9fb83a2396c62e5231b11aaff013e94ed7f239dc /src/qml/qml/v8/qv8sequencewrapper.cpp | |
parent | 8bb5677f45935a03f1ed439e8a01ca71e9f1152c (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/qml/qml/v8/qv8sequencewrapper.cpp')
-rw-r--r-- | src/qml/qml/v8/qv8sequencewrapper.cpp | 44 |
1 files changed, 42 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()); |