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 b8f0bd8317
commit 7e28db3ce2
9 changed files with 134 additions and 64 deletions

View File

@ -206,6 +206,10 @@ public:
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,
* scaling and translation.
@ -259,6 +263,21 @@ public:
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
{
MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform");
@ -266,6 +285,17 @@ public:
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
{
return Is2D() && As2D().IsIntegerTranslation();

View File

@ -29,7 +29,8 @@ void ImageLayer::SetContainer(ImageContainer* aContainer)
void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{
gfx3DMatrix local = GetLocalTransform();
gfx::Matrix4x4 local;
gfx::ToMatrix4x4(GetLocalTransform(), local);
// Snap image edges to pixel boundaries
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
// was drawn into a ThebesLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the ThebesLayer).
gfx3DMatrix snappedTransform =
gfx::Matrix4x4 transformToSurface;
gfx::ToMatrix4x4(aTransformToSurface, transformToSurface);
mEffectiveTransform =
SnapTransform(local, sourceRect, nullptr) *
SnapTransformTranslation(aTransformToSurface, nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
SnapTransformTranslation(transformToSurface, nullptr);
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
}

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS
// 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
// containers.
gfxMatrix residual;
Matrix residual;
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
idealTransform.ProjectTo2D();
@ -51,8 +51,9 @@ BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS
return;
}
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, &residual);
ToMatrix4x4(snappedTransform, mEffectiveTransform);
Matrix4x4 ideal;
ToMatrix4x4(idealTransform, ideal);
mEffectiveTransform = SnapTransformTranslation(ideal, &residual);
// We always pass the ideal matrix down to our children, so there is no
// need to apply any compensation using the residual from SnapTransformTranslation.
ComputeEffectiveTransformsForChildren(idealTransform);

View File

@ -106,7 +106,8 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
void
ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
{
gfx3DMatrix local = GetLocalTransform();
gfx::Matrix4x4 local;
gfx::ToMatrix4x4(GetLocalTransform(), local);
// Snap image edges to pixel boundaries
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
// was drawn into a ThebesLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the ThebesLayer).
gfx3DMatrix snappedTransform =
gfx::Matrix4x4 transformToSurface;
gfx::ToMatrix4x4(aTransformToSurface, transformToSurface);
mEffectiveTransform =
SnapTransform(local, sourceRect, nullptr) *
SnapTransformTranslation(aTransformToSurface, nullptr);
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
SnapTransformTranslation(transformToSurface, nullptr);
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
}

View File

@ -676,6 +676,30 @@ gfxUtils::TransformRectToRect(const gfxRect& aFrom, const gfxPoint& aToTopLeft,
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
gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
{

View File

@ -22,6 +22,8 @@ class PlanarYCbCrData;
class gfxUtils {
public:
typedef mozilla::gfx::IntPoint IntPoint;
typedef mozilla::gfx::Matrix Matrix;
/*
* Premultiply or Unpremultiply aSourceSurface, writing the result
* to aDestSurface or back into aSourceSurface if aDestSurface is null.
@ -109,6 +111,11 @@ public:
const gfxPoint& aToTopRight,
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.
* integer-aligned edges and coordinates in the int32_t range) then we