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

Side by Side Diff: lib/html/src/dart2js_Conversions.dart

Issue 10868067: dart2js dart:html conversions for serialized script values. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 months 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
« no previous file with comments | « lib/html/dart2js/html_dart2js.dart ('k') | tests/html/html.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Conversions for IDBKey. 6 // Conversions for IDBKey.
6 // 7 //
7 // Per http://www.w3.org/TR/IndexedDB/#key-construct 8 // Per http://www.w3.org/TR/IndexedDB/#key-construct
8 // 9 //
9 // "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
10 // JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float 11 // JavaScript objects [ECMA-262], DOMString [WEBIDL], Date [ECMA-262] or float
11 // [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
12 // 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
13 // 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
14 // 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
15 // 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
16 // 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
17 // [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN." 18 // [[PrimitiveValue]] internal property, as defined by [ECMA-262], is not NaN."
18 19
19 // 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
20 // JavaScript arrays, and any Dates are JavaScript Dates. 21 // JavaScript arrays, and any Dates are JavaScript Dates.
21 22
22 /**
23 * Converts a native IDBKey into a Dart object.
24 *
25 * May return the original input. May mutate the original input (but will be
26 * idempotent if mutation occurs). It is assumed that this conversion happens
27 * on native IDBKeys on all paths that return IDBKeys from native DOM calls.
28 *
29 * If necessary, JavaScript Dates are converted into Dart Dates.
30 */
31 _convertNativeToDart_IDBKey(nativeKey) {
32 // TODO: Implement.
33 // TODO: Cache conversion somewhere.
34 return nativeKey;
35 }
36
37 /**
38 * Converts a Dart object into a valid IDBKey.
39 *
40 * May return the original input. Does not mutate input.
41 *
42 * If necessary, [dartKey] may be copied to ensure all lists are converted into
43 * JavaScript Arrays and Dart Dates into JavaScript Dates.
44 */
45
46 _convertDartToNative_IDBKey(dartKey) {
47 // TODO: Implement.
48 // TODO: Cache conversion on object.
49 return dartKey;
50 }
51
52
53 // Conversions for ImageData 23 // Conversions for ImageData
54 // 24 //
55 // On Firefox, the returned ImageData is a plain object. 25 // On Firefox, the returned ImageData is a plain object.
56 26
57 class _TypedImageData implements ImageData { 27 class _TypedImageData implements ImageData {
58 final Uint8ClampedArray data; 28 final Uint8ClampedArray data;
59 final int height; 29 final int height;
60 final int width; 30 final int width;
61 31
62 _TypedImageData(this.data, this.height, this.width); 32 _TypedImageData(this.data, this.height, this.width);
(...skipping 16 matching lines...) Expand all
79 _convertDartToNative_ImageData(ImageData imageData) { 49 _convertDartToNative_ImageData(ImageData imageData) {
80 if (imageData is _ImageDataImpl) return imageData; 50 if (imageData is _ImageDataImpl) return imageData;
81 return JS('Object', '{data: #, height: #, width: #}', 51 return JS('Object', '{data: #, height: #, width: #}',
82 imageData.data, imageData.height, imageData.width); 52 imageData.data, imageData.height, imageData.width);
83 } 53 }
84 54
85 55
86 /// Converts a JavaScript object with properties into a Dart Map. 56 /// Converts a JavaScript object with properties into a Dart Map.
87 /// Not suitable for nested objects. 57 /// Not suitable for nested objects.
88 Map _convertNativeToDart_Dictionary(object) { 58 Map _convertNativeToDart_Dictionary(object) {
89 // TODO: Implement. 59 if (object == null) return null;
90 var dict = {}; 60 var dict = {};
91 for (final key in JS('List', 'Object.getOwnPropertyNames(#)', object)) { 61 for (final key in JS('List', 'Object.getOwnPropertyNames(#)', object)) {
92 dict[key] = JS('var', '#[#]', object, key); 62 dict[key] = JS('var', '#[#]', object, key);
93 } 63 }
94 return dict; 64 return dict;
95 } 65 }
96 66
97 /// Converts a flat Dart map into a JavaScript object with properties. 67 /// Converts a flat Dart map into a JavaScript object with properties.
98 _convertDartToNative_Dictionary(Map dict) { 68 _convertDartToNative_Dictionary(Map dict) {
69 if (dict == null) return null;
99 var object = JS('var', '{}'); 70 var object = JS('var', '{}');
100 dict.forEach((String key, value) { 71 dict.forEach((String key, value) {
101 JS('void', '#[#] = #', object, key, value); 72 JS('void', '#[#] = #', object, key, value);
102 }); 73 });
103 return object; 74 return object;
104 } 75 }
105 76
106 77
107 /** 78 /**
108 * Ensures that the input is a JavaScript Array. 79 * Ensures that the input is a JavaScript Array.
109 * 80 *
110 * Creates a new JavaScript array if necessary, otherwise returns the original. 81 * Creates a new JavaScript array if necessary, otherwise returns the original.
111 */ 82 */
112 List _convertDartToNative_StringArray(List<String> input) { 83 List _convertDartToNative_StringArray(List<String> input) {
84 // TODO(sra). Implement this.
113 return input; 85 return input;
114 } 86 }
87
88
89 // -----------------------------------------------------------------------------
90
91 /**
92 * Converts a native IDBKey into a Dart object.
93 *
94 * May return the original input. May mutate the original input (but will be
95 * idempotent if mutation occurs). It is assumed that this conversion happens
96 * on native IDBKeys on all paths that return IDBKeys from native DOM calls.
97 *
98 * If necessary, JavaScript Dates are converted into Dart Dates.
99 */
100 _convertNativeToDart_IDBKey(nativeKey) {
101 containsDate(object) {
102 if (_isJavaScriptDate(object)) return true;
103 if (object is List) {
104 for (int i = 0; i < object.length; i++) {
105 if (containsDate(object[i])) return true;
106 }
107 }
108 return false; // number, string.
109 }
110 if (containsDate(nativeKey)) {
111 throw const NotImplementedException('IDBKey containing Date');
112 }
113 // TODO: Cache conversion somewhere?
114 return nativeKey;
115 }
116
117 /**
118 * Converts a Dart object into a valid IDBKey.
119 *
120 * May return the original input. Does not mutate input.
121 *
122 * If necessary, [dartKey] may be copied to ensure all lists are converted into
123 * JavaScript Arrays and Dart Dates into JavaScript Dates.
124 */
125 _convertDartToNative_IDBKey(dartKey) {
126 // TODO: Implement.
127 return dartKey;
128 }
129
130
131
132 // May modify original. If so, action is idempotent.
133 _convertNativeToDart_IDBAny(object) {
134 return _convertNativeToDart_AcceptStructuredClone(object);
135 }
136
137 /// Converts a Dart value into
138 _convertDartToNative_SerializedScriptValue(value) {
139 return _convertDartToNative_PrepareForStructuredClone(value);
140 }
141
142
143 /**
144 * Converts a Dart value into a JavaScript SerializedScriptValue. Returns the
145 * original input or a functional 'copy'. Does not mutate the original.
146 *
147 * The main transformation is the translation of Dart Maps are converted to
148 * JavaScript Objects.
149 *
150 * The algorithm is essentially a dry-run of the structured clone algorithm
151 * described at
152 * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interf aces.html#structured-clone
153 * https://www.khronos.org/registry/typedarray/specs/latest/#9
154 *
155 */
156 _convertDartToNative_PrepareForStructuredClone(value) {
157
158 // TODO(sra): Replace slots with identity hash table.
159 var values = [];
160 var copies = []; // initially 'null', 'true' during initial DFS, then a copy.
161
162 int findSlot(value) {
163 int length = values.length;
164 for (int i = 0; i < length; i++) {
165 if (values[i] === value) return i;
166 }
167 values.add(value);
168 copies.add(null);
169 return length;
170 }
171 readSlot(int i) => copies[i];
172 writeSlot(int i, x) { copies[i] = x; }
173 cleanupSlots() {} // Will be needed if we mark objects with a property.
174
175 // Returns the input, or a clone of the input.
176 walk(e) {
177 if (e == null) return e;
178 if (e is bool) return e;
179 if (e is num) return e;
180 if (e is String) return e;
181 if (e is Date) {
182 // TODO(sra).
183 throw const NotImplementedException('structured clone of Date');
184 }
185 if (e is RegExp) {
186 // TODO(sra).
187 throw const NotImplementedException('structured clone of RegExp');
188 }
189
190 // The browser's internal structured cloning algorithm will copy certain
191 // types of object, but it will copy only its own implementations and not
192 // just any Dart implementations of the interface.
193
194 // TODO(sra): The JavaScript objects suitable for direct cloning by the
195 // structured clone algorithm could be tagged with an private interface.
196
197 if (e is _FileImpl) return e;
198 if (e is File) {
199 throw const NotImplementedException('structured clone of File');
200 }
201
202 if (e is _BlobImpl) return e;
203 if (e is Blob) {
204 throw const NotImplementedException('structured clone of Blob');
205 }
206
207 if (e is _FileListImpl) return e;
208 if (e is FileList) {
209 throw const NotImplementedException('structured clone of FileList');
210 }
211
212 // TODO(sra): Firefox: How to convert _TypedImageData on the other end?
213 if (e is _ImageDataImpl) return e;
214 if (e is ImageData) {
215 throw const NotImplementedException('structured clone of FileList');
216 }
217
218 if (e is _ArrayBufferImpl) return e;
219 if (e is ArrayBuffer) {
220 throw const NotImplementedException('structured clone of ArrayBuffer');
221 }
222
223 if (e is _ArrayBufferViewImpl) return e;
224 if (e is ArrayBufferView) {
225 throw const NotImplementedException('structured clone of ArrayBufferView') ;
226 }
227
228 if (e is Map) {
229 var slot = findSlot(e);
230 var copy = readSlot(slot);
231 if (copy != null) return copy;
232 copy = JS('var', '{}');
233 writeSlot(slot, copy);
234 e.forEach((key, value) {
235 JS('void', '#[#] = #', copy, key, walk(value));
236 });
237 return copy;
238 }
239
240 if (e is List) {
241 // Since a JavaScript Array is an instance of Dart List it is possible to
242 // avoid making a copy of the list if there is no need to copy anything
243 // reachable from the array. We defer creating a new array until a cycle
244 // is detected or a subgraph was copied.
245 int length = e.length;
246 var slot = findSlot(e);
247 var copy = readSlot(slot);
248 if (copy != null) {
249 if (true == copy) { // Cycle, so commit to making a copy.
250 copy = JS('List', 'new Array(#)', length);
251 writeSlot(slot, copy);
252 }
253 return copy;
254 }
255
256 int i = 0;
257
258 if (_isJavaScriptArray(e) &&
259 // We have to copy immutable lists, otherwise the structured clone
260 // algorithm will copy the .immutable$list marker property, making the
261 // list immutable when received!
262 !_isImmutableJavaScriptArray(e)) {
263 writeSlot(slot, true); // Deferred copy.
264 for ( ; i < length; i++) {
265 var element = e[i];
266 var elementCopy = walk(element);
267 if (elementCopy !== element) {
268 copy = readSlot(slot); // Cyclic reference may have created it.
269 if (true == copy) {
270 copy = JS('List', 'new Array(#)', length);
271 writeSlot(slot, copy);
272 }
273 for (int j = 0; j < i; j++) {
274 copy[j] = e[j];
275 }
276 copy[i] = elementCopy;
277 i++;
278 break;
279 }
280 }
281 if (copy == null) {
282 copy = e;
283 writeSlot(slot, copy);
284 }
285 } else {
286 // Not a JavaScript Array. We are forced to make a copy.
287 copy = JS('List', 'new Array(#)', length);
288 writeSlot(slot, copy);
289 }
290
291 for ( ; i < length; i++) {
292 copy[i] = walk(e[i]);
293 }
294 return copy;
295 }
296
297 throw const NotImplementedException('structured clone of other type');
298 }
299
300 var copy = walk(value);
301 cleanupSlots();
302 return copy;
303 }
304
305 /**
306 * Converts a native value into a Dart object.
307 *
308 * May return the original input. May mutate the original input (but will be
309 * idempotent if mutation occurs). It is assumed that this conversion happens
310 * on native serializable script values such values from native DOM calls.
311 *
312 * [object] is the result of a structured clone operation.
313 *
314 * If necessary, JavaScript Dates are converted into Dart Dates.
315 */
316 _convertNativeToDart_AcceptStructuredClone(object) {
317
318 // TODO(sra): Replace slots with identity hash table that works on non-dart
319 // objects.
320 var values = [];
321 var copies = [];
322
323 int findSlot(value) {
324 int length = values.length;
325 for (int i = 0; i < length; i++) {
326 if (values[i] === value) return i;
327 }
328 values.add(value);
329 copies.add(null);
330 return length;
331 }
332 readSlot(int i) => copies[i];
333 writeSlot(int i, x) { copies[i] = x; }
334
335 walk(e) {
336 if (e == null) return e;
337 if (e is bool) return e;
338 if (e is num) return e;
339 if (e is String) return e;
340
341 if (_isJavaScriptDate(e)) {
342 // TODO(sra).
343 throw const NotImplementedException('structured clone of Date');
344 }
345
346 if (_isJavaScriptRegExp(e)) {
347 // TODO(sra).
348 throw const NotImplementedException('structured clone of RegExp');
349 }
350
351 if (_isJavaScriptSimpleObject(e)) {
352 // TODO(sra): Swizzle the prototype for one of a Map implementation that
353 // uses the properies as storage.
354 var slot = findSlot(e);
355 var copy = readSlot(slot);
356 if (copy != null) return copy;
357 copy = {};
358
359 writeSlot(slot, copy);
360 for (final key in JS('List', 'Object.keys(#)', e)) {
361 copy[key] = walk(JS('var', '#[#]', e, key));
362 }
363 return copy;
364 }
365
366 if (_isJavaScriptArray(e)) {
367 // Since a JavaScript Array is an instance of Dart List, we can modify it
368 // in-place.
369 var slot = findSlot(e);
370 var copy = readSlot(slot);
371 if (copy != null) return copy;
372 writeSlot(slot, e);
373
374 int length = e.length;
375 for (int i = 0; i < length; i++) {
376 e[i] = walk(e[i]);
377 }
378 return e;
379 }
380
381 // Assume anything else is already a valid Dart object, either by having
382 // already been processed, or e.g. a clonable native class.
383 return e;
384 }
385
386 var copy = walk(object);
387 return copy;
388 }
389
390
391 bool _isJavaScriptDate(value) => JS('bool', '# instanceof Date', value);
392 bool _isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value);
393 bool _isJavaScriptArray(value) => JS('bool', '# instanceof Array', value);
394 bool _isJavaScriptSimpleObject(value) =>
395 JS('bool', 'Object.getPrototypeOf(#) === Object.prototype', value);
396 bool _isImmutableJavaScriptArray(value) =>
397 JS('bool', @'!!(#.immutable$list)', value);
OLDNEW
« no previous file with comments | « lib/html/dart2js/html_dart2js.dart ('k') | tests/html/html.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698