OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 Google Inc. All rights reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 (function(scope, testing) { |
| 16 |
| 17 // This returns a function for converting transform functions to equivalent |
| 18 // primitive functions, which will take an array of values from the |
| 19 // derivative type and fill in the blanks (underscores) with them. |
| 20 var _ = null; |
| 21 function cast(pattern) { |
| 22 return function(contents) { |
| 23 var i = 0; |
| 24 return pattern.map(function(x) { return x === _ ? contents[i++] : x; }); |
| 25 } |
| 26 } |
| 27 |
| 28 function id(x) { return x; } |
| 29 |
| 30 var Opx = {px: 0}; |
| 31 var Odeg = {deg: 0}; |
| 32 |
| 33 // type: [argTypes, convertTo3D, convertTo2D] |
| 34 // In the argument types string, lowercase characters represent optional argum
ents |
| 35 var transformFunctions = { |
| 36 matrix: ['NNNNNN', [_, _, 0, 0, _, _, 0, 0, 0, 0, 1, 0, _, _, 0, 1], id], |
| 37 matrix3d: ['NNNNNNNNNNNNNNNN', id], |
| 38 rotate: ['A'], |
| 39 rotatex: ['A'], |
| 40 rotatey: ['A'], |
| 41 rotatez: ['A'], |
| 42 rotate3d: ['NNNA'], |
| 43 perspective: ['L'], |
| 44 scale: ['Nn', cast([_, _, 1]), id], |
| 45 scalex: ['N', cast([_, 1, 1]), cast([_, 1])], |
| 46 scaley: ['N', cast([1, _, 1]), cast([1, _])], |
| 47 scalez: ['N', cast([1, 1, _])], |
| 48 scale3d: ['NNN', id], |
| 49 skew: ['Aa', null, id], |
| 50 skewx: ['A', null, cast([_, Odeg])], |
| 51 skewy: ['A', null, cast([Odeg, _])], |
| 52 translate: ['Tt', cast([_, _, Opx]), id], |
| 53 translatex: ['T', cast([_, Opx, Opx]), cast([_, Opx])], |
| 54 translatey: ['T', cast([Opx, _, Opx]), cast([Opx, _])], |
| 55 translatez: ['L', cast([Opx, Opx, _])], |
| 56 translate3d: ['TTL', id], |
| 57 }; |
| 58 |
| 59 function parseTransform(string) { |
| 60 string = string.toLowerCase().trim(); |
| 61 if (string == 'none') |
| 62 return []; |
| 63 // FIXME: Using a RegExp means calcs won't work here |
| 64 var transformRegExp = /\s*(\w+)\(([^)]*)\)/g; |
| 65 var result = []; |
| 66 var match; |
| 67 var prevLastIndex = 0; |
| 68 while (match = transformRegExp.exec(string)) { |
| 69 if (match.index != prevLastIndex) |
| 70 return; |
| 71 prevLastIndex = match.index + match[0].length; |
| 72 var functionName = match[1]; |
| 73 var functionData = transformFunctions[functionName]; |
| 74 if (!functionData) |
| 75 return; |
| 76 var args = match[2].split(','); |
| 77 var argTypes = functionData[0]; |
| 78 if (argTypes.length < args.length) |
| 79 return; |
| 80 |
| 81 var parsedArgs = []; |
| 82 for (var i = 0; i < argTypes.length; i++) { |
| 83 var arg = args[i]; |
| 84 var type = argTypes[i]; |
| 85 var parsedArg; |
| 86 if (!arg) |
| 87 parsedArg = ({a: Odeg, |
| 88 n: parsedArgs[0], |
| 89 t: Opx})[type]; |
| 90 else |
| 91 parsedArg = ({A: function(s) { return s.trim() == '0' ? Odeg : scope.p
arseAngle(s); }, |
| 92 N: scope.parseNumber, |
| 93 T: scope.parseLengthOrPercent, |
| 94 L: scope.parseLength})[type.toUpperCase()](arg); |
| 95 if (parsedArg === undefined) |
| 96 return; |
| 97 parsedArgs.push(parsedArg); |
| 98 } |
| 99 result.push({t: functionName, d: parsedArgs}); |
| 100 |
| 101 if (transformRegExp.lastIndex == string.length) |
| 102 return result; |
| 103 } |
| 104 }; |
| 105 |
| 106 function numberToLongString(x) { |
| 107 return x.toFixed(6).replace('.000000', ''); |
| 108 } |
| 109 |
| 110 function mergeMatrices(left, right) { |
| 111 if (left.decompositionPair !== right) { |
| 112 left.decompositionPair = right; |
| 113 var leftArgs = scope.makeMatrixDecomposition(left); |
| 114 } |
| 115 if (right.decompositionPair !== left) { |
| 116 right.decompositionPair = left; |
| 117 var rightArgs = scope.makeMatrixDecomposition(right); |
| 118 } |
| 119 if (leftArgs[0] == null || rightArgs[0] == null) |
| 120 return [[false], [true], function(x) { return x ? right[0].d : left[0].d;
}]; |
| 121 leftArgs[0].push(0); |
| 122 rightArgs[0].push(1); |
| 123 return [ |
| 124 leftArgs, |
| 125 rightArgs, |
| 126 function(list) { |
| 127 var quat = scope.quat(leftArgs[0][3], rightArgs[0][3], list[5]); |
| 128 var mat = scope.composeMatrix(list[0], list[1], list[2], quat, list[4]); |
| 129 var stringifiedArgs = mat.map(numberToLongString).join(','); |
| 130 return stringifiedArgs; |
| 131 } |
| 132 ]; |
| 133 } |
| 134 |
| 135 function typeTo2D(type) { |
| 136 return type.replace(/[xy]/, ''); |
| 137 } |
| 138 |
| 139 function typeTo3D(type) { |
| 140 return type.replace(/(x|y|z|3d)?$/, '3d'); |
| 141 } |
| 142 |
| 143 function mergeTransforms(left, right) { |
| 144 var matrixModulesLoaded = scope.makeMatrixDecomposition && true; |
| 145 |
| 146 var flipResults = false; |
| 147 if (!left.length || !right.length) { |
| 148 if (!left.length) { |
| 149 flipResults = true; |
| 150 left = right; |
| 151 right = []; |
| 152 } |
| 153 for (var i = 0; i < left.length; i++) { |
| 154 var type = left[i].t; |
| 155 var args = left[i].d; |
| 156 var defaultValue = type.substr(0, 5) == 'scale' ? 1 : 0; |
| 157 right.push({t: type, d: args.map(function(arg) { |
| 158 if (typeof arg == 'number') |
| 159 return defaultValue; |
| 160 var result = {}; |
| 161 for (var unit in arg) |
| 162 result[unit] = defaultValue; |
| 163 return result; |
| 164 })}); |
| 165 } |
| 166 } |
| 167 |
| 168 var isMatrixOrPerspective = function(lt, rt) { |
| 169 return ((lt == 'perspective') && (rt == 'perspective')) || |
| 170 ((lt == 'matrix' || lt == 'matrix3d') && (rt == 'matrix' || rt == 'mat
rix3d')); |
| 171 }; |
| 172 var leftResult = []; |
| 173 var rightResult = []; |
| 174 var types = []; |
| 175 |
| 176 if (left.length != right.length) { |
| 177 if (!matrixModulesLoaded) |
| 178 return; |
| 179 var merged = mergeMatrices(left, right); |
| 180 leftResult = [merged[0]]; |
| 181 rightResult = [merged[1]]; |
| 182 types = [['matrix', [merged[2]]]]; |
| 183 } else { |
| 184 for (var i = 0; i < left.length; i++) { |
| 185 var leftType = left[i].t; |
| 186 var rightType = right[i].t; |
| 187 var leftArgs = left[i].d; |
| 188 var rightArgs = right[i].d; |
| 189 |
| 190 var leftFunctionData = transformFunctions[leftType]; |
| 191 var rightFunctionData = transformFunctions[rightType]; |
| 192 |
| 193 var type; |
| 194 if (isMatrixOrPerspective(leftType, rightType)) { |
| 195 if (!matrixModulesLoaded) |
| 196 return; |
| 197 var merged = mergeMatrices([left[i]], [right[i]]); |
| 198 leftResult.push(merged[0]); |
| 199 rightResult.push(merged[1]); |
| 200 types.push(['matrix', [merged[2]]]); |
| 201 continue; |
| 202 } else if (leftType == rightType) { |
| 203 type = leftType; |
| 204 } else if (leftFunctionData[2] && rightFunctionData[2] && typeTo2D(leftT
ype) == typeTo2D(rightType)) { |
| 205 type = typeTo2D(leftType); |
| 206 leftArgs = leftFunctionData[2](leftArgs); |
| 207 rightArgs = rightFunctionData[2](rightArgs); |
| 208 } else if (leftFunctionData[1] && rightFunctionData[1] && typeTo3D(leftT
ype) == typeTo3D(rightType)) { |
| 209 type = typeTo3D(leftType); |
| 210 leftArgs = leftFunctionData[1](leftArgs); |
| 211 rightArgs = rightFunctionData[1](rightArgs); |
| 212 } else { |
| 213 if (!matrixModulesLoaded) |
| 214 return; |
| 215 var merged = mergeMatrices(left, right); |
| 216 leftResult = [merged[0]]; |
| 217 rightResult = [merged[1]]; |
| 218 types = [['matrix', [merged[2]]]]; |
| 219 break; |
| 220 } |
| 221 |
| 222 var leftArgsCopy = []; |
| 223 var rightArgsCopy = []; |
| 224 var stringConversions = []; |
| 225 for (var j = 0; j < leftArgs.length; j++) { |
| 226 var merge = typeof leftArgs[j] == 'number' ? scope.mergeNumbers : scop
e.mergeDimensions; |
| 227 var merged = merge(leftArgs[j], rightArgs[j]); |
| 228 leftArgsCopy[j] = merged[0]; |
| 229 rightArgsCopy[j] = merged[1]; |
| 230 stringConversions.push(merged[2]); |
| 231 } |
| 232 leftResult.push(leftArgsCopy); |
| 233 rightResult.push(rightArgsCopy); |
| 234 types.push([type, stringConversions]); |
| 235 } |
| 236 } |
| 237 |
| 238 if (flipResults) { |
| 239 var tmp = leftResult; |
| 240 leftResult = rightResult; |
| 241 rightResult = tmp; |
| 242 } |
| 243 |
| 244 return [leftResult, rightResult, function(list) { |
| 245 return list.map(function(args, i) { |
| 246 var stringifiedArgs = args.map(function(arg, j) { |
| 247 return types[i][1][j](arg); |
| 248 }).join(','); |
| 249 if (types[i][0] == 'matrix' && stringifiedArgs.split(',').length == 16) |
| 250 types[i][0] = 'matrix3d'; |
| 251 return types[i][0] + '(' + stringifiedArgs + ')'; |
| 252 |
| 253 }).join(' '); |
| 254 }]; |
| 255 } |
| 256 |
| 257 scope.addPropertiesHandler(parseTransform, mergeTransforms, ['transform']); |
| 258 |
| 259 if (WEB_ANIMATIONS_TESTING) |
| 260 testing.parseTransform = parseTransform; |
| 261 |
| 262 })(webAnimationsMinifill, webAnimationsTesting); |
OLD | NEW |