1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsStyleTransformMatrix.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,631 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * A class used for intermediate representations of the -moz-transform property. 1.11 + */ 1.12 + 1.13 +#include "nsStyleTransformMatrix.h" 1.14 +#include "nsCSSValue.h" 1.15 +#include "nsPresContext.h" 1.16 +#include "nsRuleNode.h" 1.17 +#include "nsCSSKeywords.h" 1.18 +#include "nsStyleAnimation.h" 1.19 +#include "gfxMatrix.h" 1.20 + 1.21 +using namespace mozilla; 1.22 + 1.23 +namespace nsStyleTransformMatrix { 1.24 + 1.25 +/* Note on floating point precision: The transform matrix is an array 1.26 + * of single precision 'float's, and so are most of the input values 1.27 + * we get from the style system, but intermediate calculations 1.28 + * involving angles need to be done in 'double'. 1.29 + */ 1.30 + 1.31 +/* Force small values to zero. We do this to avoid having sin(360deg) 1.32 + * evaluate to a tiny but nonzero value. 1.33 + */ 1.34 +static double FlushToZero(double aVal) 1.35 +{ 1.36 + if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON) 1.37 + return 0.0f; 1.38 + else 1.39 + return aVal; 1.40 +} 1.41 + 1.42 +float 1.43 +ProcessTranslatePart(const nsCSSValue& aValue, 1.44 + nsStyleContext* aContext, 1.45 + nsPresContext* aPresContext, 1.46 + bool& aCanStoreInRuleTree, 1.47 + nscoord aSize, 1.48 + float aAppUnitsPerMatrixUnit) 1.49 +{ 1.50 + nscoord offset = 0; 1.51 + float percent = 0.0f; 1.52 + 1.53 + if (aValue.GetUnit() == eCSSUnit_Percent) { 1.54 + percent = aValue.GetPercentValue(); 1.55 + } else if (aValue.GetUnit() == eCSSUnit_Pixel || 1.56 + aValue.GetUnit() == eCSSUnit_Number) { 1.57 + // Handle this here (even though nsRuleNode::CalcLength handles it 1.58 + // fine) so that callers are allowed to pass a null style context 1.59 + // and pres context to SetToTransformFunction if they know (as 1.60 + // nsStyleAnimation does) that all lengths within the transform 1.61 + // function have already been computed to pixels and percents. 1.62 + // 1.63 + // Raw numbers are treated as being pixels. 1.64 + // 1.65 + // Don't convert to aValue to AppUnits here to avoid precision issues. 1.66 + return aValue.GetFloatValue() * 1.67 + (float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit); 1.68 + } else if (aValue.IsCalcUnit()) { 1.69 + nsRuleNode::ComputedCalc result = 1.70 + nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext, 1.71 + aCanStoreInRuleTree); 1.72 + percent = result.mPercent; 1.73 + offset = result.mLength; 1.74 + } else { 1.75 + offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext, 1.76 + aCanStoreInRuleTree); 1.77 + } 1.78 + 1.79 + return (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) + 1.80 + NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit); 1.81 +} 1.82 + 1.83 +/** 1.84 + * Helper functions to process all the transformation function types. 1.85 + * 1.86 + * These take a matrix parameter to accumulate the current matrix. 1.87 + */ 1.88 + 1.89 +/* Helper function to process a matrix entry. */ 1.90 +static void 1.91 +ProcessMatrix(gfx3DMatrix& aMatrix, 1.92 + const nsCSSValue::Array* aData, 1.93 + nsStyleContext* aContext, 1.94 + nsPresContext* aPresContext, 1.95 + bool& aCanStoreInRuleTree, 1.96 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.97 +{ 1.98 + NS_PRECONDITION(aData->Count() == 7, "Invalid array!"); 1.99 + 1.100 + gfxMatrix result; 1.101 + 1.102 + /* Take the first four elements out of the array as floats and store 1.103 + * them. 1.104 + */ 1.105 + result.xx = aData->Item(1).GetFloatValue(); 1.106 + result.yx = aData->Item(2).GetFloatValue(); 1.107 + result.xy = aData->Item(3).GetFloatValue(); 1.108 + result.yy = aData->Item(4).GetFloatValue(); 1.109 + 1.110 + /* The last two elements have their length parts stored in aDelta 1.111 + * and their percent parts stored in aX[0] and aY[1]. 1.112 + */ 1.113 + result.x0 = ProcessTranslatePart(aData->Item(5), 1.114 + aContext, aPresContext, aCanStoreInRuleTree, 1.115 + aBounds.Width(), aAppUnitsPerMatrixUnit); 1.116 + result.y0 = ProcessTranslatePart(aData->Item(6), 1.117 + aContext, aPresContext, aCanStoreInRuleTree, 1.118 + aBounds.Height(), aAppUnitsPerMatrixUnit); 1.119 + 1.120 + aMatrix.PreMultiply(result); 1.121 +} 1.122 + 1.123 +static void 1.124 +ProcessMatrix3D(gfx3DMatrix& aMatrix, 1.125 + const nsCSSValue::Array* aData, 1.126 + nsStyleContext* aContext, 1.127 + nsPresContext* aPresContext, 1.128 + bool& aCanStoreInRuleTree, 1.129 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.130 +{ 1.131 + NS_PRECONDITION(aData->Count() == 17, "Invalid array!"); 1.132 + 1.133 + gfx3DMatrix temp; 1.134 + 1.135 + temp._11 = aData->Item(1).GetFloatValue(); 1.136 + temp._12 = aData->Item(2).GetFloatValue(); 1.137 + temp._13 = aData->Item(3).GetFloatValue(); 1.138 + temp._14 = aData->Item(4).GetFloatValue(); 1.139 + temp._21 = aData->Item(5).GetFloatValue(); 1.140 + temp._22 = aData->Item(6).GetFloatValue(); 1.141 + temp._23 = aData->Item(7).GetFloatValue(); 1.142 + temp._24 = aData->Item(8).GetFloatValue(); 1.143 + temp._31 = aData->Item(9).GetFloatValue(); 1.144 + temp._32 = aData->Item(10).GetFloatValue(); 1.145 + temp._33 = aData->Item(11).GetFloatValue(); 1.146 + temp._34 = aData->Item(12).GetFloatValue(); 1.147 + temp._44 = aData->Item(16).GetFloatValue(); 1.148 + 1.149 + temp._41 = ProcessTranslatePart(aData->Item(13), 1.150 + aContext, aPresContext, aCanStoreInRuleTree, 1.151 + aBounds.Width(), aAppUnitsPerMatrixUnit); 1.152 + temp._42 = ProcessTranslatePart(aData->Item(14), 1.153 + aContext, aPresContext, aCanStoreInRuleTree, 1.154 + aBounds.Height(), aAppUnitsPerMatrixUnit); 1.155 + temp._43 = ProcessTranslatePart(aData->Item(15), 1.156 + aContext, aPresContext, aCanStoreInRuleTree, 1.157 + aBounds.Height(), aAppUnitsPerMatrixUnit); 1.158 + 1.159 + aMatrix.PreMultiply(temp); 1.160 +} 1.161 + 1.162 +/* Helper function to process two matrices that we need to interpolate between */ 1.163 +void 1.164 +ProcessInterpolateMatrix(gfx3DMatrix& aMatrix, 1.165 + const nsCSSValue::Array* aData, 1.166 + nsStyleContext* aContext, 1.167 + nsPresContext* aPresContext, 1.168 + bool& aCanStoreInRuleTree, 1.169 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.170 +{ 1.171 + NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); 1.172 + 1.173 + gfx3DMatrix matrix1, matrix2; 1.174 + if (aData->Item(1).GetUnit() == eCSSUnit_List) { 1.175 + matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(), 1.176 + aContext, aPresContext, 1.177 + aCanStoreInRuleTree, 1.178 + aBounds, aAppUnitsPerMatrixUnit); 1.179 + } 1.180 + if (aData->Item(2).GetUnit() == eCSSUnit_List) { 1.181 + matrix2 = ReadTransforms(aData->Item(2).GetListValue(), 1.182 + aContext, aPresContext, 1.183 + aCanStoreInRuleTree, 1.184 + aBounds, aAppUnitsPerMatrixUnit); 1.185 + } 1.186 + double progress = aData->Item(3).GetPercentValue(); 1.187 + 1.188 + aMatrix = nsStyleAnimation::InterpolateTransformMatrix(matrix1, matrix2, progress) * aMatrix; 1.189 +} 1.190 + 1.191 +/* Helper function to process a translatex function. */ 1.192 +static void 1.193 +ProcessTranslateX(gfx3DMatrix& aMatrix, 1.194 + const nsCSSValue::Array* aData, 1.195 + nsStyleContext* aContext, 1.196 + nsPresContext* aPresContext, 1.197 + bool& aCanStoreInRuleTree, 1.198 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.199 +{ 1.200 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.201 + 1.202 + gfxPoint3D temp; 1.203 + 1.204 + temp.x = ProcessTranslatePart(aData->Item(1), 1.205 + aContext, aPresContext, aCanStoreInRuleTree, 1.206 + aBounds.Width(), aAppUnitsPerMatrixUnit); 1.207 + aMatrix.Translate(temp); 1.208 +} 1.209 + 1.210 +/* Helper function to process a translatey function. */ 1.211 +static void 1.212 +ProcessTranslateY(gfx3DMatrix& aMatrix, 1.213 + const nsCSSValue::Array* aData, 1.214 + nsStyleContext* aContext, 1.215 + nsPresContext* aPresContext, 1.216 + bool& aCanStoreInRuleTree, 1.217 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.218 +{ 1.219 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.220 + 1.221 + gfxPoint3D temp; 1.222 + 1.223 + temp.y = ProcessTranslatePart(aData->Item(1), 1.224 + aContext, aPresContext, aCanStoreInRuleTree, 1.225 + aBounds.Height(), aAppUnitsPerMatrixUnit); 1.226 + aMatrix.Translate(temp); 1.227 +} 1.228 + 1.229 +static void 1.230 +ProcessTranslateZ(gfx3DMatrix& aMatrix, 1.231 + const nsCSSValue::Array* aData, 1.232 + nsStyleContext* aContext, 1.233 + nsPresContext* aPresContext, 1.234 + bool& aCanStoreInRuleTree, 1.235 + float aAppUnitsPerMatrixUnit) 1.236 +{ 1.237 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.238 + 1.239 + gfxPoint3D temp; 1.240 + 1.241 + temp.z = ProcessTranslatePart(aData->Item(1), 1.242 + aContext, aPresContext, aCanStoreInRuleTree, 1.243 + 0, aAppUnitsPerMatrixUnit); 1.244 + aMatrix.Translate(temp); 1.245 +} 1.246 + 1.247 +/* Helper function to process a translate function. */ 1.248 +static void 1.249 +ProcessTranslate(gfx3DMatrix& aMatrix, 1.250 + const nsCSSValue::Array* aData, 1.251 + nsStyleContext* aContext, 1.252 + nsPresContext* aPresContext, 1.253 + bool& aCanStoreInRuleTree, 1.254 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.255 +{ 1.256 + NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!"); 1.257 + 1.258 + gfxPoint3D temp; 1.259 + 1.260 + temp.x = ProcessTranslatePart(aData->Item(1), 1.261 + aContext, aPresContext, aCanStoreInRuleTree, 1.262 + aBounds.Width(), aAppUnitsPerMatrixUnit); 1.263 + 1.264 + /* If we read in a Y component, set it appropriately */ 1.265 + if (aData->Count() == 3) { 1.266 + temp.y = ProcessTranslatePart(aData->Item(2), 1.267 + aContext, aPresContext, aCanStoreInRuleTree, 1.268 + aBounds.Height(), aAppUnitsPerMatrixUnit); 1.269 + } 1.270 + aMatrix.Translate(temp); 1.271 +} 1.272 + 1.273 +static void 1.274 +ProcessTranslate3D(gfx3DMatrix& aMatrix, 1.275 + const nsCSSValue::Array* aData, 1.276 + nsStyleContext* aContext, 1.277 + nsPresContext* aPresContext, 1.278 + bool& aCanStoreInRuleTree, 1.279 + nsRect& aBounds, float aAppUnitsPerMatrixUnit) 1.280 +{ 1.281 + NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); 1.282 + 1.283 + gfxPoint3D temp; 1.284 + 1.285 + temp.x = ProcessTranslatePart(aData->Item(1), 1.286 + aContext, aPresContext, aCanStoreInRuleTree, 1.287 + aBounds.Width(), aAppUnitsPerMatrixUnit); 1.288 + 1.289 + temp.y = ProcessTranslatePart(aData->Item(2), 1.290 + aContext, aPresContext, aCanStoreInRuleTree, 1.291 + aBounds.Height(), aAppUnitsPerMatrixUnit); 1.292 + 1.293 + temp.z = ProcessTranslatePart(aData->Item(3), 1.294 + aContext, aPresContext, aCanStoreInRuleTree, 1.295 + 0, aAppUnitsPerMatrixUnit); 1.296 + 1.297 + aMatrix.Translate(temp); 1.298 +} 1.299 + 1.300 +/* Helper function to set up a scale matrix. */ 1.301 +static void 1.302 +ProcessScaleHelper(gfx3DMatrix& aMatrix, 1.303 + float aXScale, 1.304 + float aYScale, 1.305 + float aZScale) 1.306 +{ 1.307 + aMatrix.Scale(aXScale, aYScale, aZScale); 1.308 +} 1.309 + 1.310 +/* Process a scalex function. */ 1.311 +static void 1.312 +ProcessScaleX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.313 +{ 1.314 + NS_PRECONDITION(aData->Count() == 2, "Bad array!"); 1.315 + ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), 1.0f, 1.0f); 1.316 +} 1.317 + 1.318 +/* Process a scaley function. */ 1.319 +static void 1.320 +ProcessScaleY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.321 +{ 1.322 + NS_PRECONDITION(aData->Count() == 2, "Bad array!"); 1.323 + ProcessScaleHelper(aMatrix, 1.0f, aData->Item(1).GetFloatValue(), 1.0f); 1.324 +} 1.325 + 1.326 +static void 1.327 +ProcessScaleZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.328 +{ 1.329 + NS_PRECONDITION(aData->Count() == 2, "Bad array!"); 1.330 + ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aData->Item(1).GetFloatValue()); 1.331 +} 1.332 + 1.333 +static void 1.334 +ProcessScale3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.335 +{ 1.336 + NS_PRECONDITION(aData->Count() == 4, "Bad array!"); 1.337 + ProcessScaleHelper(aMatrix, 1.338 + aData->Item(1).GetFloatValue(), 1.339 + aData->Item(2).GetFloatValue(), 1.340 + aData->Item(3).GetFloatValue()); 1.341 +} 1.342 + 1.343 +/* Process a scale function. */ 1.344 +static void 1.345 +ProcessScale(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.346 +{ 1.347 + NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); 1.348 + /* We either have one element or two. If we have one, it's for both X and Y. 1.349 + * Otherwise it's one for each. 1.350 + */ 1.351 + const nsCSSValue& scaleX = aData->Item(1); 1.352 + const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX : 1.353 + aData->Item(2)); 1.354 + 1.355 + ProcessScaleHelper(aMatrix, 1.356 + scaleX.GetFloatValue(), 1.357 + scaleY.GetFloatValue(), 1.358 + 1.0f); 1.359 +} 1.360 + 1.361 +/* Helper function that, given a set of angles, constructs the appropriate 1.362 + * skew matrix. 1.363 + */ 1.364 +static void 1.365 +ProcessSkewHelper(gfx3DMatrix& aMatrix, double aXAngle, double aYAngle) 1.366 +{ 1.367 + aMatrix.SkewXY(aXAngle, aYAngle); 1.368 +} 1.369 + 1.370 +/* Function that converts a skewx transform into a matrix. */ 1.371 +static void 1.372 +ProcessSkewX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.373 +{ 1.374 + NS_ASSERTION(aData->Count() == 2, "Bad array!"); 1.375 + ProcessSkewHelper(aMatrix, aData->Item(1).GetAngleValueInRadians(), 0.0); 1.376 +} 1.377 + 1.378 +/* Function that converts a skewy transform into a matrix. */ 1.379 +static void 1.380 +ProcessSkewY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.381 +{ 1.382 + NS_ASSERTION(aData->Count() == 2, "Bad array!"); 1.383 + ProcessSkewHelper(aMatrix, 0.0, aData->Item(1).GetAngleValueInRadians()); 1.384 +} 1.385 + 1.386 +/* Function that converts a skew transform into a matrix. */ 1.387 +static void 1.388 +ProcessSkew(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.389 +{ 1.390 + NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); 1.391 + 1.392 + double xSkew = aData->Item(1).GetAngleValueInRadians(); 1.393 + double ySkew = (aData->Count() == 2 1.394 + ? 0.0 : aData->Item(2).GetAngleValueInRadians()); 1.395 + 1.396 + ProcessSkewHelper(aMatrix, xSkew, ySkew); 1.397 +} 1.398 + 1.399 +/* Function that converts a rotate transform into a matrix. */ 1.400 +static void 1.401 +ProcessRotateZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.402 +{ 1.403 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.404 + double theta = aData->Item(1).GetAngleValueInRadians(); 1.405 + aMatrix.RotateZ(theta); 1.406 +} 1.407 + 1.408 +static void 1.409 +ProcessRotateX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.410 +{ 1.411 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.412 + double theta = aData->Item(1).GetAngleValueInRadians(); 1.413 + aMatrix.RotateX(theta); 1.414 +} 1.415 + 1.416 +static void 1.417 +ProcessRotateY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.418 +{ 1.419 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.420 + double theta = aData->Item(1).GetAngleValueInRadians(); 1.421 + aMatrix.RotateY(theta); 1.422 +} 1.423 + 1.424 +static void 1.425 +ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) 1.426 +{ 1.427 + NS_PRECONDITION(aData->Count() == 5, "Invalid array!"); 1.428 + 1.429 + /* We want our matrix to look like this: 1.430 + * | 1 + (1-cos(angle))*(x*x-1) -z*sin(angle)+(1-cos(angle))*x*y y*sin(angle)+(1-cos(angle))*x*z 0 | 1.431 + * | z*sin(angle)+(1-cos(angle))*x*y 1 + (1-cos(angle))*(y*y-1) -x*sin(angle)+(1-cos(angle))*y*z 0 | 1.432 + * | -y*sin(angle)+(1-cos(angle))*x*z x*sin(angle)+(1-cos(angle))*y*z 1 + (1-cos(angle))*(z*z-1) 0 | 1.433 + * | 0 0 0 1 | 1.434 + * (see http://www.w3.org/TR/css3-3d-transforms/#transform-functions) 1.435 + */ 1.436 + 1.437 + /* The current spec specifies a matrix that rotates in the wrong direction. For now we just negate 1.438 + * the angle provided to get the correct rotation direction until the spec is updated. 1.439 + * See bug 704468. 1.440 + */ 1.441 + double theta = -aData->Item(4).GetAngleValueInRadians(); 1.442 + float cosTheta = FlushToZero(cos(theta)); 1.443 + float sinTheta = FlushToZero(sin(theta)); 1.444 + 1.445 + float x = aData->Item(1).GetFloatValue(); 1.446 + float y = aData->Item(2).GetFloatValue(); 1.447 + float z = aData->Item(3).GetFloatValue(); 1.448 + 1.449 + /* Normalize [x,y,z] */ 1.450 + float length = sqrt(x*x + y*y + z*z); 1.451 + if (length == 0.0) { 1.452 + return; 1.453 + } 1.454 + x /= length; 1.455 + y /= length; 1.456 + z /= length; 1.457 + 1.458 + gfx3DMatrix temp; 1.459 + 1.460 + /* Create our matrix */ 1.461 + temp._11 = 1 + (1 - cosTheta) * (x * x - 1); 1.462 + temp._12 = -z * sinTheta + (1 - cosTheta) * x * y; 1.463 + temp._13 = y * sinTheta + (1 - cosTheta) * x * z; 1.464 + temp._14 = 0.0f; 1.465 + temp._21 = z * sinTheta + (1 - cosTheta) * x * y; 1.466 + temp._22 = 1 + (1 - cosTheta) * (y * y - 1); 1.467 + temp._23 = -x * sinTheta + (1 - cosTheta) * y * z; 1.468 + temp._24 = 0.0f; 1.469 + temp._31 = -y * sinTheta + (1 - cosTheta) * x * z; 1.470 + temp._32 = x * sinTheta + (1 - cosTheta) * y * z; 1.471 + temp._33 = 1 + (1 - cosTheta) * (z * z - 1); 1.472 + temp._34 = 0.0f; 1.473 + temp._41 = 0.0f; 1.474 + temp._42 = 0.0f; 1.475 + temp._43 = 0.0f; 1.476 + temp._44 = 1.0f; 1.477 + 1.478 + aMatrix = temp * aMatrix; 1.479 +} 1.480 + 1.481 +static void 1.482 +ProcessPerspective(gfx3DMatrix& aMatrix, 1.483 + const nsCSSValue::Array* aData, 1.484 + nsStyleContext *aContext, 1.485 + nsPresContext *aPresContext, 1.486 + bool &aCanStoreInRuleTree, 1.487 + float aAppUnitsPerMatrixUnit) 1.488 +{ 1.489 + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); 1.490 + 1.491 + float depth = ProcessTranslatePart(aData->Item(1), aContext, 1.492 + aPresContext, aCanStoreInRuleTree, 1.493 + 0, aAppUnitsPerMatrixUnit); 1.494 + aMatrix.Perspective(depth); 1.495 +} 1.496 + 1.497 + 1.498 +/** 1.499 + * SetToTransformFunction is essentially a giant switch statement that fans 1.500 + * out to many smaller helper functions. 1.501 + */ 1.502 +static void 1.503 +MatrixForTransformFunction(gfx3DMatrix& aMatrix, 1.504 + const nsCSSValue::Array * aData, 1.505 + nsStyleContext* aContext, 1.506 + nsPresContext* aPresContext, 1.507 + bool& aCanStoreInRuleTree, 1.508 + nsRect& aBounds, 1.509 + float aAppUnitsPerMatrixUnit) 1.510 +{ 1.511 + NS_PRECONDITION(aData, "Why did you want to get data from a null array?"); 1.512 + // It's OK if aContext and aPresContext are null if the caller already 1.513 + // knows that all length units have been converted to pixels (as 1.514 + // nsStyleAnimation does). 1.515 + 1.516 + 1.517 + /* Get the keyword for the transform. */ 1.518 + switch (TransformFunctionOf(aData)) { 1.519 + case eCSSKeyword_translatex: 1.520 + ProcessTranslateX(aMatrix, aData, aContext, aPresContext, 1.521 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.522 + break; 1.523 + case eCSSKeyword_translatey: 1.524 + ProcessTranslateY(aMatrix, aData, aContext, aPresContext, 1.525 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.526 + break; 1.527 + case eCSSKeyword_translatez: 1.528 + ProcessTranslateZ(aMatrix, aData, aContext, aPresContext, 1.529 + aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); 1.530 + break; 1.531 + case eCSSKeyword_translate: 1.532 + ProcessTranslate(aMatrix, aData, aContext, aPresContext, 1.533 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.534 + break; 1.535 + case eCSSKeyword_translate3d: 1.536 + ProcessTranslate3D(aMatrix, aData, aContext, aPresContext, 1.537 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.538 + break; 1.539 + case eCSSKeyword_scalex: 1.540 + ProcessScaleX(aMatrix, aData); 1.541 + break; 1.542 + case eCSSKeyword_scaley: 1.543 + ProcessScaleY(aMatrix, aData); 1.544 + break; 1.545 + case eCSSKeyword_scalez: 1.546 + ProcessScaleZ(aMatrix, aData); 1.547 + break; 1.548 + case eCSSKeyword_scale: 1.549 + ProcessScale(aMatrix, aData); 1.550 + break; 1.551 + case eCSSKeyword_scale3d: 1.552 + ProcessScale3D(aMatrix, aData); 1.553 + break; 1.554 + case eCSSKeyword_skewx: 1.555 + ProcessSkewX(aMatrix, aData); 1.556 + break; 1.557 + case eCSSKeyword_skewy: 1.558 + ProcessSkewY(aMatrix, aData); 1.559 + break; 1.560 + case eCSSKeyword_skew: 1.561 + ProcessSkew(aMatrix, aData); 1.562 + break; 1.563 + case eCSSKeyword_rotatex: 1.564 + ProcessRotateX(aMatrix, aData); 1.565 + break; 1.566 + case eCSSKeyword_rotatey: 1.567 + ProcessRotateY(aMatrix, aData); 1.568 + break; 1.569 + case eCSSKeyword_rotatez: 1.570 + case eCSSKeyword_rotate: 1.571 + ProcessRotateZ(aMatrix, aData); 1.572 + break; 1.573 + case eCSSKeyword_rotate3d: 1.574 + ProcessRotate3D(aMatrix, aData); 1.575 + break; 1.576 + case eCSSKeyword_matrix: 1.577 + ProcessMatrix(aMatrix, aData, aContext, aPresContext, 1.578 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.579 + break; 1.580 + case eCSSKeyword_matrix3d: 1.581 + ProcessMatrix3D(aMatrix, aData, aContext, aPresContext, 1.582 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.583 + break; 1.584 + case eCSSKeyword_interpolatematrix: 1.585 + ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext, 1.586 + aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); 1.587 + break; 1.588 + case eCSSKeyword_perspective: 1.589 + ProcessPerspective(aMatrix, aData, aContext, aPresContext, 1.590 + aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); 1.591 + break; 1.592 + default: 1.593 + NS_NOTREACHED("Unknown transform function!"); 1.594 + } 1.595 +} 1.596 + 1.597 +/** 1.598 + * Return the transform function, as an nsCSSKeyword, for the given 1.599 + * nsCSSValue::Array from a transform list. 1.600 + */ 1.601 +nsCSSKeyword 1.602 +TransformFunctionOf(const nsCSSValue::Array* aData) 1.603 +{ 1.604 + MOZ_ASSERT(aData->Item(0).GetUnit() == eCSSUnit_Enumerated); 1.605 + return aData->Item(0).GetKeywordValue(); 1.606 +} 1.607 + 1.608 +gfx3DMatrix 1.609 +ReadTransforms(const nsCSSValueList* aList, 1.610 + nsStyleContext* aContext, 1.611 + nsPresContext* aPresContext, 1.612 + bool &aCanStoreInRuleTree, 1.613 + nsRect& aBounds, 1.614 + float aAppUnitsPerMatrixUnit) 1.615 +{ 1.616 + gfx3DMatrix result; 1.617 + 1.618 + for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) { 1.619 + const nsCSSValue &currElem = curr->mValue; 1.620 + NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function, 1.621 + "Stream should consist solely of functions!"); 1.622 + NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1, 1.623 + "Incoming function is too short!"); 1.624 + 1.625 + /* Read in a single transform matrix. */ 1.626 + MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext, 1.627 + aPresContext, aCanStoreInRuleTree, 1.628 + aBounds, aAppUnitsPerMatrixUnit); 1.629 + } 1.630 + 1.631 + return result; 1.632 +} 1.633 + 1.634 +} // namespace nsStyleTransformMatrix