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