Bug 885939 (Part 1) - Scale SVG images using the graphics context matrix instead of the viewport. r=dholbert
authorSeth Fowler <seth@mozilla.com>
Tue, 16 Jul 2013 15:41:30 -0400
changeset 138748 7c49f7bbd12928b570674d4960ae8d883c39b8d6
parent 138747 71233da022ea5543353c61470022983a705c9d54
child 138749 de46c9ce71ef6291d80f0472cc0f88ff5483c091
push idunknown
push userunknown
push dateunknown
reviewersdholbert
bugs885939
milestone25.0a1
Bug 885939 (Part 1) - Scale SVG images using the graphics context matrix instead of the viewport. r=dholbert
image/src/VectorImage.cpp
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -225,28 +225,31 @@ private:
 
 NS_IMPL_ISUPPORTS1(SVGLoadEventListener, nsIDOMEventListener)
 
 // Helper-class: SVGDrawingCallback
 class SVGDrawingCallback : public gfxDrawingCallback {
 public:
   SVGDrawingCallback(SVGDocumentWrapper* aSVGDocumentWrapper,
                      const nsIntRect& aViewport,
+                     const gfxSize& aScale,
                      uint32_t aImageFlags) :
     mSVGDocumentWrapper(aSVGDocumentWrapper),
     mViewport(aViewport),
+    mScale(aScale),
     mImageFlags(aImageFlags)
   {}
   virtual bool operator()(gfxContext* aContext,
                             const gfxRect& aFillRect,
                             const gfxPattern::GraphicsFilter& aFilter,
                             const gfxMatrix& aTransform);
 private:
   nsRefPtr<SVGDocumentWrapper> mSVGDocumentWrapper;
   const nsIntRect mViewport;
+  const gfxSize   mScale;
   uint32_t        mImageFlags;
 };
 
 // Based loosely on nsSVGIntegrationUtils' PaintFrameCallback::operator()
 bool
 SVGDrawingCallback::operator()(gfxContext* aContext,
                                const gfxRect& aFillRect,
                                const gfxPattern::GraphicsFilter& aFilter,
@@ -266,16 +269,17 @@ SVGDrawingCallback::operator()(gfxContex
 
   // Clip to aFillRect so that we don't paint outside.
   aContext->NewPath();
   aContext->Rectangle(aFillRect);
   aContext->Clip();
 
   gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext);
   aContext->Multiply(gfxMatrix(aTransform).Invert());
+  aContext->Scale(1.0 / mScale.width, 1.0 / mScale.height);
 
   nsPresContext* presContext = presShell->GetPresContext();
   MOZ_ASSERT(presContext, "pres shell w/out pres context");
 
   nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x),
                  presContext->DevPixelsToAppUnits(mViewport.y),
                  presContext->DevPixelsToAppUnits(mViewport.width),
                  presContext->DevPixelsToAppUnits(mViewport.height));
@@ -693,58 +697,53 @@ VectorImage::Draw(gfxContext* aContext,
   AutoSVGRenderingState autoSVGState(aSVGContext,
                                      time,
                                      mSVGDocumentWrapper->GetRootSVGElem());
 
   // gfxUtils::DrawPixelSnapped may rasterize this image to a temporary surface
   // if we hit the tiling path. Unfortunately, the temporary surface isn't
   // created at the size at which we'll ultimately draw, causing fuzzy output.
   // To fix this we pre-apply the transform's scaling to the drawing parameters
-  // and then remove the scaling from the transform, so the fact that temporary
+  // and remove the scaling from the transform, so the fact that temporary
   // surfaces won't take the scaling into account doesn't matter. (Bug 600207.)
   gfxSize scale(aUserSpaceToImageSpace.ScaleFactors(true));
   gfxPoint translation(aUserSpaceToImageSpace.GetTranslation());
 
-  // Rescale everything.
-  nsIntSize scaledViewport(aViewportSize.width / scale.width,
-                           aViewportSize.height / scale.height);
-  gfxIntSize scaledViewportGfx(scaledViewport.width, scaledViewport.height);
-  nsIntRect scaledSubimage(aSubimage);
-  scaledSubimage.ScaleRoundOut(1.0 / scale.width, 1.0 / scale.height);
-
   // Remove the scaling from the transform.
   gfxMatrix unscale;
   unscale.Translate(gfxPoint(translation.x / scale.width,
                              translation.y / scale.height));
   unscale.Scale(1.0 / scale.width, 1.0 / scale.height);
   unscale.Translate(-translation);
   gfxMatrix unscaledTransform(aUserSpaceToImageSpace * unscale);
 
-  mSVGDocumentWrapper->UpdateViewportBounds(scaledViewport);
+  mSVGDocumentWrapper->UpdateViewportBounds(aViewportSize);
   mSVGDocumentWrapper->FlushImageTransformInvalidation();
 
-  // Based on imgFrame::Draw
-  gfxRect sourceRect = unscaledTransform.Transform(aFill);
-  gfxRect imageRect(0, 0, scaledViewport.width, scaledViewport.height);
-  gfxRect subimage(scaledSubimage.x, scaledSubimage.y,
-                   scaledSubimage.width, scaledSubimage.height);
-
+  // Rescale drawing parameters.
+  gfxIntSize drawableSize(aViewportSize.width / scale.width,
+                          aViewportSize.height / scale.height);
+  gfxRect drawableSourceRect = unscaledTransform.Transform(aFill);
+  gfxRect drawableImageRect(0, 0, drawableSize.width, drawableSize.height);
+  gfxRect drawableSubimage(aSubimage.x, aSubimage.y,
+                           aSubimage.width, aSubimage.height);
+  drawableSubimage.ScaleRoundOut(1.0 / scale.width, 1.0 / scale.height);
 
   nsRefPtr<gfxDrawingCallback> cb =
     new SVGDrawingCallback(mSVGDocumentWrapper,
-                           nsIntRect(nsIntPoint(0, 0), scaledViewport),
+                           nsIntRect(nsIntPoint(0, 0), aViewportSize),
+                           scale,
                            aFlags);
 
-  nsRefPtr<gfxDrawable> drawable = new gfxCallbackDrawable(cb, scaledViewportGfx);
+  nsRefPtr<gfxDrawable> drawable = new gfxCallbackDrawable(cb, drawableSize);
 
-  gfxUtils::DrawPixelSnapped(aContext, drawable,
-                             unscaledTransform,
-                             subimage, sourceRect, imageRect, aFill,
-                             gfxASurface::ImageFormatARGB32, aFilter,
-                             aFlags);
+  gfxUtils::DrawPixelSnapped(aContext, drawable, unscaledTransform,
+                             drawableSubimage, drawableSourceRect,
+                             drawableImageRect, aFill,
+                             gfxASurface::ImageFormatARGB32, aFilter, aFlags);
 
   MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now");
   mRenderingObserver->ResumeHonoringInvalidations();
 
   return NS_OK;
 }
 
 //******************************************************************************