/*
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.scenario.animation.shared;

import javafx.animation.Animation;
import javafx.util.Duration;
import com.sun.javafx.animation.TickCalculation;

An instance of ClipEnvelope handles the loop-part of a clip. The functionality to react on a pulse-signal from the timer is implemented in two classes: ClipEnvelope and ClipCore. ClipEnvelope is responsible for the "loop-part" (keeping track of the number of cycles, handling the direction of the clip etc.). ClipCore takes care of the inner part (interpolating the values, triggering the action-functions, ...) Both classes have an abstract public definition and can only be created using the factory method create(). The intent is to provide a general implementation plus eventually some fast-track implementations for common use cases.
/** * An instance of ClipEnvelope handles the loop-part of a clip. * * The functionality to react on a pulse-signal from the timer is implemented in * two classes: ClipEnvelope and ClipCore. ClipEnvelope is responsible for the * "loop-part" (keeping track of the number of cycles, handling the direction of * the clip etc.). ClipCore takes care of the inner part (interpolating the * values, triggering the action-functions, ...) * * Both classes have an abstract public definition and can only be created using * the factory method create(). The intent is to provide a general * implementation plus eventually some fast-track implementations for common use * cases. */
public abstract class ClipEnvelope { protected static final long INDEFINITE = Long.MAX_VALUE; protected static final double EPSILON = 1e-12; protected Animation animation; protected double rate = 1; protected long cycleTicks = 0; // internal state-variables used by all implementations protected long deltaTicks = 0; protected long ticks = 0; protected double currentRate = rate; protected boolean inTimePulse = false; protected boolean aborted = false; protected ClipEnvelope(Animation animation) { this.animation = animation; if (animation != null) { final Duration cycleDuration = animation.getCycleDuration(); cycleTicks = TickCalculation.fromDuration(cycleDuration); rate = animation.getRate(); } } public static ClipEnvelope create(Animation animation) { if ((animation.getCycleCount() == 1) || (animation.getCycleDuration().isIndefinite())) { return new SingleLoopClipEnvelope(animation); } else if (animation.getCycleCount() == Animation.INDEFINITE) { return new InfiniteClipEnvelope(animation); } else { return new FiniteClipEnvelope(animation); } } public abstract ClipEnvelope setCycleDuration(Duration cycleDuration); public abstract void setRate(double rate); public abstract void setAutoReverse(boolean autoReverse); public abstract ClipEnvelope setCycleCount(int cycleCount); protected void updateCycleTicks(Duration cycleDuration) { cycleTicks = TickCalculation.fromDuration(cycleDuration); } public boolean wasSynched() { return cycleTicks != 0; } public void start() { setCurrentRate(calculateCurrentRate()); deltaTicks = ticks; } public abstract void timePulse(long currentTick); public abstract void jumpTo(long ticks); public void abortCurrentPulse() { if (inTimePulse) { aborted = true; inTimePulse = false; } } protected abstract double calculateCurrentRate(); protected void setCurrentRate(double currentRate) { this.currentRate = currentRate; AnimationAccessor.getDefault().setCurrentRate(animation, currentRate); } protected static long checkBounds(long value, long max) { return Math.max(0L, Math.min(value, max)); } public double getCurrentRate() { return currentRate; } }