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 | |
100 @DocsEditable() | 7 @DocsEditable() |
101 $if DART2JS | 8 $if DART2JS |
102 $(ANNOTATIONS)@Native("Window,DOMWindow") | 9 $(ANNOTATIONS)@Native("Window,DOMWindow") |
103 $(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS { | 10 $(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS { |
104 $else | 11 $else |
105 $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
{ | 12 $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
{ |
106 $endif | 13 $endif |
107 | 14 |
108 /** | 15 /** |
109 * Returns a Future that completes just before the window is about to | 16 * Returns a Future that completes just before the window is about to |
110 * repaint so the user can draw an animation frame. | 17 * repaint so the user can draw an animation frame. |
111 * | 18 * |
112 * If you need to later cancel this animation, use [requestAnimationFrame] | 19 * If you need to later cancel this animation, use [requestAnimationFrame] |
113 * instead. | 20 * instead. |
114 * | 21 * |
115 * The [Future] completes to a timestamp that represents a floating | 22 * The [Future] completes to a timestamp that represents a floating |
116 * point value of the number of milliseconds that have elapsed since the page | 23 * point value of the number of milliseconds that have elapsed since the page |
117 * started to load (which is also the timestamp at this call to | 24 * started to load (which is also the timestamp at this call to |
118 * animationFrame). | 25 * animationFrame). |
119 * | 26 * |
120 * Note: The code that runs when the future completes should call | 27 * Note: The code that runs when the future completes should call |
121 * [animationFrame] again for the animation to continue. | 28 * [animationFrame] again for the animation to continue. |
122 */ | 29 */ |
123 Future<num> get animationFrame { | 30 Future<num> get animationFrame { |
124 var completer = new Completer<num>.sync(); | 31 var completer = new Completer<num>.sync(); |
125 requestAnimationFrame(completer.complete); | 32 requestAnimationFrame((time) { |
| 33 completer.complete(time); |
| 34 }); |
126 return completer.future; | 35 return completer.future; |
127 } | 36 } |
128 | 37 |
129 $if DART2JS | 38 $if DART2JS |
130 /** | 39 /** |
131 * The newest document in this window. | 40 * The newest document in this window. |
132 * | 41 * |
133 * ## Other resources | 42 * ## Other resources |
134 * | 43 * |
135 * * [Loading web | 44 * * [Loading web |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 * cancel. | 112 * cancel. |
204 * | 113 * |
205 * Note: The supplied [callback] needs to call [requestAnimationFrame] again | 114 * Note: The supplied [callback] needs to call [requestAnimationFrame] again |
206 * for the animation to continue. | 115 * for the animation to continue. |
207 */ | 116 */ |
208 @DomName('Window.requestAnimationFrame') | 117 @DomName('Window.requestAnimationFrame') |
209 int requestAnimationFrame(FrameRequestCallback callback) { | 118 int requestAnimationFrame(FrameRequestCallback callback) { |
210 $if DART2JS | 119 $if DART2JS |
211 _ensureRequestAnimationFrame(); | 120 _ensureRequestAnimationFrame(); |
212 $endif | 121 $endif |
213 if (identical(Zone.current, Zone.ROOT)) { | 122 return _requestAnimationFrame(_wrapZone/*<num, dynamic>*/(callback)); |
214 return _requestAnimationFrame(callback); | |
215 } | |
216 var spec = new AnimationFrameRequestSpecification(this, callback); | |
217 var task = Zone.current.createTask/*<AnimationFrameTask>*/( | |
218 _createAnimationFrameTask, spec); | |
219 AnimationFrameTask._tasks[task.id] = task; | |
220 return task.id; | |
221 } | |
222 | |
223 static _AnimationFrameTask _createAnimationFrameTask( | |
224 AnimationFrameRequestSpecification spec, Zone zone) { | |
225 var task; | |
226 var id = spec.window._requestAnimationFrame((num time) { | |
227 AnimationFrameTask.removeMapping(task.id); | |
228 zone.runTask(_runAnimationFrame, task, time); | |
229 }); | |
230 var callback = zone.registerUnaryCallback(spec.callback); | |
231 task = new _AnimationFrameTask(id, zone, callback); | |
232 return task; | |
233 } | |
234 | |
235 static void _runAnimationFrame(_AnimationFrameTask task, num time) { | |
236 task._callback(time); | |
237 } | 123 } |
238 | 124 |
239 /** | 125 /** |
240 * Cancels an animation frame request. | 126 * Cancels an animation frame request. |
241 * | 127 * |
242 * ## Other resources | 128 * ## Other resources |
243 * | 129 * |
244 * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/We
b/API/Window.cancelAnimationFrame) | 130 * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/We
b/API/Window.cancelAnimationFrame) |
245 * from MDN. | 131 * from MDN. |
246 */ | 132 */ |
247 @DomName('Window.cancelAnimationFrame') | 133 @DomName('Window.cancelAnimationFrame') |
248 void cancelAnimationFrame(int id) { | 134 void cancelAnimationFrame(int id) { |
249 $if DART2JS | 135 $if DART2JS |
250 _ensureRequestAnimationFrame(); | 136 _ensureRequestAnimationFrame(); |
251 $endif | 137 $endif |
252 var task = AnimationFrameTask._tasks.remove(id); | 138 _cancelAnimationFrame(id); |
253 if (task == null) { | |
254 // Assume that the animation frame request wasn't intercepted by a zone. | |
255 _cancelAnimationFrame(id); | |
256 return; | |
257 } | |
258 task.cancel(this); | |
259 } | 139 } |
260 | 140 |
261 $if DART2JS | 141 $if DART2JS |
262 @JSName('requestAnimationFrame') | 142 @JSName('requestAnimationFrame') |
263 int _requestAnimationFrame(FrameRequestCallback callback) native; | 143 int _requestAnimationFrame(FrameRequestCallback callback) native; |
264 | 144 |
265 @JSName('cancelAnimationFrame') | 145 @JSName('cancelAnimationFrame') |
266 void _cancelAnimationFrame(int id) native; | 146 void _cancelAnimationFrame(int id) native; |
267 | 147 |
268 _ensureRequestAnimationFrame() { | 148 _ensureRequestAnimationFrame() { |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 {bool useCapture: false}) { | 361 {bool useCapture: false}) { |
482 $if DART2JS | 362 $if DART2JS |
483 // Specify the generic type for _ElementEventStreamImpl only in dart2js to | 363 // Specify the generic type for _ElementEventStreamImpl only in dart2js to |
484 // avoid checked mode errors in dartium. | 364 // avoid checked mode errors in dartium. |
485 return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, use
Capture); | 365 return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, use
Capture); |
486 $else | 366 $else |
487 return new _ElementListEventStreamImpl(e, _eventType, useCapture); | 367 return new _ElementListEventStreamImpl(e, _eventType, useCapture); |
488 $endif | 368 $endif |
489 } | 369 } |
490 } | 370 } |
OLD | NEW |