OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Support for interoperating with JavaScript. | 6 * Support for interoperating with JavaScript. |
7 * | 7 * |
8 * This library provides access to JavaScript objects from Dart, allowing | 8 * This library provides access to JavaScript objects from Dart, allowing |
9 * Dart code to get and set properties, and call methods of JavaScript objects | 9 * Dart code to get and set properties, and call methods of JavaScript objects |
10 * and invoke JavaScript functions. The library takes care of converting | 10 * and invoke JavaScript functions. The library takes care of converting |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 import 'dart:typed_data'; | 97 import 'dart:typed_data'; |
98 | 98 |
99 // Pretend we are always in checked mode as we aren't interested in users | 99 // Pretend we are always in checked mode as we aren't interested in users |
100 // running Dartium code outside of checked mode. | 100 // running Dartium code outside of checked mode. |
101 final bool CHECK_JS_INVOCATIONS = true; | 101 final bool CHECK_JS_INVOCATIONS = true; |
102 | 102 |
103 final _allowedMethods = new Map<Symbol, _DeclarationSet>(); | 103 final _allowedMethods = new Map<Symbol, _DeclarationSet>(); |
104 final _allowedGetters = new Map<Symbol, _DeclarationSet>(); | 104 final _allowedGetters = new Map<Symbol, _DeclarationSet>(); |
105 final _allowedSetters = new Map<Symbol, _DeclarationSet>(); | 105 final _allowedSetters = new Map<Symbol, _DeclarationSet>(); |
106 | 106 |
107 final _jsInterfaceTypes = new Set<Type>(); | 107 final _jsInterfaceTypes = new Set<mirrors.ClassMirror>(); |
108 Iterable<Type> get jsInterfaceTypes => _jsInterfaceTypes; | 108 Iterable<mirrors.ClassMirror> get jsInterfaceTypes => _jsInterfaceTypes; |
109 | 109 |
110 /// A collection of methods where all methods have the same name. | 110 /// A collection of methods where all methods have the same name. |
111 /// This class is intended to optimize whether a specific invocation is | 111 /// This class is intended to optimize whether a specific invocation is |
112 /// appropritate for at least some of the methods in the collection. | 112 /// appropritate for at least some of the methods in the collection. |
113 class _DeclarationSet { | 113 class _DeclarationSet { |
114 _DeclarationSet() : _members = <mirrors.DeclarationMirror>[]; | 114 _DeclarationSet() : _members = <mirrors.DeclarationMirror>[]; |
115 | 115 |
116 static bool _checkType(obj, mirrors.TypeMirror type) { | 116 static bool _checkType(obj, mirrors.TypeMirror type) { |
117 if (obj == null) return true; | 117 if (obj == null) return true; |
118 return mirrors.reflectType(obj.runtimeType).isSubtypeOf(type); | 118 return mirrors.reflectType(obj.runtimeType).isSubtypeOf(type); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 /** | 206 /** |
207 * Temporary method that we hope to remove at some point. This method should | 207 * Temporary method that we hope to remove at some point. This method should |
208 * generally only be called by machine generated code. | 208 * generally only be called by machine generated code. |
209 */ | 209 */ |
210 void registerJsInterfaces([List<Type> classes]) { | 210 void registerJsInterfaces([List<Type> classes]) { |
211 // This method is now obsolete in Dartium. | 211 // This method is now obsolete in Dartium. |
212 } | 212 } |
213 | 213 |
214 void _registerJsInterfaces(List<Type> classes) { | 214 void _registerJsInterfaces(List<Type> classes) { |
215 for (Type type in classes) { | 215 for (Type type in classes) { |
216 if (!_jsInterfaceTypes.add(type)) continue; // Already registered. | |
217 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); | 216 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); |
218 typeMirror.declarations.forEach((symbol, declaration) { | 217 typeMirror.declarations.forEach((symbol, declaration) { |
219 if (declaration is mirrors.MethodMirror || | 218 if (declaration is mirrors.MethodMirror || |
220 declaration is mirrors.VariableMirror && !declaration.isStatic) { | 219 declaration is mirrors.VariableMirror && !declaration.isStatic) { |
221 bool treatAsGetter = false; | 220 bool treatAsGetter = false; |
222 bool treatAsSetter = false; | 221 bool treatAsSetter = false; |
223 if (declaration is mirrors.VariableMirror) { | 222 if (declaration is mirrors.VariableMirror) { |
224 treatAsGetter = true; | 223 treatAsGetter = true; |
225 if (!declaration.isConst && !declaration.isFinal) { | 224 if (!declaration.isConst && !declaration.isFinal) { |
226 treatAsSetter = true; | 225 treatAsSetter = true; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 String _getJsName(mirrors.DeclarationMirror mirror) { | 258 String _getJsName(mirrors.DeclarationMirror mirror) { |
260 for (var annotation in mirror.metadata) { | 259 for (var annotation in mirror.metadata) { |
261 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "JS") { | 260 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "JS") { |
262 mirrors.LibraryMirror library = annotation.type.owner; | 261 mirrors.LibraryMirror library = annotation.type.owner; |
263 var uri = library.uri; | 262 var uri = library.uri; |
264 // make sure the annotation is from package://js | 263 // make sure the annotation is from package://js |
265 if (uri.scheme == 'package' && uri.path == 'js/js.dart') { | 264 if (uri.scheme == 'package' && uri.path == 'js/js.dart') { |
266 try { | 265 try { |
267 var name = annotation.reflectee.name; | 266 var name = annotation.reflectee.name; |
268 return name != null ? name : ""; | 267 return name != null ? name : ""; |
269 } catch (e) { | 268 } catch (e) {} |
270 } | |
271 } | 269 } |
272 } | 270 } |
273 } | 271 } |
274 return null; | 272 return null; |
275 } | 273 } |
276 | 274 |
277 bool _hasJsName(mirrors.DeclarationMirror mirror) => | 275 bool _isAnonymousClass(mirrors.ClassMirror mirror) { |
278 _getJsName(mirror) != null; | 276 for (var annotation in mirror.metadata) { |
| 277 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == |
| 278 "_Anonymous") { |
| 279 mirrors.LibraryMirror library = annotation.type.owner; |
| 280 var uri = library.uri; |
| 281 // make sure the annotation is from package://js |
| 282 if (uri.scheme == 'package' && uri.path == 'js/js.dart') { |
| 283 return true; |
| 284 } |
| 285 } |
| 286 } |
| 287 return false; |
| 288 } |
279 | 289 |
| 290 bool _hasJsName(mirrors.DeclarationMirror mirror) => _getJsName(mirror) != null; |
280 | 291 |
281 _getJsMemberName(mirrors.DeclarationMirror mirror) { | 292 _getJsMemberName(mirrors.DeclarationMirror mirror) { |
282 var name = _getJsName(mirror); | 293 var name = _getJsName(mirror); |
283 return name == null || name.isEmpty ? _getDeclarationName(mirror) : | 294 return name == null || name.isEmpty ? _getDeclarationName(mirror) : name; |
284 name; | |
285 } | 295 } |
286 | 296 |
287 // TODO(jacobr): handle setters correctyl. | 297 // TODO(jacobr): handle setters correctyl. |
288 String _getDeclarationName(mirrors.DeclarationMirror declaration) { | 298 String _getDeclarationName(mirrors.DeclarationMirror declaration) { |
289 var name = mirrors.MirrorSystem.getName(declaration.simpleName); | 299 var name = mirrors.MirrorSystem.getName(declaration.simpleName); |
290 if (declaration is mirrors.MethodMirror && declaration.isSetter) { | 300 if (declaration is mirrors.MethodMirror && declaration.isSetter) { |
291 assert(name.endsWith("=")); | 301 assert(name.endsWith("=")); |
292 name = name.substring(0, name.length - 1); | 302 name = name.substring(0, name.length - 1); |
293 } | 303 } |
294 return name; | 304 return name; |
295 } | 305 } |
296 | 306 |
297 final _JS_LIBRARY_PREFIX = "js_library"; | 307 final _JS_LIBRARY_PREFIX = "js_library"; |
298 final _UNDEFINED_VAR = "_UNDEFINED_JS_CONST"; | 308 final _UNDEFINED_VAR = "_UNDEFINED_JS_CONST"; |
299 | 309 |
300 String _accessJsPath(String path) => | 310 String _accessJsPath(String path) => |
301 "${_JS_LIBRARY_PREFIX}.context${path.split(".").map((p) => "['$p']").join(''
)}"; | 311 "${_JS_LIBRARY_PREFIX}.context${path.split(".").map((p) => "['$p']").join(''
)}"; |
302 | 312 |
303 @Deprecated("Internal Use Only") | 313 @Deprecated("Internal Use Only") |
304 void addMemberHelper(mirrors.MethodMirror declaration, String path, StringBuffer
sb, {bool isStatic: false, String memberName}) { | 314 void addMemberHelper( |
305 var jsName = _getJsMemberName(declaration); | 315 mirrors.MethodMirror declaration, String path, StringBuffer sb, |
306 path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName; | 316 {bool isStatic: false, String memberName}) { |
| 317 if (!declaration.isConstructor) { |
| 318 var jsName = _getJsMemberName(declaration); |
| 319 path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName; |
| 320 } |
307 var name = memberName != null ? memberName : _getDeclarationName(declaration); | 321 var name = memberName != null ? memberName : _getDeclarationName(declaration); |
308 if (declaration.isConstructor) { | 322 if (declaration.isConstructor) { |
309 sb.write("factory"); | 323 sb.write("factory"); |
310 } else if (isStatic) { | 324 } else if (isStatic) { |
311 sb.write("static"); | 325 sb.write("static"); |
312 } else { | 326 } else { |
313 sb.write("patch"); | 327 sb.write("patch"); |
314 } | 328 } |
315 sb.write(" "); | 329 sb.write(" "); |
316 if (declaration.isGetter) { | 330 if (declaration.isGetter) { |
(...skipping 22 matching lines...) Expand all Loading... |
339 sb.write("=${_UNDEFINED_VAR}"); | 353 sb.write("=${_UNDEFINED_VAR}"); |
340 } | 354 } |
341 i++; | 355 i++; |
342 } | 356 } |
343 if (hasOptional) { | 357 if (hasOptional) { |
344 sb.write("]"); | 358 sb.write("]"); |
345 } | 359 } |
346 // TODO(jacobr): | 360 // TODO(jacobr): |
347 sb.write(") => "); | 361 sb.write(") => "); |
348 if (declaration.isConstructor) { | 362 if (declaration.isConstructor) { |
349 sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject("); | 363 sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject("); |
350 } | 364 } |
351 sb | 365 sb |
352 ..write(_accessJsPath(path)) | 366 ..write(_accessJsPath(path)) |
353 ..write(declaration.isConstructor ? "," : ".apply(") | 367 ..write(declaration.isConstructor ? "," : ".apply(") |
354 ..write("[${args.join(",")}]"); | 368 ..write("[${args.join(",")}]"); |
355 | 369 |
356 if (hasOptional) { | 370 if (hasOptional) { |
357 sb.write(".takeWhile((i) => i != ${_UNDEFINED_VAR}).toList()"); | 371 sb.write(".takeWhile((i) => i != ${_UNDEFINED_VAR}).toList()"); |
358 } | 372 } |
359 sb.write(");"); | 373 sb.write(");"); |
360 } | 374 } |
361 sb.write("\n"); | 375 sb.write("\n"); |
362 } | 376 } |
363 | 377 |
364 // TODO(jacobr): make this check more robust. | 378 // TODO(jacobr): make this check more robust. |
365 bool _isExternal(mirrors.MethodMirror mirror) => | 379 bool _isExternal(mirrors.Mirror mirror) { |
366 mirror.source != null && mirror.source.startsWith("external "); | 380 /* |
| 381 var source = mirror.source; |
| 382 return source != null && source.startsWith("external "); |
| 383 */ |
| 384 return mirror.isExternal; |
| 385 } |
367 | 386 |
368 List<String> _generateExternalMethods() { | 387 List<String> _generateExternalMethods() { |
369 var staticCodegen = <String>[]; | 388 var staticCodegen = <String>[]; |
370 mirrors.currentMirrorSystem().libraries.forEach((uri, library) { | 389 mirrors.currentMirrorSystem().libraries.forEach((uri, library) { |
371 var sb = new StringBuffer(); | 390 var sb = new StringBuffer(); |
372 String jsLibraryName = _getJsName(library); | 391 String jsLibraryName = _getJsName(library); |
373 library.declarations.forEach((name, declaration) { | 392 library.declarations.forEach((name, declaration) { |
374 if (declaration is mirrors.MethodMirror) { | 393 if (declaration is mirrors.MethodMirror) { |
375 if (_isExternal(declaration) && (_hasJsName(declaration) || jsLibraryNam
e != null)) { | 394 if ((_hasJsName(declaration) || jsLibraryName != null) && |
| 395 _isExternal(declaration)) { |
376 addMemberHelper(declaration, jsLibraryName, sb); | 396 addMemberHelper(declaration, jsLibraryName, sb); |
377 } | 397 } |
378 } else if (declaration is mirrors.ClassMirror) { | 398 } else if (declaration is mirrors.ClassMirror) { |
379 mirrors.ClassMirror clazz = declaration; | 399 mirrors.ClassMirror clazz = declaration; |
380 if (_hasJsName(clazz)) { | 400 if (_hasJsName(clazz)) { |
381 // TODO(jacobr): verify class implements JavaScriptObject. | 401 // TODO(jacobr): verify class implements JavaScriptObject. |
382 assert(clazz.hasReflectedType); | |
383 jsInterfaceTypes.add(clazz.reflectedType); | |
384 String jsClassName = _getJsMemberName(clazz); | 402 String jsClassName = _getJsMemberName(clazz); |
385 var className = mirrors.MirrorSystem.getName(clazz.simpleName); | 403 var className = mirrors.MirrorSystem.getName(clazz.simpleName); |
386 var sbPatch = new StringBuffer(); | 404 var sbPatch = new StringBuffer(); |
| 405 jsInterfaceTypes.add(clazz); |
387 clazz.declarations.forEach((name, declaration) { | 406 clazz.declarations.forEach((name, declaration) { |
388 if (declaration is! mirrors.MethodMirror || !_isExternal(declaration
)) return; | 407 if (declaration is! mirrors.MethodMirror || |
389 if (declaration.isFactoryConstructor) { | 408 !_isExternal(declaration)) return; |
| 409 if (declaration.isFactoryConstructor && _isAnonymousClass(clazz)) { |
390 sbPatch.write(" factory ${className}({"); | 410 sbPatch.write(" factory ${className}({"); |
391 int i = 0; | 411 int i = 0; |
392 var args = <String>[]; | 412 var args = <String>[]; |
| 413 for (var p in declaration.parameters) { |
| 414 args.add(mirrors.MirrorSystem.getName(p.simpleName)); |
| 415 i++; |
| 416 } |
| 417 sbPatch |
| 418 ..write( |
| 419 args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ")) |
| 420 ..write("}) {\n" |
| 421 " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});
\n"); |
| 422 i = 0; |
| 423 for (var p in declaration.parameters) { |
| 424 assert(p.isNamed); // XXX throw |
| 425 var name = args[i]; |
| 426 var jsName = mirrors.MirrorSystem.getName(p.simpleName); |
| 427 // XXX apply name conversion rules. |
| 428 sbPatch.write( |
| 429 " if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\
n"); |
| 430 i++; |
| 431 } |
| 432 |
| 433 sbPatch.write(" return ret;\n" |
| 434 " }\n"); |
| 435 } else if (declaration.isConstructor || |
| 436 declaration.isFactoryConstructor) { |
| 437 sbPatch.write(" "); |
| 438 addMemberHelper( |
| 439 declaration, |
| 440 (jsLibraryName != null && jsLibraryName.isNotEmpty) |
| 441 ? "${jsLibraryName}.${jsClassName}" |
| 442 : jsClassName, |
| 443 sbPatch, |
| 444 isStatic: true, |
| 445 memberName: className); |
| 446 } |
| 447 }); |
| 448 |
| 449 clazz.staticMembers.forEach((memberName, member) { |
| 450 if (_isExternal(member)) { |
| 451 sbPatch.write(" "); |
| 452 addMemberHelper( |
| 453 member, |
| 454 (jsLibraryName != null && jsLibraryName.isNotEmpty) |
| 455 ? "${jsLibraryName}.${jsClassName}" |
| 456 : jsClassName, |
| 457 sbPatch, |
| 458 isStatic: true); |
| 459 } |
| 460 }); |
| 461 var typeVariablesClause = ''; |
| 462 if (!clazz.typeVariables.isEmpty) { |
| 463 typeVariablesClause = |
| 464 '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(
m.simpleName)).join(',')}>'; |
| 465 } |
| 466 if (sbPatch.isNotEmpty) { |
| 467 sb.write(""" |
| 468 patch class $className$typeVariablesClause { |
| 469 $sbPatch |
| 470 } |
| 471 """); |
| 472 } |
| 473 } |
| 474 } |
| 475 }); |
| 476 if (sb.isNotEmpty) { |
| 477 staticCodegen |
| 478 ..add(uri.toString()) |
| 479 ..add("${uri}_js_interop_patch.dart") |
| 480 ..add(""" |
| 481 import 'dart:js' as ${_JS_LIBRARY_PREFIX}; |
| 482 |
| 483 /** |
| 484 * Placeholder object for cases where we need to determine exactly how many |
| 485 * args were passed to a function. |
| 486 */ |
| 487 const ${_UNDEFINED_VAR} = const Object(); |
| 488 |
| 489 ${sb} |
| 490 """); |
| 491 } |
| 492 }); |
| 493 |
| 494 return staticCodegen; |
| 495 } |
| 496 |
| 497 List<String> _generateExternalMethods2() { |
| 498 var staticCodegen = <String>[]; |
| 499 mirrors.currentMirrorSystem().libraries.forEach((uri, library) { |
| 500 var sb = new StringBuffer(); |
| 501 String jsLibraryName = _getJsName(library); |
| 502 library.declarations.forEach((name, declaration) { |
| 503 var isExternal = _isExternal(declaration); |
| 504 if (declaration is mirrors.MethodMirror) { |
| 505 if (isExternal && (_hasJsName(declaration) || jsLibraryName != null)) { |
| 506 addMemberHelper(declaration, jsLibraryName, sb); |
| 507 } |
| 508 } else if (declaration is mirrors.ClassMirror) { |
| 509 mirrors.ClassMirror clazz = declaration; |
| 510 if (_hasJsName(clazz)) { |
| 511 // TODO(jacobr): verify class implements JavaScriptObject. |
| 512 String jsClassName = _getJsMemberName(clazz); |
| 513 var className = mirrors.MirrorSystem.getName(clazz.simpleName); |
| 514 var sbPatch = new StringBuffer(); |
| 515 jsInterfaceTypes.add(clazz); |
| 516 clazz.declarations.forEach((name, declaration) { |
| 517 if (declaration is! mirrors.MethodMirror || |
| 518 !declaration.isAbstract || |
| 519 !isExternal) return; |
| 520 if (_hasLiteralAnnotation(declaration) && |
| 521 declaration.isFactoryConstructor) { |
| 522 sbPatch.write(" factory ${className}({"); |
| 523 int i = 0; |
| 524 var args = <String>[]; |
393 for (var p in declaration.parameters) { | 525 for (var p in declaration.parameters) { |
394 assert(p.isNamed); // XXX throw | 526 assert(p.isNamed); // XXX throw |
395 args.add(mirrors.MirrorSystem.getName(p.simpleName)); | 527 args.add(mirrors.MirrorSystem.getName(p.simpleName)); |
396 i++; | 528 i++; |
397 } | 529 } |
398 sbPatch | 530 sbPatch |
399 ..write(args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ")
) | 531 ..write( |
| 532 args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ")) |
400 ..write("}) {\n" | 533 ..write("}) {\n" |
401 " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify(
{});\n"); | 534 " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});
\n"); |
402 i = 0; | 535 i = 0; |
403 for (var p in declaration.parameters) { | 536 for (var p in declaration.parameters) { |
404 assert(p.isNamed); // XXX throw | 537 assert(p.isNamed); // XXX throw |
405 var name = args[i]; | 538 var name = args[i]; |
406 var jsName = mirrors.MirrorSystem.getName(p.simpleName); | 539 var jsName = mirrors.MirrorSystem.getName(p.simpleName); |
407 // XXX apply name conversion rules. | 540 // XXX apply name conversion rules. |
408 sbPatch.write(" if($name != ${_UNDEFINED_VAR}) ret['$jsName']
= $name;\n"); | 541 sbPatch.write( |
| 542 " if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\
n"); |
409 i++; | 543 i++; |
410 } | 544 } |
411 | 545 |
412 sbPatch.write(" return ret;\n" | 546 sbPatch.write(" return ret;\n" |
413 " }\n"); | 547 " }\n"); |
414 } else if (declaration.isConstructor) { | 548 } else if (declaration.isConstructor || |
| 549 declaration.isFactoryConstructor) { |
415 sbPatch.write(" "); | 550 sbPatch.write(" "); |
416 addMemberHelper(declaration, | 551 addMemberHelper( |
417 (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLib
raryName}" : "", | 552 declaration, |
| 553 (jsLibraryName != null && jsLibraryName.isNotEmpty) |
| 554 ? "${jsLibraryName}.${jsClassName}" |
| 555 : jsClassName, |
418 sbPatch, | 556 sbPatch, |
419 isStatic: true, | 557 isStatic: true, |
420 memberName: className); | 558 memberName: className); |
421 } | 559 } |
422 }); | 560 }); |
423 | 561 |
424 clazz.staticMembers.forEach((memberName, member) { | 562 clazz.staticMembers.forEach((memberName, member) { |
425 if (_isExternal(member)) { | 563 if (_isExternal(member)) { |
426 sbPatch.write(" "); | 564 sbPatch.write(" "); |
427 addMemberHelper(member, | 565 addMemberHelper( |
428 (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLib
raryName}.${jsClassName}" : jsClassName, | 566 member, |
| 567 (jsLibraryName != null && jsLibraryName.isNotEmpty) |
| 568 ? "${jsLibraryName}.${jsClassName}" |
| 569 : jsClassName, |
429 sbPatch, | 570 sbPatch, |
430 isStatic: true); | 571 isStatic: true); |
431 } | 572 } |
432 }); | 573 }); |
| 574 var typeVariablesClause = ''; |
| 575 if (!clazz.typeVariables.isEmpty) { |
| 576 typeVariablesClause = |
| 577 '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(
m.simpleName)).join(',')}>'; |
| 578 } |
433 if (sbPatch.isNotEmpty) { | 579 if (sbPatch.isNotEmpty) { |
434 sb.write(""" | 580 sb.write(""" |
435 patch class $className { | 581 patch class $className$typeVariablesClause { |
436 $sbPatch | 582 $sbPatch |
437 } | 583 } |
438 """); | 584 """); |
439 } | 585 } |
440 } | 586 } |
441 } | 587 } |
442 }); | 588 }); |
443 if (sb.isNotEmpty) { | 589 if (sb.isNotEmpty) { |
444 staticCodegen | 590 staticCodegen |
445 ..add(uri.toString()) | 591 ..add(uri.toString()) |
(...skipping 23 matching lines...) Expand all Loading... |
469 List<String> _generateInteropPatchFiles() { | 615 List<String> _generateInteropPatchFiles() { |
470 var ret = _generateExternalMethods(); | 616 var ret = _generateExternalMethods(); |
471 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>(); | 617 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>(); |
472 var prefixNames = new Set<String>(); | 618 var prefixNames = new Set<String>(); |
473 var sb = new StringBuffer(); | 619 var sb = new StringBuffer(); |
474 | 620 |
475 var implements = <String>[]; | 621 var implements = <String>[]; |
476 var implementsArray = <String>[]; | 622 var implementsArray = <String>[]; |
477 var listMirror = mirrors.reflectType(List); | 623 var listMirror = mirrors.reflectType(List); |
478 | 624 |
479 for (var type in jsInterfaceTypes) { | 625 for (var typeMirror in jsInterfaceTypes) { |
480 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); | |
481 mirrors.LibraryMirror libraryMirror = typeMirror.owner; | 626 mirrors.LibraryMirror libraryMirror = typeMirror.owner; |
482 var prefixName; | 627 var prefixName; |
483 if (libraryPrefixes.containsKey(libraryMirror)) { | 628 if (libraryPrefixes.containsKey(libraryMirror)) { |
484 prefixName = libraryPrefixes[libraryMirror]; | 629 prefixName = libraryPrefixes[libraryMirror]; |
485 } else { | 630 } else { |
486 var basePrefixName = | 631 var basePrefixName = |
487 mirrors.MirrorSystem.getName(libraryMirror.simpleName); | 632 mirrors.MirrorSystem.getName(libraryMirror.simpleName); |
488 basePrefixName = basePrefixName.replaceAll('.', '_'); | 633 basePrefixName = basePrefixName.replaceAll('.', '_'); |
489 if (basePrefixName.isEmpty) basePrefixName = "lib"; | 634 if (basePrefixName.isEmpty) basePrefixName = "lib"; |
490 prefixName = basePrefixName; | 635 prefixName = basePrefixName; |
491 var i = 1; | 636 var i = 1; |
492 while (prefixNames.contains(prefixName)) { | 637 while (prefixNames.contains(prefixName)) { |
493 prefixName = '$basePrefixName$i'; | 638 prefixName = '$basePrefixName$i'; |
494 i++; | 639 i++; |
495 } | 640 } |
496 prefixNames.add(prefixName); | 641 prefixNames.add(prefixName); |
497 libraryPrefixes[libraryMirror] = prefixName; | 642 libraryPrefixes[libraryMirror] = prefixName; |
498 } | 643 } |
499 var isArray = typeMirror.isSubtypeOf(listMirror); | 644 var isArray = typeMirror.isSubtypeOf(listMirror); |
500 (isArray ? implementsArray : implements).add( | 645 (isArray ? implementsArray : implements).add( |
501 '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}'); | 646 '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}'); |
502 } | 647 } |
503 libraryPrefixes.forEach((libraryMirror, prefix) { | 648 libraryPrefixes.forEach((libraryMirror, prefix) { |
504 sb.writeln('import "${libraryMirror.uri}" as $prefix;'); | 649 sb.writeln('import "${libraryMirror.uri}" as $prefix;'); |
505 }); | 650 }); |
506 buildImplementsClause(classes) => | 651 buildImplementsClause(classes) => |
507 classes.isEmpty ? "" : "implements ${classes.join(', ')}" | 652 classes.isEmpty ? "" : "implements ${classes.join(', ')}"; |
508 var implementsClause = buildImplementsClause(implements); | 653 var implementsClause = buildImplementsClause(implements); |
509 // TODO(jacobr): only certain classes need to be implemented by | 654 // TODO(jacobr): only certain classes need to be implemented by |
510 // JsFunctionImpl. | 655 // JsFunctionImpl. |
511 var allTypes = []..addAll(implements)..addAll(implementsArray); | 656 var allTypes = []..addAll(implements)..addAll(implementsArray); |
512 sb.write(''' | 657 sb.write(''' |
513 class JsObjectImpl extends JsObject $implementsClause { | 658 class JsObjectImpl extends JsObject $implementsClause { |
514 JsObjectImpl.internal() : super.internal(); | 659 JsObjectImpl.internal() : super.internal(); |
515 } | 660 } |
516 | 661 |
517 class JsFunctionImpl extends JsFunction $implementsClause { | 662 class JsFunctionImpl extends JsFunction $implementsClause { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 sep = ","; | 717 sep = ","; |
573 } | 718 } |
574 return list.map((e) => e == null ? "" : e.toString()).join(sep.toString()); | 719 return list.map((e) => e == null ? "" : e.toString()).join(sep.toString()); |
575 } | 720 } |
576 | 721 |
577 // TODO(jacobr): should we really bother with this method instead of just | 722 // TODO(jacobr): should we really bother with this method instead of just |
578 // shallow copying to a JS array and using the toString method? | 723 // shallow copying to a JS array and using the toString method? |
579 String _arrayToString(List list) => _arrayJoin(list, ","); | 724 String _arrayToString(List list) => _arrayJoin(list, ","); |
580 | 725 |
581 int _arrayPush(List list, List args) { | 726 int _arrayPush(List list, List args) { |
582 for(var e in args) { | 727 for (var e in args) { |
583 list.add(e); | 728 list.add(e); |
584 } | 729 } |
585 return list.length; | 730 return list.length; |
586 } | 731 } |
587 | 732 |
588 _arrayPop(List list) { | 733 _arrayPop(List list) { |
589 if (list.length > 0) return list.removeLast(); | 734 if (list.length > 0) return list.removeLast(); |
590 } | 735 } |
591 | 736 |
592 // TODO(jacobr): would it be better to just copy input to a JS List | 737 // TODO(jacobr): would it be better to just copy input to a JS List |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 JsObject get context { | 841 JsObject get context { |
697 if (_cachedContext == null) { | 842 if (_cachedContext == null) { |
698 _cachedContext = _context; | 843 _cachedContext = _context; |
699 } | 844 } |
700 return _cachedContext; | 845 return _cachedContext; |
701 } | 846 } |
702 | 847 |
703 _maybeWrap(o) { | 848 _maybeWrap(o) { |
704 var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o); | 849 var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o); |
705 if (identical(wrapped, o)) return o; | 850 if (identical(wrapped, o)) return o; |
706 return (wrapped is html.Blob | 851 return (wrapped is html.Blob || |
707 || wrapped is html.Event | 852 wrapped is html.Event || |
708 || wrapped is indexed_db.KeyRange | 853 wrapped is indexed_db.KeyRange || |
709 || wrapped is html.ImageData | 854 wrapped is html.ImageData || |
710 || wrapped is html.Node | 855 wrapped is html.Node || |
711 || wrapped is TypedData | 856 wrapped is TypedData || |
712 || wrapped is html.Window) ? wrapped : o; | 857 wrapped is html.Window) ? wrapped : o; |
713 } | 858 } |
714 | 859 |
715 /** | 860 /** |
716 * Get the dart wrapper object for object. Top-level so we | 861 * Get the dart wrapper object for object. Top-level so we |
717 * we can access it from other libraries without it being | 862 * we can access it from other libraries without it being |
718 * a public instance field on JsObject. | 863 * a public instance field on JsObject. |
719 */ | 864 */ |
720 @Deprecated("Internal Use Only") | 865 @Deprecated("Internal Use Only") |
721 getDartHtmlWrapperFor(JsObject object) => object._dartHtmlWrapper; | 866 getDartHtmlWrapperFor(JsObject object) => object._dartHtmlWrapper; |
722 | 867 |
723 /** | 868 /** |
724 * Set the dart wrapper object for object. Top-level so we | 869 * Set the dart wrapper object for object. Top-level so we |
725 * we can access it from other libraries without it being | 870 * we can access it from other libraries without it being |
726 * a public instance field on JsObject. | 871 * a public instance field on JsObject. |
727 */ | 872 */ |
728 @Deprecated("Internal Use Only") | 873 @Deprecated("Internal Use Only") |
729 void setDartHtmlWrapperFor(JsObject object, wrapper) { | 874 void setDartHtmlWrapperFor(JsObject object, wrapper) { |
730 object._dartHtmlWrapper = wrapper; | 875 object._dartHtmlWrapper = wrapper; |
731 } | 876 } |
732 | 877 |
733 /** | 878 /** |
734 * Used by callMethod to get the JS object for each argument passed if the | 879 * Used by callMethod to get the JS object for each argument passed if the |
735 * argument is a Dart class instance that delegates to a DOM object. See | 880 * argument is a Dart class instance that delegates to a DOM object. See |
736 * wrap_jso defined in dart:html. | 881 * wrap_jso defined in dart:html. |
737 */ | 882 */ |
738 @Deprecated("Internal Use Only") | 883 @Deprecated("Internal Use Only") |
739 unwrap_jso(dartClass_instance) { | 884 unwrap_jso(dartClass_instance) { |
740 if (dartClass_instance is html.DartHtmlDomObject) | 885 if (dartClass_instance is html.DartHtmlDomObject && |
741 return dartClass_instance.blink_jsObject; | 886 dartClass_instance is! JsObject) return dartClass_instance.blink_jsObject; |
742 else | 887 else return dartClass_instance; |
743 return dartClass_instance; | |
744 } | 888 } |
745 | 889 |
746 /** | 890 /** |
747 * Proxies a JavaScript object to Dart. | 891 * Proxies a JavaScript object to Dart. |
748 * | 892 * |
749 * The properties of the JavaScript object are accessible via the `[]` and | 893 * The properties of the JavaScript object are accessible via the `[]` and |
750 * `[]=` operators. Methods are callable via [callMethod]. | 894 * `[]=` operators. Methods are callable via [callMethod]. |
751 */ | 895 */ |
752 class JsObject extends NativeFieldWrapperClass2 { | 896 class JsObject extends NativeFieldWrapperClass2 { |
753 JsObject.internal(); | 897 JsObject.internal(); |
754 | 898 |
755 /** | 899 /** |
756 * If this JsObject is wrapped, e.g. DOM objects, then we can save the | 900 * If this JsObject is wrapped, e.g. DOM objects, then we can save the |
757 * wrapper here and preserve its identity. | 901 * wrapper here and preserve its identity. |
758 */ | 902 */ |
759 var _dartHtmlWrapper; | 903 var _dartHtmlWrapper; |
760 | 904 |
761 /** | 905 /** |
762 * Constructs a new JavaScript object from [constructor] and returns a proxy | 906 * Constructs a new JavaScript object from [constructor] and returns a proxy |
763 * to it. | 907 * to it. |
764 */ | 908 */ |
765 factory JsObject(JsFunction constructor, [List arguments]) { | 909 factory JsObject(JsFunction constructor, [List arguments]) { |
766 try { | 910 try { |
767 return _create(constructor, arguments); | 911 return html_common.unwrap_jso(_create(constructor, arguments)); |
768 } catch (e) { | 912 } catch (e) { |
769 // Re-throw any errors (returned as a string) as a DomException. | 913 // Re-throw any errors (returned as a string) as a DomException. |
770 throw new html.DomException.jsInterop(e); | 914 throw new html.DomException.jsInterop(e); |
771 } | 915 } |
772 } | 916 } |
773 | 917 |
774 static JsObject _create( | 918 static JsObject _create(JsFunction constructor, arguments) |
775 JsFunction constructor, arguments) native "JsObject_constructorCallback"; | 919 native "JsObject_constructorCallback"; |
776 | 920 |
777 _buildArgs(Invocation invocation) { | 921 _buildArgs(Invocation invocation) { |
778 if (invocation.namedArguments.isEmpty) { | 922 if (invocation.namedArguments.isEmpty) { |
779 return invocation.positionalArguments; | 923 return invocation.positionalArguments; |
780 } else { | 924 } else { |
781 var varArgs = new Map<String, Object>(); | 925 var varArgs = new Map<String, Object>(); |
782 invocation.namedArguments.forEach((symbol, val) { | 926 invocation.namedArguments.forEach((symbol, val) { |
783 varArgs[mirrors.MirrorSystem.getName(symbol)] = val; | 927 varArgs[mirrors.MirrorSystem.getName(symbol)] = val; |
784 }); | 928 }); |
785 return invocation.positionalArguments.toList() | 929 return invocation.positionalArguments.toList() |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
832 * The type of [property] must be either [String] or [num]. | 976 * The type of [property] must be either [String] or [num]. |
833 */ | 977 */ |
834 operator [](property) { | 978 operator [](property) { |
835 try { | 979 try { |
836 return _maybeWrap(_operator_getter(property)); | 980 return _maybeWrap(_operator_getter(property)); |
837 } catch (e) { | 981 } catch (e) { |
838 // Re-throw any errors (returned as a string) as a DomException. | 982 // Re-throw any errors (returned as a string) as a DomException. |
839 throw new html.DomException.jsInterop(e); | 983 throw new html.DomException.jsInterop(e); |
840 } | 984 } |
841 } | 985 } |
| 986 |
842 _operator_getter(property) native "JsObject_[]"; | 987 _operator_getter(property) native "JsObject_[]"; |
843 | 988 |
844 /** | 989 /** |
845 * Sets the value associated with [property] on the proxied JavaScript | 990 * Sets the value associated with [property] on the proxied JavaScript |
846 * object. | 991 * object. |
847 * | 992 * |
848 * The type of [property] must be either [String] or [num]. | 993 * The type of [property] must be either [String] or [num]. |
849 */ | 994 */ |
850 operator []=(property, value) { | 995 operator []=(property, value) { |
851 try { | 996 try { |
852 _operator_setter(property, value); | 997 _operator_setter(property, value); |
853 } catch (e) { | 998 } catch (e) { |
854 // Re-throw any errors (returned as a string) as a DomException. | 999 // Re-throw any errors (returned as a string) as a DomException. |
855 throw new html.DomException.jsInterop(e); | 1000 throw new html.DomException.jsInterop(e); |
856 } | 1001 } |
857 } | 1002 } |
| 1003 |
858 _operator_setter(property, value) native "JsObject_[]="; | 1004 _operator_setter(property, value) native "JsObject_[]="; |
859 | 1005 |
860 int get hashCode native "JsObject_hashCode"; | 1006 int get hashCode native "JsObject_hashCode"; |
861 | 1007 |
862 operator ==(other) { | 1008 operator ==(other) { |
863 var is_JsObject = other is JsObject; | 1009 var is_JsObject = other is JsObject; |
864 if (!is_JsObject) { | 1010 if (!is_JsObject) { |
865 other = html_common.unwrap_jso(other); | 1011 other = html_common.unwrap_jso(other); |
866 is_JsObject = other is JsObject; | 1012 is_JsObject = other is JsObject; |
867 } | 1013 } |
868 return is_JsObject && _identityEquality(this, other); | 1014 return is_JsObject && _identityEquality(this, other); |
869 } | 1015 } |
870 | 1016 |
871 static bool _identityEquality( | 1017 static bool _identityEquality(JsObject a, JsObject b) |
872 JsObject a, JsObject b) native "JsObject_identityEquality"; | 1018 native "JsObject_identityEquality"; |
873 | 1019 |
874 /** | 1020 /** |
875 * Returns `true` if the JavaScript object contains the specified property | 1021 * Returns `true` if the JavaScript object contains the specified property |
876 * either directly or though its prototype chain. | 1022 * either directly or though its prototype chain. |
877 * | 1023 * |
878 * This is the equivalent of the `in` operator in JavaScript. | 1024 * This is the equivalent of the `in` operator in JavaScript. |
879 */ | 1025 */ |
880 bool hasProperty(String property) native "JsObject_hasProperty"; | 1026 bool hasProperty(String property) native "JsObject_hasProperty"; |
881 | 1027 |
882 /** | 1028 /** |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 * Returns a [JsFunction] that captures its 'this' binding and calls [f] | 1158 * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
1013 * with the value of this passed as the first argument. | 1159 * with the value of this passed as the first argument. |
1014 */ | 1160 */ |
1015 factory JsFunction.withThis(Function f) => _withThis(f); | 1161 factory JsFunction.withThis(Function f) => _withThis(f); |
1016 | 1162 |
1017 /** | 1163 /** |
1018 * Invokes the JavaScript function with arguments [args]. If [thisArg] is | 1164 * Invokes the JavaScript function with arguments [args]. If [thisArg] is |
1019 * supplied it is the value of `this` for the invocation. | 1165 * supplied it is the value of `this` for the invocation. |
1020 */ | 1166 */ |
1021 dynamic apply(List args, {thisArg}) => | 1167 dynamic apply(List args, {thisArg}) => |
1022 _maybeWrap(_apply(args, thisArg: thisArg)); | 1168 _maybeWrap(_apply(args, thisArg: thisArg)); |
1023 | 1169 |
1024 dynamic _apply(List args, {thisArg}) native "JsFunction_apply"; | 1170 dynamic _apply(List args, {thisArg}) native "JsFunction_apply"; |
1025 | 1171 |
1026 noSuchMethod(Invocation invocation) { | 1172 noSuchMethod(Invocation invocation) { |
1027 if (invocation.isMethod && invocation.memberName == #call) { | 1173 if (invocation.isMethod && invocation.memberName == #call) { |
1028 return apply(_buildArgs(invocation)); | 1174 return apply(_buildArgs(invocation)); |
1029 } | 1175 } |
1030 return super.noSuchMethod(invocation); | 1176 return super.noSuchMethod(invocation); |
1031 } | 1177 } |
1032 | 1178 |
1033 /** | 1179 /** |
1034 * Internal only version of apply which uses debugger proxies of Dart objects | 1180 * Internal only version of apply which uses debugger proxies of Dart objects |
1035 * rather than opaque handles. This method is private because it cannot be | 1181 * rather than opaque handles. This method is private because it cannot be |
1036 * efficiently implemented in Dart2Js so should only be used by internal | 1182 * efficiently implemented in Dart2Js so should only be used by internal |
1037 * tools. | 1183 * tools. |
1038 */ | 1184 */ |
1039 _applyDebuggerOnly(List args, | 1185 _applyDebuggerOnly(List args, {thisArg}) |
1040 {thisArg}) native "JsFunction_applyDebuggerOnly"; | 1186 native "JsFunction_applyDebuggerOnly"; |
1041 | 1187 |
1042 static JsFunction _withThis(Function f) native "JsFunction_withThis"; | 1188 static JsFunction _withThis(Function f) native "JsFunction_withThis"; |
1043 } | 1189 } |
1044 | 1190 |
1045 /** | 1191 /** |
1046 * A [List] proxying a JavaScript Array. | 1192 * A [List] proxying a JavaScript Array. |
1047 */ | 1193 */ |
1048 class JsArray<E> extends JsObject with ListMixin<E> { | 1194 class JsArray<E> extends JsObject with ListMixin<E> { |
1049 JsArray.internal() : super.internal(); | 1195 JsArray.internal() : super.internal(); |
1050 | 1196 |
1051 factory JsArray() => _newJsArray(); | 1197 factory JsArray() => _newJsArray(); |
1052 | 1198 |
1053 static JsArray _newJsArray() native "JsArray_newJsArray"; | 1199 static JsArray _newJsArray() native "JsArray_newJsArray"; |
1054 | 1200 |
1055 factory JsArray.from(Iterable<E> other) => | 1201 factory JsArray.from(Iterable<E> other) => |
1056 _newJsArrayFromSafeList(new List.from(other)); | 1202 _newJsArrayFromSafeList(new List.from(other)); |
1057 | 1203 |
1058 static JsArray _newJsArrayFromSafeList( | 1204 static JsArray _newJsArrayFromSafeList(List list) |
1059 List list) native "JsArray_newJsArrayFromSafeList"; | 1205 native "JsArray_newJsArrayFromSafeList"; |
1060 | 1206 |
1061 _checkIndex(int index, {bool insert: false}) { | 1207 _checkIndex(int index, {bool insert: false}) { |
1062 int length = insert ? this.length + 1 : this.length; | 1208 int length = insert ? this.length + 1 : this.length; |
1063 if (index is int && (index < 0 || index >= length)) { | 1209 if (index is int && (index < 0 || index >= length)) { |
1064 throw new RangeError.range(index, 0, length); | 1210 throw new RangeError.range(index, 0, length); |
1065 } | 1211 } |
1066 } | 1212 } |
1067 | 1213 |
1068 _checkRange(int start, int end) { | 1214 _checkRange(int start, int end) { |
1069 int cachedLength = this.length; | 1215 int cachedLength = this.length; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1151 | 1297 |
1152 // TODO(jacobr): this method is a hack to work around the lack of proper dart | 1298 // TODO(jacobr): this method is a hack to work around the lack of proper dart |
1153 // support for varargs methods. | 1299 // support for varargs methods. |
1154 List _stripUndefinedArgs(List args) => | 1300 List _stripUndefinedArgs(List args) => |
1155 args.takeWhile((i) => i != _UNDEFINED).toList(); | 1301 args.takeWhile((i) => i != _UNDEFINED).toList(); |
1156 | 1302 |
1157 /** | 1303 /** |
1158 * Returns a method that can be called with an arbitrary number (for n less | 1304 * Returns a method that can be called with an arbitrary number (for n less |
1159 * than 11) of arguments without violating Dart type checks. | 1305 * than 11) of arguments without violating Dart type checks. |
1160 */ | 1306 */ |
1161 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => | 1307 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => ( |
1162 ([a1 = _UNDEFINED, a2 = _UNDEFINED, a3 = _UNDEFINED, a4 = _UNDEFINED, | 1308 [a1 = _UNDEFINED, |
1163 a5 = _UNDEFINED, a6 = _UNDEFINED, a7 = _UNDEFINED, a8 = _UNDEFINED, | 1309 a2 = _UNDEFINED, |
1164 a9 = _UNDEFINED, a10 = _UNDEFINED]) => jsFunction._applyDebuggerOnly( | 1310 a3 = _UNDEFINED, |
1165 _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])); | 1311 a4 = _UNDEFINED, |
| 1312 a5 = _UNDEFINED, |
| 1313 a6 = _UNDEFINED, |
| 1314 a7 = _UNDEFINED, |
| 1315 a8 = _UNDEFINED, |
| 1316 a9 = _UNDEFINED, |
| 1317 a10 = _UNDEFINED]) => |
| 1318 jsFunction._applyDebuggerOnly( |
| 1319 _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])); |
1166 | 1320 |
1167 // The allowInterop method is a no-op in Dartium. | 1321 // The allowInterop method is a no-op in Dartium. |
1168 // TODO(jacobr): tag methods so we can throw if a Dart method is passed to | 1322 // TODO(jacobr): tag methods so we can throw if a Dart method is passed to |
1169 // JavaScript using the new interop without calling allowInterop. | 1323 // JavaScript using the new interop without calling allowInterop. |
1170 | 1324 |
1171 /// Returns a wrapper around function [f] that can be called from JavaScript | 1325 /// Returns a wrapper around function [f] that can be called from JavaScript |
1172 /// using the package:js Dart-JavaScript interop. | 1326 /// using the package:js Dart-JavaScript interop. |
1173 /// | 1327 /// |
1174 /// For performance reasons in Dart2Js, by default Dart functions cannot be | 1328 /// For performance reasons in Dart2Js, by default Dart functions cannot be |
1175 /// passed directly to JavaScript unless this method is called to create | 1329 /// passed directly to JavaScript unless this method is called to create |
(...skipping 21 matching lines...) Expand all Loading... |
1197 return f; | 1351 return f; |
1198 } else { | 1352 } else { |
1199 var ret = _interopCaptureThisExpando[f]; | 1353 var ret = _interopCaptureThisExpando[f]; |
1200 if (ret == null) { | 1354 if (ret == null) { |
1201 ret = new JsFunction.withThis(f); | 1355 ret = new JsFunction.withThis(f); |
1202 _interopCaptureThisExpando[f] = ret; | 1356 _interopCaptureThisExpando[f] = ret; |
1203 } | 1357 } |
1204 return ret; | 1358 return ret; |
1205 } | 1359 } |
1206 } | 1360 } |
OLD | NEW |