Chromium Code Reviews| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 library dart.js; | 88 library dart.js; |
| 89 | 89 |
| 90 import 'dart:collection' show ListMixin; | 90 import 'dart:collection' show ListMixin; |
| 91 import 'dart:nativewrappers'; | 91 import 'dart:nativewrappers'; |
| 92 import 'dart:math' as math; | 92 import 'dart:math' as math; |
| 93 import 'dart:mirrors' as mirrors; | 93 import 'dart:mirrors' as mirrors; |
| 94 import 'dart:html' as html; | 94 import 'dart:html' as html; |
| 95 import 'dart:html_common' as html_common; | 95 import 'dart:html_common' as html_common; |
| 96 import 'dart:indexed_db' as indexed_db; | 96 import 'dart:indexed_db' as indexed_db; |
| 97 import 'dart:typed_data'; | 97 import 'dart:typed_data'; |
| 98 import 'dart:core'; | |
| 99 | |
| 100 import 'cached_patches.dart'; | |
| 98 | 101 |
| 99 // Pretend we are always in checked mode as we aren't interested in users | 102 // Pretend we are always in checked mode as we aren't interested in users |
| 100 // running Dartium code outside of checked mode. | 103 // running Dartium code outside of checked mode. |
| 101 @Deprecated("Internal Use Only") | 104 @Deprecated("Internal Use Only") |
| 102 final bool CHECK_JS_INVOCATIONS = true; | 105 final bool CHECK_JS_INVOCATIONS = true; |
| 103 | 106 |
| 104 final String _DART_RESERVED_NAME_PREFIX = r'JS$'; | 107 final String _DART_RESERVED_NAME_PREFIX = r'JS$'; |
| 105 | 108 |
| 106 String _stripReservedNamePrefix(String name) => | 109 String _stripReservedNamePrefix(String name) => |
| 107 name.startsWith(_DART_RESERVED_NAME_PREFIX) | 110 name.startsWith(_DART_RESERVED_NAME_PREFIX) |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 .putIfAbsent(symbol, () => new _DeclarationSet()) | 274 .putIfAbsent(symbol, () => new _DeclarationSet()) |
| 272 .add(declaration); | 275 .add(declaration); |
| 273 } | 276 } |
| 274 } | 277 } |
| 275 }); | 278 }); |
| 276 } | 279 } |
| 277 } | 280 } |
| 278 | 281 |
| 279 _finalizeJsInterfaces() native "Js_finalizeJsInterfaces"; | 282 _finalizeJsInterfaces() native "Js_finalizeJsInterfaces"; |
| 280 | 283 |
| 284 // Create the files for the generated Dart files from IDLs. These only change | |
| 285 // when browser's Dart files change (dart:*). | |
| 286 String createCachedPatchesFile() { | |
|
Jacob
2016/03/28 14:23:58
can you keep this method out of dart:js which is a
terry
2016/03/28 14:45:31
Added @Deprecated("Internal Use Only")
Done.
| |
| 287 var patches = _generateInteropPatchFiles(['dart:html', | |
| 288 'dart:indexed_db', | |
| 289 'dart:web_gl', | |
| 290 'dart:web_sql', | |
| 291 'dart:svg', | |
| 292 'dart:web_audio']); | |
| 293 var sb = new StringBuffer(); | |
| 294 | |
| 295 sb.write(""" | |
| 296 | |
| 297 // START_OF_CACHED_PATCHES | |
| 298 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 299 // for details. All rights reserved. Use of this source code is governed by a | |
| 300 // BSD-style license that can be found in the LICENSE file. | |
| 301 | |
| 302 // DO NOT EDIT GENERATED FILE. | |
| 303 | |
| 304 library cached_patches; | |
| 305 | |
| 306 var cached_patches = {"""); | |
| 307 | |
| 308 for (var baseIndex = 0; baseIndex < patches.length; baseIndex += 3) { | |
| 309 var uri = patches[baseIndex + 0]; | |
| 310 var uri_js_interop = patches[baseIndex + 1]; | |
| 311 var source = patches[baseIndex + 2]; | |
| 312 | |
| 313 if (uri != 'dart:js') { | |
| 314 sb.write('"$uri": ["$uri", "$uri_js_interop", """$source"""],'); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 sb.write("""}; | |
| 319 // END_OF_CACHED_PATCHES | |
| 320 """); | |
| 321 | |
| 322 return "$sb"; | |
| 323 } | |
| 324 | |
| 281 String _getJsName(mirrors.DeclarationMirror mirror) { | 325 String _getJsName(mirrors.DeclarationMirror mirror) { |
| 282 for (var annotation in mirror.metadata) { | 326 if (_atJsType != null) { |
| 283 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "JS") { | 327 for (var annotation in mirror.metadata) { |
| 284 mirrors.LibraryMirror library = annotation.type.owner; | 328 if (annotation.type.reflectedType == _atJsType) { |
| 285 var uri = library.uri; | |
| 286 // make sure the annotation is from package://js | |
| 287 if (uri.scheme == 'package' && uri.path == 'js/js.dart') { | |
| 288 try { | 329 try { |
| 289 var name = annotation.reflectee.name; | 330 var name = annotation.reflectee.name; |
| 290 return name != null ? name : ""; | 331 return name != null ? name : ""; |
| 291 } catch (e) {} | 332 } catch (e) {} |
| 292 } | 333 } |
| 293 } | 334 } |
| 294 } | 335 } |
| 295 return null; | 336 return null; |
| 296 } | 337 } |
| 297 | 338 |
| 298 bool _isAnonymousClass(mirrors.ClassMirror mirror) { | 339 bool _isAnonymousClass(mirrors.ClassMirror mirror) { |
| 299 for (var annotation in mirror.metadata) { | 340 for (var annotation in mirror.metadata) { |
| 300 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == | 341 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == |
| 301 "_Anonymous") { | 342 "_Anonymous") { |
| 302 mirrors.LibraryMirror library = annotation.type.owner; | 343 mirrors.LibraryMirror library = annotation.type.owner; |
| 303 var uri = library.uri; | 344 var uri = library.uri; |
| 304 // make sure the annotation is from package://js | 345 // make sure the annotation is from package://js |
| 305 if (uri.scheme == 'package' && uri.path == 'js/js.dart') { | 346 if (uri.scheme == 'package' && uri.path == 'js/js.dart') { |
| 306 return true; | 347 return true; |
| 307 } | 348 } |
| 308 } | 349 } |
| 309 } | 350 } |
| 310 return false; | 351 return false; |
| 311 } | 352 } |
| 312 | 353 |
| 313 bool _hasJsName(mirrors.DeclarationMirror mirror) => _getJsName(mirror) != null; | 354 bool _hasJsName(mirrors.DeclarationMirror mirror) => _getJsName(mirror) != null; |
| 314 | 355 |
| 356 var _domNameType; | |
| 357 | |
| 315 bool hasDomName(mirrors.DeclarationMirror mirror) { | 358 bool hasDomName(mirrors.DeclarationMirror mirror) { |
| 316 var location = mirror.location; | 359 var location = mirror.location; |
| 317 if (location == null || location.sourceUri.scheme != 'dart') return false; | 360 if (location == null || location.sourceUri.scheme != 'dart') return false; |
| 318 for (var annotation in mirror.metadata) { | 361 for (var annotation in mirror.metadata) { |
| 319 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "DomName") { | 362 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "DomName") { |
| 320 // We can't make sure the annotation is in dart: as Dartium believes it | 363 // We can't make sure the annotation is in dart: as Dartium believes it |
| 321 // is file://dart/sdk/lib/html/html_common/metadata.dart | 364 // is file://dart/sdk/lib/html/html_common/metadata.dart |
| 322 // instead of a proper dart: location. | 365 // instead of a proper dart: location. |
| 323 return true; | 366 return true; |
| 324 } | 367 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 438 } | 481 } |
| 439 | 482 |
| 440 bool _isExternal(mirrors.MethodMirror mirror) { | 483 bool _isExternal(mirrors.MethodMirror mirror) { |
| 441 // This try-catch block is a workaround for BUG:24834. | 484 // This try-catch block is a workaround for BUG:24834. |
| 442 try { | 485 try { |
| 443 return mirror.isExternal; | 486 return mirror.isExternal; |
| 444 } catch (e) {} | 487 } catch (e) {} |
| 445 return false; | 488 return false; |
| 446 } | 489 } |
| 447 | 490 |
| 448 List<String> _generateExternalMethods() { | 491 List<String> _generateExternalMethods(List<String> libraryPaths) { |
| 449 var staticCodegen = <String>[]; | 492 var staticCodegen = <String>[]; |
| 450 mirrors.currentMirrorSystem().libraries.forEach((uri, library) { | 493 |
| 494 if (libraryPaths.length == 0) { | |
| 495 mirrors.currentMirrorSystem().libraries.forEach((uri, library) { | |
| 496 var library_name = "${uri.scheme}:${uri.path}"; | |
| 497 if (cached_patches.containsKey(library_name)) { | |
| 498 var patch = cached_patches[library_name]; | |
| 499 staticCodegen.addAll(patch); | |
| 500 } else { | |
| 501 _generateLibraryCodegen(uri, library, staticCodegen); | |
| 502 } | |
| 503 }); // End of library foreach | |
| 504 } else { | |
| 505 // Used to generate cached_patches.dart file for all IDL generated dart: | |
| 506 // files to the WebKit DOM. | |
| 507 for (var library_name in libraryPaths) { | |
| 508 var parts = library_name.split(':'); | |
| 509 var uri = new Uri(scheme: parts[0], path: parts[1]); | |
| 510 var library = mirrors.currentMirrorSystem().libraries[uri]; | |
| 511 _generateLibraryCodegen(uri, library, staticCodegen); | |
| 512 } | |
| 513 } | |
| 514 | |
| 515 return staticCodegen; | |
| 516 } | |
| 517 | |
| 518 _generateLibraryCodegen(uri, library, staticCodegen) { | |
| 519 // Is it a dart generated library? | |
| 520 var dartLibrary = uri.scheme == 'dart'; | |
| 521 | |
| 451 var sb = new StringBuffer(); | 522 var sb = new StringBuffer(); |
| 452 String jsLibraryName = _getJsName(library); | 523 String jsLibraryName = _getJsName(library); |
| 453 library.declarations.forEach((name, declaration) { | 524 library.declarations.forEach((name, declaration) { |
| 454 if (declaration is mirrors.MethodMirror) { | 525 if (declaration is mirrors.MethodMirror) { |
| 455 if ((_hasJsName(declaration) || jsLibraryName != null) && | 526 if ((_hasJsName(declaration) || jsLibraryName != null) && |
| 456 _isExternal(declaration)) { | 527 _isExternal(declaration)) { |
| 457 addMemberHelper(declaration, jsLibraryName, sb); | 528 addMemberHelper(declaration, jsLibraryName, sb); |
| 458 } | 529 } |
| 459 } else if (declaration is mirrors.ClassMirror) { | 530 } else if (declaration is mirrors.ClassMirror) { |
| 460 mirrors.ClassMirror clazz = declaration; | 531 mirrors.ClassMirror clazz = declaration; |
| 461 var isDom = hasDomName(clazz); | 532 var isDom = dartLibrary ? hasDomName(clazz) : false; |
| 462 var isJsInterop = _hasJsName(clazz); | 533 var isJsInterop = _hasJsName(clazz); |
| 463 if (isDom || isJsInterop) { | 534 if (isDom || isJsInterop) { |
| 464 // TODO(jacobr): verify class implements JavaScriptObject. | 535 // TODO(jacobr): verify class implements JavaScriptObject. |
| 465 var className = mirrors.MirrorSystem.getName(clazz.simpleName); | 536 var className = mirrors.MirrorSystem.getName(clazz.simpleName); |
| 466 var classNameImpl = '${className}Impl'; | 537 var classNameImpl = '${className}Impl'; |
| 467 var sbPatch = new StringBuffer(); | 538 var sbPatch = new StringBuffer(); |
| 468 if (isJsInterop) { | 539 if (isJsInterop) { |
| 469 String jsClassName = _getJsMemberName(clazz); | 540 String jsClassName = _getJsMemberName(clazz); |
| 470 | 541 |
| 471 jsInterfaceTypes.add(clazz); | 542 jsInterfaceTypes.add(clazz); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 512 sbPatch.write(" "); | 583 sbPatch.write(" "); |
| 513 addMemberHelper( | 584 addMemberHelper( |
| 514 declaration, | 585 declaration, |
| 515 (jsLibraryName != null && jsLibraryName.isNotEmpty) | 586 (jsLibraryName != null && jsLibraryName.isNotEmpty) |
| 516 ? "${jsLibraryName}.${jsClassName}" | 587 ? "${jsLibraryName}.${jsClassName}" |
| 517 : jsClassName, | 588 : jsClassName, |
| 518 sbPatch, | 589 sbPatch, |
| 519 isStatic: true, | 590 isStatic: true, |
| 520 memberName: className); | 591 memberName: className); |
| 521 } | 592 } |
| 522 }); | 593 }); // End of clazz.declarations.forEach |
| 523 | 594 |
| 524 clazz.staticMembers.forEach((memberName, member) { | 595 clazz.staticMembers.forEach((memberName, member) { |
| 525 if (_isExternal(member)) { | 596 if (_isExternal(member)) { |
| 526 sbPatch.write(" "); | 597 sbPatch.write(" "); |
| 527 addMemberHelper( | 598 addMemberHelper( |
| 528 member, | 599 member, |
| 529 (jsLibraryName != null && jsLibraryName.isNotEmpty) | 600 (jsLibraryName != null && jsLibraryName.isNotEmpty) |
| 530 ? "${jsLibraryName}.${jsClassName}" | 601 ? "${jsLibraryName}.${jsClassName}" |
| 531 : jsClassName, | 602 : jsClassName, |
| 532 sbPatch, | 603 sbPatch, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 571 | 642 |
| 572 /** | 643 /** |
| 573 * Placeholder object for cases where we need to determine exactly how many | 644 * Placeholder object for cases where we need to determine exactly how many |
| 574 * args were passed to a function. | 645 * args were passed to a function. |
| 575 */ | 646 */ |
| 576 const ${_UNDEFINED_VAR} = const Object(); | 647 const ${_UNDEFINED_VAR} = const Object(); |
| 577 | 648 |
| 578 ${sb} | 649 ${sb} |
| 579 """); | 650 """); |
| 580 } | 651 } |
| 581 }); | 652 } |
| 582 | 653 |
| 583 return staticCodegen; | 654 // Remember the @JS type to compare annotation type. |
| 584 } | 655 var _atJsType = -1; |
| 585 | 656 |
| 586 /** | 657 /** |
| 587 * Generates part files defining source code for JSObjectImpl, all DOM classes | 658 * Generates part files defining source code for JSObjectImpl, all DOM classes |
| 588 * classes. This codegen is needed so that type checks for all registered | 659 * classes. This codegen is needed so that type checks for all registered |
| 589 * JavaScript interop classes pass. | 660 * JavaScript interop classes pass. |
| 590 */ | 661 */ |
| 591 List<String> _generateInteropPatchFiles() { | 662 List<String> _generateInteropPatchFiles(List<String> libraryPaths) { |
| 592 var ret = _generateExternalMethods(); | 663 // Cache the @JS Type. |
| 664 if (_atJsType == -1) { | |
| 665 var uri = new Uri(scheme: "package", path: "js/js.dart"); | |
| 666 var jsLibrary = mirrors.currentMirrorSystem().libraries[uri]; | |
| 667 if (jsLibrary != null) { | |
| 668 // @ JS used somewhere. | |
| 669 var jsDeclaration = jsLibrary.declarations[new Symbol("JS")]; | |
| 670 _atJsType = jsDeclaration.reflectedType; | |
| 671 } else { | |
| 672 // @ JS not used in any library. | |
| 673 _atJsType = null; | |
| 674 } | |
| 675 } | |
| 676 | |
| 677 var ret = _generateExternalMethods(libraryPaths); | |
| 593 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>(); | 678 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>(); |
| 594 var prefixNames = new Set<String>(); | 679 var prefixNames = new Set<String>(); |
| 595 var sb = new StringBuffer(); | 680 var sb = new StringBuffer(); |
| 596 | 681 |
| 597 var implements = <String>[]; | 682 var implements = <String>[]; |
| 598 var implementsArray = <String>[]; | 683 var implementsArray = <String>[]; |
| 599 var implementsDom = <String>[]; | 684 var implementsDom = <String>[]; |
| 600 var listMirror = mirrors.reflectType(List); | 685 var listMirror = mirrors.reflectType(List); |
| 601 var functionMirror = mirrors.reflectType(Function); | 686 var functionMirror = mirrors.reflectType(Function); |
| 602 var jsObjectMirror = mirrors.reflectType(JSObject); | 687 var jsObjectMirror = mirrors.reflectType(JSObject); |
| (...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1560 var ret = _interopCaptureThisExpando[f]; | 1645 var ret = _interopCaptureThisExpando[f]; |
| 1561 if (ret == null) { | 1646 if (ret == null) { |
| 1562 // TODO(jacobr): we could optimize this. | 1647 // TODO(jacobr): we could optimize this. |
| 1563 ret = new JSFunction.create( | 1648 ret = new JSFunction.create( |
| 1564 new JsFunction.withThis(new _CreateDartFunctionForInterop(f))); | 1649 new JsFunction.withThis(new _CreateDartFunctionForInterop(f))); |
| 1565 _interopCaptureThisExpando[f] = ret; | 1650 _interopCaptureThisExpando[f] = ret; |
| 1566 } | 1651 } |
| 1567 return ret; | 1652 return ret; |
| 1568 } | 1653 } |
| 1569 } | 1654 } |
| OLD | NEW |