| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.animation.client; |
| |
| import com.google.gwt.core.client.Duration; |
| import com.google.gwt.dom.client.Element; |
| import com.google.gwt.user.client.Timer; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Implementation using a timer for browsers that do not support animation |
| * frames. |
| */ |
| class AnimationSchedulerImplTimer extends AnimationScheduler { |
| |
| /** |
| * Timer based implementation of {@link AnimationScheduler.AnimationHandle}. |
| */ |
| private class AnimationHandleImpl extends AnimationHandle { |
| private final AnimationCallback callback; |
| |
| public AnimationHandleImpl(AnimationCallback callback) { |
| this.callback = callback; |
| } |
| |
| @Override |
| public void cancel() { |
| cancelAnimationFrame(this); |
| } |
| |
| public AnimationCallback getCallback() { |
| return callback; |
| } |
| } |
| |
| /** |
| * The default time in milliseconds between frames. 60 fps == 16.67 ms. |
| */ |
| private static final int DEFAULT_FRAME_DELAY = 16; |
| |
| /** |
| * The minimum delay in milliseconds between frames. The minimum delay is |
| * imposed to prevent freezing the UI. |
| */ |
| private static final int MIN_FRAME_DELAY = 5; |
| |
| /** |
| * The list of animations that are currently running. |
| */ |
| private final List<AnimationHandleImpl> animationRequests = new ArrayList<AnimationHandleImpl>(); |
| |
| /** |
| * The singleton timer that updates all animations. |
| */ |
| private final Timer timer = new Timer() { |
| @Override |
| public void run() { |
| updateAnimations(); |
| } |
| }; |
| |
| @Override |
| public AnimationHandle requestAnimationFrame(final AnimationCallback callback, Element element) { |
| // Save the animation frame request. |
| AnimationHandleImpl requestId = new AnimationHandleImpl(callback); |
| animationRequests.add(requestId); |
| |
| // Start the timer if it isn't started. |
| if (animationRequests.size() == 1) { |
| timer.schedule(DEFAULT_FRAME_DELAY); |
| } |
| |
| // Return the request id. |
| return requestId; |
| } |
| |
| private void cancelAnimationFrame(AnimationHandle requestId) { |
| // Remove the request from the list. |
| animationRequests.remove(requestId); |
| |
| // Stop the timer if there are no more requests. |
| if (animationRequests.size() == 0) { |
| timer.cancel(); |
| } |
| } |
| |
| /** |
| * Iterate over all animations and update them. |
| */ |
| private void updateAnimations() { |
| // Copy the animation requests to avoid concurrent modifications. |
| AnimationHandleImpl[] curAnimations = new AnimationHandleImpl[animationRequests.size()]; |
| curAnimations = animationRequests.toArray(curAnimations); |
| |
| // Iterate over the animation requests. |
| Duration duration = new Duration(); |
| for (AnimationHandleImpl requestId : curAnimations) { |
| // Remove the current request. |
| animationRequests.remove(requestId); |
| |
| // Execute the callback. |
| requestId.getCallback().execute(duration.getStartMillis()); |
| } |
| |
| // Reschedule the timer if there are more animation requests. |
| if (animationRequests.size() > 0) { |
| /* |
| * In order to achieve as close to 60fps as possible, we calculate the new |
| * delay based on the execution time of this method. The delay will be |
| * less than 16ms, assuming this method takes more than 1ms to complete. |
| */ |
| timer.schedule(Math.max(MIN_FRAME_DELAY, DEFAULT_FRAME_DELAY - duration.elapsedMillis())); |
| } |
| } |
| } |