| Index: third_party/polymer/components/web-animations-js/src/timing-utilities.js
|
| diff --git a/third_party/polymer/components/web-animations-js/src/timing-utilities.js b/third_party/polymer/components/web-animations-js/src/timing-utilities.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2f16f3b1598ad616996f6e2cbb3ae4eb2c170a38
|
| --- /dev/null
|
| +++ b/third_party/polymer/components/web-animations-js/src/timing-utilities.js
|
| @@ -0,0 +1,420 @@
|
| +// Copyright 2014 Google Inc. All rights reserved.
|
| +//
|
| +// 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.
|
| +
|
| +(function(shared, testing) {
|
| +
|
| + var fills = 'backwards|forwards|both|none'.split('|');
|
| + var directions = 'reverse|alternate|alternate-reverse'.split('|');
|
| + var linear = function(x) { return x; };
|
| +
|
| + function cloneTimingInput(timingInput) {
|
| + if (typeof timingInput == 'number') {
|
| + return timingInput;
|
| + }
|
| + var clone = {};
|
| + for (var m in timingInput) {
|
| + clone[m] = timingInput[m];
|
| + }
|
| + return clone;
|
| + }
|
| +
|
| + function AnimationEffectTiming() {
|
| + this._delay = 0;
|
| + this._endDelay = 0;
|
| + this._fill = 'none';
|
| + this._iterationStart = 0;
|
| + this._iterations = 1;
|
| + this._duration = 0;
|
| + this._playbackRate = 1;
|
| + this._direction = 'normal';
|
| + this._easing = 'linear';
|
| + this._easingFunction = linear;
|
| + }
|
| +
|
| + function isInvalidTimingDeprecated() {
|
| + return shared.isDeprecated('Invalid timing inputs', '2016-03-02', 'TypeError exceptions will be thrown instead.', true);
|
| + }
|
| +
|
| + AnimationEffectTiming.prototype = {
|
| + _setMember: function(member, value) {
|
| + this['_' + member] = value;
|
| + if (this._effect) {
|
| + this._effect._timingInput[member] = value;
|
| + this._effect._timing = shared.normalizeTimingInput(this._effect._timingInput);
|
| + this._effect.activeDuration = shared.calculateActiveDuration(this._effect._timing);
|
| + if (this._effect._animation) {
|
| + this._effect._animation._rebuildUnderlyingAnimation();
|
| + }
|
| + }
|
| + },
|
| + get playbackRate() {
|
| + return this._playbackRate;
|
| + },
|
| + set delay(value) {
|
| + this._setMember('delay', value);
|
| + },
|
| + get delay() {
|
| + return this._delay;
|
| + },
|
| + set endDelay(value) {
|
| + this._setMember('endDelay', value);
|
| + },
|
| + get endDelay() {
|
| + return this._endDelay;
|
| + },
|
| + set fill(value) {
|
| + this._setMember('fill', value);
|
| + },
|
| + get fill() {
|
| + return this._fill;
|
| + },
|
| + set iterationStart(value) {
|
| + if ((isNaN(value) || value < 0) && isInvalidTimingDeprecated()) {
|
| + throw new TypeError('iterationStart must be a non-negative number, received: ' + timing.iterationStart);
|
| + }
|
| + this._setMember('iterationStart', value);
|
| + },
|
| + get iterationStart() {
|
| + return this._iterationStart;
|
| + },
|
| + set duration(value) {
|
| + if (value != 'auto' && (isNaN(value) || value < 0) && isInvalidTimingDeprecated()) {
|
| + throw new TypeError('duration must be non-negative or auto, received: ' + value);
|
| + }
|
| + this._setMember('duration', value);
|
| + },
|
| + get duration() {
|
| + return this._duration;
|
| + },
|
| + set direction(value) {
|
| + this._setMember('direction', value);
|
| + },
|
| + get direction() {
|
| + return this._direction;
|
| + },
|
| + set easing(value) {
|
| + this._easingFunction = parseEasingFunction(normalizeEasing(value));
|
| + this._setMember('easing', value);
|
| + },
|
| + get easing() {
|
| + return this._easing;
|
| + },
|
| + set iterations(value) {
|
| + if ((isNaN(value) || value < 0) && isInvalidTimingDeprecated()) {
|
| + throw new TypeError('iterations must be non-negative, received: ' + value);
|
| + }
|
| + this._setMember('iterations', value);
|
| + },
|
| + get iterations() {
|
| + return this._iterations;
|
| + }
|
| + };
|
| +
|
| + function makeTiming(timingInput, forGroup, effect) {
|
| + var timing = new AnimationEffectTiming();
|
| + if (forGroup) {
|
| + timing.fill = 'both';
|
| + timing.duration = 'auto';
|
| + }
|
| + if (typeof timingInput == 'number' && !isNaN(timingInput)) {
|
| + timing.duration = timingInput;
|
| + } else if (timingInput !== undefined) {
|
| + Object.getOwnPropertyNames(timingInput).forEach(function(property) {
|
| + if (timingInput[property] != 'auto') {
|
| + if (typeof timing[property] == 'number' || property == 'duration') {
|
| + if (typeof timingInput[property] != 'number' || isNaN(timingInput[property])) {
|
| + return;
|
| + }
|
| + }
|
| + if ((property == 'fill') && (fills.indexOf(timingInput[property]) == -1)) {
|
| + return;
|
| + }
|
| + if ((property == 'direction') && (directions.indexOf(timingInput[property]) == -1)) {
|
| + return;
|
| + }
|
| + if (property == 'playbackRate' && timingInput[property] !== 1 && shared.isDeprecated('AnimationEffectTiming.playbackRate', '2014-11-28', 'Use Animation.playbackRate instead.')) {
|
| + return;
|
| + }
|
| + timing[property] = timingInput[property];
|
| + }
|
| + });
|
| + }
|
| + return timing;
|
| + }
|
| +
|
| + function numericTimingToObject(timingInput) {
|
| + if (typeof timingInput == 'number') {
|
| + if (isNaN(timingInput)) {
|
| + timingInput = { duration: 0 };
|
| + } else {
|
| + timingInput = { duration: timingInput };
|
| + }
|
| + }
|
| + return timingInput;
|
| + }
|
| +
|
| + function normalizeTimingInput(timingInput, forGroup) {
|
| + timingInput = shared.numericTimingToObject(timingInput);
|
| + return makeTiming(timingInput, forGroup);
|
| + }
|
| +
|
| + function cubic(a, b, c, d) {
|
| + if (a < 0 || a > 1 || c < 0 || c > 1) {
|
| + return linear;
|
| + }
|
| + return function(x) {
|
| + if (x <= 0) {
|
| + var start_gradient = 0;
|
| + if (a > 0)
|
| + start_gradient = b / a;
|
| + else if (!b && c > 0)
|
| + start_gradient = d / c;
|
| + return start_gradient * x;
|
| + }
|
| + if (x >= 1) {
|
| + var end_gradient = 0;
|
| + if (c < 1)
|
| + end_gradient = (d - 1) / (c - 1);
|
| + else if (c == 1 && a < 1)
|
| + end_gradient = (b - 1) / (a - 1);
|
| + return 1 + end_gradient * (x - 1);
|
| + }
|
| +
|
| + var start = 0, end = 1;
|
| + while (start < end) {
|
| + var mid = (start + end) / 2;
|
| + function f(a, b, m) { return 3 * a * (1 - m) * (1 - m) * m + 3 * b * (1 - m) * m * m + m * m * m};
|
| + var xEst = f(a, c, mid);
|
| + if (Math.abs(x - xEst) < 0.00001) {
|
| + return f(b, d, mid);
|
| + }
|
| + if (xEst < x) {
|
| + start = mid;
|
| + } else {
|
| + end = mid;
|
| + }
|
| + }
|
| + return f(b, d, mid);
|
| + }
|
| + }
|
| +
|
| + var Start = 1;
|
| + var Middle = 0.5;
|
| + var End = 0;
|
| +
|
| + function step(count, pos) {
|
| + return function(x) {
|
| + if (x >= 1) {
|
| + return 1;
|
| + }
|
| + var stepSize = 1 / count;
|
| + x += pos * stepSize;
|
| + return x - x % stepSize;
|
| + }
|
| + }
|
| +
|
| + var presets = {
|
| + 'ease': cubic(0.25, 0.1, 0.25, 1),
|
| + 'ease-in': cubic(0.42, 0, 1, 1),
|
| + 'ease-out': cubic(0, 0, 0.58, 1),
|
| + 'ease-in-out': cubic(0.42, 0, 0.58, 1),
|
| + 'step-start': step(1, Start),
|
| + 'step-middle': step(1, Middle),
|
| + 'step-end': step(1, End)
|
| + };
|
| +
|
| + var styleForCleaning = null;
|
| + var numberString = '\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*';
|
| + var cubicBezierRe = new RegExp('cubic-bezier\\(' + numberString + ',' + numberString + ',' + numberString + ',' + numberString + '\\)');
|
| + var stepRe = /steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/;
|
| +
|
| + function normalizeEasing(easing) {
|
| + if (!styleForCleaning) {
|
| + styleForCleaning = document.createElement('div').style;
|
| + }
|
| + styleForCleaning.animationTimingFunction = '';
|
| + styleForCleaning.animationTimingFunction = easing;
|
| + var normalizedEasing = styleForCleaning.animationTimingFunction;
|
| + if (normalizedEasing == '' && isInvalidTimingDeprecated()) {
|
| + throw new TypeError(easing + ' is not a valid value for easing');
|
| + }
|
| + return normalizedEasing;
|
| + }
|
| +
|
| + function parseEasingFunction(normalizedEasing) {
|
| + if (normalizedEasing == 'linear') {
|
| + return linear;
|
| + }
|
| + var cubicData = cubicBezierRe.exec(normalizedEasing);
|
| + if (cubicData) {
|
| + return cubic.apply(this, cubicData.slice(1).map(Number));
|
| + }
|
| + var stepData = stepRe.exec(normalizedEasing);
|
| + if (stepData) {
|
| + return step(Number(stepData[1]), {'start': Start, 'middle': Middle, 'end': End}[stepData[2]]);
|
| + }
|
| + var preset = presets[normalizedEasing];
|
| + if (preset) {
|
| + return preset;
|
| + }
|
| + // At this point none of our parse attempts succeeded; the easing is invalid.
|
| + // Fall back to linear in the interest of not crashing the page.
|
| + return linear;
|
| + }
|
| +
|
| + function calculateActiveDuration(timing) {
|
| + return Math.abs(repeatedDuration(timing) / timing.playbackRate);
|
| + }
|
| +
|
| + function repeatedDuration(timing) {
|
| + // https://w3c.github.io/web-animations/#calculating-the-active-duration
|
| + if (timing.duration === 0 || timing.iterations === 0) {
|
| + return 0;
|
| + }
|
| + return timing.duration * timing.iterations;
|
| + }
|
| +
|
| + var PhaseNone = 0;
|
| + var PhaseBefore = 1;
|
| + var PhaseAfter = 2;
|
| + var PhaseActive = 3;
|
| +
|
| + function calculatePhase(activeDuration, localTime, timing) {
|
| + // https://w3c.github.io/web-animations/#animation-effect-phases-and-states
|
| + if (localTime == null) {
|
| + return PhaseNone;
|
| + }
|
| +
|
| + var endTime = timing.delay + activeDuration + timing.endDelay;
|
| + if (localTime < Math.min(timing.delay, endTime)) {
|
| + return PhaseBefore;
|
| + }
|
| + if (localTime >= Math.min(timing.delay + activeDuration, endTime)) {
|
| + return PhaseAfter;
|
| + }
|
| +
|
| + return PhaseActive;
|
| + }
|
| +
|
| + function calculateActiveTime(activeDuration, fillMode, localTime, phase, delay) {
|
| + // https://w3c.github.io/web-animations/#calculating-the-active-time
|
| + switch (phase) {
|
| + case PhaseBefore:
|
| + if (fillMode == 'backwards' || fillMode == 'both')
|
| + return 0;
|
| + return null;
|
| + case PhaseActive:
|
| + return localTime - delay;
|
| + case PhaseAfter:
|
| + if (fillMode == 'forwards' || fillMode == 'both')
|
| + return activeDuration;
|
| + return null;
|
| + case PhaseNone:
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + function calculateOverallProgress(iterationDuration, phase, iterations, activeTime, iterationStart) {
|
| + // https://w3c.github.io/web-animations/#calculating-the-overall-progress
|
| + var overallProgress = iterationStart;
|
| + if (iterationDuration === 0) {
|
| + if (phase !== PhaseBefore) {
|
| + overallProgress += iterations;
|
| + }
|
| + } else {
|
| + overallProgress += activeTime / iterationDuration;
|
| + }
|
| + return overallProgress;
|
| + }
|
| +
|
| + function calculateSimpleIterationProgress(overallProgress, iterationStart, phase, iterations, activeTime, iterationDuration) {
|
| + // https://w3c.github.io/web-animations/#calculating-the-simple-iteration-progress
|
| +
|
| + var simpleIterationProgress = (overallProgress === Infinity) ? iterationStart % 1 : overallProgress % 1;
|
| + if (simpleIterationProgress === 0 && phase === PhaseAfter && iterations !== 0 &&
|
| + (activeTime !== 0 || iterationDuration === 0)) {
|
| + simpleIterationProgress = 1;
|
| + }
|
| + return simpleIterationProgress;
|
| + }
|
| +
|
| + function calculateCurrentIteration(phase, iterations, simpleIterationProgress, overallProgress) {
|
| + // https://w3c.github.io/web-animations/#calculating-the-current-iteration
|
| + if (phase === PhaseAfter && iterations === Infinity) {
|
| + return Infinity;
|
| + }
|
| + if (simpleIterationProgress === 1) {
|
| + return Math.floor(overallProgress) - 1;
|
| + }
|
| + return Math.floor(overallProgress);
|
| + }
|
| +
|
| + function calculateDirectedProgress(playbackDirection, currentIteration, simpleIterationProgress) {
|
| + // https://w3c.github.io/web-animations/#calculating-the-directed-progress
|
| + var currentDirection = playbackDirection;
|
| + if (playbackDirection !== 'normal' && playbackDirection !== 'reverse') {
|
| + var d = currentIteration;
|
| + if (playbackDirection === 'alternate-reverse') {
|
| + d += 1;
|
| + }
|
| + currentDirection = 'normal';
|
| + if (d !== Infinity && d % 2 !== 0) {
|
| + currentDirection = 'reverse';
|
| + }
|
| + }
|
| + if (currentDirection === 'normal') {
|
| + return simpleIterationProgress;
|
| + }
|
| + return 1 - simpleIterationProgress;
|
| + }
|
| +
|
| + function calculateIterationProgress(activeDuration, localTime, timing) {
|
| + var phase = calculatePhase(activeDuration, localTime, timing);
|
| + var activeTime = calculateActiveTime(activeDuration, timing.fill, localTime, phase, timing.delay);
|
| + if (activeTime === null)
|
| + return null;
|
| +
|
| + var overallProgress = calculateOverallProgress(timing.duration, phase, timing.iterations, activeTime, timing.iterationStart);
|
| + var simpleIterationProgress = calculateSimpleIterationProgress(overallProgress, timing.iterationStart, phase, timing.iterations, activeTime, timing.duration);
|
| + var currentIteration = calculateCurrentIteration(phase, timing.iterations, simpleIterationProgress, overallProgress);
|
| + var directedProgress = calculateDirectedProgress(timing.direction, currentIteration, simpleIterationProgress);
|
| +
|
| + // https://w3c.github.io/web-animations/#calculating-the-transformed-progress
|
| + // https://w3c.github.io/web-animations/#calculating-the-iteration-progress
|
| + return timing._easingFunction(directedProgress);
|
| + }
|
| +
|
| + shared.cloneTimingInput = cloneTimingInput;
|
| + shared.makeTiming = makeTiming;
|
| + shared.numericTimingToObject = numericTimingToObject;
|
| + shared.normalizeTimingInput = normalizeTimingInput;
|
| + shared.calculateActiveDuration = calculateActiveDuration;
|
| + shared.calculateIterationProgress = calculateIterationProgress;
|
| + shared.calculatePhase = calculatePhase;
|
| + shared.normalizeEasing = normalizeEasing;
|
| + shared.parseEasingFunction = parseEasingFunction;
|
| +
|
| + if (WEB_ANIMATIONS_TESTING) {
|
| + testing.normalizeTimingInput = normalizeTimingInput;
|
| + testing.normalizeEasing = normalizeEasing;
|
| + testing.parseEasingFunction = parseEasingFunction;
|
| + testing.calculateActiveDuration = calculateActiveDuration;
|
| + testing.calculatePhase = calculatePhase;
|
| + testing.PhaseNone = PhaseNone;
|
| + testing.PhaseBefore = PhaseBefore;
|
| + testing.PhaseActive = PhaseActive;
|
| + testing.PhaseAfter = PhaseAfter;
|
| + }
|
| +
|
| +})(webAnimationsShared, webAnimationsTesting);
|
|
|