layout/style/nsStyleTransformMatrix.cpp

changeset 0
6474c204b198
     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

mercurial