Bug 957366 - Skip the temporary surface during filter drawing for DrawTarget-backed gfxContexts. r=roc
authorMarkus Stange <mstange@themasta.com>
Wed, 08 Jan 2014 10:30:57 +0100
changeset 162572 ab6bc5637e29f3f8dad7212db75abcdd1db74c4e
parent 162571 1a31d585b193bd12ac0402322074df9f25b1f039
child 162573 1ff04cca465b386934de5d4df79351e743255f05
push id25960
push userryanvm@gmail.com
push dateWed, 08 Jan 2014 20:34:35 +0000
treeherdermozilla-central@0449f682dd31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs957366
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 957366 - Skip the temporary surface during filter drawing for DrawTarget-backed gfxContexts. r=roc
layout/svg/nsSVGFilterInstance.cpp
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/layout/svg/nsSVGFilterInstance.cpp
+++ b/layout/svg/nsSVGFilterInstance.cpp
@@ -454,67 +454,75 @@ nsSVGFilterInstance::Render(gfxContext* 
     return rv;
 
   if (mPrimitiveDescriptions.IsEmpty()) {
     // Nothing should be rendered.
     return NS_OK;
   }
 
   nsIntRect filterRect = mPostFilterDirtyRect.Intersect(mFilterSpaceBounds);
+  gfxMatrix ctm = GetFilterSpaceToDeviceSpaceTransform();
 
-  if (filterRect.IsEmpty()) {
+  if (filterRect.IsEmpty() || ctm.IsSingular()) {
     return NS_OK;
   }
 
+  Matrix oldDTMatrix;
   nsRefPtr<gfxASurface> resultImage;
-  RefPtr<DrawTarget> resultImageDT;
+  RefPtr<DrawTarget> dt;
   if (aContext->IsCairo()) {
     resultImage =
       gfxPlatform::GetPlatform()->CreateOffscreenSurface(filterRect.Size(),
                                                          GFX_CONTENT_COLOR_ALPHA);
     if (!resultImage || resultImage->CairoStatus())
       return NS_ERROR_OUT_OF_MEMORY;
 
     // Create a Cairo DrawTarget around resultImage.
-    resultImageDT =
-      gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(
-        resultImage, ToIntSize(filterRect.Size()));
+    dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(
+           resultImage, ToIntSize(filterRect.Size()));
   } else {
-    resultImageDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
-      ToIntSize(filterRect.Size()), FORMAT_B8G8R8A8);
+    // When we have a DrawTarget-backed context, we can call DrawFilter
+    // directly on the target DrawTarget and don't need a temporary DT.
+    dt = aContext->GetDrawTarget();
+    oldDTMatrix = dt->GetTransform();
+    Matrix matrix = ToMatrix(ctm);
+    matrix.Translate(filterRect.x, filterRect.y);
+    dt->SetTransform(matrix * oldDTMatrix);
   }
 
   ComputeNeededBoxes();
 
-  rv = BuildSourceImage(resultImage, resultImageDT);
+  rv = BuildSourceImage(resultImage, dt);
   if (NS_FAILED(rv))
     return rv;
-  rv = BuildSourcePaints(resultImage, resultImageDT);
+  rv = BuildSourcePaints(resultImage, dt);
   if (NS_FAILED(rv))
     return rv;
 
   IntRect filterSpaceBounds = ToIntRect(mFilterSpaceBounds);
   FilterDescription filter(mPrimitiveDescriptions, filterSpaceBounds);
 
   FilterSupport::RenderFilterDescription(
-    resultImageDT, filter, ToRect(filterRect),
+    dt, filter, ToRect(filterRect),
     mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
     mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
     mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
     mInputImages);
 
-  RefPtr<SourceSurface> resultImageSource;
-  if (!resultImage) {
-    resultImageSource = resultImageDT->Snapshot();
+  if (resultImage) {
+    aContext->Save();
+    aContext->Multiply(ctm);
+    aContext->Translate(filterRect.TopLeft());
+    aContext->SetSource(resultImage);
+    aContext->Paint();
+    aContext->Restore();
+  } else {
+    dt->SetTransform(oldDTMatrix);
   }
 
-  gfxMatrix ctm = GetFilterSpaceToDeviceSpaceTransform();
-  nsSVGUtils::CompositeSurfaceMatrix(aContext, resultImage, resultImageSource,
-                                     filterRect.TopLeft(), ctm);
-
   return NS_OK;
 }
 
 nsresult
 nsSVGFilterInstance::ComputePostFilterDirtyRect(nsIntRect* aPostFilterDirtyRect)
 {
   *aPostFilterDirtyRect = nsIntRect();
   if (mPreFilterDirtyRect.IsEmpty()) {
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -837,47 +837,16 @@ nsSVGUtils::GetClipRectForFrame(nsIFrame
     }
      
     return clipRect;
   }
   return gfxRect(aX, aY, aWidth, aHeight);
 }
 
 void
-nsSVGUtils::CompositeSurfaceMatrix(gfxContext *aContext,
-                                   gfxASurface *aSurface,
-                                   SourceSurface *aSourceSurface,
-                                   const gfxPoint &aSurfaceOffset,
-                                   const gfxMatrix &aCTM)
-{
-  if (aCTM.IsSingular())
-    return;
-
-  if (aSurface) {
-    aContext->Save();
-    aContext->Multiply(aCTM);
-    aContext->Translate(aSurfaceOffset);
-    aContext->SetSource(aSurface);
-    aContext->Paint();
-    aContext->Restore();
-  } else {
-    DrawTarget *destDT = aContext->GetDrawTarget();
-    Matrix oldMat = destDT->GetTransform();
-    destDT->SetTransform(ToMatrix(aCTM) * oldMat);
-
-    IntSize size = aSourceSurface->GetSize();
-    Rect sourceRect(Point(0, 0), Size(size.width, size.height));
-    Rect drawRect = sourceRect + ToPoint(aSurfaceOffset);
-    destDT->DrawSurface(aSourceSurface, drawRect, sourceRect);
-
-    destDT->SetTransform(oldMat);
-  }
-}
-
-void
 nsSVGUtils::SetClipRect(gfxContext *aContext,
                         const gfxMatrix &aCTM,
                         const gfxRect &aRect)
 {
   if (aCTM.IsSingular())
     return;
 
   gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(aContext);
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -408,27 +408,16 @@ public:
    * http://www.w3.org/TR/SVG11/masking.html#OverflowAndClipProperties
    * The arguments for aX, aY, aWidth and aHeight should be the dimensions of
    * the viewport established by aFrame.
    */
   static gfxRect
   GetClipRectForFrame(nsIFrame *aFrame,
                       float aX, float aY, float aWidth, float aHeight);
 
-  /**
-   * Composites a surface into a context with a given surface offset and an
-   * additional transform. Supports both Thebes and DrawTarget drawing.
-   * If aSurface is null, aSourceSurface will be used instead.
-   */
-  static void CompositeSurfaceMatrix(gfxContext *aContext,
-                                     gfxASurface *aSurface,
-                                     mozilla::gfx::SourceSurface *aSourceSurface,
-                                     const gfxPoint &aSurfaceOffset,
-                                     const gfxMatrix &aCTM);
-
   static void SetClipRect(gfxContext *aContext,
                           const gfxMatrix &aCTM,
                           const gfxRect &aRect);
 
   /* Using group opacity instead of fill or stroke opacity on a
    * geometry object seems to be a common authoring mistake.  If we're
    * not applying filters and not both stroking and filling, we can
    * generate the same result without going through the overhead of a