Bug 570625, part 0: Don't throw out buffers when scrolling with a resolution applied. r=roc
authorChris Jones <jones.chris.g@gmail.com>
Tue, 14 Sep 2010 00:23:08 -0500
changeset 54100 324632361f18ce038234184757d878b5fe21f550
parent 54099 16b228558c58fd66ee3bfb95821f9fa92e204feb
child 54101 5004f6392fb29c0a3a3a54d4b2ffc7ac5bbec4bf
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs570625
milestone2.0b6pre
Bug 570625, part 0: Don't throw out buffers when scrolling with a resolution applied. r=roc
gfx/layers/ThebesLayerBuffer.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicLayers.cpp
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -173,22 +173,23 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
     Clear();
   }
 
   if (result.mRegionToDraw.IsEmpty())
     return result;
   nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
 
   nsIntRect visibleBounds = aLayer->GetVisibleRegion().GetBounds();
-  nsIntSize scaledBufferSize = ScaledSize(visibleBounds.Size(),
-                                          aXResolution, aYResolution);
+  nsIntSize destBufferDims = ScaledSize(visibleBounds.Size(),
+                                        aXResolution, aYResolution);
   nsRefPtr<gfxASurface> destBuffer;
   nsIntRect destBufferRect;
+  PRBool bufferDimsChanged = PR_FALSE;
 
-  if (BufferSizeOkFor(scaledBufferSize)) {
+  if (BufferSizeOkFor(destBufferDims)) {
     NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
                  "resolution changes must Clear()!");
 
     // The current buffer is big enough to hold the visible area.
     if (mBufferRect.Contains(visibleBounds)) {
       // We don't need to adjust mBufferRect.
       destBufferRect = mBufferRect;
     } else {
@@ -214,19 +215,20 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
         // The stuff we need to redraw will wrap around an edge of the
         // buffer, so we will need to do a self-copy
         if (mBufferRotation == nsIntPoint(0,0)) {
           destBuffer = mBuffer;
         } else {
           // We can't do a real self-copy because the buffer is rotated.
           // So allocate a new buffer for the destination.
           destBufferRect = visibleBounds;
-          destBuffer = CreateBuffer(aContentType,
-                                    ScaledSize(destBufferRect.Size(),
-                                               aXResolution, aYResolution));
+          destBufferDims = ScaledSize(destBufferRect.Size(),
+                                      aXResolution, aYResolution);
+          bufferDimsChanged = PR_TRUE;
+          destBuffer = CreateBuffer(aContentType, destBufferDims);
           if (!destBuffer)
             return result;
         }
       } else {
         mBufferRect = destBufferRect;
         mBufferRotation = newRotation;
       }
     } else {
@@ -234,19 +236,20 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
       // will be redrawn, so we don't need to copy anything, so we don't
       // set destBuffer.
       mBufferRect = destBufferRect;
       mBufferRotation = nsIntPoint(0,0);
     }
   } else {
     // The buffer's not big enough, so allocate a new one
     destBufferRect = visibleBounds;
-    destBuffer = CreateBuffer(aContentType,
-                              ScaledSize(destBufferRect.Size(),
-                                         aXResolution, aYResolution));
+    destBufferDims = ScaledSize(destBufferRect.Size(),
+                                aXResolution, aYResolution);
+    bufferDimsChanged = PR_TRUE;
+    destBuffer = CreateBuffer(aContentType, destBufferDims);
     if (!destBuffer)
       return result;
   }
 
   // If we have no buffered data already, then destBuffer will be a fresh buffer
   // and we do not need to clear it below.
   PRBool isClear = mBuffer == nsnull;
 
@@ -262,16 +265,19 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
                    "resolution changes must Clear()!");
       DrawBufferWithRotation(tmpCtx, 1.0, aXResolution, aYResolution);
     }
 
     mBuffer = destBuffer.forget();
     mBufferRect = destBufferRect;
     mBufferRotation = nsIntPoint(0,0);
   }
+  if (bufferDimsChanged) {
+    mBufferDims = destBufferDims;
+  }
 
   nsIntRegion invalidate;
   invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
 
   result.mContext = new gfxContext(mBuffer);
 
   // Figure out which quadrant to draw in
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -77,33 +77,35 @@ public:
    *   fit visible bounds.  May be larger.
    */
   enum BufferSizePolicy {
     SizedToVisibleBounds,
     ContainsVisibleBounds
   };
 
   ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
-    : mBufferRotation(0,0)
+    : mBufferDims(0,0)
+    , mBufferRotation(0,0)
     , mBufferSizePolicy(aBufferSizePolicy)
   {
     MOZ_COUNT_CTOR(ThebesLayerBuffer);
   }
   virtual ~ThebesLayerBuffer()
   {
     MOZ_COUNT_DTOR(ThebesLayerBuffer);
   }
 
   /**
    * Wipe out all retained contents. Call this when the entire
    * buffer becomes invalid.
    */
   void Clear()
   {
     mBuffer = nsnull;
+    mBufferDims.SizeTo(0, 0);
     mBufferRect.Empty();
   }
 
   /**
    * This is returned by BeginPaint. The caller should draw into mContext.
    * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
    * by ThebesLayerBuffer and must be redrawn on the screen.
    * mRegionToInvalidate is set when the buffer has changed from
@@ -152,35 +154,42 @@ protected:
                           float aOpacity, float aXRes, float aYRes);
   void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
                               float aXRes, float aYRes);
 
   const nsIntRect& BufferRect() const { return mBufferRect; }
   const nsIntPoint& BufferRotation() const { return mBufferRotation; }
 
   already_AddRefed<gfxASurface>
-  SetBuffer(gfxASurface* aBuffer,
+  SetBuffer(gfxASurface* aBuffer, const nsIntSize& aBufferDims,
             const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation)
   {
     nsRefPtr<gfxASurface> tmp = mBuffer.forget();
     mBuffer = aBuffer;
+    mBufferDims = aBufferDims;
     mBufferRect = aBufferRect;
     mBufferRotation = aBufferRotation;
     return tmp.forget();
   }
 
 private:
   PRBool BufferSizeOkFor(const nsIntSize& aSize)
   {
-    return (aSize == mBufferRect.Size() ||
+    return (aSize == mBufferDims ||
             (SizedToVisibleBounds != mBufferSizePolicy &&
-             aSize < mBufferRect.Size()));
+             aSize < mBufferDims));
   }
 
   nsRefPtr<gfxASurface> mBuffer;
+  /**
+   * The actual dimensions of mBuffer.  For the ContainsVisibleBounds
+   * policy or with resolution-scaled drawing, mBufferDims might be
+   * different than mBufferRect.Size().
+   */
+  nsIntSize             mBufferDims;
   /** The area of the ThebesLayer that is covered by the buffer as a whole */
   nsIntRect             mBufferRect;
   /**
    * The x and y rotation of the buffer. Conceptually the buffer
    * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
    * is tiled to fill the plane, and the result is clipped to mBufferRect.
    * So the pixel at mBufferRotation within the buffer is what gets painted at
    * mBufferRect.TopLeft().
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1659,21 +1659,22 @@ public:
   }
 
   ~ShadowThebesLayerBuffer()
   {
     MOZ_COUNT_DTOR(ShadowThebesLayerBuffer);
   }
 
   already_AddRefed<gfxSharedImageSurface>
-  Swap(gfxSharedImageSurface* aNewFrontBuffer,
+  Swap(gfxSharedImageSurface* aNewFrontBuffer, const nsIntSize& aBufferDims,
        const nsIntRect& aBufferRect,
        const nsIntPoint& aRotation=nsIntPoint(0, 0))
   {
     nsRefPtr<gfxASurface> newBackBuffer = SetBuffer(aNewFrontBuffer,
+                                                    aBufferDims,
                                                     aBufferRect, aRotation);
     return static_cast<gfxSharedImageSurface*>(newBackBuffer.forget().get());
   }
 
 protected:
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(ContentType aType, const nsIntSize& aSize)
   {
@@ -1703,23 +1704,25 @@ public:
     ShadowThebesLayer::Disconnect();
   }
 
   virtual already_AddRefed<gfxSharedImageSurface>
   Swap(gfxSharedImageSurface* aNewFront,
        const nsIntRect& aBufferRect,
        const nsIntPoint& aRotation)
   {
-    return mFrontBuffer.Swap(aNewFront, aBufferRect, aRotation);
+    gfxIntSize size = aNewFront->GetSize();
+    return mFrontBuffer.Swap(aNewFront, nsIntSize(size.width, size.height),
+                             aBufferRect, aRotation);
   }
 
   virtual void DestroyFrontBuffer()
   {
     nsRefPtr<gfxSharedImageSurface> frontBuffer =
-      mFrontBuffer.Swap(0, nsIntRect());
+      mFrontBuffer.Swap(0, nsIntSize(), nsIntRect());
     if (frontBuffer) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer);
     }
   }
 
   virtual void Paint(gfxContext* aContext,
                      LayerManager::DrawThebesLayerCallback aCallback,
                      void* aCallbackData,