Bug 1025553, part 3 - Give gfxMatrix::Invert() the same semantics as Moz2D's Matrix::Invert(). r=Bas

This commit is contained in:
Jonathan Watt 2014-07-11 08:06:39 +01:00
parent abac46757a
commit 7645116817
19 changed files with 98 additions and 42 deletions

View File

@ -119,11 +119,12 @@ SVGMatrix::Multiply(SVGMatrix& aMatrix)
already_AddRefed<SVGMatrix>
SVGMatrix::Inverse(ErrorResult& rv)
{
if (GetMatrix().IsSingular()) {
gfxMatrix mat = GetMatrix();
if (!mat.Invert()) {
rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
nsRefPtr<SVGMatrix> matrix = new SVGMatrix(gfxMatrix(GetMatrix()).Invert());
nsRefPtr<SVGMatrix> matrix = new SVGMatrix(mat);
return matrix.forget();
}

View File

@ -55,8 +55,11 @@ public:
if (state.patternTransformChanged) {
Matrix mat = mContext->GetDTTransform();
mat.Invert();
if (!mat.Invert()) {
mPattern = new (mColorPattern.addr())
ColorPattern(Color()); // transparent black to paint nothing
return *mPattern;
}
transform = transform * state.patternTransform * mat;
}
@ -360,10 +363,12 @@ gfxContext::Rectangle(const gfxRect& rect, bool snapToPixels)
gfxRect newRect(rect);
if (UserToDevicePixelSnapped(newRect, true)) {
gfxMatrix mat = ThebesMatrix(mTransform);
mat.Invert();
// We need the user space rect.
rec = ToRect(mat.TransformBounds(newRect));
if (mat.Invert()) {
// We need the user space rect.
rec = ToRect(mat.TransformBounds(newRect));
} else {
rec = Rect();
}
}
}

View File

@ -52,7 +52,10 @@ DeviceToImageTransform(gfxContext* aContext,
nsRefPtr<gfxASurface> currentTarget =
aContext->CurrentSurface(&deviceX, &deviceY);
gfxMatrix currentMatrix = aContext->CurrentMatrix();
gfxMatrix deviceToUser = gfxMatrix(currentMatrix).Invert();
gfxMatrix deviceToUser = currentMatrix;
if (!deviceToUser.Invert()) {
return gfxMatrix(0, 0, 0, 0, 0, 0); // singular
}
deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
return gfxMatrix(deviceToUser).Multiply(aUserSpaceToImageSpace);
}

View File

@ -17,11 +17,10 @@ gfxMatrix::Reset()
return *this;
}
const gfxMatrix&
bool
gfxMatrix::Invert()
{
cairo_matrix_invert(CAIRO_MATRIX(this));
return *this;
return cairo_matrix_invert(CAIRO_MATRIX(this)) == CAIRO_STATUS_SUCCESS;
}
const gfxMatrix&

View File

@ -98,7 +98,7 @@ public:
* XXX should this do something with the return value of
* cairo_matrix_invert?
*/
const gfxMatrix& Invert();
bool Invert();
/**
* Check if matrix is singular (no inverse exists).

View File

@ -232,7 +232,9 @@ public:
return gfxMatrix();
}
gfxMatrix deviceToUser = aCTM;
deviceToUser.Invert();
if (!deviceToUser.Invert()) {
return gfxMatrix(0, 0, 0, 0, 0, 0); // singular
}
return deviceToUser * aPattern->GetMatrix();
}

View File

@ -496,7 +496,10 @@ DeviceToImageTransform(gfxContext* aContext,
nsRefPtr<gfxASurface> currentTarget =
aContext->CurrentSurface(&deviceX, &deviceY);
gfxMatrix currentMatrix = aContext->CurrentMatrix();
gfxMatrix deviceToUser = gfxMatrix(currentMatrix).Invert();
gfxMatrix deviceToUser = currentMatrix;
if (!deviceToUser.Invert()) {
return gfxMatrix(0, 0, 0, 0, 0, 0); // singular
}
deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
return gfxMatrix(deviceToUser).Multiply(aUserSpaceToImageSpace);
}

View File

@ -268,7 +268,10 @@ OrientedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
}
// Transform the invalidation rect into the correct orientation.
gfxMatrix matrix(OrientationMatrix(nsIntSize(width, height)).Invert());
gfxMatrix matrix(OrientationMatrix(nsIntSize(width, height)));
if (!matrix.Invert()) {
return nsIntRect();
}
gfxRect invalidRect(matrix.TransformBounds(gfxRect(rect.x, rect.y,
rect.width, rect.height)));
invalidRect.RoundOut();

View File

@ -2600,7 +2600,9 @@ RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
nsIntRect framerect = frame->GetRect();
gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace;
imageSpaceToUserSpace.Invert();
if (!imageSpaceToUserSpace.Invert()) {
return false;
}
gfxSize scale = imageSpaceToUserSpace.ScaleFactors(true);
nsIntRect subimage = aSubimage;
RefPtr<SourceSurface> surf;

View File

@ -284,7 +284,11 @@ SVGDrawingCallback::operator()(gfxContext* aContext,
aContext->Clip();
gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext);
aContext->Multiply(gfxMatrix(aTransform).Invert());
gfxMatrix matrix = aTransform;
if (!matrix.Invert()) {
return false;
}
aContext->Multiply(matrix);
aContext->Scale(1.0 / mScale.width, 1.0 / mScale.height);
nsPresContext* presContext = presShell->GetPresContext();

View File

@ -1064,7 +1064,10 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
// Convert the point from user space into run user space, and take
// into account any mFontSizeScaleFactor.
gfxMatrix m = GetTransformFromRunUserSpaceToUserSpace(aContext).Invert();
gfxMatrix m = GetTransformFromRunUserSpaceToUserSpace(aContext);
if (!m.Invert()) {
return -1;
}
gfxPoint p = m.Transform(aPoint) / cssPxPerDevPx * mFontSizeScaleFactor;
// First check that the point lies vertically between the top and bottom
@ -3033,7 +3036,9 @@ SVGTextContextPaint::Paint::GetPattern(float aOpacity,
// m maps original-user-space to pattern space
gfxMatrix m = pattern->GetMatrix();
gfxMatrix deviceToOriginalUserSpace = mContextMatrix;
deviceToOriginalUserSpace.Invert();
if (!deviceToOriginalUserSpace.Invert()) {
return nullptr;
}
// mPatternMatrix maps device space to pattern space via original user space
mPatternMatrix = deviceToOriginalUserSpace * m;
}
@ -3715,7 +3720,9 @@ SVGTextFrame::GetFrameForPoint(const nsPoint& aPoint)
gfxMatrix m = GetCanvasTM(FOR_HIT_TESTING);
m.PreMultiply(run.GetTransformFromRunUserSpaceToUserSpace(presContext));
m.Invert();
if (!m.Invert()) {
return nullptr;
}
gfxPoint pointInRunUserSpace = m.Transform(pointInOuterSVGUserUnits);
gfxRect frameRect =
@ -5364,9 +5371,11 @@ SVGTextFrame::TransformFramePointToTextChild(const gfxPoint& aPoint,
TextRenderedRun::eNoHorizontalOverflow;
gfxRect runRect = run.GetRunUserSpaceRect(presContext, flags).ToThebesRect();
gfxPoint pointInRunUserSpace =
run.GetTransformFromRunUserSpaceToUserSpace(presContext).Invert().
Transform(pointInUserSpace);
gfxMatrix m = run.GetTransformFromRunUserSpaceToUserSpace(presContext);
if (!m.Invert()) {
return aPoint;
}
gfxPoint pointInRunUserSpace = m.Transform(pointInUserSpace);
if (Inside(runRect, pointInRunUserSpace)) {
// The point was inside the rendered run's rect, so we choose it.
@ -5437,8 +5446,13 @@ SVGTextFrame::TransformFrameRectToTextChild(const gfxRect& aRect,
aChildFrame);
for (TextRenderedRun run = it.Current(); run.mFrame; run = it.Next()) {
// Convert the incoming rect into frame user space.
gfxMatrix userSpaceToRunUserSpace =
run.GetTransformFromRunUserSpaceToUserSpace(presContext);
if (!userSpaceToRunUserSpace.Invert()) {
return result;
}
gfxMatrix m;
m.PreMultiply(run.GetTransformFromRunUserSpaceToUserSpace(presContext).Invert());
m.PreMultiply(userSpaceToRunUserSpace);
m.PreMultiply(run.GetTransformFromRunUserSpaceToFrameUserSpace(presContext));
gfxRect incomingRectInFrameUserSpace =
m.TransformBounds(incomingRectInUserSpace);

View File

@ -315,7 +315,10 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
nsRefPtr<nsRenderingContext> tmpCtx(new nsRenderingContext());
tmpCtx->Init(mTargetFrame->PresContext()->DeviceContext(), ctx);
gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform();
if (!deviceToFilterSpace.Invert()) {
return NS_ERROR_FAILURE;
}
gfxContext *gfx = tmpCtx->ThebesContext();
gfx->Multiply(deviceToFilterSpace);
@ -398,7 +401,10 @@ nsFilterInstance::BuildSourceImage(DrawTarget* aTargetDT)
// space to device space and back again). However, that would make the
// code more complex while being hard to get right without introducing
// subtle bugs, and in practice it probably makes no real difference.)
gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform();
if (!deviceToFilterSpace.Invert()) {
return NS_ERROR_FAILURE;
}
tmpCtx->ThebesContext()->Multiply(deviceToFilterSpace);
mPaintCallback->Paint(tmpCtx, mTargetFrame, &dirty, mTransformRoot);

View File

@ -222,9 +222,8 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
"Display lists handle dirty rect intersection test");
// Transform the dirty rect into app units in our userspace.
gfxMatrix invmatrix = canvasTM;
invmatrix.Invert();
NS_ASSERTION(!invmatrix.IsSingular(),
"inverse of non-singular matrix should be non-singular");
DebugOnly<bool> ok = invmatrix.Invert();
NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
aDirtyRect->width, aDirtyRect->height);
@ -297,10 +296,11 @@ nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
static_cast<nsSVGElement*>(mContent)->
GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
gfxMatrix tm = GetCanvasTM(FOR_HIT_TESTING).Invert();
if (tm.IsSingular())
gfxMatrix tm = GetCanvasTM(FOR_HIT_TESTING);
if (!tm.Invert()) {
return nullptr;
}
// Convert aPoint from app units in canvas space to user space:
gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerCSSPixel();

View File

@ -264,10 +264,16 @@ nsSVGGradientFrame::GetPaintServerPattern(nsIFrame *aSource,
// revert the vector effect transform so that the gradient appears unchanged
if (aFillOrStroke == &nsStyleSVG::mStroke) {
patternMatrix.Multiply(nsSVGUtils::GetStrokeTransform(aSource).Invert());
gfxMatrix nonScalingStrokeTM = nsSVGUtils::GetStrokeTransform(aSource);
if (!nonScalingStrokeTM.Invert()) {
return nullptr;
}
patternMatrix.Multiply(nonScalingStrokeTM);
}
patternMatrix.Invert();
if (!patternMatrix.Invert()) {
return nullptr;
}
nsRefPtr<gfxPattern> gradient = CreateGradient();
if (!gradient || gradient->CairoStatus())

View File

@ -628,7 +628,11 @@ PaintFrameCallback::operator()(gfxContext* aContext,
aContext->Rectangle(aFillRect);
aContext->Clip();
aContext->Multiply(gfxMatrix(aTransform).Invert());
gfxMatrix invmatrix = aTransform;
if (!invmatrix.Invert()) {
return false;
}
aContext->Multiply(invmatrix);
// nsLayoutUtils::PaintFrame will anchor its painting at mFrame. But we want
// to have it anchored at the top left corner of the bounding box of all of

View File

@ -270,8 +270,7 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(gfxContext* aContext,
maskSurface->Unmap();
// Moz2D transforms in the opposite direction to Thebes
maskSurfaceMatrix.Invert();
if (maskSurfaceMatrix.IsSingular()) {
if (!maskSurfaceMatrix.Invert()) {
return nullptr;
}
nsRefPtr<gfxPattern> retval =

View File

@ -302,7 +302,9 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
// coordinate system in order for non-scaled stroke to be correct.
// Naturally we also need to transform the point into the same
// coordinate system in order to hit-test against the path.
nonScalingStrokeMatrix.Invert();
if (!nonScalingStrokeMatrix.Invert()) {
return nullptr;
}
userSpacePoint = ToMatrix(hitTestingTM) * nonScalingStrokeMatrix * userSpacePoint;
RefPtr<PathBuilder> builder =
path->TransformedCopyToBuilder(nonScalingStrokeMatrix, fillRule);

View File

@ -324,8 +324,8 @@ nsSVGPatternFrame::PaintPattern(Matrix* patternMatrix,
// revert the vector effect transform so that the pattern appears unchanged
if (aFillOrStroke == &nsStyleSVG::mStroke) {
Matrix strokeTransform = ToMatrix(nsSVGUtils::GetStrokeTransform(aSource).Invert());
if (strokeTransform.IsSingular()) {
Matrix strokeTransform = ToMatrix(nsSVGUtils::GetStrokeTransform(aSource));
if (!strokeTransform.Invert()) {
NS_WARNING("Should we get here if the stroke transform is singular?");
return nullptr;
}

View File

@ -539,7 +539,10 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
if (static_cast<nsSVGContainerFrame*>(aFrame)->
HasChildrenOnlyTransform(&childrenOnlyTM)) {
// Undo the children-only transform:
tm = ThebesMatrix(childrenOnlyTM).Invert() * tm;
if (!childrenOnlyTM.Invert()) {
return;
}
tm = ThebesMatrix(childrenOnlyTM) * tm;
}
}
nsIntRect bounds = TransformFrameRectToOuterSVG(overflowRect,