Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Unified Diff: Source/bindings/core/dart/DartJsInterop.cpp

Issue 1177953010: Support new style JS interop (Closed) Base URL: svn://svn.chromium.org/blink/branches/dart/dartium
Patch Set: ptal. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/bindings/core/dart/DartInjectedScript.cpp ('k') | Source/bindings/core/dart/DartJsInteropData.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..af37d6419a74c8b35930e317d3d64d6a3fd85910 100644
--- a/Source/bindings/core/dart/DartJsInterop.cpp
+++ b/Source/bindings/core/dart/DartJsInterop.cpp
@@ -52,8 +52,93 @@ const int JsObject::dartClassId = _JsObjectClassId;
const int JsFunction::dartClassId = _JsFunctionClassId;
const int JsArray::dartClassId = _JsArrayClassId;
+// TODO(jacobr): v8::String::NewFromUtf8 usages should be cached for constant
+// strings to improve performance.
+/**
+ * Polyfill script to make Dart List objects look like JavaScript arrays when
+ * passed to JavaScript via JavaScript interop. Handling the edge cases
+ * requires patching the JavaScript Array prototype for a couple methods
+ * and implementing all of the JavaScript Array methods on the JavaScript
+ * proxy object for the Dart List. Some of the JavaScript methods are
+ * implemented in Dart and C++ code, some are implemented in this JavaScript
+ * polyfill script.
+ */
+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 +315,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 +396,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 +447,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 +467,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 +1013,20 @@ 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);
+}
+
+static void interfacesFinalizedCallback(Dart_NativeArguments args)
+{
+ DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateData(args));
+ DartJsInteropData* interopData = domData->jsInteropData();
+ // Skip if the JSObjectImpl class has already been defined.
+ Dart_SetBooleanReturnValue(args, interopData->jsObjectImplDefined());
+}
+
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 +1165,8 @@ fail:
static DartNativeEntry nativeEntries[] = {
{ JsInteropInternal::jsObjectConstructorCallback, 2, "JsObject_constructorCallback" },
{ JsInteropInternal::contextCallback, 0, "Js_context_Callback" },
+ { JsInteropInternal::finalizeJsInterfacesCallback, 0, "Js_finalizeJsInterfaces" },
+ { JsInteropInternal::interfacesFinalizedCallback, 0, "Js_interfacesFinalized_Callback" },
{ JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" },
{ JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" },
{ JsInteropInternal::getterCallback, 2, "JsObject_[]" },
@@ -1055,4 +1212,331 @@ 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;
+}
+
+// If one of the methods we added to the Dart List proxy to make it mascarade
+// as JavaScript Array happens to get called on a JavaScript object instead of
+// a Dart List proxy object we use the corresponding regular JavaScript Array
+// method which will do something plausible in most cases even if the
+// JavaScript object isn't actually a JavaScript array.
+bool handleNonDartProxyThis(const v8::FunctionCallbackInfo<v8::Value>& info, const char* jsMethodName)
+{
+ if (DartHandleProxy::isDartProxy(info.Holder())) {
+ return false;
+ }
+ v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
vsm 2015/06/29 13:49:26 Do we actually ever get down this path? And if so
Jacob 2015/06/29 17:56:08 Yeah it is a bit strange but I'm trying to make th
+ // Get the method on JS array in an inefficient way.
+ v8::Local<v8::Function> method = v8::Array::New(v8Isolate)->Get(v8::String::NewFromUtf8(v8Isolate, jsMethodName)).As<v8::Function>();
+ ASSERT(!method.IsEmpty());
+ int length = info.Length();
+ Vector<v8::Local<v8::Value> > v8Args(length);
+ for (int i = 0; i < length; ++i) {
+ v8Args[i] = info[i];
+ }
+ v8SetReturnValue(info, method->Call(info.Holder(), length, v8Args.data()));
+ return true;
+}
+
+void arrayHelper(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName, const char* jsMethodName)
+{
+ if (handleNonDartProxyThis(info, jsMethodName)) {
+ 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, const char* jsMethodName)
+{
+ if (handleNonDartProxyThis(info, jsMethodName)) {
+ 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);
+}
+
+void arrayHelperWithArgsAsList(const v8::FunctionCallbackInfo<v8::Value>& info, const char* methodName, const char* jsMethodName)
+{
+ if (handleNonDartProxyThis(info, jsMethodName)) {
+ 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));
+}
+
+static void arrayNamedPropertyGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)
+{
+ if (!DartHandleProxy::isDartProxy(info.Holder())) {
+ // I don't think this case can occur but avoid crashing if there is an
+ // exotic way to trigger it.
+ 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())) {
+ // I don't think this case can occur but avoid crashing if there is an
+ // exotic way to trigger it.
+ 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", "toString");
+}
+
+
+void arrayJoinCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelper1Arg(info, "_arrayJoin", "join");
+}
+
+void arrayPushCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelperWithArgsAsList(info, "_arrayPush", "push");
+}
+
+void arrayPopCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelper(info, "_arrayPop", "pop");
+}
+
+void concatCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelperWithArgsAsList(info, "_arrayConcat", "concat");
+}
+
+void arrayReverseCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelper(info, "_arrayReverse", "reverse");
+}
+
+void arrayShiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelper(info, "_arrayShift", "shift");
+}
+
+void arrayUnshiftCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelperWithArgsAsList(info, "_arrayUnshift", "unshift");
+}
+
+void arraySpliceCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ arrayHelperWithArgsAsList(info, "_arraySplice", "splice");
+}
+
+void toJsArrayCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
+{
+ // This isn't a method on the JavaScript Array class so it is fine to
+ // just return the existing hopefully Array like JS object if not called on
+ // a Dart List.
+ if (!DartHandleProxy::isDartProxy(info.Holder())) {
+ v8SetReturnValue(info, info.Holder());
+ }
+ 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", "sort");
+}
+
+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;
+}
+
}
« no previous file with comments | « Source/bindings/core/dart/DartInjectedScript.cpp ('k') | Source/bindings/core/dart/DartJsInteropData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698