Bug 626602. Part 3: Hook up ReadbackLayers in nsObjectFrame. r=cjones
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 08 Feb 2011 18:44:13 -0600
changeset 62201 f47bc2d59e5275bb85316aa7b1ee2d7a09010670
parent 62200 5300b2ae26ade1f858f4489eea872a82ebcf8485
child 62202 a4cc7836fc3c01edb27e5102cfb6f54cb84a6c13
push id18641
push usercjones@mozilla.com
push dateWed, 09 Feb 2011 00:44:41 +0000
treeherdermozilla-central@fa1a4b6abff0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs626602
milestone2.0b12pre
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 626602. Part 3: Hook up ReadbackLayers in nsObjectFrame. r=cjones
layout/base/nsDisplayItemTypes.h
layout/generic/nsObjectFrame.cpp
layout/generic/nsObjectFrame.h
--- a/layout/base/nsDisplayItemTypes.h
+++ b/layout/base/nsDisplayItemTypes.h
@@ -73,16 +73,17 @@ enum Type {
   TYPE_LIST_FOCUS,
   TYPE_OPACITY,
   TYPE_OPTION_EVENT_GRABBER,
   TYPE_OUTLINE,
   TYPE_OWN_LAYER,
   TYPE_PAGE_CONTENT,
   TYPE_PAGE_SEQUENCE,
   TYPE_PLUGIN,
+  TYPE_PLUGIN_READBACK,
   TYPE_PRINT_PREVIEW_BACKGROUND,
   TYPE_PRINT_PLUGIN,
   TYPE_REMOTE,
   TYPE_REMOTE_SHADOW,
   TYPE_SCROLL_LAYER,
   TYPE_SELECTION_OVERLAY,
   TYPE_SOLID_COLOR,
   TYPE_TABLE_CELL_BACKGROUND,
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -158,16 +158,17 @@ enum { XKeyPress = KeyPress };
 #ifdef XP_WIN
 #include "gfxWindowsNativeDrawing.h"
 #include "gfxWindowsSurface.h"
 #endif
 
 #include "gfxImageSurface.h"
 #include "gfxUtils.h"
 #include "Layers.h"
+#include "ReadbackLayer.h"
 
 // accessibility support
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
@@ -232,16 +233,18 @@ using mozilla::DefaultXDisplay;
 #ifdef PR_LOGGING 
 static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
 #endif /* PR_LOGGING */
 
 #if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
 #define MAC_CARBON_PLUGINS
 #endif
 
+using namespace mozilla;
+using namespace mozilla::plugins;
 using namespace mozilla::layers;
 
 // special class for handeling DOM context menu events because for
 // some reason it starves other mouse events if implemented on the
 // same class
 class nsPluginDOMContextMenuListener : public nsIDOMContextMenuListener
 {
 public:
@@ -459,26 +462,32 @@ public:
                                      nsIDOMClientRect* position,
                                      nsIDOMClientRect* clip);
 #endif
 
   void NotifyPaintWaiter(nsDisplayListBuilder* aBuilder);
   // Return true if we set image with valid surface
   PRBool SetCurrentImage(ImageContainer* aContainer);
 
+  // Methods to update the background image we send to async plugins
+  void SetBackgroundUnknown() {}
+  already_AddRefed<gfxContext> BeginUpdateBackground(const nsIntRect& aRect) { return nsnull; }
+  void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect) {}
+
   PRBool UseLayers()
   {
     PRBool useAsyncRendering;
     return (mInstance &&
             NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
             useAsyncRendering &&
             (!mPluginWindow ||
              mPluginWindow->type == NPWindowTypeDrawable));
   }
 
+
 private:
   // return FALSE if LayerSurface dirty (newly created and don't have valid plugin content yet)
   PRBool IsUpToDate()
   {
     nsRefPtr<gfxASurface> readyToUse;
     return NS_SUCCEEDED(mInstance->GetSurface(getter_AddRefs(readyToUse))) &&
            readyToUse && readyToUse->GetSize() == gfxIntSize(mPluginWindow->width,
                                                              mPluginWindow->height);
@@ -601,16 +610,63 @@ private:
   PRBool UpdateVisibility(PRBool aVisible);
 
 #endif
 
   nsRefPtr<gfxASurface> mLayerSurface;
   PRPackedBool          mWaitingForPaint;
 };
 
+class PluginBackgroundSink : public ReadbackSink {
+public:
+  PluginBackgroundSink(nsObjectFrame* aFrame, PRUint64 aStartSequenceNumber)
+    : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
+  ~PluginBackgroundSink()
+  {
+    if (mFrame) {
+      mFrame->mBackgroundSink = nsnull;
+    }
+  }
+
+  virtual void SetUnknown(PRUint64 aSequenceNumber)
+  {
+    if (!AcceptUpdate(aSequenceNumber))
+      return;
+    mFrame->mInstanceOwner->SetBackgroundUnknown();
+  }
+
+  virtual already_AddRefed<gfxContext>
+      BeginUpdate(const nsIntRect& aRect, PRUint64 aSequenceNumber)
+  {
+    if (!AcceptUpdate(aSequenceNumber))
+      return nsnull;
+    return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
+  }
+
+  virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect)
+  {
+    return mFrame->mInstanceOwner->EndUpdateBackground(aContext, aRect);
+  }
+
+  void Destroy() { mFrame = nsnull; }
+
+protected:
+  PRBool AcceptUpdate(PRUint64 aSequenceNumber) {
+    if (aSequenceNumber > mLastSequenceNumber && mFrame &&
+        mFrame->mInstanceOwner) {
+      mLastSequenceNumber = aSequenceNumber;
+      return PR_TRUE;
+    }
+    return PR_FALSE;
+  }
+
+  PRUint64 mLastSequenceNumber;
+  nsObjectFrame* mFrame;
+};
+
   // Mac specific code to fix up port position and clip
 #ifdef XP_MACOSX
 
   enum { ePluginPaintEnable, ePluginPaintDisable };
 
 #endif // XP_MACOSX
 
 nsObjectFrame::nsObjectFrame(nsStyleContext* aContext)
@@ -646,17 +702,16 @@ nsObjectFrame::CreateAccessible()
 NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
 {
   *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget();
   return NS_OK;
 }
 #endif
 #endif
 
-
 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
 
 NS_IMETHODIMP 
 nsObjectFrame::Init(nsIContent*      aContent,
                     nsIFrame*        aParent,
                     nsIFrame*        aPrevInFlow)
 {
   NS_PRECONDITION(aContent, "How did that happen?");
@@ -684,16 +739,20 @@ nsObjectFrame::DestroyFrom(nsIFrame* aDe
 
   // StopPluginInternal might have disowned the widget; if it has,
   // mWidget will be null.
   if (mWidget) {
     mInnerView->DetachWidgetEventHandler(mWidget);
     mWidget->Destroy();
   }
 
+  if (mBackgroundSink) {
+    mBackgroundSink->Destroy();
+  }
+
   nsObjectFrameSuper::DestroyFrom(aDestructRoot);
 }
 
 /* virtual */ void
 nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   if (HasView()) {
     nsIView* view = GetView();
@@ -1248,42 +1307,96 @@ nsObjectFrame::PaintPrintPlugin(nsIFrame
                                 const nsRect& aDirtyRect, nsPoint aPt)
 {
   nsPoint pt = aPt + aFrame->GetUsedBorderAndPadding().TopLeft();
   nsIRenderingContext::AutoPushTranslation translate(aCtx, pt.x, pt.y);
   // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
   static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
 }
 
-nsRect
-nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
-{
-  nsRect r = mFrame->GetContentRect() - mFrame->GetPosition() +
-    ToReferenceFrame();
-  if (aBuilder->IsForPluginGeometry()) {
-    // Return the geometry we want, not the geometry we have (which is based
-    // on the surface the plugin last gave us)
-    return r;
-  }
-
-  nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
-  if (mozilla::LAYER_ACTIVE == f->GetLayerState(aBuilder, nsnull)) {
+class nsDisplayPluginReadback : public nsDisplayItem {
+public:
+  nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+    : nsDisplayItem(aBuilder, aFrame)
+  {
+    MOZ_COUNT_CTOR(nsDisplayPluginReadback);
+  }
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayPluginReadback() {
+    MOZ_COUNT_DTOR(nsDisplayPluginReadback);
+  }
+#endif
+
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                   nsRegion* aVisibleRegion,
+                                   PRBool& aContainsRootContentDocBG);
+
+  NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
+
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager)
+  {
+    return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
+  }
+
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager)
+  {
+    return LAYER_ACTIVE;
+  }
+};
+
+static nsRect
+GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
+{
+  nsRect r = aFrame->GetContentRect() - aFrame->GetPosition() +
+    aItem->ToReferenceFrame();
+
+  nsObjectFrame* f = static_cast<nsObjectFrame*>(aFrame);
+  if (LAYER_ACTIVE == f->GetLayerState(aBuilder)) {
     ImageContainer* c = f->GetImageContainer();
     if (c) {
       gfxIntSize size = c->GetCurrentSize();
       PRInt32 appUnitsPerDevPixel = f->PresContext()->AppUnitsPerDevPixel();
       nsSize sizeAppUnits(size.width*appUnitsPerDevPixel, size.height*appUnitsPerDevPixel);
       r += nsPoint((r.width - sizeAppUnits.width) / 2,
                    (r.height - sizeAppUnits.height) / 2);
       r.SizeTo(sizeAppUnits);
     }
   }
   return r;
 }
 
+nsRect
+nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder)
+{
+  return GetDisplayItemBounds(aBuilder, this, mFrame);
+}
+
+PRBool
+nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                           nsRegion* aVisibleRegion,
+                                           PRBool& aContainsRootContentDocBG)
+{
+  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, aContainsRootContentDocBG))
+    return PR_FALSE;
+  // *Add* our bounds to the visible region so that stuff underneath us is
+  // likely to be made visible, so we can use it for a background! This is
+  // a bit crazy since we normally only subtract from the visible region.
+  aVisibleRegion->Or(*aVisibleRegion, GetBounds(aBuilder));
+  return PR_TRUE;
+}
+
+nsRect
+nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
+{
+  return GetDisplayItemBounds(aBuilder, this, mFrame);
+}
+
 void
 nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
                        nsIRenderingContext* aCtx)
 {
   nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
   f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder));
 }
 
@@ -1451,20 +1564,22 @@ nsObjectFrame::IsOpaque() const
 #endif
 }
 
 NS_IMETHODIMP
 nsObjectFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists)
 {
+  AddStateBits(NS_OBJECT_NEEDS_SET_IMAGE);
+
   // XXX why are we painting collapsed object frames?
   if (!IsVisibleOrCollapsedForPainting(aBuilder))
     return NS_OK;
-    
+
   nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsPresContext::nsPresContextType type = PresContext()->Type();
 
   // If we are painting in Print Preview do nothing....
   if (type == nsPresContext::eContext_PrintPreview)
     return NS_OK;
@@ -1499,16 +1614,22 @@ nsObjectFrame::BuildDisplayList(nsDispla
   }
 
   // determine if we are printing
   if (type == nsPresContext::eContext_Print) {
     rv = replacedContent.AppendNewToTop(new (aBuilder)
         nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
                          nsDisplayItem::TYPE_PRINT_PLUGIN));
   } else {
+    if (aBuilder->IsPaintingToWindow() && GetLayerState(aBuilder) == LAYER_ACTIVE) {
+      rv = replacedContent.AppendNewToTop(new (aBuilder)
+          nsDisplayPluginReadback(aBuilder, this));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
     rv = replacedContent.AppendNewToTop(new (aBuilder)
         nsDisplayPlugin(aBuilder, this));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
 
   return NS_OK;
@@ -1802,24 +1923,21 @@ nsPluginInstanceOwner::SetCurrentImage(I
   cairoData.mSurface = mLayerSurface.get();
   cairoData.mSize = mLayerSurface->GetSize();
   pluginImage->SetData(cairoData);
   aContainer->SetCurrentImage(image);
 
   return PR_TRUE;
 }
 
-mozilla::LayerState
-nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
-                             LayerManager* aManager)
-{
-  if (!mInstanceOwner || !mInstanceOwner->UseLayers())
-    return mozilla::LAYER_NONE;
-
-  return mozilla::LAYER_ACTIVE;
+LayerState
+nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder)
+{
+  return mInstanceOwner && mInstanceOwner->UseLayers() ?
+      LAYER_ACTIVE : LAYER_NONE;
 }
 
 already_AddRefed<Layer>
 nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
                           LayerManager* aManager,
                           nsDisplayItem* aItem)
 {
   if (!mInstanceOwner)
@@ -1828,58 +1946,87 @@ nsObjectFrame::BuildLayer(nsDisplayListB
   NPWindow* window = nsnull;
   mInstanceOwner->GetWindow(window);
   if (!window)
     return nsnull;
 
   if (window->width <= 0 || window->height <= 0)
     return nsnull;
 
+  // Create image
+  nsRefPtr<ImageContainer> container = GetImageContainer(aManager);
+  if (!container)
+    return nsnull;
+  if (GetStateBits() & NS_OBJECT_NEEDS_SET_IMAGE) {
+    RemoveStateBits(NS_OBJECT_NEEDS_SET_IMAGE);
+    if (!mInstanceOwner->SetCurrentImage(container)) {
+      return nsnull;
+    }
+  }
+  gfxIntSize size = container->GetCurrentSize();
+
   nsRect area = GetContentRect() + aBuilder->ToReferenceFrame(GetParent());
   gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
   // to provide crisper and faster drawing.
   r.Round();
   nsRefPtr<Layer> layer =
     (aBuilder->LayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
 
-  if (!layer) {
-    mInstanceOwner->NotifyPaintWaiter(aBuilder);
-    // Initialize ImageLayer
-    layer = aManager->CreateImageLayer();
-  }
-
-  if (!layer)
-    return nsnull;
-
-  NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "ObjectFrame works only with ImageLayer");
-  // Create image
-  nsRefPtr<ImageContainer> container = GetImageContainer(aManager);
-  if (!container)
-    return nsnull;
-
-  if (!mInstanceOwner->SetCurrentImage(container)) {
-    return nsnull;
-  }
-
-  ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
-  imglayer->SetContainer(container);
-  imglayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
-
-  layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
+  if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
+    if (!layer) {
+      mInstanceOwner->NotifyPaintWaiter(aBuilder);
+      // Initialize ImageLayer
+      layer = aManager->CreateImageLayer();
+      if (!layer)
+        return nsnull;
+    }
+    NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
+
+    ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
+    imglayer->SetContainer(container);
+    imglayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
+
+    layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
+  } else {
+    NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
+                 "Unknown item type");
+    if (!layer) {
+      layer = aManager->CreateReadbackLayer();
+      if (!layer)
+        return nsnull;
+    }
+    NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
+
+    ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
+    if (readback->GetSize() != nsIntSize(size.width, size.height)) {
+      // This will destroy any old background sink and notify us that the
+      // background is now unknown
+      readback->SetSink(nsnull);
+      NS_ASSERTION(!mBackgroundSink, "Should have been cleared");
+
+      readback->SetSize(nsIntSize(size.width, size.height));
+
+      mBackgroundSink =
+        new PluginBackgroundSink(this,
+                                 readback->AllocateSequenceNumber());
+      readback->SetSink(mBackgroundSink);
+      // The layer has taken ownership of our sink. When either the sink dies
+      // or the frame dies, the connection from the surviving object is nulled out.
+    }
+  }
 
   // Set a transform on the layer to draw the plugin in the right place
   gfxMatrix transform;
   // Center plugin if layer size != frame rect
-  r.pos.x += (r.Width() - container->GetCurrentSize().width) / 2;
-  r.pos.y += (r.Height() - container->GetCurrentSize().height) / 2;
+  r.pos.x += (r.Width() - size.width) / 2;
+  r.pos.y += (r.Height() - size.height) / 2;
   transform.Translate(r.pos);
 
   layer->SetTransform(gfx3DMatrix::From2D(transform));
-  nsRefPtr<Layer> result = layer.forget();
-  return result.forget();
+  return layer.forget();
 }
 
 void
 nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
                            nsIRenderingContext& aRenderingContext,
                            const nsRect& aDirtyRect, const nsRect& aPluginRect)
 {
   // Screen painting code
@@ -2034,17 +2181,17 @@ nsObjectFrame::PaintPlugin(nsDisplayList
 
       gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect);
 #ifdef MOZ_IPC
       if (nativeDraw.IsDoublePass()) {
         // OOP plugin specific: let the shim know before we paint if we are doing a
         // double pass render. If this plugin isn't oop, the register window message
         // will be ignored.
         NPEvent pluginEvent;
-        pluginEvent.event = mozilla::plugins::DoublePassRenderingEvent();
+        pluginEvent.event = DoublePassRenderingEvent();
         pluginEvent.wParam = 0;
         pluginEvent.lParam = 0;
         if (pluginEvent.event)
           inst->HandleEvent(&pluginEvent, nsnull);
       }
 #endif
       do {
         HDC hdc = nativeDraw.BeginNativeDrawing();
--- a/layout/generic/nsObjectFrame.h
+++ b/layout/generic/nsObjectFrame.h
@@ -57,19 +57,22 @@ class nsIAccessible;
 #endif
 
 class nsPluginInstanceOwner;
 class nsIPluginHost;
 class nsIPluginInstance;
 class nsPresContext;
 class nsDisplayPlugin;
 class nsIDOMElement;
+class PluginBackgroundSink;
 
 #define nsObjectFrameSuper nsFrame
 
+#define NS_OBJECT_NEEDS_SET_IMAGE NS_FRAME_STATE_BIT(31)
+
 class nsObjectFrame : public nsObjectFrameSuper,
                       public nsIObjectFrame,
                       public nsIReflowCallback {
 public:
   typedef mozilla::LayerState LayerState;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
@@ -171,22 +174,25 @@ public:
   // for a given aRoot, this walks the frame tree looking for the next outFrame
   static nsIObjectFrame* GetNextObjectFrame(nsPresContext* aPresContext,
                                             nsIFrame* aRoot);
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
   virtual void ReflowCallbackCanceled();
 
+  /**
+   * Builds either an ImageLayer or a ReadbackLayer, depending on the type
+   * of aItem (TYPE_PLUGIN or TYPE_PLUGIN_READBACK respectively).
+   */
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      nsDisplayItem* aItem);
 
-  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
-                                   LayerManager* aManager);
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder);
 
   ImageContainer* GetImageContainer(LayerManager* aManager = nsnull);
 
   /**
    * If aContent has a nsObjectFrame, then prepare it for a DocShell swap.
    * @see nsSubDocumentFrame::BeginSwapDocShells.
    * There will be a call to EndSwapDocShells after we were moved to the
    * new view tree.
@@ -267,16 +273,17 @@ protected:
   nsresult SetAbsoluteScreenPosition(nsIDOMElement* element,
                                      nsIDOMClientRect* position,
                                      nsIDOMClientRect* clip);
 
   void NotifyPluginReflowObservers();
 
   friend class nsPluginInstanceOwner;
   friend class nsDisplayPlugin;
+  friend class PluginBackgroundSink;
 
 private:
   
   class PluginEventNotifier : public nsRunnable {
   public:
     PluginEventNotifier(const nsString &aEventType) : 
       mEventType(aEventType) {}
     
@@ -284,16 +291,21 @@ private:
   private:
     nsString mEventType;
   };
   
   nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
   nsIView*                        mInnerView;
   nsCOMPtr<nsIWidget>             mWidget;
   nsIntRect                       mWindowlessRect;
+  /**
+   * This is owned by the ReadbackLayer for this nsObjectFrame. It is
+   * automatically cleared if the PluginBackgroundSink is destroyed.
+   */
+  PluginBackgroundSink*           mBackgroundSink;
 
   // For assertions that make it easier to determine if a crash is due
   // to the underlying problem described in bug 136927, and to prevent
   // reentry into instantiation.
   PRBool mPreventInstantiation;
 
   PRPackedBool mReflowCallbackPosted;
 
@@ -340,16 +352,16 @@ public:
                                              LayerManager* aManager)
   {
     return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
   }
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager)
   {
-    return static_cast<nsObjectFrame*>(mFrame)->GetLayerState(aBuilder, aManager);
+    return static_cast<nsObjectFrame*>(mFrame)->GetLayerState(aBuilder);
   }
 
 private:
   nsRegion mVisibleRegion;
 };
 
 #endif /* nsObjectFrame_h___ */