Back out bug 622072 because it caused bug 645987
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 29 Mar 2011 14:31:53 -0400
changeset 64162 8c373f9e40569a81d1f8c34a73c3fd8e86814fa8
parent 63981 d9c2c2e76a37a8f6f5c337e7a445dd4a9ec4d197
child 64163 a2937d08aefbd86fd8f852565f15daeadac0ad07
push idunknown
push userunknown
push dateunknown
bugs622072, 645987
milestone2.2a1pre
Back out bug 622072 because it caused bug 645987
content/canvas/public/nsICanvasRenderingContextInternal.h
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/html/content/public/nsHTMLCanvasElement.h
content/html/content/src/nsHTMLCanvasElement.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/d3d10/CanvasLayerD3D10.cpp
gfx/layers/d3d10/CanvasLayerD3D10.h
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/CanvasLayerD3D9.h
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/generic/nsFrame.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsIFrame.h
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -38,25 +38,24 @@
 #ifndef nsICanvasRenderingContextInternal_h___
 #define nsICanvasRenderingContextInternal_h___
 
 #include "nsISupports.h"
 #include "nsIInputStream.h"
 #include "nsIDocShell.h"
 #include "gfxPattern.h"
 
+// {EC90F32E-7848-4819-A1E3-02E64C682A72}
 #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
-{ 0xffb42d3c, 0x8281, 0x44c8, \
-  { 0xac, 0xba, 0x73, 0x15, 0x31, 0xaa, 0xe5, 0x07 } }
+{ 0xec90f32e, 0x7848, 0x4819, { 0xa1, 0xe3, 0x2, 0xe6, 0x4c, 0x68, 0x2a, 0x72 } }
 
 class nsHTMLCanvasElement;
 class gfxContext;
 class gfxASurface;
 class nsIPropertyBag;
-class nsDisplayListBuilder;
 
 namespace mozilla {
 namespace layers {
 class CanvasLayer;
 class LayerManager;
 }
 namespace ipc {
 class Shmem;
@@ -104,18 +103,17 @@ public:
   NS_IMETHOD SetIsOpaque(PRBool isOpaque) = 0;
 
   // Invalidate this context and release any held resources, in preperation
   // for possibly reinitializing with SetDimensions/InitializeWithSurface.
   NS_IMETHOD Reset() = 0;
 
   // Return the CanvasLayer for this context, creating
   // one for the given layer manager if not available.
-  virtual already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                                                       CanvasLayer *aOldLayer,
+  virtual already_AddRefed<CanvasLayer> GetCanvasLayer(CanvasLayer *aOldLayer,
                                                        LayerManager *aManager) = 0;
 
   virtual void MarkContextClean() = 0;
 
   // Redraw the dirty rectangle of this canvas.
   NS_IMETHOD Redraw(const gfxRect &dirty) = 0;
 
   // Passes a generic nsIPropertyBag options argument, along with the
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -53,17 +53,16 @@
 
 #include "imgIEncoder.h"
 
 #include "gfxContext.h"
 #include "gfxPattern.h"
 #include "gfxUtils.h"
 
 #include "CanvasUtils.h"
-#include "nsDisplayList.h"
 
 #include "GLContextProvider.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #ifdef MOZ_SVG
 #include "nsSVGEffects.h"
 #endif
@@ -243,26 +242,26 @@ WebGLContext::DestroyResourcesAndContext
 #endif
 
     gl = nsnull;
 }
 
 void
 WebGLContext::Invalidate()
 {
-    if (mInvalidated)
-        return;
-
     if (!mCanvasElement)
         return;
 
 #ifdef MOZ_SVG
     nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());
 #endif
 
+    if (mInvalidated)
+        return;
+
     mInvalidated = PR_TRUE;
     HTMLCanvasElement()->InvalidateFrame();
 }
 
 /* readonly attribute nsIDOMHTMLCanvasElement canvas; */
 NS_IMETHODIMP
 WebGLContext::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
 {
@@ -615,64 +614,37 @@ WebGLContext::GetInputStream(const char*
 NS_IMETHODIMP
 WebGLContext::GetThebesSurface(gfxASurface **surface)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 static PRUint8 gWebGLLayerUserData;
 
-class WebGLContextUserData : public LayerUserData {
-public:
-    WebGLContextUserData(nsHTMLCanvasElement *aContent)
-    : mContent(aContent) {}
-  static void DidTransactionCallback(void* aData)
-  {
-    static_cast<WebGLContextUserData*>(aData)->mContent->MarkContextClean();
-  }
-
-private:
-  nsRefPtr<nsHTMLCanvasElement> mContent;
-};
-
 already_AddRefed<layers::CanvasLayer>
-WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                             CanvasLayer *aOldLayer,
+WebGLContext::GetCanvasLayer(CanvasLayer *aOldLayer,
                              LayerManager *aManager)
 {
     if (!mResetLayer && aOldLayer &&
         aOldLayer->HasUserData(&gWebGLLayerUserData)) {
         NS_ADDREF(aOldLayer);
+        if (mInvalidated) {
+            aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+            mInvalidated = PR_FALSE;
+            HTMLCanvasElement()->GetPrimaryCanvasFrame()->MarkLayersActive();
+        }
         return aOldLayer;
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
         return nsnull;
     }
-    WebGLContextUserData *userData = nsnull;
-    if (aBuilder->IsPaintingToWindow()) {
-      // Make the layer tell us whenever a transaction finishes (including
-      // the current transaction), so we can clear our invalidation state and
-      // start invalidating again. We need to do this for the layer that is
-      // being painted to a window (there shouldn't be more than one at a time,
-      // and if there is, flushing the invalidation state more often than
-      // necessary is harmless).
-
-      // The layer will be destroyed when we tear down the presentation
-      // (at the latest), at which time this userData will be destroyed,
-      // releasing the reference to the element.
-      // The userData will receive DidTransactionCallbacks, which flush the
-      // the invalidation state to indicate that the canvas is up to date.
-      userData = new WebGLContextUserData(HTMLCanvasElement());
-      canvasLayer->SetDidTransactionCallback(
-              WebGLContextUserData::DidTransactionCallback, userData);
-    }
-    canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
+    canvasLayer->SetUserData(&gWebGLLayerUserData, nsnull);
 
     CanvasLayer::Data data;
 
     // the gl context may either provide a native PBuffer, in which case we want to initialize
     // data with the gl context directly, or may provide a surface to which it renders (this is the case
     // of OSMesa contexts), in which case we want to initialize data with that surface.
 
     void* native_surface = gl->GetNativeData(gl::GLContext::NativeImageSurface);
@@ -684,18 +656,19 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
     }
 
     data.mSize = nsIntSize(mWidth, mHeight);
     data.mGLBufferIsPremultiplied = mOptions.premultipliedAlpha ? PR_TRUE : PR_FALSE;
 
     canvasLayer->Initialize(data);
     PRUint32 flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
     canvasLayer->SetContentFlags(flags);
-    canvasLayer->Updated();
+    canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
 
+    mInvalidated = PR_FALSE;
     mResetLayer = PR_FALSE;
 
     return canvasLayer.forget().get();
 }
 
 NS_IMETHODIMP
 WebGLContext::GetContextAttributes(jsval *aResult)
 {
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -363,20 +363,19 @@ public:
     }
     nsresult ErrorOutOfMemory(const char *fmt = 0, ...);
 
     WebGLTexture *activeBoundTextureForTarget(WebGLenum target) {
         return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
                                              : mBoundCubeMapTextures[mActiveTexture];
     }
 
-    already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                                                 CanvasLayer *aOldLayer,
+    already_AddRefed<CanvasLayer> GetCanvasLayer(CanvasLayer *aOldLayer,
                                                  LayerManager *aManager);
-    void MarkContextClean() { mInvalidated = PR_FALSE; }
+    void MarkContextClean() { }
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     PRUint32 Generation() { return mGeneration.value(); }
 
 protected:
     void SetDontKnowIfNeedFakeBlack() {
         mFakeBlackStatus = DontKnowIfNeedFakeBlack;
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -91,17 +91,16 @@
 #include "nsIDocShell.h"
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
-#include "nsDisplayList.h"
 
 #include "nsTArray.h"
 
 #include "imgIEncoder.h"
 
 #include "gfxContext.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
@@ -403,18 +402,17 @@ public:
     NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height);
     NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
     NS_IMETHOD GetThebesSurface(gfxASurface **surface);
     NS_IMETHOD SetIsOpaque(PRBool isOpaque);
     NS_IMETHOD Reset();
-    already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                                                 CanvasLayer *aOldLayer,
+    already_AddRefed<CanvasLayer> GetCanvasLayer(CanvasLayer *aOldLayer,
                                                  LayerManager *aManager);
     void MarkContextClean();
     NS_IMETHOD SetIsIPC(PRBool isIPC);
     // this rect is in canvas device space
     NS_IMETHOD Redraw(const gfxRect &r);
     // this rect is in mThebes's current user space
     NS_IMETHOD RedrawUser(const gfxRect &r);
 
@@ -452,16 +450,17 @@ public:
         }
     private:
         gfxContext *mContext;
         nsRefPtr<gfxPath> mPath;
     };
     friend class PathAutoSaveRestore;
 
 protected:
+
     /**
      * The number of living nsCanvasRenderingContexts.  When this goes down to
      * 0, we free the premultiply and unpremultiply tables, if they exist.
      */
     static PRUint32 sNumLivingContexts;
 
     /**
      * Lookup table used to speed up GetImageData().
@@ -4095,81 +4094,59 @@ nsCanvasRenderingContext2D::SetMozImageS
         DirtyAllStyles();
     }
 
     return NS_OK;
 }
 
 static PRUint8 g2DContextLayerUserData;
 
-class CanvasRenderingContext2DUserData : public LayerUserData {
-public:
-  CanvasRenderingContext2DUserData(nsHTMLCanvasElement *aContent)
-    : mContent(aContent) {}
-  static void DidTransactionCallback(void* aData)
-  {
-    static_cast<CanvasRenderingContext2DUserData*>(aData)->mContent->MarkContextClean();
-  }
-
-private:
-  nsRefPtr<nsHTMLCanvasElement> mContent;
-};
-
 already_AddRefed<CanvasLayer>
-nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                                           CanvasLayer *aOldLayer,
+nsCanvasRenderingContext2D::GetCanvasLayer(CanvasLayer *aOldLayer,
                                            LayerManager *aManager)
 {
     if (!mValid)
         return nsnull;
 
     if (!mResetLayer && aOldLayer &&
         aOldLayer->HasUserData(&g2DContextLayerUserData)) {
         NS_ADDREF(aOldLayer);
+        if (mIsEntireFrameInvalid || mInvalidateCount > 0) {
+            // XXX Need to just update the changed area here; we should keep track
+            // of the rectangle based on Redraw args.
+            aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+            MarkContextClean();
+            HTMLCanvasElement()->GetPrimaryCanvasFrame()->MarkLayersActive();
+        }
+
         return aOldLayer;
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
         return nsnull;
     }
-    CanvasRenderingContext2DUserData *userData = nsnull;
-    if (aBuilder->IsPaintingToWindow()) {
-      // Make the layer tell us whenever a transaction finishes (including
-      // the current transaction), so we can clear our invalidation state and
-      // start invalidating again. We need to do this for the layer that is
-      // being painted to a window (there shouldn't be more than one at a time,
-      // and if there is, flushing the invalidation state more often than
-      // necessary is harmless).
-
-      // The layer will be destroyed when we tear down the presentation
-      // (at the latest), at which time this userData will be destroyed,
-      // releasing the reference to the element.
-      // The userData will receive DidTransactionCallbacks, which flush the
-      // the invalidation state to indicate that the canvas is up to date.
-      userData = new CanvasRenderingContext2DUserData(HTMLCanvasElement());
-      canvasLayer->SetDidTransactionCallback(
-              CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
-    }
-    canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
+    canvasLayer->SetUserData(&g2DContextLayerUserData, nsnull);
 
     CanvasLayer::Data data;
 
     data.mSurface = mSurface.get();
     data.mSize = nsIntSize(mWidth, mHeight);
 
     canvasLayer->Initialize(data);
     PRUint32 flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
     canvasLayer->SetContentFlags(flags);
-    canvasLayer->Updated();
+    canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
 
     mResetLayer = PR_FALSE;
 
-    return canvasLayer.forget();
+    MarkContextClean();
+
+    return canvasLayer.forget().get();
 }
 
 void
 nsCanvasRenderingContext2D::MarkContextClean()
 {
     if (mInvalidateCount > 0) {
         mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
     }
--- a/content/html/content/public/nsHTMLCanvasElement.h
+++ b/content/html/content/public/nsHTMLCanvasElement.h
@@ -152,22 +152,22 @@ public:
                            PRBool aNotify);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   nsresult CopyInnerTo(nsGenericElement* aDest) const;
 
   /*
    * Helpers called by various users of Canvas
    */
 
-  already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                                               CanvasLayer *aOldLayer,
+  already_AddRefed<CanvasLayer> GetCanvasLayer(CanvasLayer *aOldLayer,
                                                LayerManager *aManager);
 
-  // Any invalidates requested by the context have been processed by updating
-  // the window. Future changes to the canvas need to trigger more invalidation.
+  // Tell the Context that all the current rendering that it's
+  // invalidated has been displayed to the screen, so that it should
+  // start requesting invalidates again as needed.
   void MarkContextClean();
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   nsIntSize GetWidthHeight();
 
   nsresult UpdateContext(nsIPropertyBag *aNewContextOptions = nsnull);
   nsresult ExtractData(const nsAString& aType,
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -643,42 +643,39 @@ void
 nsHTMLCanvasElement::InvalidateFrame(const gfxRect* damageRect)
 {
   // We don't need to flush anything here; if there's no frame or if
   // we plan to reframe we don't need to invalidate it anyway.
   nsIFrame *frame = GetPrimaryFrame();
   if (!frame)
     return;
 
-  frame->MarkLayersActive();
-
-  nsRect invalRect;
-  nsRect contentArea = frame->GetContentRect();
   if (damageRect) {
+    nsRect contentArea(frame->GetContentRect());
     nsIntSize size = GetWidthHeight();
 
     // damageRect and size are in CSS pixels; contentArea is in appunits
     // We want a rect in appunits; so avoid doing pixels-to-appunits and
     // vice versa conversion here.
     gfxRect realRect(*damageRect);
     realRect.Scale(contentArea.width / gfxFloat(size.width),
                    contentArea.height / gfxFloat(size.height));
     realRect.RoundOut();
 
     // then make it a nsRect
-    invalRect = nsRect(realRect.X(), realRect.Y(),
-                       realRect.Width(), realRect.Height());
+    nsRect invalRect(realRect.X(), realRect.Y(),
+                     realRect.Width(), realRect.Height());
+
+    // account for border/padding
+    invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
+
+    frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS);
   } else {
-    invalRect = nsRect(nsPoint(0, 0), contentArea.Size());
-  }
-  invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
-
-  Layer* layer = frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS);
-  if (layer) {
-    static_cast<CanvasLayer*>(layer)->Updated();
+    nsRect r(frame->GetContentRect() - frame->GetPosition());
+    frame->InvalidateLayer(r, nsDisplayItem::TYPE_CANVAS);
   }
 }
 
 PRInt32
 nsHTMLCanvasElement::CountContexts()
 {
   if (mCurrentContext)
     return 1;
@@ -697,24 +694,23 @@ nsHTMLCanvasElement::GetContextAtIndex (
 
 PRBool
 nsHTMLCanvasElement::GetIsOpaque()
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
 }
 
 already_AddRefed<CanvasLayer>
-nsHTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
-                                    CanvasLayer *aOldLayer,
+nsHTMLCanvasElement::GetCanvasLayer(CanvasLayer *aOldLayer,
                                     LayerManager *aManager)
 {
   if (!mCurrentContext)
     return nsnull;
 
-  return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
+  return mCurrentContext->GetCanvasLayer(aOldLayer, aManager);
 }
 
 void
 nsHTMLCanvasElement::MarkContextClean()
 {
   if (!mCurrentContext)
     return;
 
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1171,30 +1171,23 @@ public:
    * have either mSurface or mGLContext initialized (but not both), as
    * well as mSize.
    *
    * This must only be called once.
    */
   virtual void Initialize(const Data& aData) = 0;
 
   /**
-   * Notify this CanvasLayer that the canvas surface contents have
-   * changed (or will change) before the next transaction.
+   * CONSTRUCTION PHASE ONLY
+   * Notify this CanvasLayer that the rectangle given by aRect
+   * has been updated, and any work that needs to be done
+   * to bring the contents from the Surface/GLContext to the
+   * Layer in preparation for compositing should be performed.
    */
-  void Updated() { mDirty = PR_TRUE; }
-
-  /**
-   * Register a callback to be called at the end of each transaction.
-   */
-  typedef void (* DidTransactionCallback)(void* aClosureData);
-  void SetDidTransactionCallback(DidTransactionCallback aCallback, void* aClosureData)
-  {
-    mCallback = aCallback;
-    mCallbackData = aClosureData;
-  }
+  virtual void Updated(const nsIntRect& aRect) = 0;
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Set the filter used to resample this image (if necessary).
    */
   void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
   gfxPattern::GraphicsFilter GetFilter() const { return mFilter; }
 
@@ -1209,38 +1202,23 @@ public:
     mEffectiveTransform =
         SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height),
                       nsnull)*
         SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nsnull);
   }
 
 protected:
   CanvasLayer(LayerManager* aManager, void* aImplData)
-    : Layer(aManager, aImplData),
-      mCallback(nsnull), mCallbackData(nsnull), mFilter(gfxPattern::FILTER_GOOD),
-      mDirty(PR_FALSE) {}
+    : Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD) {}
 
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
-  void FireDidTransactionCallback()
-  {
-    if (mCallback) {
-      mCallback(mCallbackData);
-    }
-  }
-
   /**
    * 0, 0, canvaswidth, canvasheight
    */
   nsIntRect mBounds;
-  DidTransactionCallback mCallback;
-  void* mCallbackData;
   gfxPattern::GraphicsFilter mFilter;
-  /**
-   * Set to true in Updated(), cleared during a transaction.
-   */
-  PRPackedBool mDirty;
 };
 
 }
 }
 
 #endif /* GFX_LAYERS_H */
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -888,41 +888,45 @@ public:
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
 
   virtual void Initialize(const Data& aData);
+  virtual void Updated(const nsIntRect& aRect);
   virtual void Paint(gfxContext* aContext);
 
   virtual void PaintWithOpacity(gfxContext* aContext,
                                 float aOpacity);
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
-  void UpdateSurface();
 
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   PRUint32 mCanvasFramebuffer;
 
+  nsIntRect mUpdatedRect;
+
   PRPackedBool mGLBufferIsPremultiplied;
   PRPackedBool mNeedsYFlip;
 };
 
 void
 BasicCanvasLayer::Initialize(const Data& aData)
 {
   NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
 
+  mUpdatedRect.Empty();
+
   if (aData.mSurface) {
     mSurface = aData.mSurface;
     NS_ASSERTION(aData.mGLContext == nsnull,
                  "CanvasLayer can't have both surface and GLContext");
     mNeedsYFlip = PR_FALSE;
   } else if (aData.mGLContext) {
     NS_ASSERTION(aData.mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
     mGLContext = aData.mGLContext;
@@ -932,21 +936,22 @@ BasicCanvasLayer::Initialize(const Data&
   } else {
     NS_ERROR("CanvasLayer created without mSurface or mGLContext?");
   }
 
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 }
 
 void
-BasicCanvasLayer::UpdateSurface()
+BasicCanvasLayer::Updated(const nsIntRect& aRect)
 {
-  if (!mDirty)
-    return;
-  mDirty = PR_FALSE;
+  NS_ASSERTION(mUpdatedRect.IsEmpty(),
+               "CanvasLayer::Updated called more than once in a transaction!");
+
+  mUpdatedRect.UnionRect(mUpdatedRect, aRect);
 
   if (mGLContext) {
     nsRefPtr<gfxImageSurface> isurf =
       new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
                           (GetContentFlags() & CONTENT_OPAQUE)
                             ? gfxASurface::ImageFormatRGB24
                             : gfxASurface::ImageFormatARGB32);
     if (!isurf || isurf->CairoStatus() != 0) {
@@ -966,16 +971,19 @@ BasicCanvasLayer::UpdateSurface()
 
     mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&currentFramebuffer);
 
     // Make sure that we read pixels from the correct framebuffer, regardless
     // of what's currently bound.
     if (currentFramebuffer != mCanvasFramebuffer)
       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
 
+    // For simplicity, we read the entire framebuffer for now -- in
+    // the future we should use mUpdatedRect, though with WebGL we don't
+    // have an easy way to generate one.
     mGLContext->ReadPixelsIntoImageSurface(0, 0,
                                            mBounds.width, mBounds.height,
                                            isurf);
 
     // Put back the previous framebuffer binding.
     if (currentFramebuffer != mCanvasFramebuffer)
       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, currentFramebuffer);
 
@@ -984,23 +992,25 @@ BasicCanvasLayer::UpdateSurface()
     // Note that this is a WebGL attribute; GL itself has no knowledge of
     // premultiplied or unpremultiplied alpha.
     if (!mGLBufferIsPremultiplied)
       gfxUtils::PremultiplyImageSurface(isurf);
 
     // stick our surface into mSurface, so that the Paint() path is the same
     mSurface = isurf;
   }
+
+  // sanity
+  NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
+               "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
 BasicCanvasLayer::Paint(gfxContext* aContext)
 {
-  UpdateSurface();
-  FireDidTransactionCallback();
   PaintWithOpacity(aContext, GetEffectiveOpacity());
 }
 
 void
 BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext,
                                    float aOpacity)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
@@ -1022,16 +1032,18 @@ BasicCanvasLayer::PaintWithOpacity(gfxCo
   // No need to snap here; our transform is already set up to snap our rect
   aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height));
   aContext->SetPattern(pat);
   aContext->FillWithOpacity(aOpacity);
 
   if (mNeedsYFlip) {
     aContext->SetMatrix(m);
   }
+
+  mUpdatedRect.Empty();
 }
 
 class BasicReadbackLayer : public ReadbackLayer,
                            BasicImplData
 {
 public:
   BasicReadbackLayer(BasicLayerManager* aLayerManager) :
     ReadbackLayer(aLayerManager, static_cast<BasicImplData*>(this))
@@ -2540,16 +2552,19 @@ public:
   virtual void Disconnect()
   {
     DestroyFrontBuffer();
     ShadowCanvasLayer::Disconnect();
   }
 
   virtual void Initialize(const Data& aData);
 
+  virtual void Updated(const nsIntRect& aRect)
+  {}
+
   virtual already_AddRefed<gfxSharedImageSurface>
   Swap(gfxSharedImageSurface* newFront);
 
   virtual void DestroyFrontBuffer()
   {
     if (mFrontSurface) {
       BasicManager()->ShadowLayerManager::DestroySharedSurface(mFrontSurface, mAllocator);
     }
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -109,22 +109,18 @@ CanvasLayerD3D10::Initialize(const Data&
       return;
     }
   }
 
   device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
 }
 
 void
-CanvasLayerD3D10::UpdateSurface()
+CanvasLayerD3D10::Updated(const nsIntRect& aRect)
 {
-  if (!mDirty)
-    return;
-  mDirty = PR_FALSE;
-
   if (mIsD2DTexture) {
     mSurface->Flush();
     return;
   }
 
   if (mUsingSharedTexture) {
     // need to sync on the d3d9 device
     if (mGLContext) {
@@ -160,16 +156,19 @@ CanvasLayerD3D10::UpdateSurface()
 
     mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&currentFramebuffer);
 
     // Make sure that we read pixels from the correct framebuffer, regardless
     // of what's currently bound.
     if (currentFramebuffer != mCanvasFramebuffer)
       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
 
+    // For simplicity, we read the entire framebuffer for now -- in
+    // the future we should use aRect, though with WebGL we don't
+    // have an easy way to generate one.
     nsRefPtr<gfxImageSurface> tmpSurface =
       new gfxImageSurface(destination,
                           gfxIntSize(mBounds.width, mBounds.height),
                           mBounds.width * 4,
                           gfxASurface::ImageFormatARGB32);
     mGLContext->ReadPixelsIntoImageSurface(0, 0,
                                            mBounds.width, mBounds.height,
                                            tmpSurface);
@@ -185,36 +184,40 @@ CanvasLayerD3D10::UpdateSurface()
                destination + mBounds.width * 4 * y,
                mBounds.width * 4);
       }
       delete [] destination;
     }
     mTexture->Unmap(0);
   } else if (mSurface) {
     RECT r;
-    r.left = 0;
-    r.top = 0;
-    r.right = mBounds.width;
-    r.bottom = mBounds.height;
+    r.left = aRect.x;
+    r.top = aRect.y;
+    r.right = aRect.XMost();
+    r.bottom = aRect.YMost();
 
     D3D10_MAPPED_TEXTURE2D map;
     HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
 
     if (FAILED(hr)) {
       NS_WARNING("Failed to lock CanvasLayer texture.");
       return;
     }
 
+    PRUint8 *startBits;
+    PRUint32 sourceStride;
+
     nsRefPtr<gfxImageSurface> dstSurface;
 
     dstSurface = new gfxImageSurface((unsigned char*)map.pData,
-                                     gfxIntSize(mBounds.width, mBounds.height),
+                                     gfxIntSize(aRect.width, aRect.height),
                                      map.RowPitch,
                                      gfxASurface::ImageFormatARGB32);
     nsRefPtr<gfxContext> ctx = new gfxContext(dstSurface);
+    ctx->Translate(gfxPoint(-aRect.x, -aRect.y));
     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
     ctx->SetSource(mSurface);
     ctx->Paint();
     
     mTexture->Unmap(0);
   }
 }
 
@@ -222,21 +225,19 @@ Layer*
 CanvasLayerD3D10::GetLayer()
 {
   return this;
 }
 
 void
 CanvasLayerD3D10::RenderLayer()
 {
-  UpdateSurface();
-  FireDidTransactionCallback();
-
-  if (!mTexture)
+  if (!mTexture) {
     return;
+  }
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
 
   SetEffectTransformAndOpacity();
 
   ID3D10EffectTechnique *technique;
 
   if (mDataIsPremultiplied) {
--- a/gfx/layers/d3d10/CanvasLayerD3D10.h
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.h
@@ -59,26 +59,25 @@ public:
   {
       mImplData = static_cast<LayerD3D10*>(this);
   }
 
   ~CanvasLayerD3D10();
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
+  virtual void Updated(const nsIntRect& aRect);
 
   // LayerD3D10 implementation
   virtual Layer* GetLayer();
   virtual void RenderLayer();
 
 private:
   typedef mozilla::gl::GLContext GLContext;
 
-  void UpdateSurface();
-
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<GLContext> mGLContext;
   nsRefPtr<ID3D10Texture2D> mTexture;
   nsRefPtr<ID3D10ShaderResourceView> mSRView;
 
   PRUint32 mCanvasFramebuffer;
 
   PRPackedBool mDataIsPremultiplied;
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -74,22 +74,18 @@ CanvasLayerD3D9::Initialize(const Data& 
   }
 
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 
   CreateTexture();
 }
 
 void
-CanvasLayerD3D9::UpdateSurface()
+CanvasLayerD3D9::Updated(const nsIntRect& aRect)
 {
-  if (!mDirty)
-    return;
-  mDirty = PR_FALSE;
-
   if (!mTexture) {
     CreateTexture();
     NS_WARNING("CanvasLayerD3D9::Updated called but no texture present!");
     return;
   }
 
   if (mGLContext) {
     // WebGL reads entire surface.
@@ -116,16 +112,19 @@ CanvasLayerD3D9::UpdateSurface()
 
     mGLContext->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&currentFramebuffer);
 
     // Make sure that we read pixels from the correct framebuffer, regardless
     // of what's currently bound.
     if (currentFramebuffer != mCanvasFramebuffer)
       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mCanvasFramebuffer);
 
+    // For simplicity, we read the entire framebuffer for now -- in
+    // the future we should use aRect, though with WebGL we don't
+    // have an easy way to generate one.
     nsRefPtr<gfxImageSurface> tmpSurface =
       new gfxImageSurface(destination,
                           gfxIntSize(mBounds.width, mBounds.height),
                           mBounds.width * 4,
                           gfxASurface::ImageFormatARGB32);
     mGLContext->ReadPixelsIntoImageSurface(0, 0,
                                            mBounds.width, mBounds.height,
                                            tmpSurface);
@@ -141,83 +140,90 @@ CanvasLayerD3D9::UpdateSurface()
                destination + mBounds.width * 4 * y,
                mBounds.width * 4);
       }
       delete [] destination;
     }
     mTexture->UnlockRect(0);
   } else if (mSurface) {
     RECT r;
-    r.left = mBounds.x;
-    r.top = mBounds.y;
-    r.right = mBounds.XMost();
-    r.bottom = mBounds.YMost();
+    r.left = aRect.x;
+    r.top = aRect.y;
+    r.right = aRect.XMost();
+    r.bottom = aRect.YMost();
 
     D3DLOCKED_RECT lockedRect;
     HRESULT hr = mTexture->LockRect(0, &lockedRect, &r, 0);
 
     if (FAILED(hr)) {
       NS_WARNING("Failed to lock CanvasLayer texture.");
       return;
     }
 
+    PRUint8 *startBits;
+    PRUint32 sourceStride;
+
     nsRefPtr<gfxImageSurface> sourceSurface;
 
     if (mSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
       sourceSurface = mSurface->GetAsImageSurface();
+      startBits = sourceSurface->Data() + sourceSurface->Stride() * aRect.y +
+                  aRect.x * 4;
+      sourceStride = sourceSurface->Stride();
     } else if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) {
       sourceSurface = static_cast<gfxImageSurface*>(mSurface.get());
       if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32 &&
           sourceSurface->Format() != gfxASurface::ImageFormatRGB24)
       {
         mTexture->UnlockRect(0);
         return;
       }
+      startBits = sourceSurface->Data() + sourceSurface->Stride() * aRect.y +
+                  aRect.x * 4;
+      sourceStride = sourceSurface->Stride();
     } else {
-      sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
+      sourceSurface = new gfxImageSurface(gfxIntSize(aRect.width, aRect.height),
                                           gfxASurface::ImageFormatARGB32);
       nsRefPtr<gfxContext> ctx = new gfxContext(sourceSurface);
+      ctx->Translate(gfxPoint(-aRect.x, -aRect.y));
       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
       ctx->SetSource(mSurface);
       ctx->Paint();
+      startBits = sourceSurface->Data();
+      sourceStride = sourceSurface->Stride();
     }
 
-    PRUint8 *startBits = sourceSurface->Data();
-    PRUint32 sourceStride = sourceSurface->Stride();
-
     if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
       mHasAlpha = false;
     } else {
       mHasAlpha = true;
     }
 
-    for (int y = 0; y < mBounds.height; y++) {
+    for (int y = 0; y < aRect.height; y++) {
       memcpy((PRUint8*)lockedRect.pBits + lockedRect.Pitch * y,
              startBits + sourceStride * y,
-             mBounds.width * 4);
+             aRect.width * 4);
     }
 
     mTexture->UnlockRect(0);
   }
 }
 
 Layer*
 CanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 CanvasLayerD3D9::RenderLayer()
 {
-  UpdateSurface();
-  FireDidTransactionCallback();
-
-  if (!mTexture)
-    return;
+  if (!mTexture) {
+    Updated(mBounds);
+  }
 
   /*
    * We flip the Y axis here, note we can only do this because we are in 
    * CULL_NONE mode!
    */
 
   ShaderConstantRect quad(0, 0, mBounds.width, mBounds.height);
   if (mNeedsYFlip) {
--- a/gfx/layers/d3d9/CanvasLayerD3D9.h
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.h
@@ -61,30 +61,29 @@ public:
       mImplData = static_cast<LayerD3D9*>(this);
       aManager->deviceManager()->mLayersWithResources.AppendElement(this);
   }
 
   ~CanvasLayerD3D9();
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
+  virtual void Updated(const nsIntRect& aRect);
 
   // LayerD3D9 implementation
   virtual Layer* GetLayer();
   virtual void RenderLayer();
   virtual void CleanResources();
   virtual void LayerManagerDestroyed();
 
   void CreateTexture();
 
 protected:
   typedef mozilla::gl::GLContext GLContext;
 
-  void UpdateSurface();
-
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<GLContext> mGLContext;
   nsRefPtr<IDirect3DTexture9> mTexture;
 
   PRUint32 mCanvasFramebuffer;
 
   PRPackedBool mDataIsPremultiplied;
   PRPackedBool mNeedsYFlip;
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -167,16 +167,17 @@ struct OpRemoveChild  { PLayer container
 struct OpPaintThebesBuffer {
   PLayer layer;
   ThebesBuffer newFrontBuffer;
   nsIntRegion updatedRegion;
 };
 
 struct OpPaintCanvas  {
   PLayer layer;
+  nsIntRect updated;
   Shmem newFrontBuffer;
 };
 
 struct OpPaintImage  {
   PLayer layer;
   Shmem newFrontBuffer;
 };
 
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -296,16 +296,17 @@ ShadowLayerForwarder::PaintedImage(Shado
   mTxn->AddPaint(OpPaintImage(NULL, Shadow(aImage),
                               aNewFrontSurface->GetShmem()));
 }
 void
 ShadowLayerForwarder::PaintedCanvas(ShadowableLayer* aCanvas,
                                     gfxSharedImageSurface* aNewFrontSurface)
 {
   mTxn->AddPaint(OpPaintCanvas(NULL, Shadow(aCanvas),
+                               nsIntRect(),
                                aNewFrontSurface->GetShmem()));
 }
 
 PRBool
 ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
   NS_ABORT_IF_FALSE(!mTxn->Finished(), "forgot BeginTransaction?");
--- a/gfx/layers/ipc/ShadowLayersParent.cpp
+++ b/gfx/layers/ipc/ShadowLayersParent.cpp
@@ -417,17 +417,17 @@ ShadowLayersParent::RecvUpdate(const Inf
 
       nsRefPtr<gfxSharedImageSurface> newFront =
         gfxSharedImageSurface::Open(op.newFrontBuffer());
       nsRefPtr<gfxSharedImageSurface> newBack = canvas->Swap(newFront);
       if (newFront == newBack) {
         newFront.forget();
       }
 
-      canvas->Updated();
+      canvas->Updated(op.updated());
 
       replyv.push_back(OpBufferSwap(shadow, NULL,
                                     newBack->GetShmem()));
 
       break;
     }
     case Edit::TOpPaintImage: {
       MOZ_LAYERS_LOG(("[ParentSide] Paint ImageLayer"));
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -130,67 +130,73 @@ CanvasLayerOGL::MakeTexture()
 
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 }
 
 void
-CanvasLayerOGL::UpdateSurface()
+CanvasLayerOGL::Updated(const nsIntRect& aRect)
 {
-  if (!mDirty)
-    return;
-  mDirty = PR_FALSE;
-
   if (mDestroyed || mDelayedUpdates) {
     return;
   }
 
+  NS_ASSERTION(mUpdatedRect.IsEmpty(),
+               "CanvasLayer::Updated called more than once during a transaction!");
+
   mOGLManager->MakeCurrent();
 
+  mUpdatedRect.UnionRect(mUpdatedRect, aRect);
+
   if (mCanvasGLContext &&
       mCanvasGLContext->GetContextType() == gl()->GetContextType())
   {
     if (gl()->BindOffscreenNeedsTexture(mCanvasGLContext) &&
         mTexture == 0)
     {
       MakeTexture();
     }
   } else {
+    if (!mTexture) {
+      mUpdatedRect = mBounds;
+    }
+
     nsRefPtr<gfxASurface> updatedAreaSurface;
     if (mCanvasSurface) {
       updatedAreaSurface = mCanvasSurface;
     } else if (mCanvasGLContext) {
       nsRefPtr<gfxImageSurface> updatedAreaImageSurface =
-        new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
+        new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height),
                             gfxASurface::ImageFormatARGB32);
-      mCanvasGLContext->ReadPixelsIntoImageSurface(0, 0,
-                                                   mBounds.width,
-                                                   mBounds.height,
+      mCanvasGLContext->ReadPixelsIntoImageSurface(mUpdatedRect.x, mUpdatedRect.y,
+                                                   mUpdatedRect.width,
+                                                   mUpdatedRect.height,
                                                    updatedAreaImageSurface);
       updatedAreaSurface = updatedAreaImageSurface;
     }
 
     mLayerProgram =
       gl()->UploadSurfaceToTexture(updatedAreaSurface,
-                                   mBounds,
+                                   mUpdatedRect,
                                    mTexture,
                                    false,
-                                   nsIntPoint(0, 0));
+                                   mUpdatedRect.TopLeft());
   }
+
+  // sanity
+  NS_ASSERTION(mBounds.Contains(mUpdatedRect),
+               "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
                             const nsIntPoint& aOffset)
 {
-  UpdateSurface();
-  FireDidTransactionCallback();
-
   mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
@@ -237,16 +243,18 @@ CanvasLayerOGL::RenderLayer(int aPreviou
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
 
   if (useGLContext) {
     gl()->UnbindTex2DOffscreen(mCanvasGLContext);
   }
+
+  mUpdatedRect.Empty();
 }
 
 
 #ifdef MOZ_IPC
 
 ShadowCanvasLayerOGL::ShadowCanvasLayerOGL(LayerManagerOGL* aManager)
   : ShadowCanvasLayer(aManager, nsnull)
   , LayerOGL(aManager)
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -61,33 +61,34 @@ public:
       mDelayedUpdates(PR_FALSE)
   { 
       mImplData = static_cast<LayerOGL*>(this);
   }
   ~CanvasLayerOGL() { Destroy(); }
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
+  virtual void Updated(const nsIntRect& aRect);
 
   // LayerOGL implementation
   virtual void Destroy();
   virtual Layer* GetLayer() { return this; }
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset);
 
 protected:
-  void UpdateSurface();
-
   nsRefPtr<gfxASurface> mCanvasSurface;
   nsRefPtr<GLContext> mCanvasGLContext;
   gl::ShaderProgramType mLayerProgram;
 
   void MakeTexture();
   GLuint mTexture;
 
+  nsIntRect mUpdatedRect;
+
   PRPackedBool mDelayedUpdates;
   PRPackedBool mGLBufferIsPremultiplied;
   PRPackedBool mNeedsYFlip;
 };
 
 #ifdef MOZ_IPC
 // NB: eventually we'll have separate shadow canvas2d and shadow
 // canvas3d layers, but currently they look the same from the
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1739,35 +1739,35 @@ FrameLayerBuilder::InvalidateAllLayers(L
   LayerManagerData* data = static_cast<LayerManagerData*>
     (aManager->GetUserData(&gLayerManagerUserData));
   if (data) {
     data->mInvalidateAllLayers = PR_TRUE;
   }
 }
 
 /* static */
-Layer*
-FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
+PRBool
+FrameLayerBuilder::HasDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
 {
   void* propValue = aFrame->Properties().Get(DisplayItemDataProperty());
   if (!propValue)
-    return nsnull;
+    return PR_FALSE;
 
   nsTArray<DisplayItemData>* array =
     (reinterpret_cast<nsTArray<DisplayItemData>*>(&propValue));
   for (PRUint32 i = 0; i < array->Length(); ++i) {
     if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
       Layer* layer = array->ElementAt(i).mLayer;
       if (!layer->HasUserData(&gColorLayerUserData) &&
           !layer->HasUserData(&gImageLayerUserData) &&
           !layer->HasUserData(&gThebesDisplayItemLayerUserData))
-        return layer;
+        return PR_TRUE;
     }
   }
-  return nsnull;
+  return PR_FALSE;
 }
 
 /* static */ void
 FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
                                    gfxContext* aContext,
                                    const nsIntRegion& aRegionToDraw,
                                    const nsIntRegion& aRegionToInvalidate,
                                    void* aCallbackData)
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -186,20 +186,19 @@ public:
   /**
    * Call this to force all retained layers to be discarded and recreated at
    * the next paint.
    */
   static void InvalidateAllLayers(LayerManager* aManager);
 
   /**
    * Call this to determine if a frame has a dedicated (non-Thebes) layer
-   * for the given display item key. If there isn't one, we return null,
-   * otherwise we return the layer.
+   * for the given display item key.
    */
-  static Layer* GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
+  static PRBool HasDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
 
   /**
    * This callback must be provided to EndTransaction. The callback data
    * must be the nsDisplayListBuilder containing this FrameLayerBuilder.
    */
   static void DrawThebesLayer(ThebesLayer* aLayer,
                               gfxContext* aContext,
                               const nsIntRegion& aRegionToDraw,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -126,17 +126,16 @@
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGEffects.h"
 #endif
 
 #include "gfxContext.h"
 #include "CSSCalc.h"
 
 using namespace mozilla;
-using namespace mozilla::layers;
 
 static NS_DEFINE_CID(kLookAndFeelCID,  NS_LOOKANDFEEL_CID);
 
 // Struct containing cached metrics for box-wrapped frames.
 struct nsBoxLayoutMetrics
 {
   nsSize mPrefSize;
   nsSize mMinSize;
@@ -3941,45 +3940,42 @@ nsFrame::GetType() const
 }
 
 PRBool
 nsIFrame::IsLeaf() const
 {
   return PR_TRUE;
 }
 
-Layer*
+void
 nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey)
 {
   NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
 
-  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
-  if (!layer) {
+  if (!FrameLayerBuilder::HasDedicatedLayer(this, aDisplayItemKey)) {
     Invalidate(aDamageRect);
-    return nsnull;
+    return;
   }
 
   PRUint32 flags = INVALIDATE_NO_THEBES_LAYERS;
   if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
-      aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
-      aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) {
+      aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN) {
     flags |= INVALIDATE_NO_UPDATE_LAYER_TREE;
   }
 
   InvalidateWithFlags(aDamageRect, flags);
-  return layer;
 }
 
 void
 nsIFrame::InvalidateTransformLayer()
 {
   NS_ASSERTION(mParent, "How can a viewport frame have a transform?");
 
   PRBool hasLayer =
-      FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nsnull;
+      FrameLayerBuilder::HasDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM);
   // Invalidate post-transform area in the parent. We have to invalidate
   // in the parent because our transform style may have changed from what was
   // used to paint this frame.
   // It's OK to bypass the SVG effects processing and other processing
   // performed if we called this->InvalidateWithFlags, because those effects
   // are performed before applying transforms.
   mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(),
                               0, 0, this,
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -270,20 +270,22 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayL
   nsHTMLCanvasElement* element = static_cast<nsHTMLCanvasElement*>(GetContent());
   nsIntSize canvasSize = GetCanvasSize();
 
   if (canvasSize.width <= 0 || canvasSize.height <= 0 || area.IsEmpty())
     return nsnull;
 
   CanvasLayer* oldLayer = static_cast<CanvasLayer*>
     (aBuilder->LayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
-  nsRefPtr<CanvasLayer> layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager);
+  nsRefPtr<CanvasLayer> layer = element->GetCanvasLayer(oldLayer, aManager);
   if (!layer)
     return nsnull;
 
+  element->MarkContextClean();
+
   nsPresContext* presContext = PresContext();
   gfxRect r = gfxRect(presContext->AppUnitsToGfxUnits(area.x),
                       presContext->AppUnitsToGfxUnits(area.y),
                       presContext->AppUnitsToGfxUnits(area.width),
                       presContext->AppUnitsToGfxUnits(area.height));
 
   // Transform the canvas into the right place
   gfxMatrix transform;
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -106,22 +106,16 @@ class nsLineList_iterator;
 
 struct nsPeekOffsetStruct;
 struct nsPoint;
 struct nsRect;
 struct nsSize;
 struct nsMargin;
 struct CharacterDataChangeInfo;
 
-namespace mozilla {
-namespace layers {
-class Layer;
-}
-}
-
 typedef class nsIFrame nsIBox;
 
 /**
  * Indication of how the frame can be split. This is used when doing runaround
  * of floats, and when pulling up child frames from a next-in-flow.
  *
  * The choices are splittable, not splittable at all, and splittable in
  * a non-rectangular fashion. This last type only applies to block-level
@@ -519,17 +513,16 @@ typedef PRBool nsDidReflowStatus;
  * If you're not in layout but you must call functions in here, at least
  * restrict yourself to calling virtual methods, which won't hurt you as badly.
  */
 class nsIFrame : public nsQueryFrame
 {
 public:
   typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
   typedef mozilla::FrameProperties FrameProperties;
-  typedef mozilla::layers::Layer Layer;
 
   NS_DECL_QUERYFRAME_TARGET(nsIFrame)
 
   nsPresContext* PresContext() const {
     return GetStyleContext()->GetRuleNode()->GetPresContext();
   }
 
   /**
@@ -2017,22 +2010,20 @@ public:
   virtual void InvalidateOverflowRectExternal()
   { return InvalidateOverflowRect(); }
 #endif
 
   /**
    * As Invalidate above, except that this should be called when the
    * rendering that has changed is performed using layers so we can avoid
    * updating the contents of ThebesLayers.
-   * If the frame has a dedicated layer rendering this display item, we
-   * return that layer.
    * @param aDisplayItemKey must not be zero; indicates the kind of display
    * item that is being invalidated.
    */
-  Layer* InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey);
+  void InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey);
 
   /**
    * Invalidate the area of the parent that's covered by the transformed
    * visual overflow rect of this frame. Don't depend on the transform style
    * for this frame, in case that's changed since this frame was painted.
    */
   void InvalidateTransformLayer();