Matrix4x4
ReadTransforms(const nsCSSValueList* aList,
               nsStyleContext* aContext,
               nsPresContext* aPresContext,
               RuleNodeCacheConditions& aConditions,
               TransformReferenceBox& aRefBox,
               float aAppUnitsPerMatrixUnit,
               bool* aContains3dTransform)
{
  Matrix4x4 result;

  for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) {
    const nsCSSValue &currElem = curr->mValue;
    if (currElem.GetUnit() != eCSSUnit_Function) {
      NS_ASSERTION(currElem.GetUnit() == eCSSUnit_None &&
                   !aList->mNext,
                   "stream should either be a list of functions or a "
                   "lone None");
      continue;
    }
    NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                 "Incoming function is too short!");

    /* Read in a single transform matrix. */
    MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
                               aPresContext, aConditions, aRefBox,
                               aContains3dTransform);
  }

  float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
  result.PreScale(1/scale, 1/scale, 1/scale);
  result.PostScale(scale, scale, scale);

  return result;
}
/* static */ gfx3DMatrix
nsStyleTransformMatrix::ReadTransforms(const nsCSSValueList* aList,
                                       nsStyleContext* aContext,
                                       nsPresContext* aPresContext,
                                       PRBool &aCanStoreInRuleTree,
                                       nsRect& aBounds,
                                       float aAppUnitsPerMatrixUnit)
{
  gfx3DMatrix result;

  for (const nsCSSValueList* curr = aList; curr != nsnull; curr = curr->mNext) {
    const nsCSSValue &currElem = curr->mValue;
    NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
                 "Stream should consist solely of functions!");
    NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                 "Incoming function is too short!");

    /* Read in a single transform matrix, then accumulate it with the total. */
    result = MatrixForTransformFunction(currElem.GetArrayValue(), aContext,
                                        aPresContext, aCanStoreInRuleTree,
                                        aBounds, aAppUnitsPerMatrixUnit) * result;
  }
  
  return result;
}
gfx3DMatrix
ReadTransforms(const nsCSSValueList* aList,
               nsStyleContext* aContext,
               nsPresContext* aPresContext,
               bool &aCanStoreInRuleTree,
               nsRect& aBounds,
               float aAppUnitsPerMatrixUnit)
{
  gfx3DMatrix result;

  for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) {
    const nsCSSValue &currElem = curr->mValue;
    NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
                 "Stream should consist solely of functions!");
    NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                 "Incoming function is too short!");

    /* Read in a single transform matrix. */
    MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
                               aPresContext, aCanStoreInRuleTree, aBounds);
  }

  float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
  result.Scale(1/scale, 1/scale, 1/scale);
  result.ScalePost(scale, scale, scale);
  
  return result;
}