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 73731 ba5eb1cd42f3881788740a4e5464c3547944e818
parent 73730 29232fea6e191c93c10e17d838faf616146b1b8c
child 73732 e7dc1c09ae248bc50ac98c2502ceba58d6c17fc9
push id20911
push usermak77@bonardo.net
push dateWed, 03 Aug 2011 08:47:10 +0000
treeherdermozilla-central@c35c69e1ce99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs505115
milestone8.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);