gfx3DMatrix Layer::SnapTransform(const gfx3DMatrix& aTransform, const gfxRect& aSnapRect, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && matrix2D.HasNonIntegerTranslation() && !matrix2D.IsSingular() && !matrix2D.HasNonAxisAlignedTransform()) { gfxMatrix snappedMatrix; gfxPoint topLeft = matrix2D.Transform(aSnapRect.TopLeft()); topLeft.Round(); // first compute scale factors that scale aSnapRect to the snapped rect if (aSnapRect.IsEmpty()) { snappedMatrix.xx = matrix2D.xx; snappedMatrix.yy = matrix2D.yy; } else { gfxPoint bottomRight = matrix2D.Transform(aSnapRect.BottomRight()); bottomRight.Round(); snappedMatrix.xx = (bottomRight.x - topLeft.x)/aSnapRect.Width(); snappedMatrix.yy = (bottomRight.y - topLeft.y)/aSnapRect.Height(); } // compute translation factors that will move aSnapRect to the snapped rect // given those scale factors snappedMatrix.x0 = topLeft.x - aSnapRect.X()*snappedMatrix.xx; snappedMatrix.y0 = topLeft.y - aSnapRect.Y()*snappedMatrix.yy; result = gfx3DMatrix::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; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
bool gfxContext::UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale) const { if (GetFlags() & FLAG_DISABLE_SNAPPING) return PR_FALSE; // if we're not at 1.0 scale, don't snap, unless we're // ignoring the scale. If we're not -just- a scale, // never snap. const gfxFloat epsilon = 0.0000001; #define WITHIN_E(a,b) (fabs((a)-(b)) < epsilon) cairo_matrix_t mat; cairo_get_matrix(mCairo, &mat); if (!ignoreScale && (!WITHIN_E(mat.xx,1.0) || !WITHIN_E(mat.yy,1.0) || !WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0))) return PR_FALSE; #undef WITHIN_E gfxPoint p1 = UserToDevice(rect.TopLeft()); gfxPoint p2 = UserToDevice(rect.TopRight()); gfxPoint p3 = UserToDevice(rect.BottomRight()); // Check that the rectangle is axis-aligned. For an axis-aligned rectangle, // two opposite corners define the entire rectangle. So check if // the axis-aligned rectangle with opposite corners p1 and p3 // define an axis-aligned rectangle whose other corners are p2 and p4. // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) { p1.Round(); p3.Round(); rect.MoveTo(gfxPoint(NS_MIN(p1.x, p3.x), NS_MIN(p1.y, p3.y))); rect.SizeTo(gfxSize(NS_MAX(p1.x, p3.x) - rect.X(), NS_MAX(p1.y, p3.y) - rect.Y())); return PR_TRUE; } return PR_FALSE; }
gfx3DMatrix Layer::SnapTransform(const gfx3DMatrix& aTransform, const gfxRect& aSnapRect, gfxMatrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = gfxMatrix(); } gfxMatrix matrix2D; gfx3DMatrix result; if (!(mContentFlags & CONTENT_DISABLE_TRANSFORM_SNAPPING) && mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && gfxSize(1.0, 1.0) <= 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(); gfxMatrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect, transformedTopLeft, transformedTopRight, transformedBottomRight); result = gfx3DMatrix::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; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }
bool gfxContext::UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale) const { if (mDT->GetUserData(&sDisablePixelSnapping)) return false; // if we're not at 1.0 scale, don't snap, unless we're // ignoring the scale. If we're not -just- a scale, // never snap. const gfxFloat epsilon = 0.0000001; #define WITHIN_E(a,b) (fabs((a)-(b)) < epsilon) Matrix mat = mTransform; if (!ignoreScale && (!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) || !WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0))) return false; #undef WITHIN_E gfxPoint p1 = UserToDevice(rect.TopLeft()); gfxPoint p2 = UserToDevice(rect.TopRight()); gfxPoint p3 = UserToDevice(rect.BottomRight()); // Check that the rectangle is axis-aligned. For an axis-aligned rectangle, // two opposite corners define the entire rectangle. So check if // the axis-aligned rectangle with opposite corners p1 and p3 // define an axis-aligned rectangle whose other corners are p2 and p4. // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) { p1.Round(); p3.Round(); rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(), std::max(p1.y, p3.y) - rect.Y())); return true; } return false; }
Matrix4x4 Layer::SnapTransform(const Matrix4x4& aTransform, const gfxRect& aSnapRect, Matrix* aResidualTransform) { if (aResidualTransform) { *aResidualTransform = Matrix(); } Matrix matrix2D; Matrix4x4 result; if (mManager->IsSnappingEffectiveTransforms() && aTransform.Is2D(&matrix2D) && gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) && matrix2D.PreservesAxisAlignedRectangles()) { IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft())); IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight())); IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight())); Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect, transformedTopLeft, transformedTopRight, transformedBottomRight); 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. Matrix snappedMatrixInverse = snappedMatrix; snappedMatrixInverse.Invert(); *aResidualTransform = matrix2D * snappedMatrixInverse; } } else { result = aTransform; } return result; }