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 |