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

Side by Side Diff: sky/engine/bindings-dart/core/dart/DartJsInterop.cpp

Issue 875013003: Import Dart bindings as of Blink r188698. This merely copies the files over and does not attach any… (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 10 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "config.h"
31
32 #include "bindings/core/dart/DartJsInterop.h"
33
34 #include "bindings/core/dart/DartDOMWrapper.h"
35 #include "bindings/core/dart/DartHandleProxy.h"
36 #include "bindings/core/dart/DartJsInteropData.h"
37 #include "bindings/core/dart/DartPersistentValue.h"
38 #include "bindings/core/dart/DartUtilities.h"
39 #include "bindings/core/dart/V8Converter.h"
40 #include "bindings/core/v8/V8Binding.h"
41 #include "bindings/core/v8/V8RecursionScope.h"
42 #include "bindings/core/v8/V8ScriptRunner.h"
43
44 #include "wtf/StdLibExtras.h"
45
46 #include <dart_api.h>
47 #include <limits>
48
49 namespace blink {
50
51 const int JsObject::dartClassId = _JsObjectClassId;
52 const int JsFunction::dartClassId = _JsFunctionClassId;
53 const int JsArray::dartClassId = _JsArrayClassId;
54
55 static v8::Local<v8::FunctionTemplate> dartFunctionTemplate();
56 static v8::Local<v8::FunctionTemplate> dartObjectTemplate();
57
58 template<typename CallbackInfo>
59 void setJsReturnValue(DartDOMData* domData, CallbackInfo info, Dart_Handle resul t)
60 {
61 if (Dart_IsError(result)) {
62 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
63 V8ThrowException::throwException(v8::String::NewFromUtf8(v8Isolate, Dart _GetError(result)), v8Isolate);
64 } else {
65 Dart_Handle exception = 0;
66 v8::Local<v8::Value> ret = JsInterop::fromDart(domData, result, exceptio n);
67 if (exception) {
68 V8ThrowException::throwException(V8Converter::stringToV8(Dart_ToStri ng(exception)), v8::Isolate::GetCurrent());
69 return;
70 }
71 v8SetReturnValue(info, ret);
72 }
73 }
74
75 static void functionInvocationCallback(const v8::FunctionCallbackInfo<v8::Value> & args)
76 {
77 DartScopes scopes(args.Holder());
78 Dart_Handle handle = scopes.handle;
79 DartDOMData* domData = DartDOMData::current();
80 ASSERT(domData);
81 ASSERT(DartUtilities::isFunction(domData, handle));
82
83 Vector<Dart_Handle> dartFunctionArgs;
84 ASSERT(args.Length() == 1 || args.Length() == 2);
85 // If there is 1 argument, we assume it is a v8:Array or arguments, if
86 // there are 2 arguments, the first argument is "this" and the second
87 // argument is an array of arguments.
88 if (args.Length() > 1) {
89 dartFunctionArgs.append(JsInterop::toDart(args[0]));
90 }
91
92 v8::Local<v8::Array> argsList = args[args.Length()-1].As<v8::Array>();
93 uint32_t argsListLength = argsList->Length();
94 for (uint32_t i = 0; i < argsListLength; i++) {
95 dartFunctionArgs.append(JsInterop::toDart(argsList->Get(i)));
96 }
97
98 setJsReturnValue(domData, args, Dart_InvokeClosure(handle, dartFunctionArgs. size(), dartFunctionArgs.data()));
99 }
100
101 static v8::Local<v8::ObjectTemplate> setupInstanceTemplate(v8::Local<v8::Functio nTemplate> proxyTemplate)
102 {
103 v8::Local<v8::ObjectTemplate> instanceTemplate = proxyTemplate->InstanceTemp late();
104 instanceTemplate->SetInternalFieldCount(1);
105 return instanceTemplate;
106 }
107
108 static v8::Local<v8::FunctionTemplate> dartFunctionTemplate()
109 {
110 DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ()) ;
111 v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
112 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
113 if (proxyTemplate.IsEmpty()) {
114 proxyTemplate.Reset(v8::Isolate::GetCurrent(), v8::FunctionTemplate::New (v8Isolate));
115 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
116 v8::Local<v8::ObjectTemplate> instanceTemplate = setupInstanceTemplate(p roxyTemplateLocal);
117
118 instanceTemplate->SetCallAsFunctionHandler(&functionInvocationCallback);
119 } else {
120 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
121 }
122 return proxyTemplateLocal;
123 }
124
125 static v8::Local<v8::FunctionTemplate> dartObjectTemplate()
126 {
127 DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, proxyTemplate, ()) ;
128 v8::Local<v8::FunctionTemplate> proxyTemplateLocal;
129 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
130 if (proxyTemplate.IsEmpty()) {
131 proxyTemplate.Reset(v8Isolate, v8::FunctionTemplate::New(v8Isolate));
132 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
133 proxyTemplateLocal->SetClassName(v8::String::NewFromUtf8(v8Isolate, "Dar tObject"));
134 setupInstanceTemplate(proxyTemplateLocal);
135 } else {
136 proxyTemplateLocal = v8::Local<v8::FunctionTemplate>::New(v8Isolate, pro xyTemplate);
137 }
138 return proxyTemplateLocal;
139 }
140
141 /**
142 * Helper class to manage scopes needed for JSInterop code.
143 */
144 class JsInteropScopes {
145 public:
146 Dart_NativeArguments args;
147 v8::Context::Scope v8Scope;
148 v8::TryCatch tryCatch;
149
150 JsInteropScopes(Dart_NativeArguments args)
151 : args(args)
152 , v8Scope(DartUtilities::currentV8Context())
153 {
154 ASSERT(v8::Isolate::GetCurrent());
155 }
156
157 ~JsInteropScopes()
158 {
159 // The user is expected to call handleJsException before the scope is
160 // closed so that V8 exceptions are properly sent back to Dart.
161 ASSERT(!tryCatch.HasCaught());
162 }
163
164 bool handleJsException(Dart_Handle* exception)
165 {
166 if (!tryCatch.HasCaught())
167 return false;
168 // FIXME: terminate v8 if tryCatch.CanContinue() is false.
169 ASSERT(tryCatch.CanContinue());
170 ASSERT(exception);
171 v8::Handle<v8::Value> ex(tryCatch.Exception()->ToString());
172 if (ex.IsEmpty()) {
173 *exception = Dart_NewStringFromCString("Empty JavaScript exception") ;
174 } else {
175 *exception = V8Converter::stringToDart(ex);
176 }
177 tryCatch.Reset();
178 return true;
179 }
180
181 void setReturnValue(Dart_Handle ret)
182 {
183 ASSERT(!tryCatch.HasCaught());
184 Dart_SetReturnValue(args, ret);
185 }
186
187 void setReturnValue(v8::Local<v8::Value> ret)
188 {
189 ASSERT(!tryCatch.HasCaught());
190 Dart_SetReturnValue(args, JsInterop::toDart(ret));
191 ASSERT(!tryCatch.HasCaught());
192 }
193
194 void setReturnValueInteger(int64_t ret)
195 {
196 ASSERT(!tryCatch.HasCaught());
197 Dart_SetIntegerReturnValue(args, ret);
198 }
199 };
200
201 PassRefPtr<JsObject> JsObject::create(v8::Local<v8::Object> v8Handle)
202 {
203 return adoptRef(new JsObject(v8Handle));
204 }
205
206 v8::Local<v8::Value> JsInterop::fromDart(DartDOMData* domData, Dart_Handle handl e, Dart_Handle& exception)
207 {
208 v8::Handle<v8::Value> value = V8Converter::toV8IfPrimitive(domData, handle, exception);
209 if (!value.IsEmpty() || exception)
210 return value;
211
212 value = V8Converter::toV8IfBrowserNative(domData, handle, exception);
213 if (!value.IsEmpty() || exception)
214 return value;
215
216 if (DartDOMWrapper::subtypeOf(handle, JsObject::dartClassId)) {
217 JsObject* object = DartDOMWrapper::unwrapDartWrapper<JsObject>(domData, handle, exception);
218 if (exception)
219 return v8::Local<v8::Value>();
220 return object->localV8Object();
221 }
222
223 if (DartUtilities::isFunction(domData, handle)) {
224 v8::Local<v8::Object> functionProxy = dartFunctionTemplate()->InstanceTe mplate()->NewInstance();
225 DartHandleProxy::writePointerToProxy(functionProxy, handle);
226 // The raw functionProxy doesn't behave enough like a true JS function
227 // so we wrap it in a true JS function.
228 return domData->jsInteropData()->wrapDartFunction()->Call(functionProxy, 0, 0);
229 }
230
231 v8::Local<v8::Object> proxy;
232 ASSERT(Dart_IsInstance(handle));
233 proxy = dartObjectTemplate()->InstanceTemplate()->NewInstance();
234 DartHandleProxy::writePointerToProxy(proxy, handle);
235 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent();
236 proxy->SetHiddenValue(v8::String::NewFromUtf8(v8Isolate, "dartProxy"), v8::B oolean::New(v8Isolate, true));
237
238 return proxy;
239 }
240
241 JsObject::JsObject(v8::Local<v8::Object> v8Handle)
242 {
243 v8::Isolate* isolate = v8::Isolate::GetCurrent();
244 v8::Persistent<v8::Object> persistentHandle;
245 v8Object.Reset(isolate, v8Handle);
246 }
247
248 v8::Local<v8::Object> JsObject::localV8Object()
249 {
250 return v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), v8Object);
251 }
252
253 Dart_Handle JsInterop::toDart(v8::Local<v8::Value> v8Handle)
254 {
255 Dart_Handle handle = V8Converter::toDartIfPrimitive(v8Handle);
256 if (handle)
257 return handle;
258
259 ASSERT(v8Handle->IsObject());
260 v8::Handle<v8::Object> object = v8Handle.As<v8::Object>();
261 Dart_Handle exception = 0;
262 handle = V8Converter::toDartIfBrowserNative(object, object->CreationContext( )->GetIsolate(), exception);
263 ASSERT(!exception);
264 if (handle)
265 return handle;
266
267 // Unwrap objects passed from Dart to JS that are being passed back to
268 // Dart. FIXME: we do not yet handle unwrapping JS functions passed
269 // from Dart to JS as we have to wrap them with true JS Function objects.
270 // If this use case is important we can support it at the cost of hanging
271 // an extra expando off the JS function wrapping the Dart function.
272 if (DartHandleProxy::isDartProxy(v8Handle)) {
273 DartPersistentValue* scriptValue = DartHandleProxy::readPointerFromProxy (v8Handle);
274 ASSERT(scriptValue->isIsolateAlive());
275 return scriptValue->value();
276 }
277
278 return JsObject::toDart(object);
279 }
280
281 Dart_Handle JsObject::toDart(v8::Local<v8::Object> object)
282 {
283 // FIXME: perform caching so that === can be used.
284 if (object->IsFunction()) {
285 RefPtr<JsFunction> jsFunction = JsFunction::create(object.As<v8::Functio n>());
286 return JsFunction::toDart(jsFunction);
287 }
288
289 if (object->IsArray()) {
290 RefPtr<JsArray> jsArray = JsArray::create(object.As<v8::Array>());
291 return JsArray::toDart(jsArray);
292 }
293
294 RefPtr<JsObject> jsObject = JsObject::create(object);
295 return JsObject::toDart(jsObject);
296 }
297
298 Dart_Handle JsObject::toDart(PassRefPtr<JsObject> jsObject)
299 {
300 return DartDOMWrapper::createWrapper<JsObject>(DartDOMData::current(), jsObj ect.get(), JsObject::dartClassId);
301 }
302
303 JsObject::~JsObject()
304 {
305 v8Object.Reset();
306 }
307
308 Dart_Handle JsFunction::toDart(PassRefPtr<JsFunction> jsFunction)
309 {
310 return DartDOMWrapper::createWrapper<JsFunction>(DartDOMData::current(), jsF unction.get(), JsFunction::dartClassId);
311 }
312
313 JsFunction::JsFunction(v8::Local<v8::Function> v8Handle) : JsObject(v8Handle) { }
314
315 PassRefPtr<JsFunction> JsFunction::create(v8::Local<v8::Function> v8Handle)
316 {
317 return adoptRef(new JsFunction(v8Handle));
318 }
319
320 v8::Local<v8::Function> JsFunction::localV8Function()
321 {
322 return localV8Object().As<v8::Function>();
323 }
324
325 Dart_Handle JsArray::toDart(PassRefPtr<JsArray> jsArray)
326 {
327 return DartDOMWrapper::createWrapper<JsArray>(DartDOMData::current(), jsArra y.get(), JsArray::dartClassId);
328 }
329
330 JsArray::JsArray(v8::Local<v8::Array> v8Handle) : JsObject(v8Handle) { }
331
332 PassRefPtr<JsArray> JsArray::create(v8::Local<v8::Array> v8Handle)
333 {
334 return adoptRef(new JsArray(v8Handle));
335 }
336
337 v8::Local<v8::Array> JsArray::localV8Array()
338 {
339 return localV8Object().As<v8::Array>();
340 }
341
342 namespace JsInteropInternal {
343
344 typedef HashMap<Dart_Handle, v8::Handle<v8::Value> > DartHandleToV8Map;
345 v8::Handle<v8::Value> jsifyHelper(DartDOMData*, Dart_Handle value, DartHandleToV 8Map&, Dart_Handle& exception);
346
347 void argsListToV8(DartDOMData* domData, Dart_Handle args, Vector<v8::Local<v8::V alue> >* v8Args, Dart_Handle& exception)
348 {
349 if (Dart_IsNull(args))
350 return;
351
352 if (!Dart_IsList(args)) {
353 exception = Dart_NewStringFromCString("args not type list");
354 return;
355 }
356
357 intptr_t argsLength = 0;
358 Dart_ListLength(args, &argsLength);
359 for (intptr_t i = 0; i < argsLength; i++) {
360 v8Args->append(JsInterop::fromDart(domData, Dart_ListGetAt(args, i), exc eption));
361 if (exception)
362 return;
363 }
364 }
365
366 void argsListToV8DebuggerOnly(DartDOMData* domData, Dart_Handle args, Vector<v8: :Local<v8::Value> >* v8Args, Dart_Handle& exception)
367 {
368 if (Dart_IsNull(args))
369 return;
370
371 if (!Dart_IsList(args)) {
372 exception = Dart_NewStringFromCString("args not type list");
373 return;
374 }
375
376 intptr_t argsLength = 0;
377 Dart_ListLength(args, &argsLength);
378 for (intptr_t i = 0; i < argsLength; i++) {
379 v8Args->append(DartHandleProxy::create(Dart_ListGetAt(args, i)));
380 }
381 }
382
383 static void jsObjectConstructorCallback(Dart_NativeArguments args)
384 {
385 Dart_Handle exception = 0;
386 {
387 JsInteropScopes scopes(args);
388 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
389 v8::Local<v8::Value> constructorArg = JsInterop::fromDart(domData, Dart_ GetNativeArgument(args, 0), exception);
390 if (exception)
391 goto fail;
392
393 if (!constructorArg->IsFunction()) {
394 exception = Dart_NewStringFromCString("constructor not a function");
395 goto fail;
396 }
397
398 Vector<v8::Local<v8::Value> > v8Args;
399 argsListToV8(domData, Dart_GetNativeArgument(args, 1), &v8Args, exceptio n);
400
401 v8::Local<v8::Value> ret = constructorArg.As<v8::Function>()->CallAsCons tructor(v8Args.size(), v8Args.data());
402 crashIfV8IsDead();
403
404 if (scopes.handleJsException(&exception))
405 goto fail;
406
407 // Intentionally skip auto-conversion in this case as the user expects
408 // a JSObject. FIXME: evaluate if this is the right solution.
409 // Alternately, we could throw an exception.
410 if (ret->IsObject()) {
411 scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
412 } else {
413 // This will throw an exception in Dart checked mode.
414 scopes.setReturnValue(ret);
415 }
416 return;
417 }
418
419 fail:
420 Dart_ThrowException(exception);
421 ASSERT_NOT_REACHED();
422 }
423
424 static void identityEqualityCallback(Dart_NativeArguments args)
425 {
426 Dart_Handle exception = 0;
427 {
428 JsInteropScopes scopes(args);
429 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
430 v8::Local<v8::Value> a = JsInterop::fromDart(domData, Dart_GetNativeArgu ment(args, 0), exception);
431 if (exception)
432 goto fail;
433 v8::Local<v8::Value> b = JsInterop::fromDart(domData, Dart_GetNativeArgu ment(args, 1), exception);
434 if (exception)
435 goto fail;
436
437 bool strictEquals = a->StrictEquals(b);
438
439 if (scopes.handleJsException(&exception))
440 goto fail;
441 scopes.setReturnValue(DartUtilities::boolToDart(strictEquals));
442 return;
443 }
444
445 fail:
446 Dart_ThrowException(exception);
447 ASSERT_NOT_REACHED();
448 }
449
450 static void getterCallback(Dart_NativeArguments args)
451 {
452 Dart_Handle exception = 0;
453 {
454 JsInteropScopes scopes(args);
455 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
456 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
457 Dart_Handle index = Dart_GetNativeArgument(args, 1);
458 uint64_t intIndex = 0;
459 v8::Local<v8::Value> ret;
460
461 if (Dart_IsInteger(index)) {
462 bool isUint64 = false;
463 Dart_IntegerFitsIntoUint64(index, &isUint64);
464 if (isUint64) {
465 Dart_Handle ALLOW_UNUSED result = Dart_IntegerToUint64(index, &i ntIndex);
466 if (intIndex <= std::numeric_limits<uint32_t>::max()) {
467 ASSERT(!Dart_IsError(result));
468 ret = v8Receiver->Get((uint32_t)intIndex);
469 } else {
470 ret = v8Receiver->Get(V8Converter::numberToV8(index));
471 }
472 } else {
473 ret = v8Receiver->Get(V8Converter::numberToV8(index));
474 }
475 } else if (Dart_IsString(index)) {
476 ret = v8Receiver->Get(V8Converter::stringToV8(index));
477 } else if (Dart_IsNumber(index)) {
478 ret = v8Receiver->Get(V8Converter::numberToV8(index));
479 } else {
480 ret = v8Receiver->Get(V8Converter::stringToV8(Dart_ToString(index))) ;
481 }
482
483 if (scopes.handleJsException(&exception))
484 goto fail;
485 scopes.setReturnValue(ret);
486 return;
487 }
488
489 fail:
490 Dart_ThrowException(exception);
491 ASSERT_NOT_REACHED();
492 }
493
494 static void hasPropertyCallback(Dart_NativeArguments args)
495 {
496 Dart_Handle exception = 0;
497 {
498 JsInteropScopes scopes(args);
499 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
500 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
501 Dart_Handle property = Dart_GetNativeArgument(args, 1);
502
503 if (!Dart_IsString(property))
504 property = Dart_ToString(property);
505
506 bool hasProperty = v8Receiver->Has(V8Converter::stringToV8(property));
507 if (scopes.handleJsException(&exception))
508 goto fail;
509 scopes.setReturnValue(DartUtilities::boolToDart(hasProperty));
510 return;
511 }
512
513 fail:
514 Dart_ThrowException(exception);
515 ASSERT_NOT_REACHED();
516 }
517
518 static void deletePropertyCallback(Dart_NativeArguments args)
519 {
520 Dart_Handle exception = 0;
521 {
522 JsInteropScopes scopes(args);
523 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
524 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
525 Dart_Handle property = Dart_GetNativeArgument(args, 1);
526 if (!Dart_IsString(property))
527 property = Dart_ToString(property);
528
529 v8Receiver->Delete(V8Converter::stringToV8(property));
530 if (scopes.handleJsException(&exception))
531 goto fail;
532 return;
533 }
534
535 fail:
536 Dart_ThrowException(exception);
537 ASSERT_NOT_REACHED();
538 }
539
540 static void instanceofCallback(Dart_NativeArguments args)
541 {
542 Dart_Handle exception = 0;
543 {
544 JsInteropScopes scopes(args);
545 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
546 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
547 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
548 v8::Local<v8::Value> type = JsInterop::fromDart(domData, Dart_GetNativeA rgument(args, 1), exception);
549
550 // FIXME: we could optimize the following lines slightly as the return
551 // type is bool.
552 v8::Local<v8::Value> ret = domData->jsInteropData()->instanceofFunction( )->Call(v8Receiver, 1, &type);
553 if (scopes.handleJsException(&exception))
554 goto fail;
555 scopes.setReturnValue(ret);
556 return;
557 }
558
559 fail:
560 Dart_ThrowException(exception);
561 ASSERT_NOT_REACHED();
562 }
563
564 static void setterCallback(Dart_NativeArguments args)
565 {
566 Dart_Handle exception = 0;
567 {
568 JsInteropScopes scopes(args);
569 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
570 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
571 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
572 Dart_Handle index = Dart_GetNativeArgument(args, 1);
573 v8::Local<v8::Value> value = JsInterop::fromDart(domData, Dart_GetNative Argument(args, 2), exception);
574 if (exception)
575 goto fail;
576 uint64_t intIndex = 0;
577 bool ret = false;
578 if (Dart_IsInteger(index)) {
579 bool isUint64 = false;
580 Dart_IntegerFitsIntoUint64(index, &isUint64);
581 if (isUint64) {
582 Dart_Handle ALLOW_UNUSED result = Dart_IntegerToUint64(index, &i ntIndex);
583 if (intIndex <= std::numeric_limits<uint32_t>::max()) {
584 ASSERT(!Dart_IsError(result));
585 ret = v8Receiver->Set((uint32_t)intIndex, value);
586 } else {
587 ret = v8Receiver->Set(V8Converter::numberToV8(index), value) ;
588 }
589 } else {
590 ret = v8Receiver->Set(V8Converter::numberToV8(index), value);
591 }
592 } else if (Dart_IsString(index)) {
593 ret = v8Receiver->Set(V8Converter::stringToV8(index), value);
594 } else if (Dart_IsNumber(index)) {
595 ret = v8Receiver->Set(V8Converter::numberToV8(index), value);
596 } else {
597 ret = v8Receiver->Set(V8Converter::stringToV8(Dart_ToString(index)), value);
598 }
599
600 if (scopes.handleJsException(&exception))
601 goto fail;
602 scopes.setReturnValue(DartUtilities::boolToDart(ret));
603 return;
604 }
605
606 fail:
607 Dart_ThrowException(exception);
608 ASSERT_NOT_REACHED();
609 }
610
611 static void hashCodeCallback(Dart_NativeArguments args)
612 {
613 Dart_Handle exception = 0;
614 {
615 JsInteropScopes scopes(args);
616 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
617 int hashCode = receiver->localV8Object()->GetIdentityHash();
618 // FIXME: salt the v8 hashcode so we don't leak information about v8
619 // memory allocation.
620 if (scopes.handleJsException(&exception))
621 goto fail;
622 scopes.setReturnValueInteger(hashCode);
623 return;
624 }
625
626 fail:
627 Dart_ThrowException(exception);
628 ASSERT_NOT_REACHED();
629 }
630
631 static void callMethodCallback(Dart_NativeArguments args)
632 {
633 Dart_Handle exception = 0;
634 {
635 JsInteropScopes scopes(args);
636 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
637 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
638 v8::Local<v8::Object> v8Receiver = receiver->localV8Object();
639
640 Dart_Handle name = Dart_GetNativeArgument(args, 1);
641 Vector<v8::Local<v8::Value> > v8Args;
642 argsListToV8(domData, Dart_GetNativeArgument(args, 2), &v8Args, exceptio n);
643 if (exception)
644 goto fail;
645 if (!Dart_IsString(name))
646 name = Dart_ToString(name);
647
648 v8::Local<v8::Value> value = v8Receiver->Get(V8Converter::stringToV8(nam e));
649 v8::Local<v8::Value> ret;
650 if (value->IsFunction()) {
651 ret = V8ScriptRunner::callFunction(value.As<v8::Function>(), DartUti lities::scriptExecutionContext(), receiver->localV8Object(), v8Args.size(), v8Ar gs.data(), v8::Isolate::GetCurrent());
652 } else if (value->IsObject()) {
653 ret = V8ScriptRunner::callAsFunction(v8::Isolate::GetCurrent(), valu e.As<v8::Object>(), receiver->localV8Object(), v8Args.size(), v8Args.data());
654 } else {
655 // FIXME: we currently convert this exception to a NoSuchMethod
656 // exception in the Dart code that wraps this native method.
657 // Consider throwing a NoSuchMethod exception directly instead.
658 exception = Dart_NewStringFromCString("property is not a function");
659 goto fail;
660 }
661
662 if (scopes.handleJsException(&exception))
663 goto fail;
664 scopes.setReturnValue(ret);
665 return;
666 }
667
668 fail:
669 Dart_ThrowException(exception);
670 ASSERT_NOT_REACHED();
671 }
672
673 static void newJsArrayCallback(Dart_NativeArguments args)
674 {
675 JsInteropScopes scopes(args);
676 scopes.setReturnValue(JsObject::toDart(v8::Array::New(v8::Isolate::GetCurren t())));
677 return;
678 }
679
680 static void newJsArrayFromSafeListCallback(Dart_NativeArguments args)
681 {
682 Dart_Handle exception = 0;
683 {
684 JsInteropScopes scopes(args);
685 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
686 Dart_Handle list = Dart_GetNativeArgument(args, 0);
687 // Code on the Dart side insures this arg is a native Dart list.
688 ASSERT(Dart_IsList(list));
689
690 intptr_t length = 0;
691 Dart_Handle result = Dart_ListLength(list, &length);
692 ASSERT(!Dart_IsError(result));
693 v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), l ength);
694
695 for (intptr_t i = 0; i < length; ++i) {
696 result = Dart_ListGetAt(list, i);
697 ASSERT(!Dart_IsError(result));
698 v8::Handle<v8::Value> v8value = JsInterop::fromDart(domData, result, exception);
699 if (exception)
700 goto fail;
701
702 array->Set(i, v8value);
703 }
704 scopes.setReturnValue(array);
705 return;
706 }
707
708 fail:
709 Dart_ThrowException(exception);
710 ASSERT_NOT_REACHED();
711 }
712
713
714 static void jsArrayLengthCallback(Dart_NativeArguments args)
715 {
716 Dart_Handle exception = 0;
717 {
718 JsInteropScopes scopes(args);
719 JsArray* receiver = DartDOMWrapper::receiver<JsArray>(args);
720 uint32_t length = receiver->localV8Array()->Length();
721 if (scopes.handleJsException(&exception))
722 goto fail;
723 scopes.setReturnValueInteger(length);
724 return;
725 }
726
727 fail:
728 Dart_ThrowException(exception);
729 ASSERT_NOT_REACHED();
730 }
731
732 static void fromBrowserObjectCallback(Dart_NativeArguments args)
733 {
734 Dart_Handle exception = 0;
735 {
736 JsInteropScopes scopes(args);
737 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
738
739 v8::Local<v8::Value> ret = V8Converter::toV8IfBrowserNative(domData, Dar t_GetNativeArgument(args, 0), exception);
740 if (ret.IsEmpty()) {
741 exception = Dart_NewStringFromCString("object must be an Node, Array Buffer, Blob, ImageData, or IDBKeyRange");
742 goto fail;
743 }
744 if (exception)
745 goto fail;
746 ASSERT(ret->IsObject());
747 if (scopes.handleJsException(&exception))
748 goto fail;
749 scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
750 return;
751 }
752
753 fail:
754 Dart_ThrowException(exception);
755 ASSERT_NOT_REACHED();
756 }
757
758 static void applyCallback(Dart_NativeArguments args)
759 {
760 Dart_Handle exception = 0;
761 {
762 JsInteropScopes scopes(args);
763 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
764 JsFunction* receiver = DartDOMWrapper::receiver<JsFunction>(args);
765
766 Vector<v8::Local<v8::Value> > v8Args;
767 argsListToV8(domData, Dart_GetNativeArgument(args, 1), &v8Args, exceptio n);
768 if (exception)
769 goto fail;
770
771 v8::Local<v8::Value> thisArg;
772 Dart_Handle thisArgDart = Dart_GetNativeArgument(args, 2);
773 if (Dart_IsNull(thisArgDart)) {
774 // Use the global v8 object if no Dart thisArg was passed in.
775 thisArg = DartUtilities::currentV8Context()->Global();
776 } else {
777 thisArg = JsInterop::fromDart(domData, thisArgDart, exception);
778 if (exception)
779 goto fail;
780 if (!thisArg->IsObject()) {
781 exception = Dart_NewStringFromCString("thisArg is not an object" );
782 goto fail;
783 }
784 }
785
786 v8::Local<v8::Value> ret = V8ScriptRunner::callFunction(receiver->localV 8Function(), DartUtilities::scriptExecutionContext(), thisArg.As<v8::Object>(), v8Args.size(), v8Args.data(), v8::Isolate::GetCurrent());
787 if (scopes.handleJsException(&exception))
788 goto fail;
789 scopes.setReturnValue(ret);
790 return;
791 }
792
793 fail:
794 Dart_ThrowException(exception);
795 ASSERT_NOT_REACHED();
796 }
797
798 static void applyDebuggerOnlyCallback(Dart_NativeArguments args)
799 {
800 Dart_Handle exception = 0;
801 {
802 JsInteropScopes scopes(args);
803 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
804 JsFunction* receiver = DartDOMWrapper::receiver<JsFunction>(args);
805
806 Vector<v8::Local<v8::Value> > v8Args;
807 argsListToV8DebuggerOnly(domData, Dart_GetNativeArgument(args, 1), &v8Ar gs, exception);
808 if (exception)
809 goto fail;
810
811 v8::Local<v8::Value> thisArg;
812 Dart_Handle thisArgDart = Dart_GetNativeArgument(args, 2);
813 if (Dart_IsNull(thisArgDart)) {
814 // Use the global v8 object if no Dart thisArg was passed in.
815 thisArg = DartUtilities::currentV8Context()->Global();
816 } else {
817 thisArg = JsInterop::fromDart(domData, thisArgDart, exception);
818 if (exception)
819 goto fail;
820 if (!thisArg->IsObject()) {
821 exception = Dart_NewStringFromCString("thisArg is not an object" );
822 goto fail;
823 }
824 }
825
826 v8::Local<v8::Value> ret = V8ScriptRunner::callFunction(receiver->localV 8Function(), DartUtilities::scriptExecutionContext(), thisArg.As<v8::Object>(), v8Args.size(), v8Args.data(), v8::Isolate::GetCurrent());
827 if (scopes.handleJsException(&exception))
828 goto fail;
829 scopes.setReturnValue(ret);
830 return;
831 }
832
833 fail:
834 Dart_ThrowException(exception);
835 ASSERT_NOT_REACHED();
836 }
837
838 static void toStringCallback(Dart_NativeArguments args)
839 {
840 Dart_Handle exception = 0;
841 {
842 JsInteropScopes scopes(args);
843 JsObject* receiver = DartDOMWrapper::receiver<JsObject>(args);
844 v8::Local<v8::Object> v8Object = receiver->localV8Object();
845 if (scopes.handleJsException(&exception))
846 goto fail;
847 if (v8Object.IsEmpty()) {
848 exception = Dart_NewStringFromCString("Invalid v8 handle");
849 goto fail;
850 }
851
852 v8::Local<v8::String> v8String = v8Object->ToString();
853 if (scopes.handleJsException(&exception))
854 goto fail;
855 scopes.setReturnValue(v8String);
856 return;
857 }
858 fail:
859 Dart_ThrowException(exception);
860 ASSERT_NOT_REACHED();
861 }
862
863 static void contextCallback(Dart_NativeArguments args)
864 {
865 v8::Local<v8::Context> v8Context = DartUtilities::currentV8Context();
866 v8::Context::Scope scope(v8Context);
867 Dart_SetReturnValue(args, JsObject::toDart(v8Context->Global()));
868 }
869
870 v8::Handle<v8::Value> mapToV8(DartDOMData* domData, Dart_Handle value, DartHandl eToV8Map& map, Dart_Handle& exception)
871 {
872 Dart_Handle asList = DartUtilities::invokeUtilsMethod("convertMapToList", 1, &value);
873 if (!DartUtilities::checkResult(asList, exception))
874 return v8::Handle<v8::Value>();
875 ASSERT(Dart_IsList(asList));
876
877 // Now we have a list [key, value, key, value, ....], create a v8 object and set necesary
878 // properties on it.
879 v8::Handle<v8::Object> object = v8::Object::New(v8::Isolate::GetCurrent());
880 map.set(value, object);
881
882 // We converted to internal Dart list, methods shouldn't throw exceptions no w.
883 intptr_t length = 0;
884 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(asList, &length);
885 ASSERT(!Dart_IsError(result));
886 ASSERT(!(length % 2));
887 for (intptr_t i = 0; i < length; i += 2) {
888 v8::Handle<v8::Value> key = jsifyHelper(domData, Dart_ListGetAt(asList, i), map, exception);
889 if (exception)
890 return v8::Handle<v8::Value>();
891 v8::Handle<v8::Value> value = jsifyHelper(domData, Dart_ListGetAt(asList , i + 1), map, exception);
892 if (exception)
893 return v8::Handle<v8::Value>();
894
895 object->Set(key, value);
896 }
897
898 return object;
899 }
900
901 v8::Handle<v8::Value> listToV8(DartDOMData* domData, Dart_Handle value, DartHand leToV8Map& map, Dart_Handle& exception)
902 {
903 ASSERT(Dart_IsList(value));
904
905 intptr_t length = 0;
906 Dart_Handle result = Dart_ListLength(value, &length);
907 if (!DartUtilities::checkResult(result, exception))
908 return v8::Handle<v8::Value>();
909
910 v8::Local<v8::Array> array = v8::Array::New(v8::Isolate::GetCurrent(), lengt h);
911 map.set(value, array);
912
913 for (intptr_t i = 0; i < length; ++i) {
914 result = Dart_ListGetAt(value, i);
915 if (!DartUtilities::checkResult(result, exception))
916 return v8::Handle<v8::Value>();
917 v8::Handle<v8::Value> v8value = jsifyHelper(domData, result, map, except ion);
918 if (exception)
919 return v8::Handle<v8::Value>();
920 array->Set(i, v8value);
921 }
922
923 return array;
924 }
925
926 v8::Handle<v8::Value> jsifyHelper(DartDOMData* domData, Dart_Handle value, DartH andleToV8Map& map, Dart_Handle& exception)
927 {
928 DartHandleToV8Map::iterator iter = map.find(value);
929 if (iter != map.end())
930 return iter->value;
931
932 if (Dart_IsList(value))
933 return listToV8(domData, value, map, exception);
934
935 bool isMap = DartUtilities::dartToBool(DartUtilities::invokeUtilsMethod("isM ap", 1, &value), exception);
936 ASSERT(!exception);
937 if (isMap)
938 return mapToV8(domData, value, map, exception);
939
940 Dart_Handle maybeList = DartUtilities::invokeUtilsMethod("toListIfIterable", 1, &value);
941 if (Dart_IsList(maybeList))
942 return listToV8(domData, maybeList, map, exception);
943
944 v8::Handle<v8::Value> ret = JsInterop::fromDart(domData, value, exception);
945 map.set(value, ret);
946 return ret;
947 }
948
949 static void jsifyCallback(Dart_NativeArguments args)
950 {
951 Dart_Handle exception = 0;
952 {
953 JsInteropScopes scopes(args);
954 Dart_Handle value = Dart_GetNativeArgument(args, 0);
955 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
956 DartHandleToV8Map map;
957 v8::Local<v8::Value> ret = jsifyHelper(domData, value, map, exception);
958 if (exception)
959 goto fail;
960
961 if (scopes.handleJsException(&exception))
962 goto fail;
963 // Intentionally skip auto-conversion in this case as the user expects
964 // a JSObject. FIXME: evaluate if this is the right solution.
965 // Alternately, we could throw an exception.
966 if (ret->IsObject()) {
967 scopes.setReturnValue(JsObject::toDart(ret.As<v8::Object>()));
968 } else {
969 // This will throw an exception in Dart checked mode.
970 scopes.setReturnValue(ret);
971 }
972 return;
973 }
974 fail:
975 Dart_ThrowException(exception);
976 ASSERT_NOT_REACHED();
977 }
978
979 static void withThisCallback(Dart_NativeArguments args)
980 {
981 Dart_Handle exception = 0;
982 {
983 JsInteropScopes scopes(args);
984 Dart_Handle function = Dart_GetNativeArgument(args, 0);
985 DartDOMData* domData = static_cast<DartDOMData*>(Dart_GetNativeIsolateDa ta(args));
986 ASSERT(DartUtilities::isFunction(domData, function));
987
988 v8::Local<v8::Object> proxy = dartFunctionTemplate()->InstanceTemplate() ->NewInstance();
989 DartHandleProxy::writePointerToProxy(proxy, function);
990
991 v8::Local<v8::Function> ret = v8::Local<v8::Function>::Cast(domData->jsI nteropData()->captureThisFunction()->Call(proxy, 0, 0));
992
993 if (scopes.handleJsException(&exception))
994 goto fail;
995 scopes.setReturnValue(ret);
996 return;
997 }
998 fail:
999 Dart_ThrowException(exception);
1000 ASSERT_NOT_REACHED();
1001 }
1002
1003 }
1004
1005 static DartNativeEntry nativeEntries[] = {
1006 { JsInteropInternal::jsObjectConstructorCallback, 2, "JsObject_constructorCa llback" },
1007 { JsInteropInternal::contextCallback, 0, "Js_context_Callback" },
1008 { JsInteropInternal::jsifyCallback, 1, "JsObject_jsify" },
1009 { JsInteropInternal::withThisCallback, 1, "JsFunction_withThis" },
1010 { JsInteropInternal::getterCallback, 2, "JsObject_[]" },
1011 { JsInteropInternal::setterCallback, 3, "JsObject_[]=" },
1012 { JsInteropInternal::hashCodeCallback, 1, "JsObject_hashCode" },
1013 { JsInteropInternal::callMethodCallback, 3, "JsObject_callMethod" },
1014 { JsInteropInternal::toStringCallback, 1, "JsObject_toString" },
1015 { JsInteropInternal::identityEqualityCallback, 2, "JsObject_identityEquality " },
1016 { JsInteropInternal::hasPropertyCallback, 2, "JsObject_hasProperty" },
1017 { JsInteropInternal::deletePropertyCallback, 2, "JsObject_deleteProperty" },
1018 { JsInteropInternal::instanceofCallback, 2, "JsObject_instanceof" },
1019 { JsInteropInternal::applyCallback, 3, "JsFunction_apply" },
1020 { JsInteropInternal::applyDebuggerOnlyCallback, 3, "JsFunction_applyDebugger Only" },
1021 { JsInteropInternal::newJsArrayCallback, 0, "JsArray_newJsArray" },
1022 { JsInteropInternal::newJsArrayFromSafeListCallback, 1, "JsArray_newJsArrayF romSafeList" },
1023 { JsInteropInternal::jsArrayLengthCallback, 1, "JsArray_length" },
1024 { JsInteropInternal::fromBrowserObjectCallback, 1, "JsObject_fromBrowserObje ct" },
1025 { 0, 0, 0 },
1026 };
1027
1028 Dart_NativeFunction JsInterop::resolver(Dart_Handle nameHandle, int argumentCoun t, bool* autoSetupScope)
1029 {
1030 ASSERT(autoSetupScope);
1031 *autoSetupScope = true;
1032 String name = DartUtilities::toString(nameHandle);
1033
1034 for (intptr_t i = 0; nativeEntries[i].nativeFunction != 0; i++) {
1035 if (argumentCount == nativeEntries[i].argumentCount && name == nativeEnt ries[i].name) {
1036 return nativeEntries[i].nativeFunction;
1037 }
1038 }
1039
1040 return 0;
1041 }
1042
1043 const uint8_t* JsInterop::symbolizer(Dart_NativeFunction nf)
1044 {
1045 for (intptr_t i = 0; nativeEntries[i].nativeFunction != 0; i++) {
1046 if (nf == nativeEntries[i].nativeFunction) {
1047 return reinterpret_cast<const uint8_t*>(nativeEntries[i].name);
1048 }
1049 }
1050 return 0;
1051 }
1052
1053 }
OLDNEW
« no previous file with comments | « sky/engine/bindings-dart/core/dart/DartJsInterop.h ('k') | sky/engine/bindings-dart/core/dart/DartJsInteropData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698