| Index: third_party/pkg/angular/lib/animate/animation_loop.dart
|
| diff --git a/third_party/pkg/angular/lib/animate/animation_loop.dart b/third_party/pkg/angular/lib/animate/animation_loop.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cd3f15d332b505525f2bcdbc8c24993bb0303f74
|
| --- /dev/null
|
| +++ b/third_party/pkg/angular/lib/animate/animation_loop.dart
|
| @@ -0,0 +1,110 @@
|
| +part of angular.animate;
|
| +
|
| +/**
|
| + * Window.animationFrame update loop that tracks and drives
|
| + * [LoopedAnimations]'s.
|
| + */
|
| +@Injectable()
|
| +class AnimationLoop {
|
| + final AnimationFrame _frames;
|
| + final Profiler _profiler;
|
| + final List<LoopedAnimation> _animations = [];
|
| + final VmTurnZone _zone;
|
| +
|
| + bool _animationFrameQueued = false;
|
| +
|
| + /**
|
| + * The animation runner requires an [AnimationFrame] to drive the animation
|
| + * frames, and profiler will report timing information for each of the
|
| + * animation frames.
|
| + */
|
| + AnimationLoop(this._frames, this._profiler, this._zone);
|
| +
|
| + /**
|
| + * Start and play an animation through the state transitions defined in
|
| + * [Animation].
|
| + */
|
| + void play(LoopedAnimation animation) {
|
| + _animations.add(animation);
|
| + _queueAnimationFrame();
|
| + }
|
| +
|
| + void _queueAnimationFrame() {
|
| + if (!_animationFrameQueued) {
|
| + _animationFrameQueued = true;
|
| +
|
| + // TODO(codleogic): This should run outside of an angular scope digest.
|
| + _zone.runOutsideAngular(() {
|
| + _frames.animationFrame.then((timeInMs) => _animationFrame(timeInMs))
|
| + .catchError((error) => print(error));
|
| + });
|
| + }
|
| + }
|
| +
|
| + /* On the browsers animation frame event, update each of the tracked
|
| + * animations. Group dom reads first, and and writes second.
|
| + *
|
| + * At any point any animation may be updated by calling interrupt and cancel
|
| + * with a reference to the [Animation] to cancel. The [AnimationRunner] will
|
| + * then forget about the [Animation] and will not call any further methods on
|
| + * the [Animation].
|
| + */
|
| + void _animationFrame(num timeInMs) {
|
| + _profiler.startTimer("AnimationRunner.AnimationFrame");
|
| + _animationFrameQueued = false;
|
| +
|
| + _profiler.startTimer("AnimationRunner.AnimationFrame.DomReads");
|
| + // Dom reads
|
| + _read(timeInMs);
|
| + _profiler.stopTimer("AnimationRunner.AnimationFrame.DomReads");
|
| +
|
| + _profiler.startTimer("AnimationRunner.AnimationFrame.DomMutates");
|
| + // Dom mutates
|
| + _update(timeInMs);
|
| + _profiler.stopTimer("AnimationRunner.AnimationFrame.DomMutates");
|
| +
|
| + // We don't need to continue queuing animation frames
|
| + // if there are no more animations to process.
|
| + if (_animations.length > 0) {
|
| + _queueAnimationFrame();
|
| + }
|
| +
|
| + _profiler.stopTimer("AnimationRunner.AnimationFrame");
|
| + }
|
| +
|
| + void _update(num timeInMs) {
|
| + for (int i=0; i< _animations.length; i++) {
|
| + var controller = _animations[i];
|
| + if (!controller.update(timeInMs)) {
|
| + _animations.removeAt(i--);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _read(num timeInMs) {
|
| + for (int i=0; i< _animations.length; i++) {
|
| + var animation = _animations[i];
|
| + animation.read(timeInMs);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Stop tracking and updating the [animation].
|
| + */
|
| + void forget(LoopedAnimation animation) {
|
| + assert(animation != null);
|
| + _animations.remove(animation);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Wrapper around window.requestAnimationFrame so it can be intercepted and
|
| + * tested.
|
| + */
|
| +@Injectable()
|
| +class AnimationFrame {
|
| + final dom.Window _wnd;
|
| + Future<num> get animationFrame => _wnd.animationFrame;
|
| +
|
| + AnimationFrame(this._wnd);
|
| +}
|
|
|