Implement the DidComposite NPAPI callback. (bug 1217665 part 8, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Wed, 02 Dec 2015 11:31:17 -0800
changeset 275334 5c38d2f6fb93c1edafe8e83515b1437c61eda277
parent 275333 86b8d0183c5d7ff5434ae931f295efe937e6e848
child 275335 7c063ffd2e22434ae4ed66fd391c59e0650d0976
push id29752
push usercbook@mozilla.com
push dateThu, 03 Dec 2015 11:03:31 +0000
treeherdermozilla-central@85cf2e720a84 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1217665
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Implement the DidComposite NPAPI callback. (bug 1217665 part 8, r=mattwoodrow)
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/ipc/CompositorParent.cpp
layout/generic/nsPluginFrame.cpp
layout/generic/nsPluginFrame.h
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -245,16 +245,24 @@ nsPluginInstanceOwner::GetImageContainer
 #else
   mInstance->GetImageContainer(getter_AddRefs(container));
 #endif
 
   return container.forget();
 }
 
 void
+nsPluginInstanceOwner::DidComposite()
+{
+  if (mInstance) {
+    mInstance->DidComposite();
+  }
+}
+
+void
 nsPluginInstanceOwner::SetBackgroundUnknown()
 {
   if (mInstance) {
     mInstance->SetBackgroundUnknown();
   }
 }
 
 already_AddRefed<gfxContext>
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -213,16 +213,18 @@ public:
     return strncmp(GetPluginName(), aPluginName, strlen(aPluginName)) == 0;
   }
   
   void NotifyPaintWaiter(nsDisplayListBuilder* aBuilder);
 
   // Returns the image container that has our currently displayed image.
   already_AddRefed<mozilla::layers::ImageContainer> GetImageContainer();
 
+  void DidComposite();
+
   /**
    * Returns the bounds of the current async-rendered surface. This can only
    * change in response to messages received by the event loop (i.e. not during
    * painting).
    */
   nsIntSize GetCurrentImageSize();
   
   // Methods to update the background image we send to async plugins.
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -391,25 +391,35 @@ ClientLayerManager::Composite()
 }
 
 void
 ClientLayerManager::DidComposite(uint64_t aTransactionId,
                                  const TimeStamp& aCompositeStart,
                                  const TimeStamp& aCompositeEnd)
 {
   MOZ_ASSERT(mWidget);
-  nsIWidgetListener *listener = mWidget->GetWidgetListener();
-  if (listener) {
-    listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
+
+  // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
+  // layers transaction.
+  if (aTransactionId) {
+    nsIWidgetListener *listener = mWidget->GetWidgetListener();
+    if (listener) {
+      listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
+    }
+    listener = mWidget->GetAttachedWidgetListener();
+    if (listener) {
+      listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
+    }
+    mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
   }
-  listener = mWidget->GetAttachedWidgetListener();
-  if (listener) {
-    listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
+
+  // These observers fire whether or not we were in a transaction.
+  for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
+    mDidCompositeObservers[i]->DidComposite();
   }
-  mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
 }
 
 void
 ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const
 {
   if (mForwarder->HasShadowManager()) {
     if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
       NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
@@ -818,16 +828,30 @@ ClientLayerManager::AsyncPanZoomEnabled(
 }
 
 void
 ClientLayerManager::SetNextPaintSyncId(int32_t aSyncId)
 {
   mForwarder->SetPaintSyncId(aSyncId);
 }
 
+void
+ClientLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
+{
+  if (!mDidCompositeObservers.Contains(aObserver)) {
+    mDidCompositeObservers.AppendElement(aObserver);
+  }
+}
+
+void
+ClientLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserver)
+{
+  mDidCompositeObservers.RemoveElement(aObserver);
+}
+
 ClientLayer::~ClientLayer()
 {
   if (HasShadow()) {
     PLayerChild::Send__delete__(GetShadow());
   }
   MOZ_COUNT_DTOR(ClientLayer);
 }
 
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -252,16 +252,24 @@ public:
   void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) { mTransactionIdAllocator = aAllocator; }
 
   float RequestProperty(const nsAString& aProperty) override;
 
   bool AsyncPanZoomEnabled() const override;
 
   void SetNextPaintSyncId(int32_t aSyncId);
 
+  class DidCompositeObserver {
+  public:
+    virtual void DidComposite() = 0;
+  };
+
+  void AddDidCompositeObserver(DidCompositeObserver* aObserver);
+  void RemoveDidCompositeObserver(DidCompositeObserver* aObserver);
+
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
 private:
   // Listen memory-pressure event for ClientLayerManager
@@ -346,16 +354,18 @@ private:
 
   APZTestData mApzTestData;
 
   RefPtr<ShadowLayerForwarder> mForwarder;
   nsAutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
   nsAutoTArray<dom::OverfillCallback*,0> mOverfillCallbacks;
   mozilla::TimeStamp mTransactionStart;
 
+  nsTArray<DidCompositeObserver*> mDidCompositeObservers;
+
   RefPtr<MemoryPressureObserver> mMemoryPressureObserver;
 };
 
 class ClientLayer : public ShadowableLayer
 {
 public:
   ClientLayer()
   {
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1845,20 +1845,19 @@ private:
   // is received
   bool mNotifyAfterRemotePaint;
 };
 
 void
 CompositorParent::DidComposite(TimeStamp& aCompositeStart,
                                TimeStamp& aCompositeEnd)
 {
-  if (mPendingTransaction) {
-    Unused << SendDidComposite(0, mPendingTransaction, aCompositeStart, aCompositeEnd);
-    mPendingTransaction = 0;
-  }
+  Unused << SendDidComposite(0, mPendingTransaction, aCompositeStart, aCompositeEnd);
+  mPendingTransaction = 0;
+
   if (mLayerManager) {
     nsTArray<ImageCompositeNotification> notifications;
     mLayerManager->ExtractImageCompositeNotifications(&notifications);
     if (!notifications.IsEmpty()) {
       Unused << ImageBridgeParent::NotifyImageComposites(notifications);
     }
   }
 
@@ -2170,18 +2169,17 @@ CompositorParent::UpdatePluginWindowStat
 #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 
 void
 CrossProcessCompositorParent::DidComposite(uint64_t aId,
                                            TimeStamp& aCompositeStart,
                                            TimeStamp& aCompositeEnd)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
-  LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree;
-  if (layerTree && layerTree->GetPendingTransactionId()) {
+  if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
     Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
     layerTree->SetPendingTransactionId(0);
   }
 }
 
 void
 CrossProcessCompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -84,16 +84,17 @@ using mozilla::DefaultXDisplay;
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "GLContext.h"
 #endif
 
 #include "mozilla/dom/TabChild.h"
+#include "ClientLayerManager.h"
 
 #ifdef CreateEvent // Thank you MS.
 #undef CreateEvent
 #endif
 
 static mozilla::LazyLogModule sPluginFrameLog("nsPluginFrame");
 
 using namespace mozilla;
@@ -197,16 +198,19 @@ nsPluginFrame::Init(nsIContent*       aC
 
 void
 nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   if (mReflowCallbackPosted) {
     PresContext()->PresShell()->CancelReflowCallback(this);
   }
 
+  // Ensure our DidComposite observer is gone.
+  mDidCompositeObserver = nullptr;
+
   // Tell content owner of the instance to disconnect its frame.
   nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
   NS_ASSERTION(objContent, "Why not an object loading content?");
 
   // The content might not have a reference to the instance owner any longer in
   // the case of re-entry during instantiation or teardown, so make sure we're
   // dissociated.
   if (mInstanceOwner) {
@@ -695,19 +699,24 @@ nsPluginFrame::UnregisterPluginForGeomet
 void
 nsPluginFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
 {
   // The ownership model here is historically fuzzy. This should only be called
   // by nsPluginInstanceOwner when it is given a new frame, and
   // nsObjectLoadingContent should be arbitrating frame-ownership via its
   // HasNewFrame callback.
   mInstanceOwner = aOwner;
+
+  // Reset the DidCompositeObserver since the owner changed.
+  mDidCompositeObserver = nullptr;
+
   if (mInstanceOwner) {
     return;
   }
+
   UnregisterPluginForGeometryUpdates();
   if (mWidget && mInnerView) {
     mInnerView->DetachWidgetEventHandler(mWidget);
     // Make sure the plugin is hidden in case an update of plugin geometry
     // hasn't happened since this plugin became hidden.
     nsIWidget* parent = mWidget->GetParent();
     if (parent) {
       nsTArray<nsIWidget::Configuration> configurations;
@@ -1388,16 +1397,40 @@ nsPluginFrame::GetLayerState(nsDisplayLi
 
   if (!mInstanceOwner->UseAsyncRendering()) {
     return LAYER_NONE;
   }
 
   return LAYER_ACTIVE;
 }
 
+class PluginFrameDidCompositeObserver final : public ClientLayerManager::
+  DidCompositeObserver
+{
+public:
+  PluginFrameDidCompositeObserver(nsPluginInstanceOwner* aOwner, ClientLayerManager* aLayerManager)
+    : mInstanceOwner(aOwner),
+      mLayerManager(aLayerManager)
+  {
+  }
+  ~PluginFrameDidCompositeObserver() {
+    mLayerManager->RemoveDidCompositeObserver(this);
+  }
+  void DidComposite() override {
+    mInstanceOwner->DidComposite();
+  }
+  bool IsValid(ClientLayerManager* aLayerManager) {
+    return aLayerManager == mLayerManager;
+  }
+
+private:
+  nsPluginInstanceOwner* mInstanceOwner;
+  RefPtr<ClientLayerManager> mLayerManager;
+};
+
 already_AddRefed<Layer>
 nsPluginFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
                           LayerManager* aManager,
                           nsDisplayItem* aItem,
                           const ContainerLayerParameters& aContainerParameters)
 {
   if (!mInstanceOwner)
     return nullptr;
@@ -1456,16 +1489,28 @@ nsPluginFrame::BuildLayer(nsDisplayListB
     if (!aManager->IsCompositingCheap()) {
       // Pixman just horrible with bilinear filter scaling
       filter = Filter::POINT;
     }
 #endif
     imglayer->SetFilter(filter);
 
     layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
+
+    if (aBuilder->IsPaintingToWindow() &&
+        aBuilder->GetWidgetLayerManager() &&
+        aBuilder->GetWidgetLayerManager()->AsClientLayerManager() &&
+        mInstanceOwner->UseAsyncRendering())
+    {
+      RefPtr<ClientLayerManager> lm = aBuilder->GetWidgetLayerManager()->AsClientLayerManager();
+      if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) {
+        mDidCompositeObserver = new PluginFrameDidCompositeObserver(mInstanceOwner, lm);
+      }
+      lm->AddDidCompositeObserver(mDidCompositeObserver);
+    }
 #ifdef MOZ_WIDGET_ANDROID
   } else if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_VIDEO) {
     nsDisplayPluginVideo* videoItem = reinterpret_cast<nsDisplayPluginVideo*>(aItem);
     nsNPAPIPluginInstance::VideoInfo* videoInfo = videoItem->VideoInfo();
 
     RefPtr<ImageContainer> container = mInstanceOwner->GetImageContainerForVideo(videoInfo);
     if (!container)
       return nullptr;
--- a/layout/generic/nsPluginFrame.h
+++ b/layout/generic/nsPluginFrame.h
@@ -39,19 +39,22 @@ namespace layers {
 class ImageContainer;
 class Layer;
 class LayerManager;
 } // namespace layers
 } // namespace mozilla
 
 typedef nsFrame nsPluginFrameSuper;
 
+class PluginFrameDidCompositeObserver;
+
 class nsPluginFrame : public nsPluginFrameSuper,
                       public nsIObjectFrame,
-                      public nsIReflowCallback {
+                      public nsIReflowCallback
+{
 public:
   typedef mozilla::LayerState LayerState;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
 
   NS_DECL_FRAMEARENA_HELPERS
@@ -318,16 +321,18 @@ private:
   bool mReflowCallbackPosted;
 
   // We keep this reference to ensure we can always unregister the
   // plugins we register on the root PresContext.
   // This is only non-null while we have a plugin registered for geometry
   // updates.
   RefPtr<nsRootPresContext> mRootPresContextRegisteredWith;
 
+  nsAutoPtr<PluginFrameDidCompositeObserver> mDidCompositeObserver;
+
   // Tracks windowed plugin visibility during scroll operations. See
   // SetScrollVisibility.
   bool mIsHiddenDueToScroll;
 };
 
 class nsDisplayPlugin : public nsDisplayItem {
 public:
   nsDisplayPlugin(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)