Bug 952977: Convert SnapTransforms to gfx::Matrix r=nical

This commit is contained in:
David Zbarsky
2014-01-27 10:27:20 -05:00
parent 6532ec4040
commit ec82eb78ca
9 changed files with 134 additions and 64 deletions

View File

@@ -206,6 +206,10 @@ public:
FuzzyEqual(_32, floorf(_32 + 0.5f)); FuzzyEqual(_32, floorf(_32 + 0.5f));
} }
Point GetTranslation() const {
return Point(_31, _32);
}
/** /**
* Returns true if matrix is multiple of 90 degrees rotation with flipping, * Returns true if matrix is multiple of 90 degrees rotation with flipping,
* scaling and translation. * scaling and translation.
@@ -259,6 +263,21 @@ public:
return true; return true;
} }
bool Is2D(Matrix* aMatrix) const {
if (!Is2D()) {
return false;
}
if (aMatrix) {
aMatrix->_11 = _11;
aMatrix->_12 = _12;
aMatrix->_21 = _21;
aMatrix->_22 = _22;
aMatrix->_31 = _41;
aMatrix->_32 = _42;
}
return true;
}
Matrix As2D() const Matrix As2D() const
{ {
MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform"); MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform");
@@ -266,6 +285,17 @@ public:
return Matrix(_11, _12, _21, _22, _41, _42); return Matrix(_11, _12, _21, _22, _41, _42);
} }
static Matrix4x4 From2D(const Matrix &aMatrix) {
Matrix4x4 matrix;
matrix._11 = aMatrix._11;
matrix._12 = aMatrix._12;
matrix._21 = aMatrix._21;
matrix._22 = aMatrix._22;
matrix._41 = aMatrix._31;
matrix._42 = aMatrix._32;
return matrix;
}
bool Is2DIntegerTranslation() const bool Is2DIntegerTranslation() const
{ {
return Is2D() && As2D().IsIntegerTranslation(); return Is2D() && As2D().IsIntegerTranslation();

View File

@@ -29,7 +29,8 @@ void ImageLayer::SetContainer(ImageContainer* aContainer)
void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{ {
gfx3DMatrix local = GetLocalTransform(); gfx::Matrix4x4 local;
gfx::ToMatrix4x4(GetLocalTransform(), local);
// Snap image edges to pixel boundaries // Snap image edges to pixel boundaries
gfxRect sourceRect(0, 0, 0, 0); gfxRect sourceRect(0, 0, 0, 0);
@@ -47,10 +48,11 @@ void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurfa
// This makes our snapping equivalent to what would happen if our content // This makes our snapping equivalent to what would happen if our content
// was drawn into a ThebesLayer (gfxContext would snap using the local // was drawn into a ThebesLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the ThebesLayer). // transform, then we'd snap again when compositing the ThebesLayer).
gfx3DMatrix snappedTransform = gfx::Matrix4x4 transformToSurface;
gfx::ToMatrix4x4(aTransformToSurface, transformToSurface);
mEffectiveTransform =
SnapTransform(local, sourceRect, nullptr) * SnapTransform(local, sourceRect, nullptr) *
SnapTransformTranslation(aTransformToSurface, nullptr); SnapTransformTranslation(transformToSurface, nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
ComputeEffectiveTransformForMaskLayer(aTransformToSurface); ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
} }

View File

@@ -467,30 +467,31 @@ Layer::GetEffectiveVisibleRegion()
return GetVisibleRegion(); return GetVisibleRegion();
} }
gfx3DMatrix Matrix4x4
Layer::SnapTransformTranslation(const gfx3DMatrix& aTransform, Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
gfxMatrix* aResidualTransform) Matrix* aResidualTransform)
{ {
if (aResidualTransform) { if (aResidualTransform) {
*aResidualTransform = gfxMatrix(); *aResidualTransform = Matrix();
} }
gfxMatrix matrix2D; Matrix matrix2D;
gfx3DMatrix result; Matrix4x4 result;
if (mManager->IsSnappingEffectiveTransforms() && if (mManager->IsSnappingEffectiveTransforms() &&
aTransform.Is2D(&matrix2D) && aTransform.Is2D(&matrix2D) &&
!matrix2D.HasNonTranslation() && !matrix2D.HasNonTranslation() &&
matrix2D.HasNonIntegerTranslation()) { matrix2D.HasNonIntegerTranslation()) {
gfxPoint snappedTranslation(matrix2D.GetTranslation()); IntPoint snappedTranslation = RoundedToInt(matrix2D.GetTranslation());
snappedTranslation.Round(); Matrix snappedMatrix = Matrix().Translate(snappedTranslation.x,
gfxMatrix snappedMatrix = gfxMatrix().Translate(snappedTranslation); snappedTranslation.y);
result = gfx3DMatrix::From2D(snappedMatrix); result = Matrix4x4::From2D(snappedMatrix);
if (aResidualTransform) { if (aResidualTransform) {
// set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
// (I.e., appying snappedMatrix after aResidualTransform gives the // (I.e., appying snappedMatrix after aResidualTransform gives the
// ideal transform.) // ideal transform.)
*aResidualTransform = *aResidualTransform =
gfxMatrix().Translate(matrix2D.GetTranslation() - snappedTranslation); Matrix().Translate(matrix2D._31 - snappedTranslation.x,
matrix2D._32 - snappedTranslation.y);
} }
} else { } else {
result = aTransform; result = aTransform;
@@ -498,37 +499,34 @@ Layer::SnapTransformTranslation(const gfx3DMatrix& aTransform,
return result; return result;
} }
gfx3DMatrix Matrix4x4
Layer::SnapTransform(const gfx3DMatrix& aTransform, Layer::SnapTransform(const Matrix4x4& aTransform,
const gfxRect& aSnapRect, const gfxRect& aSnapRect,
gfxMatrix* aResidualTransform) Matrix* aResidualTransform)
{ {
if (aResidualTransform) { if (aResidualTransform) {
*aResidualTransform = gfxMatrix(); *aResidualTransform = Matrix();
} }
gfxMatrix matrix2D; Matrix matrix2D;
gfx3DMatrix result; Matrix4x4 result;
if (mManager->IsSnappingEffectiveTransforms() && if (mManager->IsSnappingEffectiveTransforms() &&
aTransform.Is2D(&matrix2D) && aTransform.Is2D(&matrix2D) &&
gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) && gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) &&
matrix2D.PreservesAxisAlignedRectangles()) { matrix2D.PreservesAxisAlignedRectangles()) {
gfxPoint transformedTopLeft = matrix2D.Transform(aSnapRect.TopLeft()); IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft()));
transformedTopLeft.Round(); IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight()));
gfxPoint transformedTopRight = matrix2D.Transform(aSnapRect.TopRight()); IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight()));
transformedTopRight.Round();
gfxPoint transformedBottomRight = matrix2D.Transform(aSnapRect.BottomRight());
transformedBottomRight.Round();
gfxMatrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect, Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
transformedTopLeft, transformedTopRight, transformedBottomRight); transformedTopLeft, transformedTopRight, transformedBottomRight);
result = gfx3DMatrix::From2D(snappedMatrix); result = Matrix4x4::From2D(snappedMatrix);
if (aResidualTransform && !snappedMatrix.IsSingular()) { if (aResidualTransform && !snappedMatrix.IsSingular()) {
// set aResidualTransform so that aResidual * snappedMatrix == matrix2D. // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
// (i.e., appying snappedMatrix after aResidualTransform gives the // (i.e., appying snappedMatrix after aResidualTransform gives the
// ideal transform. // ideal transform.
gfxMatrix snappedMatrixInverse = snappedMatrix; Matrix snappedMatrixInverse = snappedMatrix;
snappedMatrixInverse.Invert(); snappedMatrixInverse.Invert();
*aResidualTransform = matrix2D * snappedMatrixInverse; *aResidualTransform = matrix2D * snappedMatrixInverse;
} }
@@ -889,11 +887,12 @@ ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
void void
ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{ {
gfxMatrix residual; Matrix residual;
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface; gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
idealTransform.ProjectTo2D(); idealTransform.ProjectTo2D();
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, &residual); Matrix4x4 ideal;
ToMatrix4x4(snappedTransform, mEffectiveTransform); ToMatrix4x4(idealTransform, ideal);
mEffectiveTransform = SnapTransformTranslation(ideal, &residual);
bool useIntermediateSurface; bool useIntermediateSurface;
if (GetMaskLayer()) { if (GetMaskLayer()) {
@@ -936,7 +935,7 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformT
mUseIntermediateSurface = useIntermediateSurface; mUseIntermediateSurface = useIntermediateSurface;
if (useIntermediateSurface) { if (useIntermediateSurface) {
ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual)); ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(ThebesMatrix(residual)));
} else { } else {
ComputeEffectiveTransformsForChildren(idealTransform); ComputeEffectiveTransformsForChildren(idealTransform);
} }

View File

@@ -1365,8 +1365,8 @@ protected:
* @param aResidualTransform a transform to apply before the result transform * @param aResidualTransform a transform to apply before the result transform
* in order to get the results to completely match aTransform. * in order to get the results to completely match aTransform.
*/ */
gfx3DMatrix SnapTransformTranslation(const gfx3DMatrix& aTransform, gfx::Matrix4x4 SnapTransformTranslation(const gfx::Matrix4x4& aTransform,
gfxMatrix* aResidualTransform); gfx::Matrix* aResidualTransform);
/** /**
* See comment for SnapTransformTranslation. * See comment for SnapTransformTranslation.
* This function implements type 2 snapping. If aTransform is a translation * This function implements type 2 snapping. If aTransform is a translation
@@ -1378,9 +1378,9 @@ protected:
* @param aResidualTransform a transform to apply before the result transform * @param aResidualTransform a transform to apply before the result transform
* in order to get the results to completely match aTransform. * in order to get the results to completely match aTransform.
*/ */
gfx3DMatrix SnapTransform(const gfx3DMatrix& aTransform, gfx::Matrix4x4 SnapTransform(const gfx::Matrix4x4& aTransform,
const gfxRect& aSnapRect, const gfxRect& aSnapRect,
gfxMatrix* aResidualTransform); gfx::Matrix* aResidualTransform);
/** /**
* Returns true if this layer's effective transform is not just * Returns true if this layer's effective transform is not just
@@ -1480,17 +1480,17 @@ public:
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{ {
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface; gfx::Matrix4x4 idealTransform;
gfxMatrix residual; gfx::ToMatrix4x4(GetLocalTransform() * aTransformToSurface, idealTransform);
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, gfx::Matrix residual;
mEffectiveTransform = SnapTransformTranslation(idealTransform,
mAllowResidualTranslation ? &residual : nullptr); mAllowResidualTranslation ? &residual : nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
// The residual can only be a translation because SnapTransformTranslation // The residual can only be a translation because SnapTransformTranslation
// only changes the transform if it's a translation // only changes the transform if it's a translation
NS_ASSERTION(!residual.HasNonTranslation(), NS_ASSERTION(residual.IsTranslation(),
"Residual transform can only be a translation"); "Residual transform can only be a translation");
if (!residual.GetTranslation().WithinEpsilonOf(mResidualTranslation, 1e-3f)) { if (!gfx::ThebesPoint(residual.GetTranslation()).WithinEpsilonOf(mResidualTranslation, 1e-3f)) {
mResidualTranslation = residual.GetTranslation(); mResidualTranslation = gfx::ThebesPoint(residual.GetTranslation());
NS_ASSERTION(-0.5 <= mResidualTranslation.x && mResidualTranslation.x < 0.5 && NS_ASSERTION(-0.5 <= mResidualTranslation.x && mResidualTranslation.x < 0.5 &&
-0.5 <= mResidualTranslation.y && mResidualTranslation.y < 0.5, -0.5 <= mResidualTranslation.y && mResidualTranslation.y < 0.5,
"Residual translation out of range"); "Residual translation out of range");
@@ -1753,9 +1753,9 @@ public:
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{ {
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface; gfx::Matrix4x4 idealTransform;
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, nullptr); gfx::ToMatrix4x4(GetLocalTransform() * aTransformToSurface, idealTransform);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform); mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr);
ComputeEffectiveTransformForMaskLayer(aTransformToSurface); ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
} }
@@ -1898,11 +1898,14 @@ public:
// This makes our snapping equivalent to what would happen if our content // This makes our snapping equivalent to what would happen if our content
// was drawn into a ThebesLayer (gfxContext would snap using the local // was drawn into a ThebesLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the ThebesLayer). // transform, then we'd snap again when compositing the ThebesLayer).
gfx3DMatrix snappedTransform = gfx::Matrix4x4 localTransform;
SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height), gfx::Matrix4x4 transformToSurface;
gfx::ToMatrix4x4(GetLocalTransform(), localTransform);
gfx::ToMatrix4x4(aTransformToSurface, transformToSurface);
mEffectiveTransform =
SnapTransform(localTransform, gfxRect(0, 0, mBounds.width, mBounds.height),
nullptr)* nullptr)*
SnapTransformTranslation(aTransformToSurface, nullptr); SnapTransformTranslation(transformToSurface, nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
ComputeEffectiveTransformForMaskLayer(aTransformToSurface); ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
} }

View File

@@ -90,11 +90,13 @@ public:
// This makes our snapping equivalent to what would happen if our content // This makes our snapping equivalent to what would happen if our content
// was drawn into a ThebesLayer (gfxContext would snap using the local // was drawn into a ThebesLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the ThebesLayer). // transform, then we'd snap again when compositing the ThebesLayer).
gfx3DMatrix snappedTransform = gfx::Matrix4x4 localTransform, transformToSurface;
SnapTransform(GetLocalTransform(), gfxRect(0, 0, mSize.width, mSize.height), gfx::ToMatrix4x4(aTransformToSurface, transformToSurface);
gfx::ToMatrix4x4(GetLocalTransform(), localTransform);
mEffectiveTransform =
SnapTransform(localTransform, gfxRect(0, 0, mSize.width, mSize.height),
nullptr)* nullptr)*
SnapTransformTranslation(aTransformToSurface, nullptr); SnapTransformTranslation(transformToSurface, nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
} }
/** /**

View File

@@ -39,7 +39,7 @@ BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS
// We push groups for container layers if we need to, which always // We push groups for container layers if we need to, which always
// are aligned in device space, so it doesn't really matter how we snap // are aligned in device space, so it doesn't really matter how we snap
// containers. // containers.
gfxMatrix residual; Matrix residual;
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface; gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
idealTransform.ProjectTo2D(); idealTransform.ProjectTo2D();
@@ -51,8 +51,9 @@ BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS
return; return;
} }
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, &residual); Matrix4x4 ideal;
ToMatrix4x4(snappedTransform, mEffectiveTransform); ToMatrix4x4(idealTransform, ideal);
mEffectiveTransform = SnapTransformTranslation(ideal, &residual);
// We always pass the ideal matrix down to our children, so there is no // We always pass the ideal matrix down to our children, so there is no
// need to apply any compensation using the residual from SnapTransformTranslation. // need to apply any compensation using the residual from SnapTransformTranslation.
ComputeEffectiveTransformsForChildren(idealTransform); ComputeEffectiveTransformsForChildren(idealTransform);

View File

@@ -106,7 +106,8 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
void void
ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{ {
gfx3DMatrix local = GetLocalTransform(); gfx::Matrix4x4 local;
gfx::ToMatrix4x4(GetLocalTransform(), local);
// Snap image edges to pixel boundaries // Snap image edges to pixel boundaries
gfxRect sourceRect(0, 0, 0, 0); gfxRect sourceRect(0, 0, 0, 0);
@@ -129,10 +130,11 @@ ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS
// This makes our snapping equivalent to what would happen if our content // This makes our snapping equivalent to what would happen if our content
// was drawn into a ThebesLayer (gfxContext would snap using the local // was drawn into a ThebesLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the ThebesLayer). // transform, then we'd snap again when compositing the ThebesLayer).
gfx3DMatrix snappedTransform = gfx::Matrix4x4 transformToSurface;
gfx::ToMatrix4x4(aTransformToSurface, transformToSurface);
mEffectiveTransform =
SnapTransform(local, sourceRect, nullptr) * SnapTransform(local, sourceRect, nullptr) *
SnapTransformTranslation(aTransformToSurface, nullptr); SnapTransformTranslation(transformToSurface, nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
ComputeEffectiveTransformForMaskLayer(aTransformToSurface); ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
} }

View File

@@ -676,6 +676,30 @@ gfxUtils::TransformRectToRect(const gfxRect& aFrom, const gfxPoint& aToTopLeft,
return m; return m;
} }
Matrix
gfxUtils::TransformRectToRect(const gfxRect& aFrom, const IntPoint& aToTopLeft,
const IntPoint& aToTopRight, const IntPoint& aToBottomRight)
{
Matrix m;
if (aToTopRight.y == aToTopLeft.y && aToTopRight.x == aToBottomRight.x) {
// Not a rotation, so xy and yx are zero
m._12 = m._21 = 0.0;
m._11 = (aToBottomRight.x - aToTopLeft.x)/aFrom.width;
m._22 = (aToBottomRight.y - aToTopLeft.y)/aFrom.height;
m._31 = aToTopLeft.x - m._11*aFrom.x;
m._32 = aToTopLeft.y - m._22*aFrom.y;
} else {
NS_ASSERTION(aToTopRight.y == aToBottomRight.y && aToTopRight.x == aToTopLeft.x,
"Destination rectangle not axis-aligned");
m._11 = m._22 = 0.0;
m._21 = (aToBottomRight.x - aToTopLeft.x)/aFrom.height;
m._12 = (aToBottomRight.y - aToTopLeft.y)/aFrom.width;
m._31 = aToTopLeft.x - m._21*aFrom.y;
m._32 = aToTopLeft.y - m._12*aFrom.x;
}
return m;
}
bool bool
gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut) gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
{ {

View File

@@ -22,6 +22,8 @@ class PlanarYCbCrData;
class gfxUtils { class gfxUtils {
public: public:
typedef mozilla::gfx::IntPoint IntPoint;
typedef mozilla::gfx::Matrix Matrix;
/* /*
* Premultiply or Unpremultiply aSourceSurface, writing the result * Premultiply or Unpremultiply aSourceSurface, writing the result
* to aDestSurface or back into aSourceSurface if aDestSurface is null. * to aDestSurface or back into aSourceSurface if aDestSurface is null.
@@ -109,6 +111,11 @@ public:
const gfxPoint& aToTopRight, const gfxPoint& aToTopRight,
const gfxPoint& aToBottomRight); const gfxPoint& aToBottomRight);
static Matrix TransformRectToRect(const gfxRect& aFrom,
const IntPoint& aToTopLeft,
const IntPoint& aToTopRight,
const IntPoint& aToBottomRight);
/** /**
* If aIn can be represented exactly using an nsIntRect (i.e. * If aIn can be represented exactly using an nsIntRect (i.e.
* integer-aligned edges and coordinates in the int32_t range) then we * integer-aligned edges and coordinates in the int32_t range) then we