OLD | NEW |
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 | |
6 // Conversions for IDBKey. | 5 // Conversions for IDBKey. |
7 // | 6 // |
8 // Per http://www.w3.org/TR/IndexedDB/#key-construct | 7 // Per http://www.w3.org/TR/IndexedDB/#key-construct |
9 // | 8 // |
10 // "A value is said to be a valid key if it is one of the following types: Array | 9 // "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 | 10 // 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 | 11 // [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 | 12 // 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 | 13 // 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 | 14 // properties are ignored, and thus does not affect whether the Array is a valid |
(...skipping 16 matching lines...) Expand all Loading... |
32 convertDartToNative_SerializedScriptValue(value) { | 31 convertDartToNative_SerializedScriptValue(value) { |
33 return convertDartToNative_PrepareForStructuredClone(value); | 32 return convertDartToNative_PrepareForStructuredClone(value); |
34 } | 33 } |
35 | 34 |
36 /// Since the source object may be viewed via a JavaScript event listener the | 35 /// Since the source object may be viewed via a JavaScript event listener the |
37 /// original may not be modified. | 36 /// original may not be modified. |
38 convertNativeToDart_SerializedScriptValue(object) { | 37 convertNativeToDart_SerializedScriptValue(object) { |
39 return convertNativeToDart_AcceptStructuredClone(object, mustCopy: true); | 38 return convertNativeToDart_AcceptStructuredClone(object, mustCopy: true); |
40 } | 39 } |
41 | 40 |
42 | |
43 /** | 41 /** |
44 * Converts a Dart value into a JavaScript SerializedScriptValue. Returns the | 42 * Converts a Dart value into a JavaScript SerializedScriptValue. Returns the |
45 * original input or a functional 'copy'. Does not mutate the original. | 43 * original input or a functional 'copy'. Does not mutate the original. |
46 * | 44 * |
47 * The main transformation is the translation of Dart Maps are converted to | 45 * The main transformation is the translation of Dart Maps are converted to |
48 * JavaScript Objects. | 46 * JavaScript Objects. |
49 * | 47 * |
50 * The algorithm is essentially a dry-run of the structured clone algorithm | 48 * The algorithm is essentially a dry-run of the structured clone algorithm |
51 * described at | 49 * described at |
52 * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interf
aces.html#structured-clone | 50 * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interf
aces.html#structured-clone |
53 * https://www.khronos.org/registry/typedarray/specs/latest/#9 | 51 * https://www.khronos.org/registry/typedarray/specs/latest/#9 |
54 * | 52 * |
55 * Since the result of this function is expected to be passed only to JavaScript | 53 * Since the result of this function is expected to be passed only to JavaScript |
56 * operations that perform the structured clone algorithm which does not mutate | 54 * operations that perform the structured clone algorithm which does not mutate |
57 * its output, the result may share structure with the input [value]. | 55 * its output, the result may share structure with the input [value]. |
58 */ | 56 */ |
59 abstract class _StructuredClone { | 57 abstract class _StructuredClone { |
60 | |
61 // TODO(sra): Replace slots with identity hash table. | 58 // TODO(sra): Replace slots with identity hash table. |
62 var values = []; | 59 var values = []; |
63 var copies = []; // initially 'null', 'true' during initial DFS, then a copy. | 60 var copies = []; // initially 'null', 'true' during initial DFS, then a copy. |
64 | 61 |
65 int findSlot(value) { | 62 int findSlot(value) { |
66 int length = values.length; | 63 int length = values.length; |
67 for (int i = 0; i < length; i++) { | 64 for (int i = 0; i < length; i++) { |
68 if (identical(values[i], value)) return i; | 65 if (identical(values[i], value)) return i; |
69 } | 66 } |
70 values.add(value); | 67 values.add(value); |
71 copies.add(null); | 68 copies.add(null); |
72 return length; | 69 return length; |
73 } | 70 } |
| 71 |
74 readSlot(int i) => copies[i]; | 72 readSlot(int i) => copies[i]; |
75 writeSlot(int i, x) { copies[i] = x; } | 73 writeSlot(int i, x) { |
76 cleanupSlots() {} // Will be needed if we mark objects with a property. | 74 copies[i] = x; |
| 75 } |
| 76 |
| 77 cleanupSlots() {} // Will be needed if we mark objects with a property. |
77 bool cloneNotRequired(object); | 78 bool cloneNotRequired(object); |
78 newJsMap(); | 79 newJsMap(); |
79 newJsList(length); | 80 newJsList(length); |
80 void putIntoMap(map, key, value); | 81 void putIntoMap(map, key, value); |
81 | 82 |
82 // Returns the input, or a clone of the input. | 83 // Returns the input, or a clone of the input. |
83 walk(e) { | 84 walk(e) { |
84 if (e == null) return e; | 85 if (e == null) return e; |
85 if (e is bool) return e; | 86 if (e is bool) return e; |
86 if (e is num) return e; | 87 if (e is num) return e; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 } | 135 } |
135 | 136 |
136 throw new UnimplementedError('structured clone of other type'); | 137 throw new UnimplementedError('structured clone of other type'); |
137 } | 138 } |
138 | 139 |
139 copyList(List e, int slot) { | 140 copyList(List e, int slot) { |
140 int i = 0; | 141 int i = 0; |
141 int length = e.length; | 142 int length = e.length; |
142 var copy = newJsList(length); | 143 var copy = newJsList(length); |
143 writeSlot(slot, copy); | 144 writeSlot(slot, copy); |
144 for ( ; i < length; i++) { | 145 for (; i < length; i++) { |
145 copy[i] = walk(e[i]); | 146 copy[i] = walk(e[i]); |
146 } | 147 } |
147 return copy; | 148 return copy; |
148 } | 149 } |
149 | 150 |
150 convertDartToNative_PrepareForStructuredClone(value) { | 151 convertDartToNative_PrepareForStructuredClone(value) { |
151 var copy = walk(value); | 152 var copy = walk(value); |
152 cleanupSlots(); | 153 cleanupSlots(); |
153 return copy; | 154 return copy; |
154 } | 155 } |
(...skipping 11 matching lines...) Expand all Loading... |
166 * | 167 * |
167 * If necessary, JavaScript Dates are converted into Dart Dates. | 168 * If necessary, JavaScript Dates are converted into Dart Dates. |
168 * | 169 * |
169 * If [mustCopy] is [:true:], the entire object is copied and the original input | 170 * If [mustCopy] is [:true:], the entire object is copied and the original input |
170 * is not mutated. This should be the case where Dart and JavaScript code can | 171 * is not mutated. This should be the case where Dart and JavaScript code can |
171 * access the value, for example, via multiple event listeners for | 172 * access the value, for example, via multiple event listeners for |
172 * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt | 173 * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt |
173 * the value as seen from the JavaScript listeners. | 174 * the value as seen from the JavaScript listeners. |
174 */ | 175 */ |
175 abstract class _AcceptStructuredClone { | 176 abstract class _AcceptStructuredClone { |
176 | |
177 // TODO(sra): Replace slots with identity hash table. | 177 // TODO(sra): Replace slots with identity hash table. |
178 var values = []; | 178 var values = []; |
179 var copies = []; // initially 'null', 'true' during initial DFS, then a copy. | 179 var copies = []; // initially 'null', 'true' during initial DFS, then a copy. |
180 bool mustCopy = false; | 180 bool mustCopy = false; |
181 | 181 |
182 int findSlot(value) { | 182 int findSlot(value) { |
183 int length = values.length; | 183 int length = values.length; |
184 for (int i = 0; i < length; i++) { | 184 for (int i = 0; i < length; i++) { |
185 if (identicalInJs(values[i], value)) return i; | 185 if (identicalInJs(values[i], value)) return i; |
186 } | 186 } |
187 values.add(value); | 187 values.add(value); |
188 copies.add(null); | 188 copies.add(null); |
189 return length; | 189 return length; |
190 } | 190 } |
191 | 191 |
192 /// Are the two objects identical, but taking into account that two JsObject | 192 /// Are the two objects identical, but taking into account that two JsObject |
193 /// wrappers may not be identical, but their underlying Js Object might be. | 193 /// wrappers may not be identical, but their underlying Js Object might be. |
194 bool identicalInJs(a, b); | 194 bool identicalInJs(a, b); |
195 readSlot(int i) => copies[i]; | 195 readSlot(int i) => copies[i]; |
196 writeSlot(int i, x) { copies[i] = x; } | 196 writeSlot(int i, x) { |
| 197 copies[i] = x; |
| 198 } |
197 | 199 |
198 /// Iterate over the JS properties. | 200 /// Iterate over the JS properties. |
199 forEachJsField(object, action); | 201 forEachJsField(object, action); |
200 | 202 |
201 /// Create a new Dart list of the given length. May create a native List or | 203 /// Create a new Dart list of the given length. May create a native List or |
202 /// a JsArray, depending if we're in Dartium or dart2js. | 204 /// a JsArray, depending if we're in Dartium or dart2js. |
203 newDartList(length); | 205 newDartList(length); |
204 | 206 |
205 walk(e) { | 207 walk(e) { |
206 if (e == null) return e; | 208 if (e == null) return e; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 // On Firefox, the returned ContextAttributes is a plain object. | 270 // On Firefox, the returned ContextAttributes is a plain object. |
269 class ContextAttributes { | 271 class ContextAttributes { |
270 bool alpha; | 272 bool alpha; |
271 bool antialias; | 273 bool antialias; |
272 bool depth; | 274 bool depth; |
273 bool premultipliedAlpha; | 275 bool premultipliedAlpha; |
274 bool preserveDrawingBuffer; | 276 bool preserveDrawingBuffer; |
275 bool stencil; | 277 bool stencil; |
276 bool failIfMajorPerformanceCaveat; | 278 bool failIfMajorPerformanceCaveat; |
277 | 279 |
278 ContextAttributes(this.alpha, this.antialias, this.depth, | 280 ContextAttributes( |
279 this.failIfMajorPerformanceCaveat, this.premultipliedAlpha, | 281 this.alpha, |
280 this.preserveDrawingBuffer, this.stencil); | 282 this.antialias, |
| 283 this.depth, |
| 284 this.failIfMajorPerformanceCaveat, |
| 285 this.premultipliedAlpha, |
| 286 this.preserveDrawingBuffer, |
| 287 this.stencil); |
281 } | 288 } |
282 | 289 |
283 convertNativeToDart_ContextAttributes(nativeContextAttributes) { | 290 convertNativeToDart_ContextAttributes(nativeContextAttributes) { |
284 // On Firefox the above test fails because ContextAttributes is a plain | 291 // On Firefox the above test fails because ContextAttributes is a plain |
285 // object so we create a _TypedContextAttributes. | 292 // object so we create a _TypedContextAttributes. |
286 | 293 |
287 return new ContextAttributes( | 294 return new ContextAttributes( |
288 JS('var', '#.alpha', nativeContextAttributes), | 295 JS('var', '#.alpha', nativeContextAttributes), |
289 JS('var', '#.antialias', nativeContextAttributes), | 296 JS('var', '#.antialias', nativeContextAttributes), |
290 JS('var', '#.depth', nativeContextAttributes), | 297 JS('var', '#.depth', nativeContextAttributes), |
291 JS('var', '#.failIfMajorPerformanceCaveat', nativeContextAttributes), | 298 JS('var', '#.failIfMajorPerformanceCaveat', nativeContextAttributes), |
292 JS('var', '#.premultipliedAlpha', nativeContextAttributes), | 299 JS('var', '#.premultipliedAlpha', nativeContextAttributes), |
293 JS('var', '#.preserveDrawingBuffer', nativeContextAttributes), | 300 JS('var', '#.preserveDrawingBuffer', nativeContextAttributes), |
294 JS('var', '#.stencil', nativeContextAttributes)); | 301 JS('var', '#.stencil', nativeContextAttributes)); |
295 } | 302 } |
296 | 303 |
297 // Conversions for ImageData | 304 // Conversions for ImageData |
298 // | 305 // |
299 // On Firefox, the returned ImageData is a plain object. | 306 // On Firefox, the returned ImageData is a plain object. |
300 | 307 |
301 class _TypedImageData implements ImageData { | 308 class _TypedImageData implements ImageData { |
302 final Uint8ClampedList data; | 309 final Uint8ClampedList data; |
303 final int height; | 310 final int height; |
304 final int width; | 311 final int width; |
305 | 312 |
306 _TypedImageData(this.data, this.height, this.width); | 313 _TypedImageData(this.data, this.height, this.width); |
307 } | 314 } |
308 | 315 |
309 ImageData convertNativeToDart_ImageData(nativeImageData) { | 316 ImageData convertNativeToDart_ImageData(nativeImageData) { |
310 | |
311 // None of the native getters that return ImageData are declared as returning | 317 // None of the native getters that return ImageData are declared as returning |
312 // [ImageData] since that is incorrect for FireFox, which returns a plain | 318 // [ImageData] since that is incorrect for FireFox, which returns a plain |
313 // Object. So we need something that tells the compiler that the ImageData | 319 // Object. So we need something that tells the compiler that the ImageData |
314 // class has been instantiated. | 320 // class has been instantiated. |
315 // TODO(sra): Remove this when all the ImageData returning APIs have been | 321 // TODO(sra): Remove this when all the ImageData returning APIs have been |
316 // annotated as returning the union ImageData + Object. | 322 // annotated as returning the union ImageData + Object. |
317 JS('ImageData', '0'); | 323 JS('ImageData', '0'); |
318 | 324 |
319 if (nativeImageData is ImageData) { | 325 if (nativeImageData is ImageData) { |
320 | |
321 // Fix for Issue 16069: on IE, the `data` field is a CanvasPixelArray which | 326 // Fix for Issue 16069: on IE, the `data` field is a CanvasPixelArray which |
322 // has Array as the constructor property. This interferes with finding the | 327 // has Array as the constructor property. This interferes with finding the |
323 // correct interceptor. Fix it by overwriting the constructor property. | 328 // correct interceptor. Fix it by overwriting the constructor property. |
324 var data = nativeImageData.data; | 329 var data = nativeImageData.data; |
325 if (JS('bool', '#.constructor === Array', data)) { | 330 if (JS('bool', '#.constructor === Array', data)) { |
326 if (JS('bool', 'typeof CanvasPixelArray !== "undefined"')) { | 331 if (JS('bool', 'typeof CanvasPixelArray !== "undefined"')) { |
327 JS('void', '#.constructor = CanvasPixelArray', data); | 332 JS('void', '#.constructor = CanvasPixelArray', data); |
328 // This TypedArray property is missing from CanvasPixelArray. | 333 // This TypedArray property is missing from CanvasPixelArray. |
329 JS('void', '#.BYTES_PER_ELEMENT = 1', data); | 334 JS('void', '#.BYTES_PER_ELEMENT = 1', data); |
330 } | 335 } |
331 } | 336 } |
332 | 337 |
333 return nativeImageData; | 338 return nativeImageData; |
334 } | 339 } |
335 | 340 |
336 // On Firefox the above test fails because [nativeImageData] is a plain | 341 // On Firefox the above test fails because [nativeImageData] is a plain |
337 // object. So we create a _TypedImageData. | 342 // object. So we create a _TypedImageData. |
338 | 343 |
339 return new _TypedImageData( | 344 return new _TypedImageData( |
340 JS('NativeUint8ClampedList', '#.data', nativeImageData), | 345 JS('NativeUint8ClampedList', '#.data', nativeImageData), |
341 JS('var', '#.height', nativeImageData), | 346 JS('var', '#.height', nativeImageData), |
342 JS('var', '#.width', nativeImageData)); | 347 JS('var', '#.width', nativeImageData)); |
343 } | 348 } |
344 | 349 |
345 // We can get rid of this conversion if _TypedImageData implements the fields | 350 // We can get rid of this conversion if _TypedImageData implements the fields |
346 // with native names. | 351 // with native names. |
347 convertDartToNative_ImageData(ImageData imageData) { | 352 convertDartToNative_ImageData(ImageData imageData) { |
348 if (imageData is _TypedImageData) { | 353 if (imageData is _TypedImageData) { |
349 return JS('', '{data: #, height: #, width: #}', | 354 return JS('', '{data: #, height: #, width: #}', imageData.data, |
350 imageData.data, imageData.height, imageData.width); | 355 imageData.height, imageData.width); |
351 } | 356 } |
352 return imageData; | 357 return imageData; |
353 } | 358 } |
OLD | NEW |