Bug 583109 - Add visibility notification for plugins by setting the NPWindow.clipRect to [0, 0, 0, 0] when the plugin is not visible, either in a background tab, or visibility: hidden. r=karlt Patch rebased against trunk by Benjamin Smedberg.
authorJan Arne Petersen <jap@gnome.org>
Fri, 05 Nov 2010 10:38:33 -0400
changeset 57224 24a2e0ac428f81256fc54025a8a9437dafde37b8
parent 57223 167349934e8dbc73de2dcf7eef7174574d6b8bd0
child 57225 6ff3fcbb784501e3dc241e511aeea04ff759a468
push id16846
push userbsmedberg@mozilla.com
push dateWed, 10 Nov 2010 15:29:47 +0000
treeherdermozilla-central@bdbef533364f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs583109
milestone2.0b8pre
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 583109 - Add visibility notification for plugins by setting the NPWindow.clipRect to [0, 0, 0, 0] when the plugin is not visible, either in a background tab, or visibility: hidden. r=karlt Patch rebased against trunk by Benjamin Smedberg.
layout/generic/nsObjectFrame.cpp
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -378,17 +378,21 @@ public:
   void* SetPluginPortAndDetectChange();
   // Flag when we've set up a Thebes (and CoreGraphics) context in
   // nsObjectFrame::PaintPlugin().  We need to know this in
   // FixUpPluginWindow() (i.e. we need to know when FixUpPluginWindow() has
   // been called from nsObjectFrame::PaintPlugin() when we're using the
   // CoreGraphics drawing model).
   void BeginCGPaint();
   void EndCGPaint();
-#endif
+#else // XP_MACOSX
+  void UpdateWindowClipRect(PRBool aSetWindow);
+  void SetWindow();
+  void UpdateWindowVisibility(PRBool aVisible);
+#endif // XP_MACOSX
 
   void SetOwner(nsObjectFrame *aOwner)
   {
     mObjectFrame = aOwner;
   }
 
   PRUint32 GetLastEventloopNestingLevel() const {
     return mLastEventloopNestingLevel; 
@@ -509,16 +513,17 @@ private:
   PRPackedBool                mWidgetVisible;    // used on Mac to store our widget's visible state
 #ifdef XP_MACOSX
   PRPackedBool                mPluginPortChanged;
 #endif
 #ifdef MOZ_X11
   // Used with windowless plugins only, initialized in CreateWidget().
   PRPackedBool                mFlash10Quirks;
 #endif
+  PRPackedBool                mPluginWindowVisible;
 
   // If true, destroy the widget on destruction. Used when plugin stop
   // is being delayed to a safer point in time.
   PRPackedBool                mDestroyWidget;
   PRUint16          mNumCachedAttrs;
   PRUint16          mNumCachedParams;
   char              **mCachedAttrParamNames;
   char              **mCachedAttrParamValues;
@@ -823,16 +828,20 @@ nsObjectFrame::CreateWidget(nscoord aWid
       return NS_ERROR_FAILURE;
     pluginWidget->SetPluginEventModel(mInstanceOwner->GetEventModel());
     pluginWidget->SetPluginDrawingModel(mInstanceOwner->GetDrawingModel());
 
     if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation) {
       mInstanceOwner->SetupCARefresh();
     }
 #endif
+  } else {
+#ifndef XP_MACOSX
+    rpc->RegisterPluginForGeometryUpdates(this);
+#endif
   }
 
   if (!IsHidden()) {
     viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
   }
 
   return NS_OK;
 }
@@ -1063,25 +1072,25 @@ nsObjectFrame::FixupWindow(const nsSize&
   window->y = origin.y;
 
   window->width = presContext->AppUnitsToDevPixels(aSize.width);
   window->height = presContext->AppUnitsToDevPixels(aSize.height);
 
   // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
   // us from drawing on screen until the widget is properly positioned, which will not
   // happen until we have finished the reflow process.
+#ifdef XP_MACOSX
   window->clipRect.top = 0;
   window->clipRect.left = 0;
-#ifdef XP_MACOSX
   window->clipRect.bottom = 0;
   window->clipRect.right = 0;
 #else
-  window->clipRect.bottom = presContext->AppUnitsToDevPixels(aSize.height);
-  window->clipRect.right = presContext->AppUnitsToDevPixels(aSize.width);
+  mInstanceOwner->UpdateWindowClipRect(PR_FALSE);
 #endif
+
   NotifyPluginReflowObservers();
 }
 
 void
 nsObjectFrame::CallSetWindow()
 {
   NPWindow *win = nsnull;
  
@@ -1097,18 +1106,16 @@ nsObjectFrame::CallSetWindow()
   nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
 #ifdef XP_MACOSX
   mInstanceOwner->FixUpPluginWindow(ePluginPaintDisable);
 #endif
 
   if (IsHidden())
     return;
 
-  PRBool windowless = (window->type == NPWindowTypeDrawable);
-
   // refresh the plugin port as well
   window->window = mInstanceOwner->GetPluginPortFromWidget();
 
   // Adjust plugin dimensions according to pixel snap results
   // and reduce amount of SetWindow calls
   nsPresContext* presContext = PresContext();
   nsRootPresContext* rootPC = presContext->GetRootPresContext();
   if (!rootPC)
@@ -1287,18 +1294,24 @@ nsDisplayPlugin::GetWidgetConfiguration(
   f->ComputeWidgetGeometry(mVisibleRegion, pluginOrigin, aConfigurations);
 }
 
 void
 nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
                                      const nsPoint& aPluginOrigin,
                                      nsTArray<nsIWidget::Configuration>* aConfigurations)
 {
-  if (!mWidget)
+  if (!mWidget) {
+#ifndef XP_MACOSX
+    if (mInstanceOwner) {
+      mInstanceOwner->UpdateWindowVisibility(!aRegion.IsEmpty());
+    }
+#endif
     return;
+  }
 
   nsPresContext* presContext = PresContext();
   nsRootPresContext* rootPC = presContext->GetRootPresContext();
   if (!rootPC)
     return;
 
   nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
   if (!configuration)
@@ -2537,35 +2550,38 @@ nsObjectFrame::StopPlugin()
 
 void
 nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
 {
   if (!mInstanceOwner) {
     return;
   }
 
-  if (mWidget) {
-    nsRootPresContext* rootPC = PresContext()->GetRootPresContext();
-    if (rootPC) {
-      rootPC->UnregisterPluginForGeometryUpdates(this);
-
-      // 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;
-        GetEmptyClipConfiguration(&configurations);
-        parent->ConfigureChildren(configurations);
-        DidSetWidgetGeometry();
-      }
+  nsRootPresContext* rpc = PresContext()->GetRootPresContext();
+  if (!rpc) {
+    NS_ASSERTION(PresContext()->PresShell()->IsFrozen(),
+                 "unable to unregister the plugin frame");
+  }
+  else if (mWidget) {
+    rpc->UnregisterPluginForGeometryUpdates(this);
+
+    // 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;
+      GetEmptyClipConfiguration(&configurations);
+      parent->ConfigureChildren(configurations);
+      DidSetWidgetGeometry();
     }
-    else {
-      NS_ASSERTION(PresContext()->PresShell()->IsFrozen(),
-                   "unable to unregister the plugin frame");
-    }
+  }
+  else {
+#ifndef XP_MACOSX
+    rpc->UnregisterPluginForGeometryUpdates(this);
+#endif
   }
 
   // Transfer the reference to the instance owner onto the stack so
   // that if we do end up re-entering this code, or if we unwind back
   // here witha deleted frame (this), we can still continue to stop
   // the plugin. Note that due to that, the ordering of the code in
   // this function is extremely important.
 
@@ -2791,16 +2807,17 @@ nsPluginInstanceOwner::nsPluginInstanceO
 #endif
   mInCGPaintLevel = 0;
   mSentInitialTopLevelWindowEvent = PR_FALSE;
   mIOSurface = nsnull;
   mPluginPortChanged = PR_FALSE;
 #endif
   mContentFocused = PR_FALSE;
   mWidgetVisible = PR_TRUE;
+  mPluginWindowVisible = PR_FALSE;
   mNumCachedAttrs = 0;
   mNumCachedParams = 0;
   mCachedAttrParamNames = nsnull;
   mCachedAttrParamValues = nsnull;
   mDestroyWidget = PR_FALSE;
 
 #ifdef MOZ_COMPOSITED_PLUGINS
   mLastPoint = nsIntPoint(0,0);
@@ -6427,16 +6444,72 @@ void* nsPluginInstanceOwner::FixUpPlugin
 #ifdef MAC_CARBON_PLUGINS
   if (drawingModel == NPDrawingModelCoreGraphics && eventModel == NPEventModelCarbon)
     return static_cast<NP_CGContext*>(pluginPort)->window;
 #endif
 
   return nsnull;
 }
 
+#else // XP_MACOSX
+void nsPluginInstanceOwner::UpdateWindowClipRect(PRBool aSetWindow)
+{
+  if (!mPluginWindow)
+    return;
+
+  // For windowless plugins a non-empty clip rectangle will be
+  // passed to the plugin during paint, an additional update
+  // of the the clip rectangle here is not required
+  if (aSetWindow && !mWidget && mPluginWindowVisible)
+    return;
+
+  const NPRect oldClipRect = mPluginWindow->clipRect;
+
+  mPluginWindow->clipRect.left = 0;
+  mPluginWindow->clipRect.top = 0;
+
+  if (mPluginWindowVisible) {
+    mPluginWindow->clipRect.right = mPluginWindow->width;
+    mPluginWindow->clipRect.bottom = mPluginWindow->height;
+  } else {
+    mPluginWindow->clipRect.right = 0;
+    mPluginWindow->clipRect.bottom = 0;
+  }
+
+  if (!aSetWindow)
+    return;
+
+  if ((mPluginWindow->clipRect.left   != oldClipRect.left   ||
+       mPluginWindow->clipRect.top    != oldClipRect.top    ||
+       mPluginWindow->clipRect.right  != oldClipRect.right  ||
+       mPluginWindow->clipRect.bottom != oldClipRect.bottom)) {
+    SetWindow();
+  }
+}
+
+void
+nsPluginInstanceOwner::SetWindow()
+{
+  if (!mInstance)
+    return;
+
+  if (UseLayers()) {
+    mInstance->AsyncSetWindow(mPluginWindow);
+  } else {
+    mInstance->SetWindow(mPluginWindow);
+  }
+}
+
+void
+nsPluginInstanceOwner::UpdateWindowVisibility(PRBool aVisible)
+{
+  mPluginWindowVisible = aVisible;
+  UpdateWindowClipRect(PR_TRUE);
+}
+
 #endif // XP_MACOSX
 
 // Little helper function to resolve relative URL in
 // |value| for certain inputs of |name|
 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
 {
   if (name.LowerCaseEqualsLiteral("pluginurl") ||
       name.LowerCaseEqualsLiteral("pluginspage")) {