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 part of $LIBRARYNAME; | 5 part of $LIBRARYNAME; |
6 | 6 |
| 7 typedef void RemoveFrameRequestMapping(int id); |
| 8 |
| 9 /** |
| 10 * The task object representing animation-frame requests. |
| 11 * |
| 12 * For historical reasons, [Window.requestAnimationFrame] returns an integer |
| 13 * to users. However, zone tasks must be unique objects, and an integer can |
| 14 * therefore not be used as task object. The [Window] class thus keeps a mapping |
| 15 * from the integer ID to the corresponding task object. All zone related |
| 16 * operations work on this task object, whereas users of |
| 17 * [Window.requestAnimationFrame] only see the integer ID. |
| 18 * |
| 19 * Since this mapping takes up space, it must be removed when the |
| 20 * animation-frame task has triggered. The default implementation does this |
| 21 * automatically, but intercepting implementations of `requestAnimationFrame` |
| 22 * must make sure to call the [AnimationFrameTask.removeMapping] |
| 23 * function that is provided in the task specification. |
| 24 * |
| 25 * *Experimental*. This class may disappear without notice. |
| 26 */ |
| 27 abstract class AnimationFrameTask { |
| 28 /** The ID that is returned to users. */ |
| 29 int get id; |
| 30 |
| 31 /** The zone in which the task will run. */ |
| 32 Zone get zone; |
| 33 |
| 34 /** |
| 35 * Cancels the animation-frame request. |
| 36 * |
| 37 * A call to [Window.cancelAnimationFrame] with an `id` argument equal to [id] |
| 38 * forwards the request to this function. |
| 39 * |
| 40 * Zones that intercept animation-frame requests implement this method so |
| 41 * that they can react to cancelation requests. |
| 42 */ |
| 43 void cancel(Window window); |
| 44 |
| 45 /** |
| 46 * Maps animation-frame request IDs to their task objects. |
| 47 */ |
| 48 static final Map<int, _AnimationFrameTask> _tasks = {}; |
| 49 |
| 50 /** |
| 51 * Removes the mapping from [id] to [AnimationFrameTask]. |
| 52 * |
| 53 * This function must be invoked by user-implemented animation-frame |
| 54 * tasks, before running [callback]. |
| 55 * |
| 56 * See [AnimationFrameTask]. |
| 57 */ |
| 58 static void removeMapping(int id) { |
| 59 _tasks.remove(id); |
| 60 } |
| 61 } |
| 62 |
| 63 class _AnimationFrameTask implements AnimationFrameTask { |
| 64 final int id; |
| 65 final Zone zone; |
| 66 final FrameRequestCallback _callback; |
| 67 |
| 68 _AnimationFrameTask(this.id, this.zone, this._callback); |
| 69 |
| 70 void cancel(Window window) { |
| 71 window._cancelAnimationFrame(this.id); |
| 72 } |
| 73 } |
| 74 |
| 75 /** |
| 76 * The task specification for an animation-frame request. |
| 77 * |
| 78 * *Experimental*. This class may disappear without notice. |
| 79 */ |
| 80 class AnimationFrameRequestSpecification implements TaskSpecification { |
| 81 /** |
| 82 * The window on which [Window.requestAnimationFrame] was invoked. |
| 83 */ |
| 84 final Window window; |
| 85 |
| 86 /** |
| 87 * The callback that is executed when the animation-frame is ready. |
| 88 * |
| 89 * Note that the callback hasn't been registered in any zone when the `create` |
| 90 * function (passed to [Zone.createTask]) is invoked. |
| 91 */ |
| 92 final FrameRequestCallback callback; |
| 93 |
| 94 AnimationFrameRequestSpecification(this.window, this.callback); |
| 95 |
| 96 String get name => "dart.html.request-animation-frame"; |
| 97 bool get isOneShot => true; |
| 98 } |
| 99 |
7 @DocsEditable() | 100 @DocsEditable() |
8 $if DART2JS | 101 $if DART2JS |
9 $(ANNOTATIONS)@Native("Window,DOMWindow") | 102 $(ANNOTATIONS)@Native("Window,DOMWindow") |
10 $(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS { | 103 $(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS { |
11 $else | 104 $else |
12 $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
{ | 105 $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
{ |
13 $endif | 106 $endif |
14 | 107 |
15 /** | 108 /** |
16 * Returns a Future that completes just before the window is about to | 109 * Returns a Future that completes just before the window is about to |
17 * repaint so the user can draw an animation frame. | 110 * repaint so the user can draw an animation frame. |
18 * | 111 * |
19 * If you need to later cancel this animation, use [requestAnimationFrame] | 112 * If you need to later cancel this animation, use [requestAnimationFrame] |
20 * instead. | 113 * instead. |
21 * | 114 * |
22 * The [Future] completes to a timestamp that represents a floating | 115 * The [Future] completes to a timestamp that represents a floating |
23 * point value of the number of milliseconds that have elapsed since the page | 116 * point value of the number of milliseconds that have elapsed since the page |
24 * started to load (which is also the timestamp at this call to | 117 * started to load (which is also the timestamp at this call to |
25 * animationFrame). | 118 * animationFrame). |
26 * | 119 * |
27 * Note: The code that runs when the future completes should call | 120 * Note: The code that runs when the future completes should call |
28 * [animationFrame] again for the animation to continue. | 121 * [animationFrame] again for the animation to continue. |
29 */ | 122 */ |
30 Future<num> get animationFrame { | 123 Future<num> get animationFrame { |
31 var completer = new Completer<num>.sync(); | 124 var completer = new Completer<num>.sync(); |
32 requestAnimationFrame((time) { | 125 requestAnimationFrame(completer.complete); |
33 completer.complete(time); | |
34 }); | |
35 return completer.future; | 126 return completer.future; |
36 } | 127 } |
37 | 128 |
38 $if DART2JS | 129 $if DART2JS |
39 /** | 130 /** |
40 * The newest document in this window. | 131 * The newest document in this window. |
41 * | 132 * |
42 * ## Other resources | 133 * ## Other resources |
43 * | 134 * |
44 * * [Loading web | 135 * * [Loading web |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 * request. This value only needs to be saved if you intend to call | 199 * request. This value only needs to be saved if you intend to call |
109 * [cancelAnimationFrame] so you can specify the particular animation to | 200 * [cancelAnimationFrame] so you can specify the particular animation to |
110 * cancel. | 201 * cancel. |
111 * | 202 * |
112 * Note: The supplied [callback] needs to call [requestAnimationFrame] again | 203 * Note: The supplied [callback] needs to call [requestAnimationFrame] again |
113 * for the animation to continue. | 204 * for the animation to continue. |
114 */ | 205 */ |
115 @DomName('Window.requestAnimationFrame') | 206 @DomName('Window.requestAnimationFrame') |
116 int requestAnimationFrame(FrameRequestCallback callback) { | 207 int requestAnimationFrame(FrameRequestCallback callback) { |
117 _ensureRequestAnimationFrame(); | 208 _ensureRequestAnimationFrame(); |
118 return _requestAnimationFrame(_wrapZone/*<dynamic, num>*/(callback)); | 209 if (identical(Zone.current, Zone.ROOT)) { |
| 210 return _requestAnimationFrame(callback); |
| 211 } |
| 212 var spec = new AnimationFrameRequestSpecification(this, callback); |
| 213 var task = Zone.current.createTask/*<AnimationFrameTask>*/( |
| 214 _createAnimationFrameTask, spec); |
| 215 AnimationFrameTask._tasks[task.id] = task; |
| 216 return task.id; |
| 217 } |
| 218 |
| 219 static _AnimationFrameTask _createAnimationFrameTask( |
| 220 AnimationFrameRequestSpecification spec, Zone zone) { |
| 221 var task; |
| 222 var id = spec.window._requestAnimationFrame((num time) { |
| 223 AnimationFrameTask.removeMapping(task.id); |
| 224 zone.runTask(_runAnimationFrame, task, time); |
| 225 }); |
| 226 var callback = zone.registerUnaryCallback(spec.callback); |
| 227 task = new _AnimationFrameTask(id, zone, callback); |
| 228 return task; |
| 229 } |
| 230 |
| 231 static void _runAnimationFrame(_AnimationFrameTask task, num time) { |
| 232 task._callback(time); |
119 } | 233 } |
120 | 234 |
121 /** | 235 /** |
122 * Cancels an animation frame request. | 236 * Cancels an animation frame request. |
123 * | 237 * |
124 * ## Other resources | 238 * ## Other resources |
125 * | 239 * |
126 * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/We
b/API/Window.cancelAnimationFrame) | 240 * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/We
b/API/Window.cancelAnimationFrame) |
127 * from MDN. | 241 * from MDN. |
128 */ | 242 */ |
129 void cancelAnimationFrame(int id) { | 243 void cancelAnimationFrame(int id) { |
130 _ensureRequestAnimationFrame(); | 244 _ensureRequestAnimationFrame(); |
131 _cancelAnimationFrame(id); | 245 var task = AnimationFrameTask._tasks.remove(id); |
| 246 if (task == null) { |
| 247 // Assume that the animation frame request wasn't intercepted by a zone. |
| 248 _cancelAnimationFrame(id); |
| 249 return; |
| 250 } |
| 251 task.cancel(this); |
132 } | 252 } |
133 | 253 |
134 @JSName('requestAnimationFrame') | 254 @JSName('requestAnimationFrame') |
135 int _requestAnimationFrame(FrameRequestCallback callback) native; | 255 int _requestAnimationFrame(FrameRequestCallback callback) native; |
136 | 256 |
137 @JSName('cancelAnimationFrame') | 257 @JSName('cancelAnimationFrame') |
138 void _cancelAnimationFrame(int id) native; | 258 void _cancelAnimationFrame(int id) native; |
139 | 259 |
140 _ensureRequestAnimationFrame() { | 260 _ensureRequestAnimationFrame() { |
141 if (JS('bool', | 261 if (JS('bool', |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 {bool useCapture: false}) { | 495 {bool useCapture: false}) { |
376 $if DART2JS | 496 $if DART2JS |
377 // Specify the generic type for _ElementEventStreamImpl only in dart2js to | 497 // Specify the generic type for _ElementEventStreamImpl only in dart2js to |
378 // avoid checked mode errors in dartium. | 498 // avoid checked mode errors in dartium. |
379 return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, use
Capture); | 499 return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, use
Capture); |
380 $else | 500 $else |
381 return new _ElementListEventStreamImpl(e, _eventType, useCapture); | 501 return new _ElementListEventStreamImpl(e, _eventType, useCapture); |
382 $endif | 502 $endif |
383 } | 503 } |
384 } | 504 } |
OLD | NEW |