From 6bd55e5bac62c445f5e955f8b861be2719284095 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 8 May 2009 15:19:41 +1200 Subject: [PATCH] Bug 489389. Limit size of temporary surface for tiling based on current clip extents. r=vlad --- gfx/src/thebes/nsThebesImage.cpp | 57 +++++++++++++++++++++----------- gfx/thebes/public/gfxContext.h | 3 +- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/gfx/src/thebes/nsThebesImage.cpp b/gfx/src/thebes/nsThebesImage.cpp index 887a7aa83ab..3fef03c8aa7 100644 --- a/gfx/src/thebes/nsThebesImage.cpp +++ b/gfx/src/thebes/nsThebesImage.cpp @@ -620,27 +620,46 @@ nsThebesImage::Draw(gfxContext* aContext, // EXTEND_PAD won't help us here; we have to create a temporary // surface to hold the subimage of pixels we're allowed to // sample - gfxRect needed = subimage.Intersect(sourceRect); + + gfxRect userSpaceClipExtents = aContext->GetClipExtents(); + // This isn't optimal --- if aContext has a rotation then + // GetClipExtents will have to do a bounding-box computation, + // and TransformBounds might too, so we could get a better + // result if we computed image space clip extents in one go + // --- but it doesn't really matter and this is easier to + // understand. + gfxRect imageSpaceClipExtents = + userSpaceToImageSpace.TransformBounds(userSpaceClipExtents); + // Inflate by one pixel because bilinear filtering will sample + // at most one pixel beyond the computed image pixel coordinate. + imageSpaceClipExtents.Outset(1.0); + + gfxRect needed = + imageSpaceClipExtents.Intersect(sourceRect).Intersect(subimage); needed.RoundOut(); - gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height())); - NS_ASSERTION(size.width > 0 && size.height > 0, - "We must have some needed pixels, otherwise we don't know what to sample"); - nsRefPtr temp = - gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, format); - if (temp && temp->CairoStatus() == 0) { - gfxContext tmpCtx(temp); - tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE); - nsRefPtr tmpPattern = new gfxPattern(surface); - if (tmpPattern) { - tmpPattern->SetExtend(gfxPattern::EXTEND_REPEAT); - tmpPattern->SetMatrix(gfxMatrix().Translate(needed.pos)); - tmpCtx.SetPattern(tmpPattern); - tmpCtx.Paint(); - tmpPattern = new gfxPattern(temp); + // if 'needed' is empty, nothing will be drawn since aFill + // must be entirely outside the clip region, so it doesn't + // matter what we do here, but we should avoid trying to + // create a zero-size surface. + if (!needed.IsEmpty()) { + gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height())); + nsRefPtr temp = + gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, format); + if (temp && temp->CairoStatus() == 0) { + gfxContext tmpCtx(temp); + tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE); + nsRefPtr tmpPattern = new gfxPattern(surface); if (tmpPattern) { - pattern.swap(tmpPattern); - pattern->SetMatrix( - gfxMatrix(userSpaceToImageSpace).Multiply(gfxMatrix().Translate(-needed.pos))); + tmpPattern->SetExtend(gfxPattern::EXTEND_REPEAT); + tmpPattern->SetMatrix(gfxMatrix().Translate(needed.pos)); + tmpCtx.SetPattern(tmpPattern); + tmpCtx.Paint(); + tmpPattern = new gfxPattern(temp); + if (tmpPattern) { + pattern.swap(tmpPattern); + pattern->SetMatrix( + gfxMatrix(userSpaceToImageSpace).Multiply(gfxMatrix().Translate(-needed.pos))); + } } } } diff --git a/gfx/thebes/public/gfxContext.h b/gfx/thebes/public/gfxContext.h index c5df2c534b3..28d448168d0 100644 --- a/gfx/thebes/public/gfxContext.h +++ b/gfx/thebes/public/gfxContext.h @@ -578,7 +578,8 @@ public: void UpdateSurfaceClip(); /** - * This will return the current bounds of the clip region. + * This will return the current bounds of the clip region in user + * space. */ gfxRect GetClipExtents();