/*
 * 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 java.util.HashMap;
import java.util.Map;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.beans.value.WritableValue;
import javafx.util.Duration;

Simplified implementation of ClipCore, which is used for timelines with exactly two keyframes.
/** * Simplified implementation of ClipCore, which is used for timelines with * exactly two keyframes. */
class SimpleClipInterpolator extends ClipInterpolator { private static final KeyFrame ZERO_FRAME = new KeyFrame(Duration.ZERO); // The list of all targets in this clip private KeyFrame startKeyFrame; private KeyFrame endKeyFrame; private long endTicks; private InterpolationInterval[] interval; private int undefinedStartValueCount; private long ticks; // Is internal representation uptodate? private boolean invalid = true; SimpleClipInterpolator(KeyFrame startKeyFrame, KeyFrame endKeyFrame, long ticks) { this.startKeyFrame = startKeyFrame; this.endKeyFrame = endKeyFrame; this.endTicks = ticks; } SimpleClipInterpolator(KeyFrame endKeyFrame, long ticks) { this.startKeyFrame = ZERO_FRAME; this.endKeyFrame = endKeyFrame; this.endTicks = ticks; } // See comment in ClipInterpolator @Override ClipInterpolator setKeyFrames(KeyFrame[] keyFrames, long[] keyFrameTicks) { if (ClipInterpolator.getRealKeyFrameCount(keyFrames) != 2) { return ClipInterpolator.create(keyFrames, keyFrameTicks); } if (keyFrames.length == 1) { startKeyFrame = ZERO_FRAME; endKeyFrame = keyFrames[0]; endTicks = keyFrameTicks[0]; } else { startKeyFrame = keyFrames[0]; endKeyFrame = keyFrames[1]; endTicks = keyFrameTicks[1]; } invalid = true; return this; } @Override void validate(boolean forceSync) { if (invalid) { ticks = endTicks; final Map<WritableValue<?>, KeyValue> map = new HashMap<>(); // create a map from target => keyValues of endFrame for (final KeyValue keyValue : endKeyFrame.getValues()) { map.put(keyValue.getTarget(), keyValue); } final int valueCount = map.size(); interval = new InterpolationInterval[valueCount]; // iterate through keyValues in startFrame and generate intervals // if we find a matching keyValue in the startFrame, the entry is // removed from the map int i = 0; for (final KeyValue startKeyValue : startKeyFrame.getValues()) { final WritableValue<?> target = startKeyValue.getTarget(); final KeyValue endKeyValue = map.get(target); if (endKeyValue != null) { interval[i++] = InterpolationInterval.create(endKeyValue, ticks, startKeyValue, ticks); map.remove(target); } } // remaining entries in the map have no start value defined undefinedStartValueCount = map.values().size(); for (final KeyValue endKeyValue : map.values()) { interval[i++] = InterpolationInterval.create(endKeyValue, ticks); } invalid = false; } else if (forceSync) { // iterate through keyValues with undefined start value final int n = interval.length; for (int i = n - undefinedStartValueCount; i < n; i++) { interval[i].recalculateStartValue(); } } } @Override void interpolate(long ticks) { final double frac = ((double)ticks / this.ticks); final int n = interval.length; for (int i = 0; i < n; i++) { interval[i].interpolate(frac); } } }