Bug 917703 - Avoid copying to a sub image in CreateSamplingRestrictedDrawable if possible. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 19 Sep 2013 17:23:31 +1200
changeset 148036 a2bd329f6ba02c55571211f386e526e7358eb993
parent 148035 663104548b52427def2595f2041f801d6d5a9d44
child 148037 063627f4d8c2fb6be7207c640ae635b9ae545b4a
push id34088
push usermwoodrow@mozilla.com
push dateFri, 20 Sep 2013 09:50:27 +0000
treeherdermozilla-inbound@e844f4ed3e1f [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)