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 })(webAnimations1, webAnimationsTesting); | |
OLD | NEW |