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); |