diff options
Diffstat (limited to 'catapult/third_party/polymer/components/web-animations-js/src/dimension-handler.js')
-rw-r--r-- | catapult/third_party/polymer/components/web-animations-js/src/dimension-handler.js | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/web-animations-js/src/dimension-handler.js b/catapult/third_party/polymer/components/web-animations-js/src/dimension-handler.js new file mode 100644 index 00000000..9e487f97 --- /dev/null +++ b/catapult/third_party/polymer/components/web-animations-js/src/dimension-handler.js @@ -0,0 +1,240 @@ +// 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(scope, testing) { + + // Evaluates a calc expression. + // https://drafts.csswg.org/css-values-3/#calc-notation + function calculate(expression) { + // In calc expressions, white space is required on both sides of the + // + and - operators. https://drafts.csswg.org/css-values-3/#calc-notation + // Thus any + or - immediately adjacent to . or 0..9 is part of the number, + // e.g. -1.23e+45 + // This regular expression matches ( ) * / + - and numbers. + var tokenRegularExpression = /([\+\-\w\.]+|[\(\)\*\/])/g; + var currentToken; + function consume() { + var matchResult = tokenRegularExpression.exec(expression); + if (matchResult) + currentToken = matchResult[0]; + else + currentToken = undefined; + } + consume(); // Read the initial token. + + function calcNumber() { + // https://drafts.csswg.org/css-values-3/#number-value + var result = Number(currentToken); + consume(); + return result; + } + + function calcValue() { + // <calc-value> = <number> | <dimension> | <percentage> | ( <calc-sum> ) + if (currentToken !== '(') + return calcNumber(); + consume(); + var result = calcSum(); + if (currentToken !== ')') + return NaN; + consume(); + return result; + } + + function calcProduct() { + // <calc-product> = <calc-value> [ '*' <calc-value> | '/' <calc-number-value> ]* + var left = calcValue(); + while (currentToken === '*' || currentToken === '/') { + var operator = currentToken; + consume(); + var right = calcValue(); + if (operator === '*') + left *= right; + else + left /= right; + } + return left; + } + + function calcSum() { + // <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* + var left = calcProduct(); + while (currentToken === '+' || currentToken === '-') { + var operator = currentToken; + consume(); + var right = calcProduct(); + if (operator === '+') + left += right; + else + left -= right; + } + return left; + } + + // <calc()> = calc( <calc-sum> ) + return calcSum(); + } + + function parseDimension(unitRegExp, string) { + string = string.trim().toLowerCase(); + + if (string == '0' && 'px'.search(unitRegExp) >= 0) + return {px: 0}; + + // If we have parenthesis, we're a calc and need to start with 'calc'. + if (!/^[^(]*$|^calc/.test(string)) + return; + string = string.replace(/calc\(/g, '('); + + // We tag units by prefixing them with 'U' (note that we are already + // lowercase) to prevent problems with types which are substrings of + // each other (although prefixes may be problematic!) + var matchedUnits = {}; + string = string.replace(unitRegExp, function(match) { + matchedUnits[match] = null; + return 'U' + match; + }); + var taggedUnitRegExp = 'U(' + unitRegExp.source + ')'; + + // Validating input is simply applying as many reductions as we can. + var typeCheck = string.replace(/[-+]?(\d*\.)?\d+([Ee][-+]?\d+)?/g, 'N') + .replace(new RegExp('N' + taggedUnitRegExp, 'g'), 'D') + .replace(/\s[+-]\s/g, 'O') + .replace(/\s/g, ''); + var reductions = [/N\*(D)/g, /(N|D)[*/]N/g, /(N|D)O\1/g, /\((N|D)\)/g]; + var i = 0; + while (i < reductions.length) { + if (reductions[i].test(typeCheck)) { + typeCheck = typeCheck.replace(reductions[i], '$1'); + i = 0; + } else { + i++; + } + } + if (typeCheck != 'D') + return; + + for (var unit in matchedUnits) { + var result = calculate(string.replace(new RegExp('U' + unit, 'g'), '').replace(new RegExp(taggedUnitRegExp, 'g'), '*0')); + if (!isFinite(result)) + return; + matchedUnits[unit] = result; + } + return matchedUnits; + } + + function mergeDimensionsNonNegative(left, right) { + return mergeDimensions(left, right, true); + } + + function mergeDimensions(left, right, nonNegative) { + var units = [], unit; + for (unit in left) + units.push(unit); + for (unit in right) { + if (units.indexOf(unit) < 0) + units.push(unit); + } + + left = units.map(function(unit) { return left[unit] || 0; }); + right = units.map(function(unit) { return right[unit] || 0; }); + return [left, right, function(values) { + var result = values.map(function(value, i) { + if (values.length == 1 && nonNegative) { + value = Math.max(value, 0); + } + // Scientific notation (e.g. 1e2) is not yet widely supported by browser vendors. + return scope.numberToString(value) + units[i]; + }).join(' + '); + return values.length > 1 ? 'calc(' + result + ')' : result; + }]; + } + + var lengthUnits = 'px|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc'; + var parseLength = parseDimension.bind(null, new RegExp(lengthUnits, 'g')); + var parseLengthOrPercent = parseDimension.bind(null, new RegExp(lengthUnits + '|%', 'g')); + var parseAngle = parseDimension.bind(null, /deg|rad|grad|turn/g); + + scope.parseLength = parseLength; + scope.parseLengthOrPercent = parseLengthOrPercent; + scope.consumeLengthOrPercent = scope.consumeParenthesised.bind(null, parseLengthOrPercent); + scope.parseAngle = parseAngle; + scope.mergeDimensions = mergeDimensions; + + var consumeLength = scope.consumeParenthesised.bind(null, parseLength); + var consumeSizePair = scope.consumeRepeated.bind(undefined, consumeLength, /^/); + var consumeSizePairList = scope.consumeRepeated.bind(undefined, consumeSizePair, /^,/); + scope.consumeSizePairList = consumeSizePairList; + + var parseSizePairList = function(input) { + var result = consumeSizePairList(input); + if (result && result[1] == '') { + return result[0]; + } + }; + + var mergeNonNegativeSizePair = scope.mergeNestedRepeated.bind(undefined, mergeDimensionsNonNegative, ' '); + var mergeNonNegativeSizePairList = scope.mergeNestedRepeated.bind(undefined, mergeNonNegativeSizePair, ','); + scope.mergeNonNegativeSizePair = mergeNonNegativeSizePair; + + scope.addPropertiesHandler(parseSizePairList, mergeNonNegativeSizePairList, [ + 'background-size' + ]); + + scope.addPropertiesHandler(parseLengthOrPercent, mergeDimensionsNonNegative, [ + 'border-bottom-width', + 'border-image-width', + 'border-left-width', + 'border-right-width', + 'border-top-width', + 'flex-basis', + 'font-size', + 'height', + 'line-height', + 'max-height', + 'max-width', + 'outline-width', + 'width', + ]); + + scope.addPropertiesHandler(parseLengthOrPercent, mergeDimensions, [ + 'border-bottom-left-radius', + 'border-bottom-right-radius', + 'border-top-left-radius', + 'border-top-right-radius', + 'bottom', + 'left', + 'letter-spacing', + 'margin-bottom', + 'margin-left', + 'margin-right', + 'margin-top', + 'min-height', + 'min-width', + 'outline-offset', + 'padding-bottom', + 'padding-left', + 'padding-right', + 'padding-top', + 'perspective', + 'right', + 'shape-margin', + 'stroke-dashoffset', + 'text-indent', + 'top', + 'vertical-align', + 'word-spacing', + ]); + +})(webAnimations1, webAnimationsTesting); |