Bug 934860 - Move paint region clipping into DrawThebesLayer. r=roc, a=
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 07 Nov 2013 08:10:50 +1300
changeset 167415 c0ab158ff96773a0129216ffa318539a1d9eecdf
parent 167414 813bcdac20ff8197bde4286c390a63f72ce17486
child 167416 05c2a19d916d7a746bb4d0b0a4e5fcc2dcddc020
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs934860
milestone27.0a2
Bug 934860 - Move paint region clipping into DrawThebesLayer. r=roc, a=
embedding/browser/webBrowser/nsWebBrowser.cpp
gfx/layers/Layers.h
gfx/layers/LayersTypes.h
gfx/layers/ThebesLayerBuffer.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicThebesLayer.cpp
gfx/layers/basic/BasicThebesLayer.h
gfx/layers/client/ClientThebesLayer.cpp
gfx/layers/client/ClientThebesLayer.h
gfx/layers/client/ClientTiledThebesLayer.h
gfx/layers/client/ContentClient.cpp
gfx/layers/client/TiledContentClient.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/d3d10/ThebesLayerD3D10.cpp
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -1657,16 +1657,17 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShe
    mDocShellTreeOwner->WebBrowser(this);
    
    return NS_OK;
 }
 
 static void DrawThebesLayer(ThebesLayer* aLayer,
                             gfxContext* aContext,
                             const nsIntRegion& aRegionToDraw,
+                            DrawRegionClip aClip,
                             const nsIntRegion& aRegionToInvalidate,
                             void* aCallbackData)
 {
   nscolor* color = static_cast<nscolor*>(aCallbackData);
   aContext->NewPath();
   aContext->SetColor(gfxRGBA(*color));
   nsIntRect dirtyRect = aRegionToDraw.GetBounds();
   aContext->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -260,16 +260,17 @@ public:
    * We guarantee that buffered contents in the visible
    * region are valid once drawing is complete.
    *
    * The origin of aContext is 0,0 in the ThebesLayer.
    */
   typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
                                            gfxContext* aContext,
                                            const nsIntRegion& aRegionToDraw,
+                                           DrawRegionClip aClip,
                                            const nsIntRegion& aRegionToInvalidate,
                                            void* aCallbackData);
 
   /**
    * Finish the construction phase of the transaction, perform the
    * drawing phase, and end the transaction.
    * During the drawing phase, all ThebesLayers in the tree are
    * drawn in tree order, exactly once each, except for those layers
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -53,16 +53,22 @@ enum LayersBackend {
   LAYERS_LAST
 };
 
 enum BufferMode {
   BUFFER_NONE,
   BUFFER_BUFFERED
 };
 
+enum DrawRegionClip {
+  CLIP_DRAW,
+  CLIP_DRAW_SNAPPED,
+  CLIP_NONE,
+};
+
 // LayerRenderState for Composer2D
 // We currently only support Composer2D using gralloc. If we want to be backed
 // by other surfaces we will need a more generic LayerRenderState.
 enum LayerRenderStateFlags {
   LAYER_RENDER_STATE_Y_FLIPPED = 1 << 0,
   LAYER_RENDER_STATE_BUFFER_ROTATION = 1 << 1,
   // Notify Composer2D to swap the RB pixels of gralloc buffer
   LAYER_RENDER_STATE_FORMAT_RB_SWAP = 1 << 2
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -811,16 +811,17 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
                "Rotation disabled, but we have nonzero rotation?");
 
   nsIntRegion invalidate;
   invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
 
   nsIntPoint topLeft;
   result.mContext = GetContextForQuadrantUpdate(drawBounds, BUFFER_BOTH, &topLeft);
+  result.mClip = CLIP_DRAW_SNAPPED;
 
   if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
     if (IsAzureBuffer()) {
       MOZ_ASSERT(mDTBuffer && mDTBufferOnWhite);
       nsIntRegionRectIterator iter(result.mRegionToDraw);
       const nsIntRect *iterRect;
       while ((iterRect = iter.Next())) {
         mDTBuffer->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height),
@@ -828,36 +829,33 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
         mDTBufferOnWhite->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height),
                                    ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
       }
     } else {
       MOZ_ASSERT(mBuffer && mBufferOnWhite);
       FillSurface(mBuffer, result.mRegionToDraw, topLeft, gfxRGBA(0.0, 0.0, 0.0, 1.0));
       FillSurface(mBufferOnWhite, result.mRegionToDraw, topLeft, gfxRGBA(1.0, 1.0, 1.0, 1.0));
     }
-    gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
   } else if (contentType == GFX_CONTENT_COLOR_ALPHA && !isClear) {
     if (IsAzureBuffer()) {
       nsIntRegionRectIterator iter(result.mRegionToDraw);
       const nsIntRect *iterRect;
       while ((iterRect = iter.Next())) {
         result.mContext->GetDrawTarget()->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
       }
       // Clear will do something expensive with a complex clip pushed, so clip
       // here.
-      gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
     } else {
       MOZ_ASSERT(result.mContext->IsCairo());
+      result.mContext->Save();
       gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
       result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
       result.mContext->Paint();
-      result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
+      result.mContext->Restore();
     }
-  } else {
-    gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
   }
 
   return result;
 }
 
 }
 }
 
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -16,16 +16,17 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "LayersTypes.h"
 
 struct gfxMatrix;
 struct nsIntSize;
 
 namespace mozilla {
 namespace gfx {
 class Matrix;
 }
@@ -211,16 +212,17 @@ public:
     PaintState()
       : mDidSelfCopy(false)
     {}
 
     nsRefPtr<gfxContext> mContext;
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
     bool mDidSelfCopy;
+    DrawRegionClip mClip;
   };
 
   enum {
     PAINT_WILL_RESAMPLE = 0x01,
     PAINT_NO_ROTATION = 0x02
   };
   /**
    * Start a drawing operation. This returns a PaintState describing what
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -126,17 +126,17 @@ BasicThebesLayer::PaintThebes(gfxContext
                                             &needsClipToVisibleRegion);
         if (GetOperator() != gfxContext::OPERATOR_OVER || mixBlendMode != gfxContext::OPERATOR_OVER) {
           needsClipToVisibleRegion = true;
         }
       } else {
         groupContext = aContext;
       }
       SetAntialiasingFlags(this, groupContext);
-      aCallback(this, groupContext, toDraw, nsIntRegion(), aCallbackData);
+      aCallback(this, groupContext, toDraw, CLIP_NONE, nsIntRegion(), aCallbackData);
       if (needsGroup) {
         BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext);
         if (needsClipToVisibleRegion) {
           gfxUtils::ClipToRegion(aContext, toDraw);
         }
         AutoSetOperator setOptimizedOperator(aContext, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator());
         PaintWithMask(aContext, opacity, aMaskLayer);
       }
@@ -231,16 +231,17 @@ BasicThebesLayer::Validate(LayerManager:
     nsIntRegion extendedDrawRegion = state.mRegionToDraw;
     SetAntialiasingFlags(this, state.mContext);
 
     RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds());
 
     PaintBuffer(state.mContext,
                 state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
                 state.mDidSelfCopy,
+                state.mClip,
                 aCallback, aCallbackData);
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
     Mutated();
 
     RenderTraceInvalidateEnd(this, "FFFF00");
   } else {
     // It's possible that state.mRegionToInvalidate is nonempty here,
     // if we are shrinking the valid region to nothing. So use mRegionToDraw
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -98,25 +98,26 @@ public:
 
 protected:
   virtual void
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
               bool aDidSelfCopy,
+              DrawRegionClip aClip,
               LayerManager::DrawThebesLayerCallback aCallback,
               void* aCallbackData)
   {
     if (!aCallback) {
       BasicManager()->SetTransactionIncomplete();
       return;
     }
-    aCallback(this, aContext, aExtendedRegionToDraw, aRegionToInvalidate,
-              aCallbackData);
+    aCallback(this, aContext, aExtendedRegionToDraw, aClip,
+              aRegionToInvalidate, aCallbackData);
     // Everything that's visible has been validated. Do this instead of just
     // OR-ing with aRegionToDraw, since that can lead to a very complex region
     // here (OR doesn't automatically simplify to the simplest possible
     // representation of a region.)
     nsIntRegion tmp;
     tmp.Or(mVisibleRegion, aExtendedRegionToDraw);
     mValidRegion.Or(mValidRegion, tmp);
   }
--- a/gfx/layers/client/ClientThebesLayer.cpp
+++ b/gfx/layers/client/ClientThebesLayer.cpp
@@ -101,17 +101,17 @@ ClientThebesLayer::PaintThebes()
       // subpixel AA)
       state.mRegionToInvalidate.And(state.mRegionToInvalidate,
                                     GetEffectiveVisibleRegion());
       nsIntRegion extendedDrawRegion = state.mRegionToDraw;
       SetAntialiasingFlags(this, state.mContext);
 
       PaintBuffer(state.mContext,
                   state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
-                  state.mDidSelfCopy);
+                  state.mDidSelfCopy, state.mClip);
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
       Mutated();
     } else {
       // It's possible that state.mRegionToInvalidate is nonempty here,
       // if we are shrinking the valid region to nothing. So use mRegionToDraw
       // instead.
       NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(),
                        "No context when we have something to draw, resource exhaustion?");
@@ -141,32 +141,33 @@ ClientThebesLayer::RenderLayer()
   mContentClient->EndPaint();
 }
 
 void
 ClientThebesLayer::PaintBuffer(gfxContext* aContext,
                                const nsIntRegion& aRegionToDraw,
                                const nsIntRegion& aExtendedRegionToDraw,
                                const nsIntRegion& aRegionToInvalidate,
-                               bool aDidSelfCopy)
+                               bool aDidSelfCopy, DrawRegionClip aClip)
 {
   ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
   MOZ_ASSERT(contentClientRemote->GetIPDLActor());
 
   // NB: this just throws away the entire valid region if there are
   // too many rects.
   mValidRegion.SimplifyInward(8);
 
   if (!ClientManager()->GetThebesLayerCallback()) {
     ClientManager()->SetTransactionIncomplete();
     return;
   }
   ClientManager()->GetThebesLayerCallback()(this, 
                                             aContext, 
-                                            aExtendedRegionToDraw, 
+                                            aExtendedRegionToDraw,
+                                            aClip,
                                             aRegionToInvalidate,
                                             ClientManager()->GetThebesLayerCallbackData());
 
   // Everything that's visible has been validated. Do this instead of just
   // OR-ing with aRegionToDraw, since that can lead to a very complex region
   // here (OR doesn't automatically simplify to the simplest possible
   // representation of a region.)
   nsIntRegion tmp;
--- a/gfx/layers/client/ClientThebesLayer.h
+++ b/gfx/layers/client/ClientThebesLayer.h
@@ -100,17 +100,18 @@ public:
   }
 
 protected:
   void
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
-              bool aDidSelfCopy);
+              bool aDidSelfCopy,
+              DrawRegionClip aClip);
   
   void PaintThebes();
   
   void DestroyBackBuffer()
   {
     mContentClient = nullptr;
   }
 
--- a/gfx/layers/client/ClientTiledThebesLayer.h
+++ b/gfx/layers/client/ClientTiledThebesLayer.h
@@ -64,28 +64,16 @@ public:
   virtual void RenderLayer();
 
 private:
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
   }
 
-  // BasicImplData
-  virtual void
-  PaintBuffer(gfxContext* aContext,
-              const nsIntRegion& aRegionToDraw,
-              const nsIntRegion& aExtendedRegionToDraw,
-              const nsIntRegion& aRegionToInvalidate,
-              bool aDidSelfCopy,
-              LayerManager::DrawThebesLayerCallback aCallback,
-              void* aCallbackData)
-  { NS_RUNTIMEABORT("Not reached."); }
-
-
   /**
    * For the initial PaintThebes of a transaction, calculates all the data
    * needed for that paint and any repeated transactions.
    */
   void BeginPaint();
 
   /**
    * When a paint ends, updates any data necessary to persist until the next
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -889,22 +889,24 @@ ContentClientIncremental::BeginPaintBuff
 
   // If we do partial updates, we have to clip drawing to the regionToDraw.
   // If we don't clip, background images will be fillrect'd to the region correctly,
   // while text or lines will paint outside of the regionToDraw. This becomes apparent
   // with concave regions. Right now the scrollbars invalidate a narrow strip of the bar
   // although they never cover it. This leads to two draw rects, the narow strip and the actually
   // newly exposed area. It would be wise to fix this glitch in any way to have simpler
   // clip and draw regions.
-  gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
+  result.mClip = CLIP_DRAW;
 
   if (mContentType == GFX_CONTENT_COLOR_ALPHA) {
+    result.mContext->Save();
+    gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
     result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
     result.mContext->Paint();
-    result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
+    result.mContext->Restore();
   }
 
   return result;
 }
 
 void
 ContentClientIncremental::Updated(const nsIntRegion& aRegionToDraw,
                                   const nsIntRegion& aVisibleRegion,
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -269,17 +269,17 @@ BasicTiledLayerBuffer::PaintThebes(const
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     if (PR_IntervalNow() - start > 3) {
       printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
     }
     start = PR_IntervalNow();
 #endif
     PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw");
 
-    mCallback(mThebesLayer, ctxt, aPaintRegion, nsIntRegion(), mCallbackData);
+    mCallback(mThebesLayer, ctxt, aPaintRegion, CLIP_NONE, nsIntRegion(), mCallbackData);
   }
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 30) {
     const nsIntRect bounds = aPaintRegion.GetBounds();
     printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
     if (aPaintRegion.IsComplex()) {
       printf_stderr("Complex region\n");
@@ -378,16 +378,17 @@ BasicTiledLayerBuffer::ValidateTileInter
   } else {
     ctxt->NewPath();
     ctxt->Scale(mResolution, mResolution);
     ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
     nsIntPoint a = nsIntPoint(aTileOrigin.x, aTileOrigin.y);
     mCallback(mThebesLayer, ctxt,
               nsIntRegion(nsIntRect(a, nsIntSize(GetScaledTileLength(),
                                                  GetScaledTileLength()))),
+              CLIP_NONE,
               nsIntRegion(), mCallbackData);
   }
 
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   DrawDebugOverlay(writableSurface, aTileOrigin.x * mResolution,
                    aTileOrigin.y * mResolution);
 #endif
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -153,30 +153,16 @@ public:
 
 
   DrawThebesLayerCallback GetThebesLayerCallback() const
   { return mThebesLayerCallback; }
 
   void* GetThebesLayerCallbackData() const
   { return mThebesLayerCallbackData; }
 
-  /*
-   * Helper functions for our layers
-   */
-  void CallThebesLayerDrawCallback(ThebesLayer* aLayer,
-                                   gfxContext* aContext,
-                                   const nsIntRegion& aRegionToDraw)
-  {
-    NS_ASSERTION(mThebesLayerCallback,
-                 "CallThebesLayerDrawCallback without callback!");
-    mThebesLayerCallback(aLayer, aContext,
-                         aRegionToDraw, nsIntRegion(),
-                         mThebesLayerCallbackData);
-  }
-
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const MOZ_OVERRIDE { return ""; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   enum WorldTransforPolicy {
     ApplyWorldTransform,
     DontApplyWorldTransform
   };
--- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp
@@ -409,50 +409,32 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion
       // only the onBlack surface will really be used, so alpha information will
       // be incorrect.
       destinationSurface->SetAllowUseAsSource(false);
     }
   } else {
     destinationSurface = mD2DSurface;
   }
 
-  nsRefPtr<gfxContext> context;
-
-  if (mDrawTarget) {
-    context = new gfxContext(mDrawTarget);
-  } else {
-    context = new gfxContext(destinationSurface);
-  }
+  MOZ_ASSERT(mDrawTarget);
+  nsRefPtr<gfxContext> context = new gfxContext(mDrawTarget);
 
-  nsIntRegionRectIterator iter(aRegion);
   context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y));
-  context->NewPath();
-  const nsIntRect *iterRect;
-  while ((iterRect = iter.Next())) {
-    context->Rectangle(gfxRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
-    if (mDrawTarget && aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
+  if (aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
+    nsIntRegionRectIterator iter(aRegion);
+    const nsIntRect *iterRect;
+    while ((iterRect = iter.Next())) {
       mDrawTarget->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
     }
   }
-  context->Clip();
 
-  if (!mDrawTarget && aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
-    context->SetOperator(gfxContext::OPERATOR_CLEAR);
-    context->Paint();
-    context->SetOperator(gfxContext::OPERATOR_OVER);
-  }
-
-  if (mD2DSurface) {
-    mD2DSurface->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
-  } else if (mDrawTarget) {
-    mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
-  }
+  mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
 
   LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
-  cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
+  cbInfo.Callback(this, context, aRegion, CLIP_DRAW, nsIntRegion(), cbInfo.CallbackData);
 }
 
 void
 ThebesLayerD3D10::CreateNewTextures(const gfxIntSize &aSize, SurfaceMode aMode)
 {
   if (aSize.width == 0 || aSize.height == 0) {
     // Nothing to do.
     return;
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -488,17 +488,17 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion 
 
     context = new gfxContext(dt);
   } else {
     context = new gfxContext(destinationSurface);
   }
 
   context->Translate(gfxPoint(-bounds.x, -bounds.y));
   LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
-  cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
+  cbInfo.Callback(this, context, aRegion, CLIP_NONE, nsIntRegion(), cbInfo.CallbackData);
 
   for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
     NS_ASSERTION(aMode == SURFACE_OPAQUE,
                  "Transparent surfaces should not be used for readback");
     const ReadbackProcessor::Update& update = aReadbackUpdates[i];
     nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset();
     nsRefPtr<gfxContext> ctx =
         update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset,
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -195,31 +195,16 @@ public:
   void* GetNSOpenGLContext() const;
 
   DrawThebesLayerCallback GetThebesLayerCallback() const
   { return mThebesLayerCallback; }
 
   void* GetThebesLayerCallbackData() const
   { return mThebesLayerCallbackData; }
 
-  /*
-   * Helper functions for our layers
-   */
-  void CallThebesLayerDrawCallback(ThebesLayer* aLayer,
-                                   gfxContext* aContext,
-                                   const nsIntRegion& aRegionToDraw)
-  {
-    NS_ASSERTION(mThebesLayerCallback,
-                 "CallThebesLayerDrawCallback without callback!");
-    mThebesLayerCallback(aLayer, aContext,
-                         aRegionToDraw, nsIntRegion(),
-                         mThebesLayerCallbackData);
-  }
-
-
   GLenum FBOTextureTarget() { return mFBOTextureTarget; }
 
   /**
    * Controls how to initialize the texture / FBO created by
    * CreateFBOWithTexture.
    *  - InitModeNone: No initialization, contents are undefined.
    *  - InitModeClear: Clears the FBO.
    *  - InitModeCopy: Copies the contents of the current glReadBuffer into the
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -823,22 +823,24 @@ BasicBufferOGL::BeginPaint(ContentType a
 
   // If we do partial updates, we have to clip drawing to the regionToDraw.
   // If we don't clip, background images will be fillrect'd to the region correctly,
   // while text or lines will paint outside of the regionToDraw. This becomes apparent
   // with concave regions. Right now the scrollbars invalidate a narrow strip of the bar
   // although they never cover it. This leads to two draw rects, the narow strip and the actually
   // newly exposed area. It would be wise to fix this glitch in any way to have simpler
   // clip and draw regions.
-  gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
+  result.mClip = CLIP_DRAW;
 
   if (mTexImage->GetContentType() == GFX_CONTENT_COLOR_ALPHA) {
+    result.mContext->Save();
+    gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
     result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
     result.mContext->Paint();
-    result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
+    result.mContext->Restore();
   }
 
   return result;
 }
 
 ThebesLayerOGL::ThebesLayerOGL(LayerManagerOGL* aManager)
   : ThebesLayer(aManager, nullptr)
   , LayerOGL(aManager)
@@ -926,17 +928,17 @@ ThebesLayerOGL::RenderLayer(int aPreviou
 
     LayerManager::DrawThebesLayerCallback callback =
       mOGLManager->GetThebesLayerCallback();
     if (!callback) {
       NS_ERROR("GL should never need to update ThebesLayers in an empty transaction");
     } else {
       void* callbackData = mOGLManager->GetThebesLayerCallbackData();
       SetAntialiasingFlags(this, state.mContext);
-      callback(this, state.mContext, state.mRegionToDraw,
+      callback(this, state.mContext, state.mRegionToDraw, state.mClip,
                state.mRegionToInvalidate, callbackData);
       // Everything that's visible has been validated. Do this instead of just
       // OR-ing with aRegionToDraw, since that can lead to a very complex region
       // here (OR doesn't automatically simplify to the simplest possible
       // representation of a region.)
       nsIntRegion tmp;
       tmp.Or(mVisibleRegion, state.mRegionToDraw);
       mValidRegion.Or(mValidRegion, tmp);
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3262,24 +3262,31 @@ FrameLayerBuilder::PaintItems(nsTArray<C
  * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
  * always falls within the visible region we computed.
  */
 
 /* static */ void
 FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
                                    gfxContext* aContext,
                                    const nsIntRegion& aRegionToDraw,
+                                   DrawRegionClip aClip,
                                    const nsIntRegion& aRegionToInvalidate,
                                    void* aCallbackData)
 {
   PROFILER_LABEL("gfx", "DrawThebesLayer");
 
   nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
     (aCallbackData);
 
+  if (aClip == CLIP_DRAW_SNAPPED) {
+    gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
+  } else if (aClip == CLIP_DRAW) {
+    gfxUtils::ClipToRegion(aContext, aRegionToDraw);
+  }
+
   FrameLayerBuilder *layerBuilder = aLayer->Manager()->GetLayerBuilder();
   NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!");
 
   if (layerBuilder->CheckDOMModified())
     return;
 
   ThebesLayerItemsEntry* entry = layerBuilder->mThebesLayerItems.GetEntry(aLayer);
   NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -239,16 +239,17 @@ public:
    * This callback must be provided to EndTransaction. The callback data
    * must be the nsDisplayListBuilder containing this FrameLayerBuilder.
    * This function can be called multiple times in a row to draw
    * different regions.
    */
   static void DrawThebesLayer(ThebesLayer* aLayer,
                               gfxContext* aContext,
                               const nsIntRegion& aRegionToDraw,
+                              mozilla::layers::DrawRegionClip aClip,
                               const nsIntRegion& aRegionToInvalidate,
                               void* aCallbackData);
 
 #ifdef MOZ_DUMP_PAINTING
   /**
    * Dumps this FrameLayerBuilder's retained layer manager's retained
    * layer tree. Defaults to dumping to stdout in non-HTML format.
    */