michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * A class used for intermediate representations of the -moz-transform property. michael@0: */ michael@0: michael@0: #include "nsStyleTransformMatrix.h" michael@0: #include "nsCSSValue.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsRuleNode.h" michael@0: #include "nsCSSKeywords.h" michael@0: #include "nsStyleAnimation.h" michael@0: #include "gfxMatrix.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: namespace nsStyleTransformMatrix { michael@0: michael@0: /* Note on floating point precision: The transform matrix is an array michael@0: * of single precision 'float's, and so are most of the input values michael@0: * we get from the style system, but intermediate calculations michael@0: * involving angles need to be done in 'double'. michael@0: */ michael@0: michael@0: /* Force small values to zero. We do this to avoid having sin(360deg) michael@0: * evaluate to a tiny but nonzero value. michael@0: */ michael@0: static double FlushToZero(double aVal) michael@0: { michael@0: if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON) michael@0: return 0.0f; michael@0: else michael@0: return aVal; michael@0: } michael@0: michael@0: float michael@0: ProcessTranslatePart(const nsCSSValue& aValue, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nscoord aSize, michael@0: float aAppUnitsPerMatrixUnit) michael@0: { michael@0: nscoord offset = 0; michael@0: float percent = 0.0f; michael@0: michael@0: if (aValue.GetUnit() == eCSSUnit_Percent) { michael@0: percent = aValue.GetPercentValue(); michael@0: } else if (aValue.GetUnit() == eCSSUnit_Pixel || michael@0: aValue.GetUnit() == eCSSUnit_Number) { michael@0: // Handle this here (even though nsRuleNode::CalcLength handles it michael@0: // fine) so that callers are allowed to pass a null style context michael@0: // and pres context to SetToTransformFunction if they know (as michael@0: // nsStyleAnimation does) that all lengths within the transform michael@0: // function have already been computed to pixels and percents. michael@0: // michael@0: // Raw numbers are treated as being pixels. michael@0: // michael@0: // Don't convert to aValue to AppUnits here to avoid precision issues. michael@0: return aValue.GetFloatValue() * michael@0: (float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit); michael@0: } else if (aValue.IsCalcUnit()) { michael@0: nsRuleNode::ComputedCalc result = michael@0: nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext, michael@0: aCanStoreInRuleTree); michael@0: percent = result.mPercent; michael@0: offset = result.mLength; michael@0: } else { michael@0: offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext, michael@0: aCanStoreInRuleTree); michael@0: } michael@0: michael@0: return (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) + michael@0: NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit); michael@0: } michael@0: michael@0: /** michael@0: * Helper functions to process all the transformation function types. michael@0: * michael@0: * These take a matrix parameter to accumulate the current matrix. michael@0: */ michael@0: michael@0: /* Helper function to process a matrix entry. */ michael@0: static void michael@0: ProcessMatrix(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 7, "Invalid array!"); michael@0: michael@0: gfxMatrix result; michael@0: michael@0: /* Take the first four elements out of the array as floats and store michael@0: * them. michael@0: */ michael@0: result.xx = aData->Item(1).GetFloatValue(); michael@0: result.yx = aData->Item(2).GetFloatValue(); michael@0: result.xy = aData->Item(3).GetFloatValue(); michael@0: result.yy = aData->Item(4).GetFloatValue(); michael@0: michael@0: /* The last two elements have their length parts stored in aDelta michael@0: * and their percent parts stored in aX[0] and aY[1]. michael@0: */ michael@0: result.x0 = ProcessTranslatePart(aData->Item(5), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Width(), aAppUnitsPerMatrixUnit); michael@0: result.y0 = ProcessTranslatePart(aData->Item(6), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Height(), aAppUnitsPerMatrixUnit); michael@0: michael@0: aMatrix.PreMultiply(result); michael@0: } michael@0: michael@0: static void michael@0: ProcessMatrix3D(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 17, "Invalid array!"); michael@0: michael@0: gfx3DMatrix temp; michael@0: michael@0: temp._11 = aData->Item(1).GetFloatValue(); michael@0: temp._12 = aData->Item(2).GetFloatValue(); michael@0: temp._13 = aData->Item(3).GetFloatValue(); michael@0: temp._14 = aData->Item(4).GetFloatValue(); michael@0: temp._21 = aData->Item(5).GetFloatValue(); michael@0: temp._22 = aData->Item(6).GetFloatValue(); michael@0: temp._23 = aData->Item(7).GetFloatValue(); michael@0: temp._24 = aData->Item(8).GetFloatValue(); michael@0: temp._31 = aData->Item(9).GetFloatValue(); michael@0: temp._32 = aData->Item(10).GetFloatValue(); michael@0: temp._33 = aData->Item(11).GetFloatValue(); michael@0: temp._34 = aData->Item(12).GetFloatValue(); michael@0: temp._44 = aData->Item(16).GetFloatValue(); michael@0: michael@0: temp._41 = ProcessTranslatePart(aData->Item(13), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Width(), aAppUnitsPerMatrixUnit); michael@0: temp._42 = ProcessTranslatePart(aData->Item(14), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Height(), aAppUnitsPerMatrixUnit); michael@0: temp._43 = ProcessTranslatePart(aData->Item(15), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Height(), aAppUnitsPerMatrixUnit); michael@0: michael@0: aMatrix.PreMultiply(temp); michael@0: } michael@0: michael@0: /* Helper function to process two matrices that we need to interpolate between */ michael@0: void michael@0: ProcessInterpolateMatrix(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); michael@0: michael@0: gfx3DMatrix matrix1, matrix2; michael@0: if (aData->Item(1).GetUnit() == eCSSUnit_List) { michael@0: matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(), michael@0: aContext, aPresContext, michael@0: aCanStoreInRuleTree, michael@0: aBounds, aAppUnitsPerMatrixUnit); michael@0: } michael@0: if (aData->Item(2).GetUnit() == eCSSUnit_List) { michael@0: matrix2 = ReadTransforms(aData->Item(2).GetListValue(), michael@0: aContext, aPresContext, michael@0: aCanStoreInRuleTree, michael@0: aBounds, aAppUnitsPerMatrixUnit); michael@0: } michael@0: double progress = aData->Item(3).GetPercentValue(); michael@0: michael@0: aMatrix = nsStyleAnimation::InterpolateTransformMatrix(matrix1, matrix2, progress) * aMatrix; michael@0: } michael@0: michael@0: /* Helper function to process a translatex function. */ michael@0: static void michael@0: ProcessTranslateX(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: michael@0: gfxPoint3D temp; michael@0: michael@0: temp.x = ProcessTranslatePart(aData->Item(1), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Width(), aAppUnitsPerMatrixUnit); michael@0: aMatrix.Translate(temp); michael@0: } michael@0: michael@0: /* Helper function to process a translatey function. */ michael@0: static void michael@0: ProcessTranslateY(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: michael@0: gfxPoint3D temp; michael@0: michael@0: temp.y = ProcessTranslatePart(aData->Item(1), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Height(), aAppUnitsPerMatrixUnit); michael@0: aMatrix.Translate(temp); michael@0: } michael@0: michael@0: static void michael@0: ProcessTranslateZ(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: michael@0: gfxPoint3D temp; michael@0: michael@0: temp.z = ProcessTranslatePart(aData->Item(1), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: 0, aAppUnitsPerMatrixUnit); michael@0: aMatrix.Translate(temp); michael@0: } michael@0: michael@0: /* Helper function to process a translate function. */ michael@0: static void michael@0: ProcessTranslate(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!"); michael@0: michael@0: gfxPoint3D temp; michael@0: michael@0: temp.x = ProcessTranslatePart(aData->Item(1), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Width(), aAppUnitsPerMatrixUnit); michael@0: michael@0: /* If we read in a Y component, set it appropriately */ michael@0: if (aData->Count() == 3) { michael@0: temp.y = ProcessTranslatePart(aData->Item(2), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Height(), aAppUnitsPerMatrixUnit); michael@0: } michael@0: aMatrix.Translate(temp); michael@0: } michael@0: michael@0: static void michael@0: ProcessTranslate3D(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 4, "Invalid array!"); michael@0: michael@0: gfxPoint3D temp; michael@0: michael@0: temp.x = ProcessTranslatePart(aData->Item(1), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Width(), aAppUnitsPerMatrixUnit); michael@0: michael@0: temp.y = ProcessTranslatePart(aData->Item(2), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: aBounds.Height(), aAppUnitsPerMatrixUnit); michael@0: michael@0: temp.z = ProcessTranslatePart(aData->Item(3), michael@0: aContext, aPresContext, aCanStoreInRuleTree, michael@0: 0, aAppUnitsPerMatrixUnit); michael@0: michael@0: aMatrix.Translate(temp); michael@0: } michael@0: michael@0: /* Helper function to set up a scale matrix. */ michael@0: static void michael@0: ProcessScaleHelper(gfx3DMatrix& aMatrix, michael@0: float aXScale, michael@0: float aYScale, michael@0: float aZScale) michael@0: { michael@0: aMatrix.Scale(aXScale, aYScale, aZScale); michael@0: } michael@0: michael@0: /* Process a scalex function. */ michael@0: static void michael@0: ProcessScaleX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Bad array!"); michael@0: ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), 1.0f, 1.0f); michael@0: } michael@0: michael@0: /* Process a scaley function. */ michael@0: static void michael@0: ProcessScaleY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Bad array!"); michael@0: ProcessScaleHelper(aMatrix, 1.0f, aData->Item(1).GetFloatValue(), 1.0f); michael@0: } michael@0: michael@0: static void michael@0: ProcessScaleZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Bad array!"); michael@0: ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aData->Item(1).GetFloatValue()); michael@0: } michael@0: michael@0: static void michael@0: ProcessScale3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 4, "Bad array!"); michael@0: ProcessScaleHelper(aMatrix, michael@0: aData->Item(1).GetFloatValue(), michael@0: aData->Item(2).GetFloatValue(), michael@0: aData->Item(3).GetFloatValue()); michael@0: } michael@0: michael@0: /* Process a scale function. */ michael@0: static void michael@0: ProcessScale(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); michael@0: /* We either have one element or two. If we have one, it's for both X and Y. michael@0: * Otherwise it's one for each. michael@0: */ michael@0: const nsCSSValue& scaleX = aData->Item(1); michael@0: const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX : michael@0: aData->Item(2)); michael@0: michael@0: ProcessScaleHelper(aMatrix, michael@0: scaleX.GetFloatValue(), michael@0: scaleY.GetFloatValue(), michael@0: 1.0f); michael@0: } michael@0: michael@0: /* Helper function that, given a set of angles, constructs the appropriate michael@0: * skew matrix. michael@0: */ michael@0: static void michael@0: ProcessSkewHelper(gfx3DMatrix& aMatrix, double aXAngle, double aYAngle) michael@0: { michael@0: aMatrix.SkewXY(aXAngle, aYAngle); michael@0: } michael@0: michael@0: /* Function that converts a skewx transform into a matrix. */ michael@0: static void michael@0: ProcessSkewX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_ASSERTION(aData->Count() == 2, "Bad array!"); michael@0: ProcessSkewHelper(aMatrix, aData->Item(1).GetAngleValueInRadians(), 0.0); michael@0: } michael@0: michael@0: /* Function that converts a skewy transform into a matrix. */ michael@0: static void michael@0: ProcessSkewY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_ASSERTION(aData->Count() == 2, "Bad array!"); michael@0: ProcessSkewHelper(aMatrix, 0.0, aData->Item(1).GetAngleValueInRadians()); michael@0: } michael@0: michael@0: /* Function that converts a skew transform into a matrix. */ michael@0: static void michael@0: ProcessSkew(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); michael@0: michael@0: double xSkew = aData->Item(1).GetAngleValueInRadians(); michael@0: double ySkew = (aData->Count() == 2 michael@0: ? 0.0 : aData->Item(2).GetAngleValueInRadians()); michael@0: michael@0: ProcessSkewHelper(aMatrix, xSkew, ySkew); michael@0: } michael@0: michael@0: /* Function that converts a rotate transform into a matrix. */ michael@0: static void michael@0: ProcessRotateZ(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: double theta = aData->Item(1).GetAngleValueInRadians(); michael@0: aMatrix.RotateZ(theta); michael@0: } michael@0: michael@0: static void michael@0: ProcessRotateX(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: double theta = aData->Item(1).GetAngleValueInRadians(); michael@0: aMatrix.RotateX(theta); michael@0: } michael@0: michael@0: static void michael@0: ProcessRotateY(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: double theta = aData->Item(1).GetAngleValueInRadians(); michael@0: aMatrix.RotateY(theta); michael@0: } michael@0: michael@0: static void michael@0: ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 5, "Invalid array!"); michael@0: michael@0: /* We want our matrix to look like this: michael@0: * | 1 + (1-cos(angle))*(x*x-1) -z*sin(angle)+(1-cos(angle))*x*y y*sin(angle)+(1-cos(angle))*x*z 0 | michael@0: * | z*sin(angle)+(1-cos(angle))*x*y 1 + (1-cos(angle))*(y*y-1) -x*sin(angle)+(1-cos(angle))*y*z 0 | michael@0: * | -y*sin(angle)+(1-cos(angle))*x*z x*sin(angle)+(1-cos(angle))*y*z 1 + (1-cos(angle))*(z*z-1) 0 | michael@0: * | 0 0 0 1 | michael@0: * (see http://www.w3.org/TR/css3-3d-transforms/#transform-functions) michael@0: */ michael@0: michael@0: /* The current spec specifies a matrix that rotates in the wrong direction. For now we just negate michael@0: * the angle provided to get the correct rotation direction until the spec is updated. michael@0: * See bug 704468. michael@0: */ michael@0: double theta = -aData->Item(4).GetAngleValueInRadians(); michael@0: float cosTheta = FlushToZero(cos(theta)); michael@0: float sinTheta = FlushToZero(sin(theta)); michael@0: michael@0: float x = aData->Item(1).GetFloatValue(); michael@0: float y = aData->Item(2).GetFloatValue(); michael@0: float z = aData->Item(3).GetFloatValue(); michael@0: michael@0: /* Normalize [x,y,z] */ michael@0: float length = sqrt(x*x + y*y + z*z); michael@0: if (length == 0.0) { michael@0: return; michael@0: } michael@0: x /= length; michael@0: y /= length; michael@0: z /= length; michael@0: michael@0: gfx3DMatrix temp; michael@0: michael@0: /* Create our matrix */ michael@0: temp._11 = 1 + (1 - cosTheta) * (x * x - 1); michael@0: temp._12 = -z * sinTheta + (1 - cosTheta) * x * y; michael@0: temp._13 = y * sinTheta + (1 - cosTheta) * x * z; michael@0: temp._14 = 0.0f; michael@0: temp._21 = z * sinTheta + (1 - cosTheta) * x * y; michael@0: temp._22 = 1 + (1 - cosTheta) * (y * y - 1); michael@0: temp._23 = -x * sinTheta + (1 - cosTheta) * y * z; michael@0: temp._24 = 0.0f; michael@0: temp._31 = -y * sinTheta + (1 - cosTheta) * x * z; michael@0: temp._32 = x * sinTheta + (1 - cosTheta) * y * z; michael@0: temp._33 = 1 + (1 - cosTheta) * (z * z - 1); michael@0: temp._34 = 0.0f; michael@0: temp._41 = 0.0f; michael@0: temp._42 = 0.0f; michael@0: temp._43 = 0.0f; michael@0: temp._44 = 1.0f; michael@0: michael@0: aMatrix = temp * aMatrix; michael@0: } michael@0: michael@0: static void michael@0: ProcessPerspective(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array* aData, michael@0: nsStyleContext *aContext, michael@0: nsPresContext *aPresContext, michael@0: bool &aCanStoreInRuleTree, michael@0: float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); michael@0: michael@0: float depth = ProcessTranslatePart(aData->Item(1), aContext, michael@0: aPresContext, aCanStoreInRuleTree, michael@0: 0, aAppUnitsPerMatrixUnit); michael@0: aMatrix.Perspective(depth); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * SetToTransformFunction is essentially a giant switch statement that fans michael@0: * out to many smaller helper functions. michael@0: */ michael@0: static void michael@0: MatrixForTransformFunction(gfx3DMatrix& aMatrix, michael@0: const nsCSSValue::Array * aData, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool& aCanStoreInRuleTree, michael@0: nsRect& aBounds, michael@0: float aAppUnitsPerMatrixUnit) michael@0: { michael@0: NS_PRECONDITION(aData, "Why did you want to get data from a null array?"); michael@0: // It's OK if aContext and aPresContext are null if the caller already michael@0: // knows that all length units have been converted to pixels (as michael@0: // nsStyleAnimation does). michael@0: michael@0: michael@0: /* Get the keyword for the transform. */ michael@0: switch (TransformFunctionOf(aData)) { michael@0: case eCSSKeyword_translatex: michael@0: ProcessTranslateX(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_translatey: michael@0: ProcessTranslateY(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_translatez: michael@0: ProcessTranslateZ(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_translate: michael@0: ProcessTranslate(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_translate3d: michael@0: ProcessTranslate3D(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_scalex: michael@0: ProcessScaleX(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_scaley: michael@0: ProcessScaleY(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_scalez: michael@0: ProcessScaleZ(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_scale: michael@0: ProcessScale(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_scale3d: michael@0: ProcessScale3D(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_skewx: michael@0: ProcessSkewX(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_skewy: michael@0: ProcessSkewY(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_skew: michael@0: ProcessSkew(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_rotatex: michael@0: ProcessRotateX(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_rotatey: michael@0: ProcessRotateY(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_rotatez: michael@0: case eCSSKeyword_rotate: michael@0: ProcessRotateZ(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_rotate3d: michael@0: ProcessRotate3D(aMatrix, aData); michael@0: break; michael@0: case eCSSKeyword_matrix: michael@0: ProcessMatrix(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_matrix3d: michael@0: ProcessMatrix3D(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_interpolatematrix: michael@0: ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: case eCSSKeyword_perspective: michael@0: ProcessPerspective(aMatrix, aData, aContext, aPresContext, michael@0: aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); michael@0: break; michael@0: default: michael@0: NS_NOTREACHED("Unknown transform function!"); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Return the transform function, as an nsCSSKeyword, for the given michael@0: * nsCSSValue::Array from a transform list. michael@0: */ michael@0: nsCSSKeyword michael@0: TransformFunctionOf(const nsCSSValue::Array* aData) michael@0: { michael@0: MOZ_ASSERT(aData->Item(0).GetUnit() == eCSSUnit_Enumerated); michael@0: return aData->Item(0).GetKeywordValue(); michael@0: } michael@0: michael@0: gfx3DMatrix michael@0: ReadTransforms(const nsCSSValueList* aList, michael@0: nsStyleContext* aContext, michael@0: nsPresContext* aPresContext, michael@0: bool &aCanStoreInRuleTree, michael@0: nsRect& aBounds, michael@0: float aAppUnitsPerMatrixUnit) michael@0: { michael@0: gfx3DMatrix result; michael@0: michael@0: for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) { michael@0: const nsCSSValue &currElem = curr->mValue; michael@0: NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function, michael@0: "Stream should consist solely of functions!"); michael@0: NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1, michael@0: "Incoming function is too short!"); michael@0: michael@0: /* Read in a single transform matrix. */ michael@0: MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext, michael@0: aPresContext, aCanStoreInRuleTree, michael@0: aBounds, aAppUnitsPerMatrixUnit); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: } // namespace nsStyleTransformMatrix