--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -338,16 +338,29 @@ static void AddTransformFunctions(nsCSSV
aContext,
aPresContext,
conditions,
aRefBox,
&dummy);
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
+ case eCSSKeyword_accumulatematrix:
+ {
+ bool dummy;
+ Matrix4x4 matrix;
+ nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, array,
+ aContext,
+ aPresContext,
+ conditions,
+ aRefBox,
+ &dummy);
+ aFunctions.AppendElement(TransformMatrix(matrix));
+ break;
+ }
case eCSSKeyword_perspective:
{
aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
break;
}
default:
NS_ERROR("Function not handled yet!");
}
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -127,16 +127,23 @@ ToPrimitive(nsCSSKeyword aKeyword)
default:
return aKeyword;
}
}
static bool
TransformFunctionsMatch(nsCSSKeyword func1, nsCSSKeyword func2)
{
+ // Handle eCSSKeyword_accumulatematrix as different function to be calculated
+ // (decomposed and recomposed) them later.
+ if (func1 == eCSSKeyword_accumulatematrix ||
+ func2 == eCSSKeyword_accumulatematrix) {
+ return false;
+ }
+
return ToPrimitive(func1) == ToPrimitive(func2);
}
static bool
TransformFunctionListsMatch(const nsCSSValueList *list1,
const nsCSSValueList *list2)
{
const nsCSSValueList *item1 = list1, *item2 = list2;
@@ -168,16 +175,17 @@ AppendFunction(nsCSSKeyword aTransformFu
break;
case eCSSKeyword_matrix:
nargs = 6;
break;
case eCSSKeyword_rotate3d:
nargs = 4;
break;
case eCSSKeyword_interpolatematrix:
+ case eCSSKeyword_accumulatematrix:
case eCSSKeyword_translate3d:
case eCSSKeyword_scale3d:
nargs = 3;
break;
case eCSSKeyword_translate:
case eCSSKeyword_skew:
case eCSSKeyword_scale:
nargs = 2;
@@ -822,17 +830,18 @@ ComputeShapeDistance(nsCSSPropertyID aPr
default:
MOZ_ASSERT_UNREACHABLE("Unknown shape type");
}
return sqrt(squareDistance);
}
static nsCSSValueList*
AddTransformLists(double aCoeff1, const nsCSSValueList* aList1,
- double aCoeff2, const nsCSSValueList* aList2);
+ double aCoeff2, const nsCSSValueList* aList2,
+ nsCSSKeyword aOperatorType = eCSSKeyword_interpolatematrix);
static double
ComputeTransform2DMatrixDistance(const Matrix& aMatrix1,
const Matrix& aMatrix2)
{
Point3D scale1(1, 1, 1);
Point3D translate1;
gfxQuaternion rotate1;
@@ -1076,16 +1085,17 @@ ComputeTransformDistance(nsCSSValue::Arr
MOZ_ASSERT(a2->Count() == 17, "unexpected count");
distance = ComputeTransform3DMatrixDistance(
nsStyleTransformMatrix::CSSValueArrayTo3DMatrix(a1),
nsStyleTransformMatrix::CSSValueArrayTo3DMatrix(a2));
break;
}
case eCSSKeyword_interpolatematrix:
+ case eCSSKeyword_accumulatematrix:
default:
MOZ_ASSERT_UNREACHABLE("Unsupported transform function");
break;
}
return distance;
}
static double
@@ -1833,24 +1843,25 @@ StyleAnimationValue::AppendTransformFunc
*aListTail = item;
aListTail = &item->mNext;
return arr.forget();
}
static nsCSSValueList*
AddDifferentTransformLists(double aCoeff1, const nsCSSValueList* aList1,
- double aCoeff2, const nsCSSValueList* aList2)
+ double aCoeff2, const nsCSSValueList* aList2,
+ nsCSSKeyword aOperatorType)
{
nsAutoPtr<nsCSSValueList> result;
nsCSSValueList **resultTail = getter_Transfers(result);
RefPtr<nsCSSValue::Array> arr;
arr =
- StyleAnimationValue::AppendTransformFunction(eCSSKeyword_interpolatematrix,
+ StyleAnimationValue::AppendTransformFunction(aOperatorType,
resultTail);
// FIXME: We should change the other transform code to also only
// take a single progress value, as having values that don't
// sum to 1 doesn't make sense for these.
if (aList1 == aList2) {
arr->Item(1).Reset();
} else {
@@ -2262,17 +2273,18 @@ AddShapeFunction(nsCSSPropertyID aProper
result->Item(1).SetIntValue(aArray1->Item(1).GetIntValue(),
eCSSUnit_Enumerated);
return result.forget();
}
static nsCSSValueList*
AddTransformLists(double aCoeff1, const nsCSSValueList* aList1,
- double aCoeff2, const nsCSSValueList* aList2)
+ double aCoeff2, const nsCSSValueList* aList2,
+ nsCSSKeyword aOperatorType)
{
nsAutoPtr<nsCSSValueList> result;
nsCSSValueList **resultTail = getter_Transfers(result);
do {
RefPtr<nsCSSValue::Array> a1 = ToPrimitive(aList1->mValue.GetArrayValue()),
a2 = ToPrimitive(aList2->mValue.GetArrayValue());
MOZ_ASSERT(
@@ -2414,31 +2426,36 @@ AddTransformLists(double aCoeff1, const
// Construct temporary lists with only this item in them.
nsCSSValueList tempList1, tempList2;
tempList1.mValue = aList1->mValue;
tempList2.mValue = aList2->mValue;
if (aList1 == aList2) {
*resultTail =
- AddDifferentTransformLists(aCoeff1, &tempList1, aCoeff2, &tempList1);
+ AddDifferentTransformLists(aCoeff1, &tempList1,
+ aCoeff2, &tempList1,
+ aOperatorType);
} else {
*resultTail =
- AddDifferentTransformLists(aCoeff1, &tempList1, aCoeff2, &tempList2);
+ AddDifferentTransformLists(aCoeff1, &tempList1,
+ aCoeff2, &tempList2,
+ aOperatorType);
}
// Now advance resultTail to point to the new tail slot.
while (*resultTail) {
resultTail = &(*resultTail)->mNext;
}
break;
}
default:
- MOZ_ASSERT(false, "unknown transform function");
+ MOZ_ASSERT_UNREACHABLE(
+ "unknown transform function or accumulatematrix");
}
aList1 = aList1->mNext;
aList2 = aList2->mNext;
} while (aList1);
MOZ_ASSERT(!aList2, "list length mismatch");
MOZ_ASSERT(!*resultTail,
"resultTail isn't pointing to the tail");
@@ -2937,17 +2954,19 @@ StyleAnimationValue::AddWeighted(nsCSSPr
result = AddTransformLists(0, list2, aCoeff2, list2);
}
} else {
if (list2->mValue.GetUnit() == eCSSUnit_None) {
result = AddTransformLists(0, list1, aCoeff1, list1);
} else if (TransformFunctionListsMatch(list1, list2)) {
result = AddTransformLists(aCoeff1, list1, aCoeff2, list2);
} else {
- result = AddDifferentTransformLists(aCoeff1, list1, aCoeff2, list2);
+ result = AddDifferentTransformLists(aCoeff1, list1,
+ aCoeff2, list2,
+ eCSSKeyword_interpolatematrix);
}
}
aResultValue.SetTransformValue(new nsCSSValueSharedList(result.forget()));
return true;
}
case eUnit_BackgroundPositionCoord: {
const nsCSSValueList *position1 = aValue1.GetCSSValueListValue();
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -330,16 +330,17 @@ CSS_KEY(inline-end, inline_end)
CSS_KEY(inline-flex, inline_flex)
CSS_KEY(inline-grid, inline_grid)
CSS_KEY(inline-start, inline_start)
CSS_KEY(inline-table, inline_table)
CSS_KEY(inset, inset)
CSS_KEY(inside, inside)
// CSS_KEY(inter-character, inter_character) // TODO see bug 1055672
CSS_KEY(interpolatematrix, interpolatematrix)
+CSS_KEY(accumulatematrix, accumulatematrix)
CSS_KEY(intersect, intersect)
CSS_KEY(isolate, isolate)
CSS_KEY(isolate-override, isolate_override)
CSS_KEY(invert, invert)
CSS_KEY(italic, italic)
CSS_KEY(japanese-formal, japanese_formal)
CSS_KEY(japanese-informal, japanese_informal)
CSS_KEY(jis78, jis78)
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -259,26 +259,85 @@ ProcessMatrix3D(Matrix4x4& aMatrix,
&aRefBox, &TransformReferenceBox::Height);
temp._43 = ProcessTranslatePart(aData->Item(15),
aContext, aPresContext, aConditions,
nullptr);
aMatrix = temp * aMatrix;
}
+// For accumulation for transform functions, |aOne| corresponds to |aB| and
+// |aTwo| corresponds to |aA| for StyleAnimationValue::Accumulate().
+class Accumulate {
+public:
+ template<typename T>
+ static T operate(const T& aOne, const T& aTwo, double aCoeff)
+ {
+ return aOne + aTwo * aCoeff;
+ }
+
+ static Point4D operateForPerspective(const Point4D& aOne,
+ const Point4D& aTwo,
+ double aCoeff)
+ {
+ return (aOne - Point4D(0, 0, 0, 1)) +
+ (aTwo - Point4D(0, 0, 0, 1)) * aCoeff +
+ Point4D(0, 0, 0, 1);
+ }
+ static Point3D operateForScale(const Point3D& aOne,
+ const Point3D& aTwo,
+ double aCoeff)
+ {
+ // For scale, the identify element is 1, see AddTransformScale in
+ // StyleAnimationValue.cpp.
+ return (aOne - Point3D(1, 1, 1)) +
+ (aTwo - Point3D(1, 1, 1)) * aCoeff +
+ Point3D(1, 1, 1);
+ }
+
+ static Matrix4x4 operateForRotate(const gfxQuaternion& aOne,
+ const gfxQuaternion& aTwo,
+ double aCoeff)
+ {
+ if (aCoeff == 0.0) {
+ return aOne.ToMatrix();
+ }
+
+ double theta = acos(mozilla::clamped(aTwo.w, -1.0, 1.0));
+ double scale = (theta != 0.0) ? 1.0 / sin(theta) : 0.0;
+ theta *= aCoeff;
+ scale *= sin(theta);
+
+ gfxQuaternion result = gfxQuaternion(scale * aTwo.x,
+ scale * aTwo.y,
+ scale * aTwo.z,
+ cos(theta)) * aOne;
+ return result.ToMatrix();
+ }
+};
+
class Interpolate {
public:
template<typename T>
static T operate(const T& aOne, const T& aTwo, double aCoeff)
{
MOZ_ASSERT(aCoeff >= 0.0 && aCoeff <= 1.0,
"Coefficient should be in the range [0.0, 1.0]");
return aOne + (aTwo - aOne) * aCoeff;
}
+ static Point4D operateForPerspective(const Point4D& aOne,
+ const Point4D& aTwo,
+ double aCoeff)
+ {
+ MOZ_ASSERT(aCoeff >= 0.0 && aCoeff <= 1.0,
+ "Coefficient should be in the range [0.0, 1.0]");
+ return aOne + (aTwo - aOne) * aCoeff;
+ }
+
static Point3D operateForScale(const Point3D& aOne,
const Point3D& aTwo,
double aCoeff)
{
MOZ_ASSERT(aCoeff >= 0.0 && aCoeff <= 1.0,
"Coefficient should be in the range [0.0, 1.0]");
return aOne + (aTwo - aOne) * aCoeff;
}
@@ -325,33 +384,33 @@ OperateTransformMatrix(const Matrix4x4 &
Decompose2DMatrix(matrix2d2, scale2, shear2, rotate2, translate2);
} else {
Decompose3DMatrix(aMatrix1, scale1, shear1,
rotate1, translate1, perspective1);
Decompose3DMatrix(aMatrix2, scale2, shear2,
rotate2, translate2, perspective2);
}
- // Interpolate each of the pieces
Matrix4x4 result;
+ // Operate each of the pieces in response to |Operator|.
Point4D perspective =
- Operator::operate(perspective1, perspective2, aProgress);
+ Operator::operateForPerspective(perspective1, perspective2, aProgress);
result.SetTransposedVector(3, perspective);
Point3D translate =
Operator::operate(translate1, translate2, aProgress);
result.PreTranslate(translate.x, translate.y, translate.z);
Matrix4x4 rotate = Operator::operateForRotate(rotate1, rotate2, aProgress);
if (!rotate.IsIdentity()) {
result = rotate * result;
}
- // TODO: Would it be better to interpolate these as angles?
+ // TODO: Would it be better to operate these as angles?
// How do we convert back to angles?
float yzshear =
Operator::operate(shear1[ShearType::YZSHEAR],
shear2[ShearType::YZSHEAR],
aProgress);
if (yzshear != 0.0) {
result.SkewYZ(yzshear);
}
@@ -424,16 +483,30 @@ ProcessInterpolateMatrix(Matrix4x4& aMat
TransformReferenceBox& aRefBox,
bool* aContains3dTransform)
{
ProcessMatrixOperator<Interpolate>(aMatrix, aData, aContext, aPresContext,
aConditions, aRefBox,
aContains3dTransform);
}
+void
+ProcessAccumulateMatrix(Matrix4x4& aMatrix,
+ const nsCSSValue::Array* aData,
+ nsStyleContext* aContext,
+ nsPresContext* aPresContext,
+ RuleNodeCacheConditions& aConditions,
+ TransformReferenceBox& aRefBox,
+ bool* aContains3dTransform)
+{
+ ProcessMatrixOperator<Accumulate>(aMatrix, aData, aContext, aPresContext,
+ aConditions, aRefBox,
+ aContains3dTransform);
+}
+
/* Helper function to process a translatex function. */
static void
ProcessTranslateX(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData,
nsStyleContext* aContext,
nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions,
TransformReferenceBox& aRefBox)
@@ -791,16 +864,21 @@ MatrixForTransformFunction(Matrix4x4& aM
ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
aConditions, aRefBox);
break;
case eCSSKeyword_interpolatematrix:
ProcessMatrixOperator<Interpolate>(aMatrix, aData, aContext, aPresContext,
aConditions, aRefBox,
aContains3dTransform);
break;
+ case eCSSKeyword_accumulatematrix:
+ ProcessMatrixOperator<Accumulate>(aMatrix, aData, aContext, aPresContext,
+ aConditions, aRefBox,
+ aContains3dTransform);
+ break;
case eCSSKeyword_perspective:
*aContains3dTransform = true;
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
aConditions);
break;
default:
NS_NOTREACHED("Unknown transform function!");
}
--- a/layout/style/nsStyleTransformMatrix.h
+++ b/layout/style/nsStyleTransformMatrix.h
@@ -146,16 +146,25 @@ namespace nsStyleTransformMatrix {
ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
const nsCSSValue::Array* aData,
nsStyleContext* aContext,
nsPresContext* aPresContext,
mozilla::RuleNodeCacheConditions& aConditions,
TransformReferenceBox& aBounds,
bool* aContains3dTransform);
+ void
+ ProcessAccumulateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
+ const nsCSSValue::Array* aData,
+ nsStyleContext* aContext,
+ nsPresContext* aPresContext,
+ mozilla::RuleNodeCacheConditions& aConditions,
+ TransformReferenceBox& aBounds,
+ bool* aContains3dTransform);
+
/**
* Given an nsCSSValueList containing -moz-transform functions,
* returns a matrix containing the value of those functions.
*
* @param aData The nsCSSValueList containing the transform functions
* @param aContext The style context, used for unit conversion.
* @param aPresContext The presentation context, used for unit conversion.
* @param aConditions Set to uncachable (by calling SetUncacheable()) if the