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

Side by Side Diff: sdk/lib/html/html_common/conversions.dart

Issue 11316113: Creating a common library for all DOM types. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 // Conversions for IDBKey. 6 // Conversions for IDBKey.
7 // 7 //
8 // Per http://www.w3.org/TR/IndexedDB/#key-construct 8 // Per http://www.w3.org/TR/IndexedDB/#key-construct
9 // 9 //
10 // "A value is said to be a valid key if it is one of the following types: Array 10 // "A value is said to be a valid key if it is one of the following types: Array
11 // JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float 11 // JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float
12 // [WEBIDL]. However Arrays are only valid keys if every item in the array is 12 // [WEBIDL]. However Arrays are only valid keys if every item in the array is
13 // defined and is a valid key (i.e. sparse arrays can not be valid keys) and if 13 // defined and is a valid key (i.e. sparse arrays can not be valid keys) and if
14 // the Array doesn't directly or indirectly contain itself. Any non-numeric 14 // the Array doesn't directly or indirectly contain itself. Any non-numeric
15 // properties are ignored, and thus does not affect whether the Array is a valid 15 // properties are ignored, and thus does not affect whether the Array is a valid
16 // key. Additionally, if the value is of type float, it is only a valid key if 16 // key. Additionally, if the value is of type float, it is only a valid key if
17 // it is not NaN, and if the value is of type Date it is only a valid key if its 17 // it is not NaN, and if the value is of type Date it is only a valid key if its
18 // [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN." 18 // [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN."
19 19
20 // What is required is to ensure that an Lists in the key are actually 20 // What is required is to ensure that an Lists in the key are actually
21 // JavaScript arrays, and any Dates are JavaScript Dates. 21 // JavaScript arrays, and any Dates are JavaScript Dates.
22 22
23 // Conversions for Window. These check if the window is the local 23 // Conversions for Window. These check if the window is the local
24 // window, and if it's not, wraps or unwraps it with a secure wrapper. 24 // window, and if it's not, wraps or unwraps it with a secure wrapper.
25 // We need to test for EventTarget here as well as it's a base type. 25 // We need to test for EventTarget here as well as it's a base type.
26 // We omit an unwrapper for Window as no methods take a non-local 26 // We omit an unwrapper for Window as no methods take a non-local
27 // window as a parameter. 27 // window as a parameter.
28 28
29 part of html; 29 part of html_common;
30
31 Window _convertNativeToDart_Window(win) {
32 return _DOMWindowCrossFrame._createSafe(win);
33 }
34
35 EventTarget _convertNativeToDart_EventTarget(e) {
36 // Assume it's a Window if it contains the setInterval property. It may be
37 // from a different frame - without a patched prototype - so we cannot
38 // rely on Dart type checking.
39 if (JS('bool', r'"setInterval" in #', e))
40 return _DOMWindowCrossFrame._createSafe(e);
41 else
42 return e;
43 }
44
45 EventTarget _convertDartToNative_EventTarget(e) {
46 if (e is _DOMWindowCrossFrame) {
47 return e._window;
48 } else {
49 return e;
50 }
51 }
52
53 // Conversions for ImageData
54 //
55 // On Firefox, the returned ImageData is a plain object.
56
57 class _TypedImageData implements ImageData {
58 final Uint8ClampedArray data;
59 final int height;
60 final int width;
61
62 _TypedImageData(this.data, this.height, this.width);
63 }
64
65 ImageData _convertNativeToDart_ImageData(nativeImageData) {
66
67 // None of the native getters that return ImageData have the type ImageData
68 // since that is incorrect for FireFox (which returns a plain Object). So we
69 // need something that tells the compiler that the ImageData class has been
70 // instantiated.
71 // TODO(sra): Remove this when all the ImageData returning APIs have been
72 // annotated as returning the union ImageData + Object.
73 JS('ImageData', '0');
74
75 if (nativeImageData is ImageData) return nativeImageData;
76
77 // On Firefox the above test fails because imagedata is a plain object.
78 // So we create a _TypedImageData.
79
80 return new _TypedImageData(
81 JS('var', '#.data', nativeImageData),
82 JS('var', '#.height', nativeImageData),
83 JS('var', '#.width', nativeImageData));
84 }
85
86 // We can get rid of this conversion if _TypedImageData implements the fields
87 // with native names.
88 _convertDartToNative_ImageData(ImageData imageData) {
89 if (imageData is _TypedImageData) {
90 return JS('', '{data: #, height: #, width: #}',
91 imageData.data, imageData.height, imageData.width);
92 }
93 return imageData;
94 }
95 30
96 31
97 /// Converts a JavaScript object with properties into a Dart Map. 32 /// Converts a JavaScript object with properties into a Dart Map.
98 /// Not suitable for nested objects. 33 /// Not suitable for nested objects.
99 Map _convertNativeToDart_Dictionary(object) { 34 Map convertNativeToDart_Dictionary(object) {
100 if (object == null) return null; 35 if (object == null) return null;
101 var dict = {}; 36 var dict = {};
102 for (final key in JS('=List', 'Object.getOwnPropertyNames(#)', object)) { 37 for (final key in JS('=List', 'Object.getOwnPropertyNames(#)', object)) {
103 dict[key] = JS('var', '#[#]', object, key); 38 dict[key] = JS('var', '#[#]', object, key);
104 } 39 }
105 return dict; 40 return dict;
106 } 41 }
107 42
108 /// Converts a flat Dart map into a JavaScript object with properties. 43 /// Converts a flat Dart map into a JavaScript object with properties.
109 _convertDartToNative_Dictionary(Map dict) { 44 convertDartToNative_Dictionary(Map dict) {
110 if (dict == null) return null; 45 if (dict == null) return null;
111 var object = JS('var', '{}'); 46 var object = JS('var', '{}');
112 dict.forEach((String key, value) { 47 dict.forEach((String key, value) {
113 JS('void', '#[#] = #', object, key, value); 48 JS('void', '#[#] = #', object, key, value);
114 }); 49 });
115 return object; 50 return object;
116 } 51 }
117 52
118 53
119 /** 54 /**
120 * Ensures that the input is a JavaScript Array. 55 * Ensures that the input is a JavaScript Array.
121 * 56 *
122 * Creates a new JavaScript array if necessary, otherwise returns the original. 57 * Creates a new JavaScript array if necessary, otherwise returns the original.
123 */ 58 */
124 List _convertDartToNative_StringArray(List<String> input) { 59 List convertDartToNative_StringArray(List<String> input) {
125 // TODO(sra). Implement this. 60 // TODO(sra). Implement this.
126 return input; 61 return input;
127 } 62 }
128 63
129 64
130 // ----------------------------------------------------------------------------- 65 // -----------------------------------------------------------------------------
131 66
132 /**
133 * Converts a native IDBKey into a Dart object.
134 *
135 * May return the original input. May mutate the original input (but will be
136 * idempotent if mutation occurs). It is assumed that this conversion happens
137 * on native IDBKeys on all paths that return IDBKeys from native DOM calls.
138 *
139 * If necessary, JavaScript Dates are converted into Dart Dates.
140 */
141 _convertNativeToDart_IDBKey(nativeKey) {
142 containsDate(object) {
143 if (_isJavaScriptDate(object)) return true;
144 if (object is List) {
145 for (int i = 0; i < object.length; i++) {
146 if (containsDate(object[i])) return true;
147 }
148 }
149 return false; // number, string.
150 }
151 if (containsDate(nativeKey)) {
152 throw new UnimplementedError('IDBKey containing Date');
153 }
154 // TODO: Cache conversion somewhere?
155 return nativeKey;
156 }
157
158 /**
159 * Converts a Dart object into a valid IDBKey.
160 *
161 * May return the original input. Does not mutate input.
162 *
163 * If necessary, [dartKey] may be copied to ensure all lists are converted into
164 * JavaScript Arrays and Dart Dates into JavaScript Dates.
165 */
166 _convertDartToNative_IDBKey(dartKey) {
167 // TODO: Implement.
168 return dartKey;
169 }
170
171
172
173 /// May modify original. If so, action is idempotent.
174 _convertNativeToDart_IDBAny(object) {
175 return _convertNativeToDart_AcceptStructuredClone(object, mustCopy: false);
176 }
177
178 /// Converts a Dart value into a JavaScript SerializedScriptValue. 67 /// Converts a Dart value into a JavaScript SerializedScriptValue.
179 _convertDartToNative_SerializedScriptValue(value) { 68 convertDartToNative_SerializedScriptValue(value) {
180 return _convertDartToNative_PrepareForStructuredClone(value); 69 return _convertDartToNative_PrepareForStructuredClone(value);
181 } 70 }
182 71
183 /// Since the source object may be viewed via a JavaScript event listener the 72 /// Since the source object may be viewed via a JavaScript event listener the
184 /// original may not be modified. 73 /// original may not be modified.
185 _convertNativeToDart_SerializedScriptValue(object) { 74 convertNativeToDart_SerializedScriptValue(object) {
186 return _convertNativeToDart_AcceptStructuredClone(object, mustCopy: true); 75 return convertNativeToDart_AcceptStructuredClone(object, mustCopy: true);
187 } 76 }
188 77
189 78
190 /** 79 /**
191 * Converts a Dart value into a JavaScript SerializedScriptValue. Returns the 80 * Converts a Dart value into a JavaScript SerializedScriptValue. Returns the
192 * original input or a functional 'copy'. Does not mutate the original. 81 * original input or a functional 'copy'. Does not mutate the original.
193 * 82 *
194 * The main transformation is the translation of Dart Maps are converted to 83 * The main transformation is the translation of Dart Maps are converted to
195 * JavaScript Objects. 84 * JavaScript Objects.
196 * 85 *
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 128
240 // The browser's internal structured cloning algorithm will copy certain 129 // The browser's internal structured cloning algorithm will copy certain
241 // types of object, but it will copy only its own implementations and not 130 // types of object, but it will copy only its own implementations and not
242 // just any Dart implementations of the interface. 131 // just any Dart implementations of the interface.
243 132
244 // TODO(sra): The JavaScript objects suitable for direct cloning by the 133 // TODO(sra): The JavaScript objects suitable for direct cloning by the
245 // structured clone algorithm could be tagged with an private interface. 134 // structured clone algorithm could be tagged with an private interface.
246 135
247 if (e is File) return e; 136 if (e is File) return e;
248 if (e is Blob) return e; 137 if (e is Blob) return e;
249 if (e is _FileList) return e; 138 if (e is FileList) return e;
250 139
251 // TODO(sra): Firefox: How to convert _TypedImageData on the other end? 140 // TODO(sra): Firefox: How to convert _TypedImageData on the other end?
252 if (e is ImageData) return e; 141 if (e is ImageData) return e;
253 if (e is ArrayBuffer) return e; 142 if (e is ArrayBuffer) return e;
254 143
255 if (e is ArrayBufferView) return e; 144 if (e is ArrayBufferView) return e;
256 145
257 if (e is Map) { 146 if (e is Map) {
258 var slot = findSlot(e); 147 var slot = findSlot(e);
259 var copy = readSlot(slot); 148 var copy = readSlot(slot);
(...skipping 17 matching lines...) Expand all
277 if (copy != null) { 166 if (copy != null) {
278 if (true == copy) { // Cycle, so commit to making a copy. 167 if (true == copy) { // Cycle, so commit to making a copy.
279 copy = JS('=List', 'new Array(#)', length); 168 copy = JS('=List', 'new Array(#)', length);
280 writeSlot(slot, copy); 169 writeSlot(slot, copy);
281 } 170 }
282 return copy; 171 return copy;
283 } 172 }
284 173
285 int i = 0; 174 int i = 0;
286 175
287 if (_isJavaScriptArray(e) && 176 if (isJavaScriptArray(e) &&
288 // We have to copy immutable lists, otherwise the structured clone 177 // We have to copy immutable lists, otherwise the structured clone
289 // algorithm will copy the .immutable$list marker property, making the 178 // algorithm will copy the .immutable$list marker property, making the
290 // list immutable when received! 179 // list immutable when received!
291 !_isImmutableJavaScriptArray(e)) { 180 !isImmutableJavaScriptArray(e)) {
292 writeSlot(slot, true); // Deferred copy. 181 writeSlot(slot, true); // Deferred copy.
293 for ( ; i < length; i++) { 182 for ( ; i < length; i++) {
294 var element = e[i]; 183 var element = e[i];
295 var elementCopy = walk(element); 184 var elementCopy = walk(element);
296 if (!identical(elementCopy, element)) { 185 if (!identical(elementCopy, element)) {
297 copy = readSlot(slot); // Cyclic reference may have created it. 186 copy = readSlot(slot); // Cyclic reference may have created it.
298 if (true == copy) { 187 if (true == copy) {
299 copy = JS('=List', 'new Array(#)', length); 188 copy = JS('=List', 'new Array(#)', length);
300 writeSlot(slot, copy); 189 writeSlot(slot, copy);
301 } 190 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 * [object] is the result of a structured clone operation. 231 * [object] is the result of a structured clone operation.
343 * 232 *
344 * If necessary, JavaScript Dates are converted into Dart Dates. 233 * If necessary, JavaScript Dates are converted into Dart Dates.
345 * 234 *
346 * If [mustCopy] is [:true:], the entire object is copied and the original input 235 * If [mustCopy] is [:true:], the entire object is copied and the original input
347 * is not mutated. This should be the case where Dart and JavaScript code can 236 * is not mutated. This should be the case where Dart and JavaScript code can
348 * access the value, for example, via multiple event listeners for 237 * access the value, for example, via multiple event listeners for
349 * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt 238 * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt
350 * the value as seen from the JavaScript listeners. 239 * the value as seen from the JavaScript listeners.
351 */ 240 */
352 _convertNativeToDart_AcceptStructuredClone(object, {mustCopy = false}) { 241 convertNativeToDart_AcceptStructuredClone(object, {mustCopy = false}) {
353 242
354 // TODO(sra): Replace slots with identity hash table that works on non-dart 243 // TODO(sra): Replace slots with identity hash table that works on non-dart
355 // objects. 244 // objects.
356 var values = []; 245 var values = [];
357 var copies = []; 246 var copies = [];
358 247
359 int findSlot(value) { 248 int findSlot(value) {
360 int length = values.length; 249 int length = values.length;
361 for (int i = 0; i < length; i++) { 250 for (int i = 0; i < length; i++) {
362 if (identical(values[i], value)) return i; 251 if (identical(values[i], value)) return i;
363 } 252 }
364 values.add(value); 253 values.add(value);
365 copies.add(null); 254 copies.add(null);
366 return length; 255 return length;
367 } 256 }
368 readSlot(int i) => copies[i]; 257 readSlot(int i) => copies[i];
369 writeSlot(int i, x) { copies[i] = x; } 258 writeSlot(int i, x) { copies[i] = x; }
370 259
371 walk(e) { 260 walk(e) {
372 if (e == null) return e; 261 if (e == null) return e;
373 if (e is bool) return e; 262 if (e is bool) return e;
374 if (e is num) return e; 263 if (e is num) return e;
375 if (e is String) return e; 264 if (e is String) return e;
376 265
377 if (_isJavaScriptDate(e)) { 266 if (isJavaScriptDate(e)) {
378 // TODO(sra). 267 // TODO(sra).
379 throw new UnimplementedError('structured clone of Date'); 268 throw new UnimplementedError('structured clone of Date');
380 } 269 }
381 270
382 if (_isJavaScriptRegExp(e)) { 271 if (isJavaScriptRegExp(e)) {
383 // TODO(sra). 272 // TODO(sra).
384 throw new UnimplementedError('structured clone of RegExp'); 273 throw new UnimplementedError('structured clone of RegExp');
385 } 274 }
386 275
387 if (_isJavaScriptSimpleObject(e)) { 276 if (isJavaScriptSimpleObject(e)) {
388 // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map 277 // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map
389 // implementation that uses the properies as storage. 278 // implementation that uses the properies as storage.
390 var slot = findSlot(e); 279 var slot = findSlot(e);
391 var copy = readSlot(slot); 280 var copy = readSlot(slot);
392 if (copy != null) return copy; 281 if (copy != null) return copy;
393 copy = {}; 282 copy = {};
394 283
395 writeSlot(slot, copy); 284 writeSlot(slot, copy);
396 for (final key in JS('=List', 'Object.keys(#)', e)) { 285 for (final key in JS('=List', 'Object.keys(#)', e)) {
397 copy[key] = walk(JS('var', '#[#]', e, key)); 286 copy[key] = walk(JS('var', '#[#]', e, key));
398 } 287 }
399 return copy; 288 return copy;
400 } 289 }
401 290
402 if (_isJavaScriptArray(e)) { 291 if (isJavaScriptArray(e)) {
403 var slot = findSlot(e); 292 var slot = findSlot(e);
404 var copy = readSlot(slot); 293 var copy = readSlot(slot);
405 if (copy != null) return copy; 294 if (copy != null) return copy;
406 295
407 int length = e.length; 296 int length = e.length;
408 // Since a JavaScript Array is an instance of Dart List, we can modify it 297 // Since a JavaScript Array is an instance of Dart List, we can modify it
409 // in-place unless we must copy. 298 // in-place unless we must copy.
410 copy = mustCopy ? JS('=List', 'new Array(#)', length) : e; 299 copy = mustCopy ? JS('=List', 'new Array(#)', length) : e;
411 writeSlot(slot, copy); 300 writeSlot(slot, copy);
412 301
413 for (int i = 0; i < length; i++) { 302 for (int i = 0; i < length; i++) {
414 copy[i] = walk(e[i]); 303 copy[i] = walk(e[i]);
415 } 304 }
416 return copy; 305 return copy;
417 } 306 }
418 307
419 // Assume anything else is already a valid Dart object, either by having 308 // Assume anything else is already a valid Dart object, either by having
420 // already been processed, or e.g. a clonable native class. 309 // already been processed, or e.g. a clonable native class.
421 return e; 310 return e;
422 } 311 }
423 312
424 var copy = walk(object); 313 var copy = walk(object);
425 return copy; 314 return copy;
426 } 315 }
427 316
428 317
429 bool _isJavaScriptDate(value) => JS('bool', '# instanceof Date', value); 318 bool isJavaScriptDate(value) => JS('bool', '# instanceof Date', value);
430 bool _isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value); 319 bool isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value);
431 bool _isJavaScriptArray(value) => JS('bool', '# instanceof Array', value); 320 bool isJavaScriptArray(value) => JS('bool', '# instanceof Array', value);
432 bool _isJavaScriptSimpleObject(value) => 321 bool isJavaScriptSimpleObject(value) =>
433 JS('bool', 'Object.getPrototypeOf(#) === Object.prototype', value); 322 JS('bool', 'Object.getPrototypeOf(#) === Object.prototype', value);
434 bool _isImmutableJavaScriptArray(value) => 323 bool isImmutableJavaScriptArray(value) =>
435 JS('bool', r'!!(#.immutable$list)', value); 324 JS('bool', r'!!(#.immutable$list)', value);
436 325
437 326
438 327
439 const String _serializedScriptValue = 328 const String _serializedScriptValue =
440 'num|String|bool|' 329 'num|String|bool|'
441 '=List|=Object|' 330 '=List|=Object|'
442 'Blob|File|ArrayBuffer|ArrayBufferView' 331 'Blob|File|ArrayBuffer|ArrayBufferView'
443 // TODO(sra): Add Date, RegExp. 332 // TODO(sra): Add Date, RegExp.
444 ; 333 ;
445 const _annotation_Creates_SerializedScriptValue = 334 const annotation_Creates_SerializedScriptValue =
446 const Creates(_serializedScriptValue); 335 const Creates(_serializedScriptValue);
447 const _annotation_Returns_SerializedScriptValue = 336 const annotation_Returns_SerializedScriptValue =
448 const Returns(_serializedScriptValue); 337 const Returns(_serializedScriptValue);
449
450 const String _idbKey = '=List|=Object|num|String'; // TODO(sra): Add Date.
451 const _annotation_Creates_IDBKey = const Creates(_idbKey);
452 const _annotation_Returns_IDBKey = const Returns(_idbKey);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698