Bug 505115 - Part 6 - Implement the 3d -moz-transform functions. r=dbaron
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 03 Aug 2011 15:04:19 +1200
changeset 73733 ba5eb1cd42f3881788740a4e5464c3547944e818
parent 73732 29232fea6e191c93c10e17d838faf616146b1b8c
child 73734 e7dc1c09ae248bc50ac98c2502ceba58d6c17fc9
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersdbaron
bugs505115
milestone8.0a1
Bug 505115 - Part 6 - Implement the 3d -moz-transform functions. r=dbaron
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/style/nsCSSKeywordList.h
layout/style/nsCSSParser.cpp
layout/style/nsStyleTransformMatrix.cpp
layout/style/nsStyleTransformMatrix.h
modules/libpref/src/init/all.js
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -102,16 +102,18 @@
 #include "nsTextFrame.h"
 #include "nsFontFaceList.h"
 
 #include "nsSVGUtils.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGForeignObjectFrame.h"
 #include "nsSVGOuterSVGFrame.h"
 
+#include "mozilla/Preferences.h"
+
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 namespace css = mozilla::css;
 
@@ -134,16 +136,32 @@ static ContentMap& GetContentMap() {
     nsresult rv =
 #endif
     sContentMap->Init();
     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Could not initialize map.");
   }
   return *sContentMap;
 }
 
+
+PRBool
+nsLayoutUtils::Are3DTransformsEnabled()
+{
+  static PRBool s3DTransformsEnabled;
+  static PRBool s3DTransformPrefCached = PR_FALSE;
+
+  if (!s3DTransformPrefCached) {
+    s3DTransformPrefCached = PR_TRUE;
+    mozilla::Preferences::AddBoolVarCache(&s3DTransformsEnabled, 
+                                          "layout.3d-transforms.enabled");
+  }
+
+  return s3DTransformsEnabled;
+}
+
 static void DestroyViewID(void* aObject, nsIAtom* aPropertyName,
                           void* aPropertyValue, void* aData)
 {
   ViewID* id = static_cast<ViewID*>(aPropertyValue);
   GetContentMap().Remove(*id);
   delete id;
 }
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1383,16 +1383,21 @@ public:
    * entire text is to be considered.
    */
   static nsresult GetFontFacesForText(nsIFrame* aFrame,
                                       PRInt32 aStartOffset,
                                       PRInt32 aEndOffset,
                                       PRBool aFollowContinuations,
                                       nsFontFaceList* aFontFaceList);
 
+  /**
+   * Checks if CSS 3D transforms are currently enabled.
+   */
+  static PRBool Are3DTransformsEnabled();
+
   static void Shutdown();
 
 #ifdef DEBUG
   /**
    * Assert that there are no duplicate continuations of the same frame
    * within aFrameList.  Optimize the tests by assuming that all frames
    * in aFrameList have parent aContainer.
    */
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -328,16 +328,17 @@ CSS_KEY(lower-alpha, lower_alpha)
 CSS_KEY(lower-greek, lower_greek)
 CSS_KEY(lower-latin, lower_latin)
 CSS_KEY(lower-roman, lower_roman)
 CSS_KEY(lowercase, lowercase)
 CSS_KEY(ltr, ltr)
 CSS_KEY(manual, manual)
 CSS_KEY(margin-box, margin_box)
 CSS_KEY(matrix, matrix)
+CSS_KEY(matrix3d, matrix3d)
 CSS_KEY(medium, medium)
 CSS_KEY(menu, menu)
 CSS_KEY(menutext, menutext)
 CSS_KEY(message-box, message_box)
 CSS_KEY(middle, middle)
 CSS_KEY(mix, mix)
 CSS_KEY(mm, mm)
 CSS_KEY(move, move)
@@ -382,25 +383,31 @@ CSS_KEY(read-write, read_write)
 CSS_KEY(relative, relative)
 CSS_KEY(repeat, repeat)
 CSS_KEY(repeat-x, repeat_x)
 CSS_KEY(repeat-y, repeat_y)
 CSS_KEY(reverse, reverse)
 CSS_KEY(ridge, ridge)
 CSS_KEY(right, right)
 CSS_KEY(rotate, rotate)
+CSS_KEY(rotate3d, rotate3d)
+CSS_KEY(rotatex, rotatex)
+CSS_KEY(rotatey, rotatey)
+CSS_KEY(rotatez, rotatez)
 CSS_KEY(round, round)
 CSS_KEY(row-resize, row_resize)
 CSS_KEY(rtl, rtl)
 CSS_KEY(running, running)
 CSS_KEY(s, s)
 CSS_KEY(s-resize, s_resize)
 CSS_KEY(scale, scale)
+CSS_KEY(scale3d, scale3d)
 CSS_KEY(scalex, scalex)
 CSS_KEY(scaley, scaley)
+CSS_KEY(scalez, scalez)
 CSS_KEY(scroll, scroll)
 CSS_KEY(scrollbar, scrollbar)
 CSS_KEY(scrollbar-small, scrollbar_small)
 CSS_KEY(se-resize, se_resize)
 CSS_KEY(select-after, select_after)
 CSS_KEY(select-all, select_all)
 CSS_KEY(select-before, select_before)
 CSS_KEY(select-menu, select_menu)
@@ -448,18 +455,20 @@ CSS_KEY(threeddarkshadow, threeddarkshad
 CSS_KEY(threedface, threedface)
 CSS_KEY(threedhighlight, threedhighlight)
 CSS_KEY(threedlightshadow, threedlightshadow)
 CSS_KEY(threedshadow, threedshadow)
 CSS_KEY(toggle, toggle)
 CSS_KEY(top, top)
 CSS_KEY(top-outside, top_outside)
 CSS_KEY(translate, translate)
+CSS_KEY(translate3d, translate3d)
 CSS_KEY(translatex, translatex)
 CSS_KEY(translatey, translatey)
+CSS_KEY(translatez, translatez)
 CSS_KEY(transparent, transparent) // for nsComputedDOMStyle only
 CSS_KEY(tri-state, tri_state)
 CSS_KEY(ultra-condensed, ultra_condensed)
 CSS_KEY(ultra-expanded, ultra_expanded)
 CSS_KEY(underline, underline)
 CSS_KEY(upper-alpha, upper_alpha)
 CSS_KEY(upper-latin, upper_latin)
 CSS_KEY(upper-roman, upper_roman)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -82,16 +82,17 @@
 #include "math.h"
 #include "nsContentUtils.h"
 #include "nsDOMError.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "prlog.h"
 #include "CSSCalc.h"
 #include "nsMediaFeatures.h"
+#include "nsLayoutUtils.h"
 
 namespace css = mozilla::css;
 
 // Flags for ParseVariant method
 #define VARIANT_KEYWORD         0x000001  // K
 #define VARIANT_LENGTH          0x000002  // L
 #define VARIANT_PERCENT         0x000004  // P
 #define VARIANT_COLOR           0x000008  // C eCSSUnit_Color, eCSSUnit_Ident (e.g.  "red")
@@ -580,17 +581,17 @@ protected:
     NS_ASSERTION(aBool == PR_TRUE || aBool == PR_FALSE, "bad PRBool value");
     mParsingCompoundProperty = aBool;
   }
   PRBool IsParsingCompoundProperty(void) const {
     return mParsingCompoundProperty;
   }
 
   /* Functions for -moz-transform Parsing */
-  PRBool ParseSingleTransform(nsCSSValue& aValue);
+  PRBool ParseSingleTransform(nsCSSValue& aValue, PRBool& aIs3D);
   PRBool ParseFunction(const nsString &aFunction, const PRInt32 aAllowedTypes[],
                        PRUint16 aMinElems, PRUint16 aMaxElems,
                        nsCSSValue &aValue);
   PRBool ParseFunctionInternals(const PRInt32 aVariantMask[],
                                 PRUint16 aMinElems,
                                 PRUint16 aMaxElems,
                                 nsTArray<nsCSSValue>& aOutput);
 
@@ -7258,74 +7259,118 @@ CSSParserImpl::ParseFunction(const nsStr
  * @param aMinElems [out] The minimum number of elements to read.
  * @param aMaxElems [out] The maximum number of elements to read
  * @param aVariantMask [out] The variant mask to use during parsing
  * @return Whether the information was loaded successfully.
  */
 static PRBool GetFunctionParseInformation(nsCSSKeyword aToken,
                                           PRUint16 &aMinElems,
                                           PRUint16 &aMaxElems,
-                                          const PRInt32 *& aVariantMask)
+                                          const PRInt32 *& aVariantMask,
+                                          PRBool &aIs3D)
 {
 /* These types represent the common variant masks that will be used to
    * parse out the individual functions.  The order in the enumeration
    * must match the order in which the masks are declared.
    */
   enum { eLengthPercentCalc,
+         eLengthCalc,
          eTwoLengthPercentCalcs,
+         eTwoLengthPercentCalcsOneLengthCalc,
          eAngle,
          eTwoAngles,
          eNumber,
          eTwoNumbers,
+         eThreeNumbers,
+         eThreeNumbersOneAngle,
          eMatrix,
+         eMatrix3d,
          eNumVariantMasks };
-  static const PRInt32 kMaxElemsPerFunction = 6;
+  static const PRInt32 kMaxElemsPerFunction = 16;
   static const PRInt32 kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = {
     {VARIANT_TRANSFORM_LPCALC},
+    {VARIANT_LENGTH|VARIANT_CALC},
     {VARIANT_TRANSFORM_LPCALC, VARIANT_TRANSFORM_LPCALC},
+    {VARIANT_TRANSFORM_LPCALC, VARIANT_TRANSFORM_LPCALC, VARIANT_LENGTH|VARIANT_CALC},
     {VARIANT_ANGLE_OR_ZERO},
     {VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO},
     {VARIANT_NUMBER},
     {VARIANT_NUMBER, VARIANT_NUMBER},
+    {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER},
+    {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO},
     {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
-     VARIANT_TRANSFORM_LPCALC, VARIANT_TRANSFORM_LPCALC}};
+     VARIANT_TRANSFORM_LPCALC, VARIANT_TRANSFORM_LPCALC},
+    {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
+     VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
+     VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
+     VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}};
 
 #ifdef DEBUG
   static const PRUint8 kVariantMaskLengths[eNumVariantMasks] =
-    {1, 2, 1, 2, 1, 2, 6};
+    {1, 1, 2, 3, 1, 2, 1, 2, 3, 4, 6, 16};
 #endif
 
   PRInt32 variantIndex = eNumVariantMasks;
 
+  aIs3D = PR_FALSE;
+
   switch (aToken) {
   case eCSSKeyword_translatex:
   case eCSSKeyword_translatey:
     /* Exactly one length or percent. */
     variantIndex = eLengthPercentCalc;
     aMinElems = 1U;
     aMaxElems = 1U;
     break;
-  case eCSSKeyword_scalex:
-    /* Exactly one scale factor. */
-    variantIndex = eNumber;
+  case eCSSKeyword_translatez:
+    /* Exactly one length */
+    variantIndex = eLengthCalc;
     aMinElems = 1U;
     aMaxElems = 1U;
+    aIs3D = PR_TRUE;
     break;
+  case eCSSKeyword_translate3d:
+    /* Exactly two lengthds or percents and a number */
+    variantIndex = eTwoLengthPercentCalcsOneLengthCalc;
+    aMinElems = 3U;
+    aMaxElems = 3U;
+    aIs3D = PR_TRUE;
+    break;
+  case eCSSKeyword_scalez:
+    aIs3D = PR_TRUE;
+  case eCSSKeyword_scalex:
   case eCSSKeyword_scaley:
     /* Exactly one scale factor. */
     variantIndex = eNumber;
     aMinElems = 1U;
     aMaxElems = 1U;
     break;
+  case eCSSKeyword_scale3d:
+    /* Exactly three scale factors. */
+    variantIndex = eThreeNumbers;
+    aMinElems = 3U;
+    aMaxElems = 3U;
+    aIs3D = PR_TRUE;
+    break;
+  case eCSSKeyword_rotatex:
+  case eCSSKeyword_rotatey:
+    aIs3D = PR_TRUE;
   case eCSSKeyword_rotate:
+  case eCSSKeyword_rotatez:
     /* Exactly one angle. */
     variantIndex = eAngle;
     aMinElems = 1U;
     aMaxElems = 1U;
     break;
+  case eCSSKeyword_rotate3d:
+    variantIndex = eThreeNumbersOneAngle;
+    aMinElems = 4U;
+    aMaxElems = 4U;
+    aIs3D = PR_TRUE;
+    break;
   case eCSSKeyword_translate:
     /* One or two lengths or percents. */
     variantIndex = eTwoLengthPercentCalcs;
     aMinElems = 1U;
     aMaxElems = 2U;
     break;
   case eCSSKeyword_skew:
     /* Exactly one or two angles. */
@@ -7351,17 +7396,24 @@ static PRBool GetFunctionParseInformatio
     aMinElems = 1U;
     aMaxElems = 1U;
     break;
   case eCSSKeyword_matrix:
     /* Six values, which can be numbers, lengths, or percents. */
     variantIndex = eMatrix;
     aMinElems = 6U;
     aMaxElems = 6U;
-    break;    
+    break;
+  case eCSSKeyword_matrix3d:
+    /* 16 matrix values, all numbers */
+    variantIndex = eMatrix3d;
+    aMinElems = 16U;
+    aMaxElems = 16U;
+    aIs3D = PR_TRUE;
+    break;
   default:
     /* Oh dear, we didn't match.  Report an error. */
     return PR_FALSE;
   }
 
   NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!");
   NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!");
   NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!");
@@ -7377,30 +7429,32 @@ static PRBool GetFunctionParseInformatio
 
   return PR_TRUE;
 }
 
 /* Reads a single transform function from the tokenizer stream, reporting an
  * error if something goes wrong.
  */
 PRBool
-CSSParserImpl::ParseSingleTransform(nsCSSValue& aValue)
+CSSParserImpl::ParseSingleTransform(nsCSSValue& aValue, PRBool& aIs3D)
 {
   if (!GetToken(PR_TRUE))
     return PR_FALSE;
 
   if (mToken.mType != eCSSToken_Function) {
     UngetToken();
     return PR_FALSE;
   }
 
   const PRInt32* variantMask;
   PRUint16 minElems, maxElems;
-  if (!GetFunctionParseInformation(nsCSSKeywords::LookupKeyword(mToken.mIdent),
-                                   minElems, maxElems, variantMask))
+  nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
+
+  if (!GetFunctionParseInformation(keyword,
+                                   minElems, maxElems, variantMask, aIs3D))
     return PR_FALSE;
 
   return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue);
 }
 
 /* Parses a -moz-transform property list by continuously reading in properties
  * and constructing a matrix from it.
  */
@@ -7410,17 +7464,21 @@ PRBool CSSParserImpl::ParseMozTransform(
   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
     // 'inherit', 'initial', and 'none' must be alone
     if (!ExpectEndProperty()) {
       return PR_FALSE;
     }
   } else {
     nsCSSValueList* cur = value.SetListValue();
     for (;;) {
-      if (!ParseSingleTransform(cur->mValue)) {
+      PRBool is3D;
+      if (!ParseSingleTransform(cur->mValue, is3D)) {
+        return PR_FALSE;
+      }
+      if (is3D && !nsLayoutUtils::Are3DTransformsEnabled()) {
         return PR_FALSE;
       }
       if (CheckEndProperty()) {
         break;
       }
       cur->mNext = new nsCSSValueList;
       cur = cur->mNext;
     }
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -167,16 +167,42 @@ nsStyleTransformMatrix::ProcessMatrix(co
                        aBounds.Width(), aAppUnitsPerMatrixUnit);
   ProcessTranslatePart(result._42, aData->Item(6),
                        aContext, aPresContext, aCanStoreInRuleTree,
                        aBounds.Height(), aAppUnitsPerMatrixUnit);
 
   return result;
 }
 
+/*static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessMatrix3D(const nsCSSValue::Array* aData)
+{
+  NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
+
+  gfx3DMatrix temp;
+
+  temp._11 = aData->Item(1).GetFloatValue();
+  temp._12 = aData->Item(2).GetFloatValue();
+  temp._13 = aData->Item(3).GetFloatValue();
+  temp._14 = aData->Item(4).GetFloatValue();
+  temp._21 = aData->Item(5).GetFloatValue();
+  temp._22 = aData->Item(6).GetFloatValue();
+  temp._23 = aData->Item(7).GetFloatValue();
+  temp._24 = aData->Item(8).GetFloatValue();
+  temp._31 = aData->Item(9).GetFloatValue();
+  temp._32 = aData->Item(10).GetFloatValue();
+  temp._33 = aData->Item(11).GetFloatValue();
+  temp._34 = aData->Item(12).GetFloatValue();
+  temp._41 = aData->Item(13).GetFloatValue();
+  temp._42 = aData->Item(14).GetFloatValue();
+  temp._43 = aData->Item(15).GetFloatValue();
+  temp._44 = aData->Item(16).GetFloatValue();
+  return temp;
+}
+
 /* Helper function to process two matrices that we need to interpolate between */
 /* static */ gfx3DMatrix
 nsStyleTransformMatrix::ProcessInterpolateMatrix(const nsCSSValue::Array* aData,
                                                  nsStyleContext* aContext,
                                                  nsPresContext* aPresContext,
                                                  PRBool& aCanStoreInRuleTree,
                                                  nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
@@ -265,49 +291,84 @@ nsStyleTransformMatrix::ProcessTranslate
    * to the percent.
    */
   ProcessTranslatePart(temp._42, aData->Item(1),
                        aContext, aPresContext, aCanStoreInRuleTree,
                        aBounds.Height(), aAppUnitsPerMatrixUnit);
   return temp;
 }
 
+/* static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessTranslateZ(const nsCSSValue::Array* aData,
+                                          nsStyleContext* aContext,
+                                          nsPresContext* aPresContext,
+                                          PRBool& aCanStoreInRuleTree,
+                                          float aAppUnitsPerMatrixUnit)
+{
+  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
+
+  gfx3DMatrix temp;
+
+  ProcessTranslatePart(temp._43, aData->Item(1),
+                       aContext, aPresContext, aCanStoreInRuleTree,
+                       0, aAppUnitsPerMatrixUnit);
+  return temp;
+}
+
 /* Helper function to process a translate function. */
 /* static */ gfx3DMatrix
 nsStyleTransformMatrix::ProcessTranslate(const nsCSSValue::Array* aData,
                                          nsStyleContext* aContext,
                                          nsPresContext* aPresContext,
                                          PRBool& aCanStoreInRuleTree,
                                          nsRect& aBounds, float aAppUnitsPerMatrixUnit)
 {
   NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
 
   gfx3DMatrix temp;
 
-  /* There are several cases to consider.
-   * First, we might have one value, or we might have two.  If we have
-   * two, we need to consider both dX and dY components.
-   * Next, the values might be lengths, or they might be percents.  If they're
-   * percents, store them in the dX and dY components.  Otherwise, store them in
-   * the main matrix.
-   */
-
   ProcessTranslatePart(temp._41, aData->Item(1),
                        aContext, aPresContext, aCanStoreInRuleTree,
                        aBounds.Width(), aAppUnitsPerMatrixUnit);
 
   /* If we read in a Y component, set it appropriately */
   if (aData->Count() == 3) {
     ProcessTranslatePart(temp._42, aData->Item(2),
                          aContext, aPresContext, aCanStoreInRuleTree,
                          aBounds.Height(), aAppUnitsPerMatrixUnit);
   }
   return temp;
 }
 
+/* static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessTranslate3D(const nsCSSValue::Array* aData,
+                                           nsStyleContext* aContext,
+                                           nsPresContext* aPresContext,
+                                           PRBool& aCanStoreInRuleTree,
+                                           nsRect& aBounds, float aAppUnitsPerMatrixUnit)
+{
+  NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
+
+  gfx3DMatrix temp;
+
+  ProcessTranslatePart(temp._41, aData->Item(1),
+                       aContext, aPresContext, aCanStoreInRuleTree,
+                       aBounds.Width(), aAppUnitsPerMatrixUnit);
+
+  ProcessTranslatePart(temp._42, aData->Item(2),
+                       aContext, aPresContext, aCanStoreInRuleTree,
+                       aBounds.Height(), aAppUnitsPerMatrixUnit);
+
+  ProcessTranslatePart(temp._43, aData->Item(3),
+                       aContext, aPresContext, aCanStoreInRuleTree,
+                       0, aAppUnitsPerMatrixUnit);
+
+  return temp;
+}
+
 /* Helper function to set up a scale matrix. */
 /* static */ gfx3DMatrix
 nsStyleTransformMatrix::ProcessScaleHelper(float aXScale, float aYScale, float aZScale)
 {
   /* We want our matrix to look like this:
    * | dx  0   0 0 |
    * |  0 dy   0 0 |
    * |  0  0  dz 0 |
@@ -332,16 +393,32 @@ nsStyleTransformMatrix::ProcessScaleX(co
 /* Process a scaley function. */
 /* static */ gfx3DMatrix
 nsStyleTransformMatrix::ProcessScaleY(const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2, "Bad array!");
   return ProcessScaleHelper(1.0f, aData->Item(1).GetFloatValue(), 1.0f);
 }
 
+/* static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessScaleZ(const nsCSSValue::Array* aData)
+{
+  NS_PRECONDITION(aData->Count() == 2, "Bad array!");
+  return ProcessScaleHelper(1.0f, 1.0f, aData->Item(1).GetFloatValue());
+}
+
+/* static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessScale3D(const nsCSSValue::Array* aData)
+{
+  NS_PRECONDITION(aData->Count() == 4, "Bad array!");
+  return ProcessScaleHelper(aData->Item(1).GetFloatValue(),
+                            aData->Item(2).GetFloatValue(),
+                            aData->Item(3).GetFloatValue());
+}
+
 /* Process a scale function. */
 /* static */ gfx3DMatrix
 nsStyleTransformMatrix::ProcessScale(const nsCSSValue::Array* aData)
 {
   NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
   /* We either have one element or two.  If we have one, it's for both X and Y.
    * Otherwise it's one for each.
    */
@@ -424,16 +501,117 @@ nsStyleTransformMatrix::ProcessRotateZ(c
 
   temp._11 = cosTheta;
   temp._12 = sinTheta;
   temp._21 = -sinTheta;
   temp._22 = cosTheta;
   return temp;
 }
 
+/* static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessRotateX(const nsCSSValue::Array* aData)
+{
+  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
+
+  /* We want our matrix to look like this:
+   * | 1           0           0 0 |
+   * | 0  cos(theta)  sin(theta) 0 |
+   * | 0 -sin(theta)  cos(theta) 0 |
+   * | 0           0           0 1 |
+   * (see http://www.w3.org/TR/SVG/coords.html#RotationDefined)
+   */
+  double theta = aData->Item(1).GetAngleValueInRadians();
+  float cosTheta = FlushToZero(cos(theta));
+  float sinTheta = FlushToZero(sin(theta));
+
+  gfx3DMatrix temp;
+
+  temp._22 = cosTheta;
+  temp._23 = sinTheta;
+  temp._32 = -sinTheta;
+  temp._33 = cosTheta;
+  return temp;
+}
+
+/* static */ gfx3DMatrix 
+nsStyleTransformMatrix::ProcessRotateY(const nsCSSValue::Array* aData)
+{
+  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
+
+  /* We want our matrix to look like this:
+   * | cos(theta) 0 -sin(theta) 0 |
+   * |          0 1           0 0 |
+   * | sin(theta) 0  cos(theta) 0 |
+   * | 0          0           0 1 |
+   * (see http://www.w3.org/TR/SVG/coords.html#RotationDefined)
+   */
+  double theta = aData->Item(1).GetAngleValueInRadians();
+  float cosTheta = FlushToZero(cos(theta));
+  float sinTheta = FlushToZero(sin(theta));
+
+  gfx3DMatrix temp;
+
+  temp._11 = cosTheta;
+  temp._13 = -sinTheta;
+  temp._31 = sinTheta;
+  temp._33 = cosTheta;
+  return temp;
+}
+
+/* static */ gfx3DMatrix
+nsStyleTransformMatrix::ProcessRotate3D(const nsCSSValue::Array* aData)
+{
+  NS_PRECONDITION(aData->Count() == 5, "Invalid array!");
+
+  /* We want our matrix to look like this:
+   * |       1 + (1-cos(angle))*(x*x-1)   -z*sin(angle)+(1-cos(angle))*x*y   y*sin(angle)+(1-cos(angle))*x*z   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 |
+   * | -y*sin(angle)+(1-cos(angle))*x*z    x*sin(angle)+(1-cos(angle))*y*z        1 + (1-cos(angle))*(z*z-1)   0 |
+   * |                                0                                  0                                 0   1 |
+   * (see http://www.w3.org/TR/css3-3d-transforms/#transform-functions)
+   */
+  double theta = aData->Item(4).GetAngleValueInRadians();
+  float cosTheta = FlushToZero(cos(theta));
+  float sinTheta = FlushToZero(sin(theta));
+
+  float x = aData->Item(1).GetFloatValue();
+  float y = aData->Item(2).GetFloatValue();
+  float z = aData->Item(3).GetFloatValue();
+
+  /* Normalize [x,y,z] */
+  float length = sqrt(x*x + y*y + z*z);
+  if (length == 0.0) {
+    return gfx3DMatrix();
+  }
+  x /= length;
+  y /= length;
+  z /= length;
+
+  gfx3DMatrix temp;
+
+  /* Create our matrix */
+  temp._11 = 1 + (1 - cosTheta) * (x * x - 1);
+  temp._12 = -z * sinTheta + (1 - cosTheta) * x * y;
+  temp._13 = y * sinTheta + (1 - cosTheta) * x * z;
+  temp._14 = 0.0f;
+  temp._21 = z * sinTheta + (1 - cosTheta) * x * y;
+  temp._22 = 1 + (1 - cosTheta) * (y * y - 1);
+  temp._23 = -x * sinTheta + (1 - cosTheta) * y * z;
+  temp._24 = 0.0f;
+  temp._31 = -y * sinTheta + (1 - cosTheta) * x * z;
+  temp._32 = x * sinTheta + (1 - cosTheta) * y * z;
+  temp._33 = 1 + (1 - cosTheta) * (z * z - 1);
+  temp._34 = 0.0f;
+  temp._41 = 0.0f;
+  temp._42 = 0.0f;
+  temp._43 = 0.0f;
+  temp._44 = 1.0f;
+  return temp;
+}
+
 /**
  * Return the transform function, as an nsCSSKeyword, for the given
  * nsCSSValue::Array from a transform list.
  */
 /* static */ nsCSSKeyword
 nsStyleTransformMatrix::TransformFunctionOf(const nsCSSValue::Array* aData)
 {
   nsAutoString keyword;
@@ -462,36 +640,55 @@ nsStyleTransformMatrix::MatrixForTransfo
   /* Get the keyword for the transform. */
   switch (TransformFunctionOf(aData)) {
   case eCSSKeyword_translatex:
     return ProcessTranslateX(aData, aContext, aPresContext,
                              aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
   case eCSSKeyword_translatey:
     return ProcessTranslateY(aData, aContext, aPresContext,
                              aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+  case eCSSKeyword_translatez:
+    return ProcessTranslateZ(aData, aContext, aPresContext,
+                             aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
   case eCSSKeyword_translate:
     return ProcessTranslate(aData, aContext, aPresContext,
                             aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+  case eCSSKeyword_translate3d:
+    return ProcessTranslate3D(aData, aContext, aPresContext,
+                              aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
   case eCSSKeyword_scalex:
     return ProcessScaleX(aData);
   case eCSSKeyword_scaley:
     return ProcessScaleY(aData);
+  case eCSSKeyword_scalez:
+    return ProcessScaleZ(aData);
   case eCSSKeyword_scale:
-    return ProcessScale(aData);
+      return ProcessScale(aData);
+  case eCSSKeyword_scale3d:
+    return ProcessScale3D(aData);
   case eCSSKeyword_skewx:
     return ProcessSkewX(aData);
   case eCSSKeyword_skewy:
     return ProcessSkewY(aData);
   case eCSSKeyword_skew:
     return ProcessSkew(aData);
+  case eCSSKeyword_rotatex:
+    return ProcessRotateX(aData);
+  case eCSSKeyword_rotatey:
+    return ProcessRotateY(aData);
+  case eCSSKeyword_rotatez:
   case eCSSKeyword_rotate:
-    return ProcessRotateZ(aData);
+      return ProcessRotateZ(aData);
+  case eCSSKeyword_rotate3d:
+    return ProcessRotate3D(aData);
   case eCSSKeyword_matrix:
     return ProcessMatrix(aData, aContext, aPresContext,
                          aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
+  case eCSSKeyword_matrix3d:
+    return ProcessMatrix3D(aData);
   case eCSSKeyword_interpolatematrix:
     return ProcessInterpolateMatrix(aData, aContext, aPresContext,
                                     aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
   default:
     NS_NOTREACHED("Unknown transform function!");
   }
   return gfx3DMatrix();
 }
--- a/layout/style/nsStyleTransformMatrix.h
+++ b/layout/style/nsStyleTransformMatrix.h
@@ -100,40 +100,56 @@ class nsStyleTransformMatrix
  private:
   static gfx3DMatrix ProcessMatrix(const nsCSSValue::Array *aData,
                                    nsStyleContext *aContext,
                                    nsPresContext *aPresContext,
                                    PRBool &aCanStoreInRuleTree,
                                    nsRect& aBounds, float aAppUnitsPerMatrixUnit,
                                    PRBool *aPercentX = nsnull, 
                                    PRBool *aPercentY = nsnull);
+  static gfx3DMatrix ProcessMatrix3D(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessInterpolateMatrix(const nsCSSValue::Array *aData,
                                               nsStyleContext *aContext,
                                               nsPresContext *aPresContext,
                                               PRBool &aCanStoreInRuleTree,
                                               nsRect& aBounds, float aAppUnitsPerMatrixUnit);
   static gfx3DMatrix ProcessTranslateX(const nsCSSValue::Array *aData,
                                        nsStyleContext *aContext,
                                        nsPresContext *aPresContext,
                                        PRBool &aCanStoreInRuleTree,
                                        nsRect& aBounds, float aAppUnitsPerMatrixUnit);
   static gfx3DMatrix ProcessTranslateY(const nsCSSValue::Array *aData,
                                        nsStyleContext *aContext,
                                        nsPresContext *aPresContext,
                                        PRBool &aCanStoreInRuleTree,
                                        nsRect& aBounds, float aAppUnitsPerMatrixUnit);
+  static gfx3DMatrix ProcessTranslateZ(const nsCSSValue::Array *aData,
+                                       nsStyleContext *aContext,
+                                       nsPresContext *aPresContext,
+                                       PRBool &aCanStoreInRuleTree,
+                                       float aAppUnitsPerMatrixUnit);
   static gfx3DMatrix ProcessTranslate(const nsCSSValue::Array *aData,
                                       nsStyleContext *aContext,
                                       nsPresContext *aPresContext,
                                       PRBool &aCanStoreInRuleTree,
                                       nsRect& aBounds, float aAppUnitsPerMatrixUnit);
+  static gfx3DMatrix ProcessTranslate3D(const nsCSSValue::Array *aData,
+                                        nsStyleContext *aContext,
+                                        nsPresContext *aPresContext,
+                                        PRBool &aCanStoreInRuleTree,
+                                        nsRect& aBounds, float aAppUnitsPerMatrixUnit);
   static gfx3DMatrix ProcessScaleHelper(float aXScale, float aYScale, float aZScale);
   static gfx3DMatrix ProcessScaleX(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessScaleY(const nsCSSValue::Array *aData);
+  static gfx3DMatrix ProcessScaleZ(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessScale(const nsCSSValue::Array *aData);
+  static gfx3DMatrix ProcessScale3D(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessSkewHelper(double aXAngle, double aYAngle);
   static gfx3DMatrix ProcessSkewX(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessSkewY(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessSkew(const nsCSSValue::Array *aData);
+  static gfx3DMatrix ProcessRotateX(const nsCSSValue::Array *aData);
+  static gfx3DMatrix ProcessRotateY(const nsCSSValue::Array *aData);
   static gfx3DMatrix ProcessRotateZ(const nsCSSValue::Array *aData);
+  static gfx3DMatrix ProcessRotate3D(const nsCSSValue::Array *aData);
 };
 
 #endif
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3334,8 +3334,11 @@ pref("browser.history.maxStateObjectSize
 pref("xpinstall.whitelist.required", true);
 pref("extensions.alwaysUnpack", false);
 
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  32768);
 
 // Desktop Notification
 pref("notification.feature.enabled", false);
+
+//3D Transforms
+pref("layout.3d-transforms.enabled, false);