Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
6 /*
7 * A class used for intermediate representations of the -moz-transform property.
8 */
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"
18 using namespace mozilla;
20 namespace nsStyleTransformMatrix {
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 */
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 }
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;
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 }
76 return (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) +
77 NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit);
78 }
80 /**
81 * Helper functions to process all the transformation function types.
82 *
83 * These take a matrix parameter to accumulate the current matrix.
84 */
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!");
97 gfxMatrix result;
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();
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);
117 aMatrix.PreMultiply(result);
118 }
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!");
130 gfx3DMatrix temp;
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();
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);
156 aMatrix.PreMultiply(temp);
157 }
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!");
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();
185 aMatrix = nsStyleAnimation::InterpolateTransformMatrix(matrix1, matrix2, progress) * aMatrix;
186 }
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!");
199 gfxPoint3D temp;
201 temp.x = ProcessTranslatePart(aData->Item(1),
202 aContext, aPresContext, aCanStoreInRuleTree,
203 aBounds.Width(), aAppUnitsPerMatrixUnit);
204 aMatrix.Translate(temp);
205 }
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!");
218 gfxPoint3D temp;
220 temp.y = ProcessTranslatePart(aData->Item(1),
221 aContext, aPresContext, aCanStoreInRuleTree,
222 aBounds.Height(), aAppUnitsPerMatrixUnit);
223 aMatrix.Translate(temp);
224 }
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!");
236 gfxPoint3D temp;
238 temp.z = ProcessTranslatePart(aData->Item(1),
239 aContext, aPresContext, aCanStoreInRuleTree,
240 0, aAppUnitsPerMatrixUnit);
241 aMatrix.Translate(temp);
242 }
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!");
255 gfxPoint3D temp;
257 temp.x = ProcessTranslatePart(aData->Item(1),
258 aContext, aPresContext, aCanStoreInRuleTree,
259 aBounds.Width(), aAppUnitsPerMatrixUnit);
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 }
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!");
280 gfxPoint3D temp;
282 temp.x = ProcessTranslatePart(aData->Item(1),
283 aContext, aPresContext, aCanStoreInRuleTree,
284 aBounds.Width(), aAppUnitsPerMatrixUnit);
286 temp.y = ProcessTranslatePart(aData->Item(2),
287 aContext, aPresContext, aCanStoreInRuleTree,
288 aBounds.Height(), aAppUnitsPerMatrixUnit);
290 temp.z = ProcessTranslatePart(aData->Item(3),
291 aContext, aPresContext, aCanStoreInRuleTree,
292 0, aAppUnitsPerMatrixUnit);
294 aMatrix.Translate(temp);
295 }
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 }
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 }
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 }
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 }
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 }
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));
352 ProcessScaleHelper(aMatrix,
353 scaleX.GetFloatValue(),
354 scaleY.GetFloatValue(),
355 1.0f);
356 }
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 }
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 }
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 }
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!");
389 double xSkew = aData->Item(1).GetAngleValueInRadians();
390 double ySkew = (aData->Count() == 2
391 ? 0.0 : aData->Item(2).GetAngleValueInRadians());
393 ProcessSkewHelper(aMatrix, xSkew, ySkew);
394 }
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 }
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 }
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 }
421 static void
422 ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData)
423 {
424 NS_PRECONDITION(aData->Count() == 5, "Invalid array!");
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 */
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));
442 float x = aData->Item(1).GetFloatValue();
443 float y = aData->Item(2).GetFloatValue();
444 float z = aData->Item(3).GetFloatValue();
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;
455 gfx3DMatrix temp;
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;
475 aMatrix = temp * aMatrix;
476 }
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!");
488 float depth = ProcessTranslatePart(aData->Item(1), aContext,
489 aPresContext, aCanStoreInRuleTree,
490 0, aAppUnitsPerMatrixUnit);
491 aMatrix.Perspective(depth);
492 }
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).
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 }
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 }
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;
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!");
622 /* Read in a single transform matrix. */
623 MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
624 aPresContext, aCanStoreInRuleTree,
625 aBounds, aAppUnitsPerMatrixUnit);
626 }
628 return result;
629 }
631 } // namespace nsStyleTransformMatrix