| 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 |