|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * A class used for intermediate representations of the -moz-transform property. |
|
8 */ |
|
9 |
|
10 #include "nsStyleTransformMatrix.h" |
|
11 #include "nsCSSValue.h" |
|
12 #include "nsPresContext.h" |
|
13 #include "nsRuleNode.h" |
|
14 #include "nsCSSKeywords.h" |
|
15 #include "nsStyleAnimation.h" |
|
16 #include "gfxMatrix.h" |
|
17 |
|
18 using namespace mozilla; |
|
19 |
|
20 namespace nsStyleTransformMatrix { |
|
21 |
|
22 /* Note on floating point precision: The transform matrix is an array |
|
23 * of single precision 'float's, and so are most of the input values |
|
24 * we get from the style system, but intermediate calculations |
|
25 * involving angles need to be done in 'double'. |
|
26 */ |
|
27 |
|
28 /* Force small values to zero. We do this to avoid having sin(360deg) |
|
29 * evaluate to a tiny but nonzero value. |
|
30 */ |
|
31 static double FlushToZero(double aVal) |
|
32 { |
|
33 if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON) |
|
34 return 0.0f; |
|
35 else |
|
36 return aVal; |
|
37 } |
|
38 |
|
39 float |
|
40 ProcessTranslatePart(const nsCSSValue& aValue, |
|
41 nsStyleContext* aContext, |
|
42 nsPresContext* aPresContext, |
|
43 bool& aCanStoreInRuleTree, |
|
44 nscoord aSize, |
|
45 float aAppUnitsPerMatrixUnit) |
|
46 { |
|
47 nscoord offset = 0; |
|
48 float percent = 0.0f; |
|
49 |
|
50 if (aValue.GetUnit() == eCSSUnit_Percent) { |
|
51 percent = aValue.GetPercentValue(); |
|
52 } else if (aValue.GetUnit() == eCSSUnit_Pixel || |
|
53 aValue.GetUnit() == eCSSUnit_Number) { |
|
54 // Handle this here (even though nsRuleNode::CalcLength handles it |
|
55 // fine) so that callers are allowed to pass a null style context |
|
56 // and pres context to SetToTransformFunction if they know (as |
|
57 // nsStyleAnimation does) that all lengths within the transform |
|
58 // function have already been computed to pixels and percents. |
|
59 // |
|
60 // Raw numbers are treated as being pixels. |
|
61 // |
|
62 // Don't convert to aValue to AppUnits here to avoid precision issues. |
|
63 return aValue.GetFloatValue() * |
|
64 (float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit); |
|
65 } else if (aValue.IsCalcUnit()) { |
|
66 nsRuleNode::ComputedCalc result = |
|
67 nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext, |
|
68 aCanStoreInRuleTree); |
|
69 percent = result.mPercent; |
|
70 offset = result.mLength; |
|
71 } else { |
|
72 offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext, |
|
73 aCanStoreInRuleTree); |
|
74 } |
|
75 |
|
76 return (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) + |
|
77 NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit); |
|
78 } |
|
79 |
|
80 /** |
|
81 * Helper functions to process all the transformation function types. |
|
82 * |
|
83 * These take a matrix parameter to accumulate the current matrix. |
|
84 */ |
|
85 |
|
86 /* Helper function to process a matrix entry. */ |
|
87 static void |
|
88 ProcessMatrix(gfx3DMatrix& aMatrix, |
|
89 const nsCSSValue::Array* aData, |
|
90 nsStyleContext* aContext, |
|
91 nsPresContext* aPresContext, |
|
92 bool& aCanStoreInRuleTree, |
|
93 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
94 { |
|
95 NS_PRECONDITION(aData->Count() == 7, "Invalid array!"); |
|
96 |
|
97 gfxMatrix result; |
|
98 |
|
99 /* Take the first four elements out of the array as floats and store |
|
100 * them. |
|
101 */ |
|
102 result.xx = aData->Item(1).GetFloatValue(); |
|
103 result.yx = aData->Item(2).GetFloatValue(); |
|
104 result.xy = aData->Item(3).GetFloatValue(); |
|
105 result.yy = aData->Item(4).GetFloatValue(); |
|
106 |
|
107 /* The last two elements have their length parts stored in aDelta |
|
108 * and their percent parts stored in aX[0] and aY[1]. |
|
109 */ |
|
110 result.x0 = ProcessTranslatePart(aData->Item(5), |
|
111 aContext, aPresContext, aCanStoreInRuleTree, |
|
112 aBounds.Width(), aAppUnitsPerMatrixUnit); |
|
113 result.y0 = ProcessTranslatePart(aData->Item(6), |
|
114 aContext, aPresContext, aCanStoreInRuleTree, |
|
115 aBounds.Height(), aAppUnitsPerMatrixUnit); |
|
116 |
|
117 aMatrix.PreMultiply(result); |
|
118 } |
|
119 |
|
120 static void |
|
121 ProcessMatrix3D(gfx3DMatrix& aMatrix, |
|
122 const nsCSSValue::Array* aData, |
|
123 nsStyleContext* aContext, |
|
124 nsPresContext* aPresContext, |
|
125 bool& aCanStoreInRuleTree, |
|
126 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
127 { |
|
128 NS_PRECONDITION(aData->Count() == 17, "Invalid array!"); |
|
129 |
|
130 gfx3DMatrix temp; |
|
131 |
|
132 temp._11 = aData->Item(1).GetFloatValue(); |
|
133 temp._12 = aData->Item(2).GetFloatValue(); |
|
134 temp._13 = aData->Item(3).GetFloatValue(); |
|
135 temp._14 = aData->Item(4).GetFloatValue(); |
|
136 temp._21 = aData->Item(5).GetFloatValue(); |
|
137 temp._22 = aData->Item(6).GetFloatValue(); |
|
138 temp._23 = aData->Item(7).GetFloatValue(); |
|
139 temp._24 = aData->Item(8).GetFloatValue(); |
|
140 temp._31 = aData->Item(9).GetFloatValue(); |
|
141 temp._32 = aData->Item(10).GetFloatValue(); |
|
142 temp._33 = aData->Item(11).GetFloatValue(); |
|
143 temp._34 = aData->Item(12).GetFloatValue(); |
|
144 temp._44 = aData->Item(16).GetFloatValue(); |
|
145 |
|
146 temp._41 = ProcessTranslatePart(aData->Item(13), |
|
147 aContext, aPresContext, aCanStoreInRuleTree, |
|
148 aBounds.Width(), aAppUnitsPerMatrixUnit); |
|
149 temp._42 = ProcessTranslatePart(aData->Item(14), |
|
150 aContext, aPresContext, aCanStoreInRuleTree, |
|
151 aBounds.Height(), aAppUnitsPerMatrixUnit); |
|
152 temp._43 = ProcessTranslatePart(aData->Item(15), |
|
153 aContext, aPresContext, aCanStoreInRuleTree, |
|
154 aBounds.Height(), aAppUnitsPerMatrixUnit); |
|
155 |
|
156 aMatrix.PreMultiply(temp); |
|
157 } |
|
158 |
|
159 /* Helper function to process two matrices that we need to interpolate between */ |
|
160 void |
|
161 ProcessInterpolateMatrix(gfx3DMatrix& aMatrix, |
|
162 const nsCSSValue::Array* aData, |
|
163 nsStyleContext* aContext, |
|
164 nsPresContext* aPresContext, |
|
165 bool& aCanStoreInRuleTree, |
|
166 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
167 { |
|
168 NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); |
|
169 |
|
170 gfx3DMatrix matrix1, matrix2; |
|
171 if (aData->Item(1).GetUnit() == eCSSUnit_List) { |
|
172 matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(), |
|
173 aContext, aPresContext, |
|
174 aCanStoreInRuleTree, |
|
175 aBounds, aAppUnitsPerMatrixUnit); |
|
176 } |
|
177 if (aData->Item(2).GetUnit() == eCSSUnit_List) { |
|
178 matrix2 = ReadTransforms(aData->Item(2).GetListValue(), |
|
179 aContext, aPresContext, |
|
180 aCanStoreInRuleTree, |
|
181 aBounds, aAppUnitsPerMatrixUnit); |
|
182 } |
|
183 double progress = aData->Item(3).GetPercentValue(); |
|
184 |
|
185 aMatrix = nsStyleAnimation::InterpolateTransformMatrix(matrix1, matrix2, progress) * aMatrix; |
|
186 } |
|
187 |
|
188 /* Helper function to process a translatex function. */ |
|
189 static void |
|
190 ProcessTranslateX(gfx3DMatrix& aMatrix, |
|
191 const nsCSSValue::Array* aData, |
|
192 nsStyleContext* aContext, |
|
193 nsPresContext* aPresContext, |
|
194 bool& aCanStoreInRuleTree, |
|
195 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
196 { |
|
197 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
198 |
|
199 gfxPoint3D temp; |
|
200 |
|
201 temp.x = ProcessTranslatePart(aData->Item(1), |
|
202 aContext, aPresContext, aCanStoreInRuleTree, |
|
203 aBounds.Width(), aAppUnitsPerMatrixUnit); |
|
204 aMatrix.Translate(temp); |
|
205 } |
|
206 |
|
207 /* Helper function to process a translatey function. */ |
|
208 static void |
|
209 ProcessTranslateY(gfx3DMatrix& aMatrix, |
|
210 const nsCSSValue::Array* aData, |
|
211 nsStyleContext* aContext, |
|
212 nsPresContext* aPresContext, |
|
213 bool& aCanStoreInRuleTree, |
|
214 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
215 { |
|
216 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
217 |
|
218 gfxPoint3D temp; |
|
219 |
|
220 temp.y = ProcessTranslatePart(aData->Item(1), |
|
221 aContext, aPresContext, aCanStoreInRuleTree, |
|
222 aBounds.Height(), aAppUnitsPerMatrixUnit); |
|
223 aMatrix.Translate(temp); |
|
224 } |
|
225 |
|
226 static void |
|
227 ProcessTranslateZ(gfx3DMatrix& aMatrix, |
|
228 const nsCSSValue::Array* aData, |
|
229 nsStyleContext* aContext, |
|
230 nsPresContext* aPresContext, |
|
231 bool& aCanStoreInRuleTree, |
|
232 float aAppUnitsPerMatrixUnit) |
|
233 { |
|
234 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
235 |
|
236 gfxPoint3D temp; |
|
237 |
|
238 temp.z = ProcessTranslatePart(aData->Item(1), |
|
239 aContext, aPresContext, aCanStoreInRuleTree, |
|
240 0, aAppUnitsPerMatrixUnit); |
|
241 aMatrix.Translate(temp); |
|
242 } |
|
243 |
|
244 /* Helper function to process a translate function. */ |
|
245 static void |
|
246 ProcessTranslate(gfx3DMatrix& aMatrix, |
|
247 const nsCSSValue::Array* aData, |
|
248 nsStyleContext* aContext, |
|
249 nsPresContext* aPresContext, |
|
250 bool& aCanStoreInRuleTree, |
|
251 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
252 { |
|
253 NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!"); |
|
254 |
|
255 gfxPoint3D temp; |
|
256 |
|
257 temp.x = ProcessTranslatePart(aData->Item(1), |
|
258 aContext, aPresContext, aCanStoreInRuleTree, |
|
259 aBounds.Width(), aAppUnitsPerMatrixUnit); |
|
260 |
|
261 /* If we read in a Y component, set it appropriately */ |
|
262 if (aData->Count() == 3) { |
|
263 temp.y = ProcessTranslatePart(aData->Item(2), |
|
264 aContext, aPresContext, aCanStoreInRuleTree, |
|
265 aBounds.Height(), aAppUnitsPerMatrixUnit); |
|
266 } |
|
267 aMatrix.Translate(temp); |
|
268 } |
|
269 |
|
270 static void |
|
271 ProcessTranslate3D(gfx3DMatrix& aMatrix, |
|
272 const nsCSSValue::Array* aData, |
|
273 nsStyleContext* aContext, |
|
274 nsPresContext* aPresContext, |
|
275 bool& aCanStoreInRuleTree, |
|
276 nsRect& aBounds, float aAppUnitsPerMatrixUnit) |
|
277 { |
|
278 NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); |
|
279 |
|
280 gfxPoint3D temp; |
|
281 |
|
282 temp.x = ProcessTranslatePart(aData->Item(1), |
|
283 aContext, aPresContext, aCanStoreInRuleTree, |
|
284 aBounds.Width(), aAppUnitsPerMatrixUnit); |
|
285 |
|
286 temp.y = ProcessTranslatePart(aData->Item(2), |
|
287 aContext, aPresContext, aCanStoreInRuleTree, |
|
288 aBounds.Height(), aAppUnitsPerMatrixUnit); |
|
289 |
|
290 temp.z = ProcessTranslatePart(aData->Item(3), |
|
291 aContext, aPresContext, aCanStoreInRuleTree, |
|
292 0, aAppUnitsPerMatrixUnit); |
|
293 |
|
294 aMatrix.Translate(temp); |
|
295 } |
|
296 |
|
297 /* Helper function to set up a scale matrix. */ |
|
298 static void |
|
299 ProcessScaleHelper(gfx3DMatrix& aMatrix, |
|
300 float aXScale, |
|
301 float aYScale, |
|
302 float aZScale) |
|
303 { |
|
304 aMatrix.Scale(aXScale, aYScale, aZScale); |
|
305 } |
|
306 |
|
307 /* Process a scalex function. */ |
|
308 static void |
|
309 ProcessScaleX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
310 { |
|
311 NS_PRECONDITION(aData->Count() == 2, "Bad array!"); |
|
312 ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), 1.0f, 1.0f); |
|
313 } |
|
314 |
|
315 /* Process a scaley function. */ |
|
316 static void |
|
317 ProcessScaleY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
318 { |
|
319 NS_PRECONDITION(aData->Count() == 2, "Bad array!"); |
|
320 ProcessScaleHelper(aMatrix, 1.0f, aData->Item(1).GetFloatValue(), 1.0f); |
|
321 } |
|
322 |
|
323 static void |
|
324 ProcessScaleZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
325 { |
|
326 NS_PRECONDITION(aData->Count() == 2, "Bad array!"); |
|
327 ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aData->Item(1).GetFloatValue()); |
|
328 } |
|
329 |
|
330 static void |
|
331 ProcessScale3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
332 { |
|
333 NS_PRECONDITION(aData->Count() == 4, "Bad array!"); |
|
334 ProcessScaleHelper(aMatrix, |
|
335 aData->Item(1).GetFloatValue(), |
|
336 aData->Item(2).GetFloatValue(), |
|
337 aData->Item(3).GetFloatValue()); |
|
338 } |
|
339 |
|
340 /* Process a scale function. */ |
|
341 static void |
|
342 ProcessScale(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
343 { |
|
344 NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); |
|
345 /* We either have one element or two. If we have one, it's for both X and Y. |
|
346 * Otherwise it's one for each. |
|
347 */ |
|
348 const nsCSSValue& scaleX = aData->Item(1); |
|
349 const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX : |
|
350 aData->Item(2)); |
|
351 |
|
352 ProcessScaleHelper(aMatrix, |
|
353 scaleX.GetFloatValue(), |
|
354 scaleY.GetFloatValue(), |
|
355 1.0f); |
|
356 } |
|
357 |
|
358 /* Helper function that, given a set of angles, constructs the appropriate |
|
359 * skew matrix. |
|
360 */ |
|
361 static void |
|
362 ProcessSkewHelper(gfx3DMatrix& aMatrix, double aXAngle, double aYAngle) |
|
363 { |
|
364 aMatrix.SkewXY(aXAngle, aYAngle); |
|
365 } |
|
366 |
|
367 /* Function that converts a skewx transform into a matrix. */ |
|
368 static void |
|
369 ProcessSkewX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
370 { |
|
371 NS_ASSERTION(aData->Count() == 2, "Bad array!"); |
|
372 ProcessSkewHelper(aMatrix, aData->Item(1).GetAngleValueInRadians(), 0.0); |
|
373 } |
|
374 |
|
375 /* Function that converts a skewy transform into a matrix. */ |
|
376 static void |
|
377 ProcessSkewY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
378 { |
|
379 NS_ASSERTION(aData->Count() == 2, "Bad array!"); |
|
380 ProcessSkewHelper(aMatrix, 0.0, aData->Item(1).GetAngleValueInRadians()); |
|
381 } |
|
382 |
|
383 /* Function that converts a skew transform into a matrix. */ |
|
384 static void |
|
385 ProcessSkew(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
386 { |
|
387 NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); |
|
388 |
|
389 double xSkew = aData->Item(1).GetAngleValueInRadians(); |
|
390 double ySkew = (aData->Count() == 2 |
|
391 ? 0.0 : aData->Item(2).GetAngleValueInRadians()); |
|
392 |
|
393 ProcessSkewHelper(aMatrix, xSkew, ySkew); |
|
394 } |
|
395 |
|
396 /* Function that converts a rotate transform into a matrix. */ |
|
397 static void |
|
398 ProcessRotateZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
399 { |
|
400 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
401 double theta = aData->Item(1).GetAngleValueInRadians(); |
|
402 aMatrix.RotateZ(theta); |
|
403 } |
|
404 |
|
405 static void |
|
406 ProcessRotateX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
407 { |
|
408 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
409 double theta = aData->Item(1).GetAngleValueInRadians(); |
|
410 aMatrix.RotateX(theta); |
|
411 } |
|
412 |
|
413 static void |
|
414 ProcessRotateY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
415 { |
|
416 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
417 double theta = aData->Item(1).GetAngleValueInRadians(); |
|
418 aMatrix.RotateY(theta); |
|
419 } |
|
420 |
|
421 static void |
|
422 ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) |
|
423 { |
|
424 NS_PRECONDITION(aData->Count() == 5, "Invalid array!"); |
|
425 |
|
426 /* We want our matrix to look like this: |
|
427 * | 1 + (1-cos(angle))*(x*x-1) -z*sin(angle)+(1-cos(angle))*x*y y*sin(angle)+(1-cos(angle))*x*z 0 | |
|
428 * | z*sin(angle)+(1-cos(angle))*x*y 1 + (1-cos(angle))*(y*y-1) -x*sin(angle)+(1-cos(angle))*y*z 0 | |
|
429 * | -y*sin(angle)+(1-cos(angle))*x*z x*sin(angle)+(1-cos(angle))*y*z 1 + (1-cos(angle))*(z*z-1) 0 | |
|
430 * | 0 0 0 1 | |
|
431 * (see http://www.w3.org/TR/css3-3d-transforms/#transform-functions) |
|
432 */ |
|
433 |
|
434 /* The current spec specifies a matrix that rotates in the wrong direction. For now we just negate |
|
435 * the angle provided to get the correct rotation direction until the spec is updated. |
|
436 * See bug 704468. |
|
437 */ |
|
438 double theta = -aData->Item(4).GetAngleValueInRadians(); |
|
439 float cosTheta = FlushToZero(cos(theta)); |
|
440 float sinTheta = FlushToZero(sin(theta)); |
|
441 |
|
442 float x = aData->Item(1).GetFloatValue(); |
|
443 float y = aData->Item(2).GetFloatValue(); |
|
444 float z = aData->Item(3).GetFloatValue(); |
|
445 |
|
446 /* Normalize [x,y,z] */ |
|
447 float length = sqrt(x*x + y*y + z*z); |
|
448 if (length == 0.0) { |
|
449 return; |
|
450 } |
|
451 x /= length; |
|
452 y /= length; |
|
453 z /= length; |
|
454 |
|
455 gfx3DMatrix temp; |
|
456 |
|
457 /* Create our matrix */ |
|
458 temp._11 = 1 + (1 - cosTheta) * (x * x - 1); |
|
459 temp._12 = -z * sinTheta + (1 - cosTheta) * x * y; |
|
460 temp._13 = y * sinTheta + (1 - cosTheta) * x * z; |
|
461 temp._14 = 0.0f; |
|
462 temp._21 = z * sinTheta + (1 - cosTheta) * x * y; |
|
463 temp._22 = 1 + (1 - cosTheta) * (y * y - 1); |
|
464 temp._23 = -x * sinTheta + (1 - cosTheta) * y * z; |
|
465 temp._24 = 0.0f; |
|
466 temp._31 = -y * sinTheta + (1 - cosTheta) * x * z; |
|
467 temp._32 = x * sinTheta + (1 - cosTheta) * y * z; |
|
468 temp._33 = 1 + (1 - cosTheta) * (z * z - 1); |
|
469 temp._34 = 0.0f; |
|
470 temp._41 = 0.0f; |
|
471 temp._42 = 0.0f; |
|
472 temp._43 = 0.0f; |
|
473 temp._44 = 1.0f; |
|
474 |
|
475 aMatrix = temp * aMatrix; |
|
476 } |
|
477 |
|
478 static void |
|
479 ProcessPerspective(gfx3DMatrix& aMatrix, |
|
480 const nsCSSValue::Array* aData, |
|
481 nsStyleContext *aContext, |
|
482 nsPresContext *aPresContext, |
|
483 bool &aCanStoreInRuleTree, |
|
484 float aAppUnitsPerMatrixUnit) |
|
485 { |
|
486 NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); |
|
487 |
|
488 float depth = ProcessTranslatePart(aData->Item(1), aContext, |
|
489 aPresContext, aCanStoreInRuleTree, |
|
490 0, aAppUnitsPerMatrixUnit); |
|
491 aMatrix.Perspective(depth); |
|
492 } |
|
493 |
|
494 |
|
495 /** |
|
496 * SetToTransformFunction is essentially a giant switch statement that fans |
|
497 * out to many smaller helper functions. |
|
498 */ |
|
499 static void |
|
500 MatrixForTransformFunction(gfx3DMatrix& aMatrix, |
|
501 const nsCSSValue::Array * aData, |
|
502 nsStyleContext* aContext, |
|
503 nsPresContext* aPresContext, |
|
504 bool& aCanStoreInRuleTree, |
|
505 nsRect& aBounds, |
|
506 float aAppUnitsPerMatrixUnit) |
|
507 { |
|
508 NS_PRECONDITION(aData, "Why did you want to get data from a null array?"); |
|
509 // It's OK if aContext and aPresContext are null if the caller already |
|
510 // knows that all length units have been converted to pixels (as |
|
511 // nsStyleAnimation does). |
|
512 |
|
513 |
|
514 /* Get the keyword for the transform. */ |
|
515 switch (TransformFunctionOf(aData)) { |
|
516 case eCSSKeyword_translatex: |
|
517 ProcessTranslateX(aMatrix, aData, aContext, aPresContext, |
|
518 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
519 break; |
|
520 case eCSSKeyword_translatey: |
|
521 ProcessTranslateY(aMatrix, aData, aContext, aPresContext, |
|
522 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
523 break; |
|
524 case eCSSKeyword_translatez: |
|
525 ProcessTranslateZ(aMatrix, aData, aContext, aPresContext, |
|
526 aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); |
|
527 break; |
|
528 case eCSSKeyword_translate: |
|
529 ProcessTranslate(aMatrix, aData, aContext, aPresContext, |
|
530 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
531 break; |
|
532 case eCSSKeyword_translate3d: |
|
533 ProcessTranslate3D(aMatrix, aData, aContext, aPresContext, |
|
534 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
535 break; |
|
536 case eCSSKeyword_scalex: |
|
537 ProcessScaleX(aMatrix, aData); |
|
538 break; |
|
539 case eCSSKeyword_scaley: |
|
540 ProcessScaleY(aMatrix, aData); |
|
541 break; |
|
542 case eCSSKeyword_scalez: |
|
543 ProcessScaleZ(aMatrix, aData); |
|
544 break; |
|
545 case eCSSKeyword_scale: |
|
546 ProcessScale(aMatrix, aData); |
|
547 break; |
|
548 case eCSSKeyword_scale3d: |
|
549 ProcessScale3D(aMatrix, aData); |
|
550 break; |
|
551 case eCSSKeyword_skewx: |
|
552 ProcessSkewX(aMatrix, aData); |
|
553 break; |
|
554 case eCSSKeyword_skewy: |
|
555 ProcessSkewY(aMatrix, aData); |
|
556 break; |
|
557 case eCSSKeyword_skew: |
|
558 ProcessSkew(aMatrix, aData); |
|
559 break; |
|
560 case eCSSKeyword_rotatex: |
|
561 ProcessRotateX(aMatrix, aData); |
|
562 break; |
|
563 case eCSSKeyword_rotatey: |
|
564 ProcessRotateY(aMatrix, aData); |
|
565 break; |
|
566 case eCSSKeyword_rotatez: |
|
567 case eCSSKeyword_rotate: |
|
568 ProcessRotateZ(aMatrix, aData); |
|
569 break; |
|
570 case eCSSKeyword_rotate3d: |
|
571 ProcessRotate3D(aMatrix, aData); |
|
572 break; |
|
573 case eCSSKeyword_matrix: |
|
574 ProcessMatrix(aMatrix, aData, aContext, aPresContext, |
|
575 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
576 break; |
|
577 case eCSSKeyword_matrix3d: |
|
578 ProcessMatrix3D(aMatrix, aData, aContext, aPresContext, |
|
579 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
580 break; |
|
581 case eCSSKeyword_interpolatematrix: |
|
582 ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext, |
|
583 aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); |
|
584 break; |
|
585 case eCSSKeyword_perspective: |
|
586 ProcessPerspective(aMatrix, aData, aContext, aPresContext, |
|
587 aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); |
|
588 break; |
|
589 default: |
|
590 NS_NOTREACHED("Unknown transform function!"); |
|
591 } |
|
592 } |
|
593 |
|
594 /** |
|
595 * Return the transform function, as an nsCSSKeyword, for the given |
|
596 * nsCSSValue::Array from a transform list. |
|
597 */ |
|
598 nsCSSKeyword |
|
599 TransformFunctionOf(const nsCSSValue::Array* aData) |
|
600 { |
|
601 MOZ_ASSERT(aData->Item(0).GetUnit() == eCSSUnit_Enumerated); |
|
602 return aData->Item(0).GetKeywordValue(); |
|
603 } |
|
604 |
|
605 gfx3DMatrix |
|
606 ReadTransforms(const nsCSSValueList* aList, |
|
607 nsStyleContext* aContext, |
|
608 nsPresContext* aPresContext, |
|
609 bool &aCanStoreInRuleTree, |
|
610 nsRect& aBounds, |
|
611 float aAppUnitsPerMatrixUnit) |
|
612 { |
|
613 gfx3DMatrix result; |
|
614 |
|
615 for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) { |
|
616 const nsCSSValue &currElem = curr->mValue; |
|
617 NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function, |
|
618 "Stream should consist solely of functions!"); |
|
619 NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1, |
|
620 "Incoming function is too short!"); |
|
621 |
|
622 /* Read in a single transform matrix. */ |
|
623 MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext, |
|
624 aPresContext, aCanStoreInRuleTree, |
|
625 aBounds, aAppUnitsPerMatrixUnit); |
|
626 } |
|
627 |
|
628 return result; |
|
629 } |
|
630 |
|
631 } // namespace nsStyleTransformMatrix |