| Index: Source/bindings/core/dart/DartJsInterop.cpp
|
| diff --git a/Source/bindings/core/dart/DartJsInterop.cpp b/Source/bindings/core/dart/DartJsInterop.cpp
|
| index 4ac046c4c6680d2598e5e426486c68b22dc3f673..1ba07d3dd24374a1f9dc3d18f5657c05c388331d 100644
|
| --- a/Source/bindings/core/dart/DartJsInterop.cpp
|
| +++ b/Source/bindings/core/dart/DartJsInterop.cpp
|
| @@ -52,8 +52,82 @@ const int JsObject::dartClassId = _JsObjectClassId;
|
| const int JsFunction::dartClassId = _JsFunctionClassId;
|
| const int JsArray::dartClassId = _JsArrayClassId;
|
|
|
| +const char* dartArrayPolyfill =
|
| + "(function() {"
|
| + // If filter has already been defined on the DartList prototype,
|
| + // another DOM isolate has beaten us to polyfilling.
|
| + " if ($DartList.prototype.hasOwnProperty('filter')) return;"
|
| + " var isArray = Array.isArray;"
|
| + " var concat = Array.prototype.concat;"
|
| + " function makeSafeArgs(args) {"
|
| + " var len = args.length;"
|
| + " for (var i = 0; i < len; ++i) {"
|
| + " var arg = args[i];"
|
| + " if (arg instanceof $DartList) {"
|
| + " args[i] = arg.$toJsArray();"
|
| + " }"
|
| + " }"
|
| + " };"
|
| +
|
| + // If performance becomes an issue, we could implement these
|
| + // methods in Dart instead of creating a shallow copy JavaScript
|
| + // array containing the elements of the Dart List and calling
|
| + // the JavaScript method.
|
| +
|
| + // Handle methods that take a callback with value, index, and thisArg
|
| + // parameters. The trick is we need to make thisArg reference the
|
| + // underlying Dart List rather than the JavaScript copy we create for
|
| + // implementation convenience.
|
| + " ['filter', 'forEach', 'some', 'every', 'map'].forEach(function(name) {"
|
| + " Object.defineProperty($DartList.prototype, name, {enumerable: false, value: function(callback, thisArg) {"
|
| + " var dartList = this;"
|
| + " return this.$toJsArray()[name](function(value, index) {"
|
| + " return callback.call(thisArg, value, index, dartList);"
|
| + " });"
|
| + " }});"
|
| + " });"
|
| +
|
| + " ['slice', 'indexOf', 'lastIndexOf'].forEach(function(name) {"
|
| + " Object.defineProperty($DartList.prototype, name, {enumerable: false, value: function() {"
|
| + " var jsArray = this.$toJsArray();"
|
| + " return jsArray[name].apply(jsArray, arguments);"
|
| + " }});"
|
| + " });"
|
| +
|
| + " ['reduce', 'reduceRight'].forEach(function(name) {"
|
| + " Object.defineProperty($DartList.prototype, name, {enumerable: false, value: function(callback, thisArg) {"
|
| + " var dartList = this;"
|
| + " return this.$toJsArray()[name](function(previousValue, currentValue, index) {"
|
| + " return callback.call(thisArg, previousValue, currentValue, index, dartList);"
|
| + " });"
|
| + " }});"
|
| + " });"
|
| +
|
| + // Arguments to concat that are Arrays are treated differently.
|
| + // Warning: this will slow down general JavaScript array concat performance in Dartium.
|
| + " Array.prototype.concat = function() {"
|
| + " makeSafeArgs(arguments);"
|
| + " return concat.apply(this, arguments);"
|
| + " };"
|
| +
|
| + // Need to make sure that Array.isArray returns true for Dart lists.
|
| + " Array.isArray = function(arr) {"
|
| + " return isArray(arr) || (arr instanceof $DartList);"
|
| + " };"
|
| + "})();";
|
| +
|
| static v8::Local<v8::FunctionTemplate> dartFunctionTemplate();
|
| static v8::Local<v8::FunctionTemplate> dartObjectTemplate();
|
| +static v8::Local<v8::FunctionTemplate> dartListTemplate();
|
| +
|
| +// TODO(jacobr): we should really be using this method everywhere instead of
|
| +// sticking interop methods in the dart:html _Utils class.
|
| +static Dart_Handle invokeTopLevelJsInteropMethod(DartDOMData* domData, const char* methodName, int argCount, Dart_Handle* args)
|
| +{
|
| + Dart_PersistentHandle library = domData->jsLibrary();
|
| + ASSERT(!Dart_IsError(library));
|
| + return Dart_Invoke(library, Dart_NewStringFromCString(methodName), argCount, args);
|
| +}
|
|
|
| template<typename CallbackInfo>
|
| void setJsReturnValue(DartDOMData* domData, CallbackInfo info, Dart_Handle result)
|
| @@ -230,7 +304,18 @@ v8::Local<v8::Value> JsInterop::fromDart(DartDOMData* domData, Dart_Handle handl
|
|
|
| v8::Local<v8::Object> proxy;
|
| ASSERT(Dart_IsInstance(handle));
|
| - proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance();
|
| + // Simulate the behavior of the Dart dev compiler where new List() is
|
| + // equivalent to a JavaScript array. We accomplish this by creating a
|
| + // JavaScript object that fakes that it is a JavaScript array but is
|
| + // actually backed by a Dart list. This is not a breaking change as
|
| + // existing Dart-JS interop passed arrays as opaque Dart handles.
|
| + // The jsify method can still be called if you wish to create a copy
|
| + // of a json like Dart data structure.
|
| + if (Dart_IsList(handle)) {
|
| + proxy = dartListTemplate()->InstanceTemplate()->NewInstance();
|
| + } else {
|
| + proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance();
|
| + }
|
| DartHandleProxy::writePointerToProxy(proxy, handle);
|
| v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| proxy->SetHiddenValue(v8::String::NewFromUtf8(v8Isolate, "dartProxy"), v8::Boolean::New(v8Isolate, true));
|
| @@ -300,9 +385,48 @@ Dart_Handle JsObject::toDart(v8::Local<v8::Object> object)
|
| return JsObject::toDart(jsObject);
|
| }
|
|
|
| +static void maybeCreateJsObjectImplClass(DartDOMData* domData)
|
| +{
|
| + DartJsInteropData* interopData = domData->jsInteropData();
|
| + // Skip if the JSObjectImpl class has already been defined.
|
| + if (interopData->jsObjectImplDefined()) {
|
| + return;
|
| + }
|
| + // Helper method that generates boilerplate source code for
|
| + // JsObjectImpl, JsFunctionImpl, and JsArrayImpl classes that implement
|
| + // all Dart types that have been passed to the dart:js registerJsInterfaces
|
| + // method. The sole purpose of these classes is to ensure that checked mode
|
| + // allows casting a JsObject to all types implemented by a JsObject.
|
| + Dart_Handle source = invokeTopLevelJsInteropMethod(domData, "_generateJsObjectImplPart", 0, 0);
|
| + ASSERT(Dart_IsString(source));
|
| +
|
| + Dart_Handle ALLOW_UNUSED ret = Dart_LibraryLoadPatch(domData->jsLibrary(), Dart_NewStringFromCString("JsInteropImpl.dart"), source);
|
| + ASSERT(!Dart_IsError(ret));
|
| + ret = Dart_FinalizeLoading(false);
|
| + ASSERT(!Dart_IsError(ret));
|
| +
|
| + interopData->setJsObjectImplDefined();
|
| +
|
| + // Start of polyfill work to make Dart List proxies behave like JavaScript
|
| + // Arrays by monkey patching JavaScript Array and the List JavaScript
|
| + // proxies as needed.
|
| + v8::Context::Scope scope(DartUtilities::currentV8Context());
|
| +
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| +
|
| + v8::Local<v8::Function> dartArrayConstructor = dartListTemplate()->GetFunction();
|
| +
|
| + DartUtilities::currentV8Context()->Global()->Set(v8::String::NewFromUtf8(v8Isolate, "$DartList"),
|
| + dartArrayConstructor);
|
| + V8ScriptRunner::compileAndRunInternalScript(v8::String::NewFromUtf8(v8Isolate, dartArrayPolyfill), v8Isolate);
|
| +}
|
| +
|
| Dart_Handle JsObject::toDart(PassRefPtr<JsObject> jsObject)
|
| {
|
| - return DartDOMWrapper::createWrapper<JsObject>(DartDOMData::current(), jsObject.get(), JsObject::dartClassId);
|
| + DartDOMData* domData = DartDOMData::current();
|
| + // We need to ensure JsObjectImpl exists before creating the wrapper.
|
| + maybeCreateJsObjectImplClass(domData);
|
| + return DartDOMWrapper::createWrapper<JsObject>(domData, jsObject.get(), JsObject::dartClassId);
|
| }
|
|
|
| JsObject::~JsObject()
|
| @@ -312,7 +436,10 @@ JsObject::~JsObject()
|
|
|
| Dart_Handle JsFunction::toDart(PassRefPtr<JsFunction> jsFunction)
|
| {
|
| - return DartDOMWrapper::createWrapper<JsFunction>(DartDOMData::current(), jsFunction.get(), JsFunction::dartClassId);
|
| + DartDOMData* domData = DartDOMData::current();
|
| + // We need to ensure JsObjectImpl exists before creating the wrapper.
|
| + maybeCreateJsObjectImplClass(domData);
|
| + return DartDOMWrapper::createWrapper<JsFunction>(domData, jsFunction.get(), JsFunction::dartClassId);
|
| }
|
|
|
| JsFunction::JsFunction(v8::Local<v8::Function> v8Handle) : JsObject(v8Handle) { }
|
| @@ -329,7 +456,10 @@ v8::Local<v8::Function> JsFunction::localV8Function()
|
|
|
| Dart_Handle JsArray::toDart(PassRefPtr<JsArray> jsArray)
|
| {
|
| - return DartDOMWrapper::createWrapper<JsArray>(DartDOMData::current(), jsArray.get(), JsArray::dartClassId);
|
| + DartDOMData* domData = DartDOMData::current();
|
| + // We need to ensure JsArrayImpl exists before creating the wrapper.
|
| + maybeCreateJsObjectImplClass(domData);
|
| + return DartDOMWrapper::createWrapper<JsArray>(domData, jsArray.get(), JsArray::dartClassId);
|
| }
|
|
|
| JsArray::JsArray(v8::Local<v8::Array> v8Handle) : JsObject(v8Handle) { }
|
| @@ -872,6 +1002,12 @@ static void contextCallback(Dart_NativeArguments args)
|
| Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global()));
|
| }
|
|
|
| +static void finalizeJsInterfacesCallback(Dart_NativeArguments args)
|
| +{
|
| + DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(args));
|
| + maybeCreateJsObjectImplClass(domData);
|
| +}
|
| +
|
| v8::Handle<v8::Value> mapToV8(DartDOMData* domData, Dart_Handle value, DartHandleToV8Map& map, Dart_Handle& exception)
|
| {
|
| Dart_Handle asList = DartUtilities::invokeUtilsMethod("convertMapToList", 1, &value);
|
| @@ -1010,6 +1146,7 @@ fail:
|
| static DartNativeEntry nativeEntries[] = {
|
| { JsInteropInternal::jsObjectConstructorCallback, 2, "JsObject_constructorCallback" },
|
| { JsInteropInternal::contextCallback, 0, "Js_context_Callback" },
|
| + { JsInteropInternal::finalizeJsInterfacesCallback, 0, "Js_finalizeJsInterfaces" },
|
| { JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" },
|
| { JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" },
|
| { JsInteropInternal::getterCallback, 2, "JsObject_[]" },
|
| @@ -1055,4 +1192,310 @@ const uint8_t* JsInterop::symbolizer(Dart_NativeFunction nf)
|
| return 0;
|
| }
|
|
|
| +// Methods enabling a Dart List to emulate a JS Array.
|
| +static void indexedGetterArray(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)
|
| +{
|
| + DartScopes scopes(info.Holder());
|
| + Dart_Handle handle = scopes.handle;
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle ret = 0;
|
| + ASSERT(Dart_IsList(handle));
|
| + ret = Dart_ListGetAt(handle, index);
|
| + if (Dart_IsError(ret)) {
|
| + // Return undefined if the index is invalid to match JS semantics.
|
| + // TODO(jacobr): we should log to the console warning of bad use of a
|
| + // Dart List.
|
| + return;
|
| + }
|
| + setJsReturnValue(domData, info, ret);
|
| +}
|
| +
|
| +static void indexedSetterArray(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
|
| +{
|
| + DartScopes scopes(info.Holder());
|
| + Dart_Handle handle = scopes.handle;
|
| + DartDOMData* domData = DartDOMData::current();
|
| +
|
| + Dart_Handle ret = 0;
|
| + ASSERT(Dart_IsList(handle));
|
| + intptr_t length = 0;
|
| + ret = Dart_ListLength(handle, &length);
|
| + ASSERT(!Dart_IsError(ret));
|
| + if (index >= length) {
|
| + // Approximate JS semantics by filling the list with nulls if we
|
| + // attempt to add an element past the end of the list.
|
| + // TODO(jacobr): ideally we would match JS semantics exactly and fill
|
| + // the list with undefined.
|
| + Dart_Handle args[2] = { handle, DartUtilities::unsignedToDart(index + 1)};
|
| + ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString("_arrayExtend"), 2, args);
|
| + ASSERT(!Dart_IsError(ret));
|
| + }
|
| + ret = Dart_ListSetAt(handle, index, DartHandleProxy::unwrapValue(value));
|
| + if (Dart_IsError(ret)) {
|
| + // Return undefined if the index is invalid to match JS semantics.
|
| + // TODO(jacobr): we should log to the console warning of bad use of a
|
| + // Dart list or add a JS expando to the object ala JS.
|
| + }
|
| + setJsReturnValue(domData, info, ret);
|
| +}
|
| +
|
| +static void indexedEnumeratorArray(const v8::PropertyCallbackInfo<v8::Array>& info)
|
| +{
|
| + DartScopes scopes(info.Holder());
|
| + Dart_Handle handle = scopes.handle;
|
| +
|
| + intptr_t length = 0;
|
| + ASSERT(Dart_IsList(handle));
|
| + Dart_ListLength(handle, &length);
|
| +
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + v8::Local<v8::Array> indexes = v8::Array::New(v8Isolate, length);
|
| + for (int i = 0; i < length; i++)
|
| + indexes->Set(i, v8::Integer::New(v8Isolate, i));
|
| +
|
| + v8SetReturnValue(info, indexes);
|
| +}
|
| +
|
| +v8::Handle<v8::Array> shallowListToV8(Dart_Handle value, DartDOMData* domData, Dart_Handle& exception)
|
| +{
|
| + ASSERT(Dart_IsList(value));
|
| +
|
| + intptr_t length = 0;
|
| + Dart_Handle result = Dart_ListLength(value, &length);
|
| + if (!DartUtilities::checkResult(result, exception))
|
| + return v8::Handle<v8::Array>();
|
| +
|
| + v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), length);
|
| +
|
| + for (intptr_t i = 0; i < length; ++i) {
|
| + result = Dart_ListGetAt(value, i);
|
| + v8::Handle<v8::Value> v8value = JsInterop::fromDart(domData, result, exception);
|
| + // TODO(jacobr): is there a better way to handle this error case?
|
| + if (exception)
|
| + return v8::Handle<v8::Array>();
|
| + array->Set(i, v8value);
|
| + }
|
| + return array;
|
| +}
|
| +
|
| +void arrayHelper(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName)
|
| +{
|
| + // We need to bail out if "this" is not a Dart proxy or we will crash the VM.
|
| + // TODO(jacob): we could generate a user readable error message instead of
|
| + // just returning.
|
| + if (!DartHandleProxy::isDartProxy(info.Holder())) {
|
| + return;
|
| + }
|
| + DartScopes scopes(info.Holder());
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle handle = scopes.handle;
|
| + Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString(methodName), 1, &handle);
|
| + setJsReturnValue(domData, info, ret);
|
| +}
|
| +
|
| +void arrayHelper1Arg(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName)
|
| +{
|
| + // We need to bail out if "this" is not a Dart proxy or we will crash the VM.
|
| + // TODO(jacob): we could generate a user readable error message instead of
|
| + // just returning.
|
| + if (!DartHandleProxy::isDartProxy(info.Holder())) {
|
| + return;
|
| + }
|
| + DartScopes scopes(info.Holder());
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle handle = scopes.handle;
|
| + Dart_Handle e;
|
| + if (info.Length() == 0) {
|
| + e = Dart_Null();
|
| + } else {
|
| + e = JsInterop::toDart(info[0]);
|
| + }
|
| + Dart_Handle args[2] = { handle, e };
|
| + Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString(methodName), 2, args);
|
| + setJsReturnValue(domData, info, ret);
|
| +}
|
| +
|
| +static void arrayNamedPropertyGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)
|
| +{
|
| + if (!DartHandleProxy::isDartProxy(info.Holder())) {
|
| + return;
|
| + }
|
| +
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + if (!name->Equals(v8::String::NewFromUtf8(v8Isolate, "length")))
|
| + return;
|
| +
|
| + DartScopes scopes(info.Holder());
|
| + Dart_Handle handle = scopes.handle;
|
| +
|
| + intptr_t length = 0;
|
| + Dart_ListLength(handle, &length);
|
| + v8SetReturnValueInt(info, length);
|
| +}
|
| +
|
| +static void arrayNamedPropertySetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)
|
| +{
|
| + if (!DartHandleProxy::isDartProxy(info.Holder())) {
|
| + return;
|
| + }
|
| +
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + if (!property->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
|
| + return;
|
| + }
|
| +
|
| + DartScopes scopes(info.Holder());
|
| + Dart_Handle handle = scopes.handle;
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle args[2] = { handle, JsInterop::toDart(value) };
|
| + Dart_Handle ret = Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString("_setListLength"), 2, args);
|
| + setJsReturnValue(domData, info, ret);
|
| +}
|
| +
|
| +static void arrayQueryProperty(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Integer>& info)
|
| +{
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + if (name->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
|
| + v8SetReturnValueInt(info, v8::DontEnum | v8::DontDelete);
|
| + }
|
| +}
|
| +
|
| +static void arrayDeleteProperty(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Boolean>& info)
|
| +{
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + if (name->Equals(v8::String::NewFromUtf8(v8Isolate, "length"))) {
|
| + v8SetReturnValueBool(info, false);
|
| + }
|
| +}
|
| +
|
| +void arrayToStringCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelper(info, "_arrayToString");
|
| +}
|
| +
|
| +
|
| +void arrayJoinCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelper1Arg(info, "_arrayJoin");
|
| +}
|
| +
|
| +void arrayPushCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelper1Arg(info, "_arrayPush");
|
| +}
|
| +
|
| +void arrayPopCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelper(info, "_arrayPop");
|
| +}
|
| +
|
| +void arrayHelperWithArgsAsList(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName)
|
| +{
|
| + // We need to bail out if "this" is not a Dart proxy or we will crash the VM.
|
| + // TODO(jacob): we could generate a user readable error message instead of
|
| + // just returning.
|
| + if (!DartHandleProxy::isDartProxy(info.Holder())) {
|
| + return;
|
| + }
|
| + DartScopes scopes(info.Holder());
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle handle = scopes.handle;
|
| + int length = info.Length();
|
| + Dart_Handle argsList = Dart_NewList(length);
|
| + for (int i = 0; i < length; ++i) {
|
| + Dart_ListSetAt(argsList, i, JsInterop::toDart(info[i]));
|
| + }
|
| + // Note: this is also just info.Holder().
|
| + Dart_Handle args[2] = { handle, argsList };
|
| + setJsReturnValue(domData, info, Dart_Invoke(domData->jsLibrary(), Dart_NewStringFromCString(methodName), 2, args));
|
| +}
|
| +
|
| +void concatCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelperWithArgsAsList(info, "_arrayConcat");
|
| +}
|
| +
|
| +void arrayReverseCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelper(info, "_arrayReverse");
|
| +}
|
| +
|
| +void arrayShiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelper(info, "_arrayShift");
|
| +}
|
| +
|
| +void arrayUnshiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelperWithArgsAsList(info, "_arrayUnshift");
|
| +}
|
| +
|
| +void arraySpliceCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + arrayHelperWithArgsAsList(info, "_arraySplice");
|
| +}
|
| +
|
| +void toJsArrayCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + if (!DartHandleProxy::isDartProxy(info.Holder())) {
|
| + return;
|
| + }
|
| + DartScopes scopes(info.Holder());
|
| + DartDOMData* domData = DartDOMData::current();
|
| + Dart_Handle handle = scopes.handle;
|
| + Dart_Handle exception = 0;
|
| + v8::Local<v8::Array> v8Array = shallowListToV8(handle, domData, exception);
|
| + ASSERT(!exception);
|
| + v8SetReturnValue(info, v8Array);
|
| +}
|
| +
|
| +void arraySortCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
|
| +{
|
| + // TODO(jacobr): consider using the JavaScript sort method instead.
|
| + arrayHelper1Arg(info, "_arraySort");
|
| +}
|
| +
|
| +v8::Local<v8::FunctionTemplate> dartListTemplate()
|
| +{
|
| + DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ());
|
| + v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
|
| + v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
|
| + if (proxyTemplate.IsEmpty()) {
|
| + proxyTemplate.Reset(v8::Isolate::GetCurrent(), v8::FunctionTemplate::New(v8Isolate));
|
| + proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, proxyTemplate);
|
| + // Set to Array because we want these instances to appear to be
|
| + // JavaScript arrays as far as user code is concerned.
|
| + proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "Array"));
|
| + // Hack to set the prototype to be the prototype of an actual JavaScript Array.
|
| +
|
| + v8::Local<v8::ObjectTemplate> protoTemplate = proxyTemplateLocal->PrototypeTemplate();
|
| +
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "toString"), v8::FunctionTemplate::New(v8Isolate, arrayToStringCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "join"), v8::FunctionTemplate::New(v8Isolate, arrayJoinCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "push"), v8::FunctionTemplate::New(v8Isolate, arrayPushCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "pop"), v8::FunctionTemplate::New(v8Isolate, arrayPopCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "concat"), v8::FunctionTemplate::New(v8Isolate, concatCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "reverse"), v8::FunctionTemplate::New(v8Isolate, arrayReverseCallback), v8::DontEnum);
|
| +
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "shift"), v8::FunctionTemplate::New(v8Isolate, arrayShiftCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "unshift"), v8::FunctionTemplate::New(v8Isolate, arrayUnshiftCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "splice"), v8::FunctionTemplate::New(v8Isolate, arraySpliceCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "sort"), v8::FunctionTemplate::New(v8Isolate, arraySortCallback), v8::DontEnum);
|
| + protoTemplate ->Set(v8::String::NewFromUtf8(v8Isolate, "$toJsArray"), v8::FunctionTemplate::New(v8Isolate, toJsArrayCallback), v8::DontEnum);
|
| +
|
| + // ES6 experimental properties not currently supported that we could support if needed.
|
| + // These would require building separate live proxy objects.
|
| + // "entries",
|
| + // "values",
|
| + // "keys"
|
| +
|
| + v8::Local<v8::ObjectTemplate> instanceTemplate = setupInstanceTemplate(proxyTemplateLocal);
|
| + instanceTemplate->SetIndexedPropertyHandler(&indexedGetterArray, &indexedSetterArray, 0, 0, &indexedEnumeratorArray);
|
| + instanceTemplate->SetNamedPropertyHandler(&arrayNamedPropertyGetter, &arrayNamedPropertySetter, &arrayQueryProperty, &arrayDeleteProperty, 0);
|
| + } else {
|
| + proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, proxyTemplate);
|
| + }
|
| + return proxyTemplateLocal;
|
| +}
|
| +
|
| }
|
|
|