Bug 917703 - Avoid copying to a sub image in CreateSamplingRestrictedDrawable if possible. r=roc
☠☠ backed out by 25ee493a6e17 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 19 Sep 2013 17:23:31 +1200
changeset 147849 8fcdbbc2dac2e6b9d1203928c2249915c7d1de35
parent 147848 aa253a1fd7e5c65c33ac076df450f20863ebb260
child 147850 ae02054863f74995a66a912c79974a345ba05f30
push id25317
push useremorley@mozilla.com
push dateThu, 19 Sep 2013 14:37:38 +0000
treeherdermozilla-central@70a765607344 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs917703
milestone27.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 917703 - Avoid copying to a sub image in CreateSamplingRestrictedDrawable if possible. r=roc
gfx/thebes/gfxDrawable.cpp
gfx/thebes/gfxDrawable.h
gfx/thebes/gfxImageSurface.cpp
gfx/thebes/gfxUtils.cpp
--- a/gfx/thebes/gfxDrawable.cpp
+++ b/gfx/thebes/gfxDrawable.cpp
@@ -129,16 +129,22 @@ gfxSurfaceDrawable::Draw(gfxContext* aCo
     pattern->SetMatrix(gfxMatrix(aTransform).Multiply(mTransform));
     aContext->NewPath();
     aContext->SetPattern(pattern);
     aContext->Rectangle(aFillRect);
     aContext->Fill();
     return true;
 }
 
+already_AddRefed<gfxImageSurface>
+gfxSurfaceDrawable::GetAsImageSurface()
+{
+    return mSurface->GetAsImageSurface();
+}
+
 gfxCallbackDrawable::gfxCallbackDrawable(gfxDrawingCallback* aCallback,
                                          const gfxIntSize aSize)
  : gfxDrawable(aSize)
  , mCallback(aCallback)
 {
 }
 
 already_AddRefed<gfxSurfaceDrawable>
--- a/gfx/thebes/gfxDrawable.h
+++ b/gfx/thebes/gfxDrawable.h
@@ -10,16 +10,17 @@
 #include "nsAutoPtr.h"
 #include "gfxTypes.h"
 #include "gfxRect.h"
 #include "gfxColor.h"
 #include "gfxMatrix.h"
 #include "gfxPattern.h"
 
 class gfxASurface;
+class gfxImageSurface;
 class gfxContext;
 
 /**
  * gfxDrawable
  * An Interface representing something that has an intrinsic size and can draw
  * itself repeatedly.
  */
 class gfxDrawable {
@@ -36,16 +37,17 @@ public:
      * pattern prior to rendering it.
      *  @return whether drawing was successful
      */
     virtual bool Draw(gfxContext* aContext,
                         const gfxRect& aFillRect,
                         bool aRepeat,
                         const gfxPattern::GraphicsFilter& aFilter,
                         const gfxMatrix& aTransform = gfxMatrix()) = 0;
+    virtual already_AddRefed<gfxImageSurface> GetAsImageSurface() { return nullptr; }
     virtual gfxIntSize Size() { return mSize; }
 
 protected:
     const gfxIntSize mSize;
 };
 
 /**
  * gfxSurfaceDrawable
@@ -57,16 +59,18 @@ public:
                        const gfxMatrix aTransform = gfxMatrix());
     virtual ~gfxSurfaceDrawable() {}
 
     virtual bool Draw(gfxContext* aContext,
                         const gfxRect& aFillRect,
                         bool aRepeat,
                         const gfxPattern::GraphicsFilter& aFilter,
                         const gfxMatrix& aTransform = gfxMatrix());
+    
+    virtual already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
 protected:
     nsRefPtr<gfxASurface> mSurface;
     const gfxMatrix mTransform;
 };
 
 /**
  * gfxDrawingCallback
--- a/gfx/thebes/gfxImageSurface.cpp
+++ b/gfx/thebes/gfxImageSurface.cpp
@@ -292,16 +292,18 @@ gfxImageSurface::CopyFrom(gfxImageSurfac
     return true;
 }
 
 already_AddRefed<gfxSubimageSurface>
 gfxImageSurface::GetSubimage(const gfxRect& aRect)
 {
     gfxRect r(aRect);
     r.Round();
+    MOZ_ASSERT(gfxRect(0, 0, mSize.width, mSize.height).Contains(r));
+
     unsigned char* subData = Data() +
         (Stride() * (int)r.Y()) +
         (int)r.X() * gfxASurface::BytePerPixelFromFormat(Format());
 
     nsRefPtr<gfxSubimageSurface> image =
         new gfxSubimageSurface(this, subData,
                                gfxIntSize((int)r.Width(), (int)r.Height()));
 
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -240,26 +240,33 @@ CreateSamplingRestrictedDrawable(gfxDraw
 
     // 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())
         return nullptr;
 
+    nsRefPtr<gfxASurface> temp;
     gfxIntSize size(int32_t(needed.Width()), int32_t(needed.Height()));
-    nsRefPtr<gfxASurface> temp =
-        gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ContentFromFormat(aFormat));
-    if (!temp || temp->CairoStatus())
-        return nullptr;
 
-    nsRefPtr<gfxContext> tmpCtx = new gfxContext(temp);
-    tmpCtx->SetOperator(OptimalFillOperator());
-    aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
-                    gfxPattern::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft()));
+    nsRefPtr<gfxImageSurface> image = aDrawable->GetAsImageSurface();
+    if (image && gfxRect(0, 0, image->GetSize().width, image->GetSize().height).Contains(needed)) {
+      temp = image->GetSubimage(needed);
+    } else {
+      temp =
+          gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ContentFromFormat(aFormat));
+      if (!temp || temp->CairoStatus())
+          return nullptr;
+
+      nsRefPtr<gfxContext> tmpCtx = new gfxContext(temp);
+      tmpCtx->SetOperator(OptimalFillOperator());
+      aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
+                      gfxPattern::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft()));
+    }
 
     nsRefPtr<gfxDrawable> drawable = 
         new gfxSurfaceDrawable(temp, size, gfxMatrix().Translate(-needed.TopLeft()));
     return drawable.forget();
 }
 #endif // !MOZ_GFX_OPTIMIZE_MOBILE
 
 // working around cairo/pixman bug (bug 364968)