/* Helper function to process a matrix entry. */
static void
ProcessMatrix(gfx3DMatrix& aMatrix,
              const nsCSSValue::Array* aData,
              nsStyleContext* aContext,
              nsPresContext* aPresContext,
              bool& aCanStoreInRuleTree,
              nsRect& aBounds)
{
  NS_PRECONDITION(aData->Count() == 7, "Invalid array!");

  gfxMatrix result;

  /* Take the first four elements out of the array as floats and store
   * them.
   */
  result._11 = aData->Item(1).GetFloatValue();
  result._12 = aData->Item(2).GetFloatValue();
  result._21 = aData->Item(3).GetFloatValue();
  result._22 = aData->Item(4).GetFloatValue();

  /* The last two elements have their length parts stored in aDelta
   * and their percent parts stored in aX[0] and aY[1].
   */
  result._31 = ProcessTranslatePart(aData->Item(5),
                                   aContext, aPresContext, aCanStoreInRuleTree,
                                   aBounds.Width());
  result._32 = ProcessTranslatePart(aData->Item(6),
                                   aContext, aPresContext, aCanStoreInRuleTree,
                                   aBounds.Height());

  aMatrix.PreMultiply(result);
}
/* Helper function to process a matrix entry. */
/* static */ gfx3DMatrix
nsStyleTransformMatrix::ProcessMatrix(const nsCSSValue::Array* aData,
                                      nsStyleContext* aContext,
                                      nsPresContext* aPresContext,
                                      PRBool& aCanStoreInRuleTree,
                                      nsRect& aBounds, float aAppUnitsPerMatrixUnit,
                                      PRBool *aPercentX, PRBool *aPercentY)
{
  NS_PRECONDITION(aData->Count() == 7, "Invalid array!");

  gfx3DMatrix result;

  /* Take the first four elements out of the array as floats and store
   * them.
   */
  result._11 = aData->Item(1).GetFloatValue();
  result._12 = aData->Item(2).GetFloatValue();
  result._21 = aData->Item(3).GetFloatValue();
  result._22 = aData->Item(4).GetFloatValue();

  /* The last two elements have their length parts stored in aDelta
   * and their percent parts stored in aX[0] and aY[1].
   */
  ProcessTranslatePart(result._41, aData->Item(5),
                       aContext, aPresContext, aCanStoreInRuleTree,
                       aBounds.Width(), aAppUnitsPerMatrixUnit);
  ProcessTranslatePart(result._42, aData->Item(6),
                       aContext, aPresContext, aCanStoreInRuleTree,
                       aBounds.Height(), aAppUnitsPerMatrixUnit);

  return result;
}
/* Helper function to process a matrix entry. */
static void
ProcessMatrix(Matrix4x4& aMatrix,
              const nsCSSValue::Array* aData,
              nsStyleContext* aContext,
              nsPresContext* aPresContext,
              RuleNodeCacheConditions& aConditions,
              TransformReferenceBox& aRefBox)
{
  NS_PRECONDITION(aData->Count() == 7, "Invalid array!");

  gfxMatrix result;

  /* Take the first four elements out of the array as floats and store
   * them.
   */
  result._11 = aData->Item(1).GetFloatValue();
  result._12 = aData->Item(2).GetFloatValue();
  result._21 = aData->Item(3).GetFloatValue();
  result._22 = aData->Item(4).GetFloatValue();

  /* The last two elements have their length parts stored in aDelta
   * and their percent parts stored in aX[0] and aY[1].
   */
  result._31 = ProcessTranslatePart(aData->Item(5),
                                   aContext, aPresContext, aConditions,
                                   &aRefBox, &TransformReferenceBox::Width);
  result._32 = ProcessTranslatePart(aData->Item(6),
                                   aContext, aPresContext, aConditions,
                                   &aRefBox, &TransformReferenceBox::Height);

  aMatrix = result * aMatrix;
}
static void
ProcessTranslate3D(gfx3DMatrix& aMatrix,
                   const nsCSSValue::Array* aData,
                   nsStyleContext* aContext,
                   nsPresContext* aPresContext,
                   bool& aCanStoreInRuleTree,
                   nsRect& aBounds)
{
  NS_PRECONDITION(aData->Count() == 4, "Invalid array!");

  Point3D temp;

  temp.x = ProcessTranslatePart(aData->Item(1),
                                aContext, aPresContext, aCanStoreInRuleTree,
                                aBounds.Width());

  temp.y = ProcessTranslatePart(aData->Item(2),
                                aContext, aPresContext, aCanStoreInRuleTree,
                                aBounds.Height());

  temp.z = ProcessTranslatePart(aData->Item(3),
                                aContext, aPresContext, aCanStoreInRuleTree,
                                0);

  aMatrix.Translate(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;
}
static void
ProcessTranslate3D(Matrix4x4& aMatrix,
                   const nsCSSValue::Array* aData,
                   nsStyleContext* aContext,
                   nsPresContext* aPresContext,
                   RuleNodeCacheConditions& aConditions,
                   TransformReferenceBox& aRefBox)
{
  NS_PRECONDITION(aData->Count() == 4, "Invalid array!");

  Point3D temp;

  temp.x = ProcessTranslatePart(aData->Item(1),
                                aContext, aPresContext, aConditions,
                                &aRefBox, &TransformReferenceBox::Width);

  temp.y = ProcessTranslatePart(aData->Item(2),
                                aContext, aPresContext, aConditions,
                                &aRefBox, &TransformReferenceBox::Height);

  temp.z = ProcessTranslatePart(aData->Item(3),
                                aContext, aPresContext, aConditions,
                                nullptr);

  aMatrix.PreTranslate(temp);
}
/* Helper function to process a translatey function. */
/* static */ gfx3DMatrix
nsStyleTransformMatrix::ProcessTranslateY(const nsCSSValue::Array* aData,
                                          nsStyleContext* aContext,
                                          nsPresContext* aPresContext,
                                          PRBool& aCanStoreInRuleTree,
                                          nsRect& aBounds, float aAppUnitsPerMatrixUnit)
{
  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");

  gfx3DMatrix temp;

  /* There are two cases.  If we have a number, we want our matrix to look
   * like this:
   *
   * |  1  0  0  0 |
   * |  0  1  0  0 |
   * |  0  0  1  0 |
   * |  0 dy  0  1 |
   * So E = value
   * 
   * Otherwise, we might have a percentage, so we want to set the dY component
   * to the percent.
   */
  ProcessTranslatePart(temp._42, aData->Item(1),
                       aContext, aPresContext, aCanStoreInRuleTree,
                       aBounds.Height(), aAppUnitsPerMatrixUnit);
  return temp;
}
/* static */ gfx3DMatrix
nsStyleTransformMatrix::ProcessPerspective(const nsCSSValue::Array* aData,
                                           nsStyleContext *aContext,
                                           nsPresContext *aPresContext,
                                           PRBool &aCanStoreInRuleTree,
                                           float aAppUnitsPerMatrixUnit)
{
  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");

  /* We want our matrix to look like this:
   * | 1 0 0        0 |
   * | 0 1 0        0 |
   * | 0 0 1 -1/depth |
   * | 0 0 0        1 |
   */

  gfx3DMatrix temp;

  float depth;
  ProcessTranslatePart(depth, aData->Item(1), aContext,
                       aPresContext, aCanStoreInRuleTree,
                       0, aAppUnitsPerMatrixUnit);
  NS_ASSERTION(depth > 0.0, "Perspective must be positive!");
  temp._34 = -1.0/depth;

  return temp;
}
static void 
ProcessMatrix3D(Matrix4x4& aMatrix,
                const nsCSSValue::Array* aData,
                nsStyleContext* aContext,
                nsPresContext* aPresContext,
                RuleNodeCacheConditions& aConditions,
                TransformReferenceBox& aRefBox)
{
  NS_PRECONDITION(aData->Count() == 17, "Invalid array!");

  Matrix4x4 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._44 = aData->Item(16).GetFloatValue();

  temp._41 = ProcessTranslatePart(aData->Item(13),
                                  aContext, aPresContext, aConditions,
                                  &aRefBox, &TransformReferenceBox::Width);
  temp._42 = ProcessTranslatePart(aData->Item(14),
                                  aContext, aPresContext, aConditions,
                                  &aRefBox, &TransformReferenceBox::Height);
  temp._43 = ProcessTranslatePart(aData->Item(15),
                                  aContext, aPresContext, aConditions,
                                  nullptr);

  aMatrix = temp * aMatrix;
}
static void 
ProcessMatrix3D(gfx3DMatrix& aMatrix,
                const nsCSSValue::Array* aData,
                nsStyleContext* aContext,
                nsPresContext* aPresContext,
                bool& aCanStoreInRuleTree,
                nsRect& aBounds)
{
  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._44 = aData->Item(16).GetFloatValue();

  temp._41 = ProcessTranslatePart(aData->Item(13),
                                  aContext, aPresContext, aCanStoreInRuleTree,
                                  aBounds.Width());
  temp._42 = ProcessTranslatePart(aData->Item(14),
                                  aContext, aPresContext, aCanStoreInRuleTree,
                                  aBounds.Height());
  temp._43 = ProcessTranslatePart(aData->Item(15),
                                  aContext, aPresContext, aCanStoreInRuleTree,
                                  aBounds.Height());

  aMatrix.PreMultiply(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;

  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 void 
ProcessPerspective(gfx3DMatrix& aMatrix, 
                   const nsCSSValue::Array* aData,
                   nsStyleContext *aContext,
                   nsPresContext *aPresContext,
                   bool &aCanStoreInRuleTree)
{
  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");

  float depth = ProcessTranslatePart(aData->Item(1), aContext,
                                     aPresContext, aCanStoreInRuleTree,
                                     0);
  aMatrix.Perspective(depth);
}
static void 
ProcessPerspective(Matrix4x4& aMatrix,
                   const nsCSSValue::Array* aData,
                   nsStyleContext *aContext,
                   nsPresContext *aPresContext,
                   RuleNodeCacheConditions& aConditions)
{
  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");

  float depth = ProcessTranslatePart(aData->Item(1), aContext,
                                     aPresContext, aConditions,
                                     nullptr);
  aMatrix.Perspective(depth);
}
/* Helper function to process a translate function. */
static void
ProcessTranslate(gfx3DMatrix& aMatrix,
                 const nsCSSValue::Array* aData,
                 nsStyleContext* aContext,
                 nsPresContext* aPresContext,
                 bool& aCanStoreInRuleTree,
                 nsRect& aBounds)
{
  NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");

  Point3D temp;

  temp.x = ProcessTranslatePart(aData->Item(1),
                                aContext, aPresContext, aCanStoreInRuleTree,
                                aBounds.Width());

  /* If we read in a Y component, set it appropriately */
  if (aData->Count() == 3) {
    temp.y = ProcessTranslatePart(aData->Item(2),
                                  aContext, aPresContext, aCanStoreInRuleTree,
                                  aBounds.Height());
  }
  aMatrix.Translate(temp);
}
static void 
ProcessTranslateZ(gfx3DMatrix& aMatrix,
                  const nsCSSValue::Array* aData,
                  nsStyleContext* aContext,
                  nsPresContext* aPresContext,
                  bool& aCanStoreInRuleTree)
{
  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");

  Point3D temp;

  temp.z = ProcessTranslatePart(aData->Item(1), aContext,
                                aPresContext, aCanStoreInRuleTree, 0);
  aMatrix.Translate(temp);
}
/* Helper function to process a translate function. */
static void
ProcessTranslate(Matrix4x4& aMatrix,
                 const nsCSSValue::Array* aData,
                 nsStyleContext* aContext,
                 nsPresContext* aPresContext,
                 RuleNodeCacheConditions& aConditions,
                 TransformReferenceBox& aRefBox)
{
  NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");

  Point3D temp;

  temp.x = ProcessTranslatePart(aData->Item(1),
                                aContext, aPresContext, aConditions,
                                &aRefBox, &TransformReferenceBox::Width);

  /* If we read in a Y component, set it appropriately */
  if (aData->Count() == 3) {
    temp.y = ProcessTranslatePart(aData->Item(2),
                                  aContext, aPresContext, aConditions,
                                  &aRefBox, &TransformReferenceBox::Height);
  }
  aMatrix.PreTranslate(temp);
}
static void 
ProcessTranslateZ(Matrix4x4& aMatrix,
                  const nsCSSValue::Array* aData,
                  nsStyleContext* aContext,
                  nsPresContext* aPresContext,
                  RuleNodeCacheConditions& aConditions)
{
  NS_PRECONDITION(aData->Count() == 2, "Invalid array!");

  Point3D temp;

  temp.z = ProcessTranslatePart(aData->Item(1), aContext,
                                aPresContext, aConditions,
                                nullptr);
  aMatrix.PreTranslate(temp);
}