Bug 1095754 - Provide a way to track and access native plugin widgets so they can be accessed from global scope. r=aklotz
authorJim Mathies <jmathies@mozilla.com>
Thu, 29 Jan 2015 13:41:53 -0600
changeset 226581 c05f8b0ce6bb97b38d858ce60c23080fc34aa262
parent 226580 25ca03634cf5f82fb9fef5e3a36833849b24a234
child 226582 fc53ac4a756e02dfe8d5b7fc756839839e9dc466
push id28200
push userkwierso@gmail.com
push dateThu, 29 Jan 2015 23:01:46 +0000
treeherderautoland@4380ed39de3a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaklotz
bugs1095754
milestone38.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
Bug 1095754 - Provide a way to track and access native plugin widgets so they can be accessed from global scope. r=aklotz
dom/plugins/ipc/PluginWidgetParent.cpp
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
--- a/dom/plugins/ipc/PluginWidgetParent.cpp
+++ b/dom/plugins/ipc/PluginWidgetParent.cpp
@@ -45,16 +45,17 @@ PluginWidgetParent::PluginWidgetParent()
 PluginWidgetParent::~PluginWidgetParent()
 {
   PWLOG("PluginWidgetParent::~PluginWidgetParent()\n");
   MOZ_COUNT_DTOR(PluginWidgetParent);
   // A destroy call can actually get skipped if a widget is associated
   // with the last out-of-process page, make sure and cleanup any left
   // over widgets if we have them.
   if (mWidget) {
+    mWidget->UnregisterPluginWindowForRemoteUpdates();
     mWidget->Destroy();
     mWidget = nullptr;
   }
 }
 
 mozilla::dom::TabParent*
 PluginWidgetParent::GetTabParent()
 {
@@ -105,16 +106,22 @@ PluginWidgetParent::RecvCreate()
     mWidget = nullptr;
     return false;
   }
 
   mWidget->EnableDragDrop(true);
   mWidget->Show(false);
   mWidget->Enable(false);
 
+  // This is a special call we make to nsBaseWidget to register this
+  // window as a remote plugin window which is expected to receive
+  // visibility updates from the compositor, which ships this data
+  // over with corresponding layer updates.
+  mWidget->RegisterPluginWindowForRemoteUpdates();
+
   // Force the initial position down into content. If we miss an
   // initial position update this insures the widget doesn't overlap
   // chrome.
   RecvMove(0, 0);
 
 #if defined(MOZ_WIDGET_GTK)
   // For setup, initially GTK code expects 'window' to hold the parent.
   mWrapper->window = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
@@ -126,16 +133,17 @@ PluginWidgetParent::RecvCreate()
   return true;
 }
 
 bool
 PluginWidgetParent::RecvDestroy()
 {
   ENSURE_CHANNEL;
   PWLOG("PluginWidgetParent::RecvDestroy()\n");
+  mWidget->UnregisterPluginWindowForRemoteUpdates();
   mWidget->Destroy();
   mWidget = nullptr;
   return true;
 }
 
 bool
 PluginWidgetParent::RecvShow(const bool& aState)
 {
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -44,17 +44,17 @@
 #include "mozilla/MouseEvents.h"
 #include "GLConsts.h"
 #include "mozilla/unused.h"
 #include "mozilla/VsyncDispatcher.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/ChromeProcessController.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/dom/TabParent.h"
-
+#include "nsRefPtrHashtable.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 #ifdef DEBUG
 #include "nsIObserver.h"
 
 static void debug_RegisterPrefCallbacks();
@@ -64,16 +64,19 @@ static void debug_RegisterPrefCallbacks(
 #ifdef NOISY_WIDGET_LEAKS
 static int32_t gNumWidgets;
 #endif
 
 #ifdef XP_MACOSX
 #include "nsCocoaFeatures.h"
 #endif
 
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+static nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>* sPluginWidgetList;
+#endif
 nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
 
 using namespace mozilla::layers;
 using namespace mozilla::ipc;
 using namespace mozilla::widget;
 using namespace mozilla;
 using base::Thread;
 
@@ -136,29 +139,40 @@ nsBaseWidget::nsBaseWidget()
   gNumWidgets++;
   printf("WIDGETS+ = %d\n", gNumWidgets);
 #endif
 
 #ifdef DEBUG
   debug_RegisterPrefCallbacks();
 #endif
 
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+  if (!sPluginWidgetList) {
+    sPluginWidgetList = new nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>();
+  }
+#endif
   mShutdownObserver = new WidgetShutdownObserver(this);
   nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
 }
 
 NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
 
 NS_IMETHODIMP
 WidgetShutdownObserver::Observe(nsISupports *aSubject,
                                 const char *aTopic,
                                 const char16_t *aData)
 {
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0 &&
       mWidget) {
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+    if (sPluginWidgetList) {
+      delete sPluginWidgetList;
+      sPluginWidgetList = nullptr;
+    }
+#endif
     mWidget->Shutdown();
     nsContentUtils::UnregisterShutdownObserver(this);
   }
  return NS_OK;
 }
 
 void
 nsBaseWidget::Shutdown()
@@ -1739,16 +1753,98 @@ nsIWidget::ClearNativeTouchSequence()
   mLongTapTimer->Cancel();
   mLongTapTimer = nullptr;
   SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
                              mLongTapTouchPoint->mPosition, 0, 0);
   mLongTapTouchPoint = nullptr;
   return NS_OK;
 }
 
+void
+nsBaseWidget::RegisterPluginWindowForRemoteUpdates()
+{
+#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+  NS_NOTREACHED("nsBaseWidget::RegisterPluginWindowForRemoteUpdates not implemented!");
+  return;
+#else
+  MOZ_ASSERT(NS_IsMainThread());
+  void* id = GetNativeData(NS_NATIVE_PLUGIN_PORT);
+  if (!id) {
+    NS_WARNING("This is not a valid native widget!");
+    return;
+  }
+  MOZ_ASSERT(sPluginWidgetList);
+  sPluginWidgetList->Put(id, this);
+#endif
+}
+
+void
+nsBaseWidget::UnregisterPluginWindowForRemoteUpdates()
+{
+#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+  NS_NOTREACHED("nsBaseWidget::UnregisterPluginWindowForRemoteUpdates not implemented!");
+  return;
+#else
+  MOZ_ASSERT(NS_IsMainThread());
+  void* id = GetNativeData(NS_NATIVE_PLUGIN_PORT);
+  if (!id) {
+    NS_WARNING("This is not a valid native widget!");
+    return;
+  }
+  MOZ_ASSERT(sPluginWidgetList);
+  sPluginWidgetList->Remove(id);
+#endif
+}
+
+// static
+nsIWidget*
+nsIWidget::LookupRegisteredPluginWindow(uintptr_t aWindowID)
+{
+#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+  NS_NOTREACHED("nsBaseWidget::LookupRegisteredPluginWindow not implemented!");
+  return nullptr;
+#else
+  MOZ_ASSERT(NS_IsMainThread());
+  nsIWidget* widget = nullptr;
+  MOZ_ASSERT(sPluginWidgetList);
+  sPluginWidgetList->Get((void*)aWindowID, &widget);
+  return widget;
+#endif
+}
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+static PLDHashOperator
+RegisteredPluginEnumerator(const void* aWindowId, nsIWidget* aWidget, void* aUserArg)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aWindowId);
+  MOZ_ASSERT(aWidget);
+  MOZ_ASSERT(aUserArg);
+  const nsTArray<uintptr_t>* visible = static_cast<const nsTArray<uintptr_t>*>(aUserArg);
+  if (!visible->Contains((uintptr_t)aWindowId) && !aWidget->Destroyed()) {
+    aWidget->Show(false);
+  }
+  return PLDHashOperator::PL_DHASH_NEXT;
+}
+#endif
+
+// static
+void
+nsIWidget::UpdateRegisteredPluginWindowVisibility(nsTArray<uintptr_t>& aVisibleList)
+{
+#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+  NS_NOTREACHED("nsBaseWidget::UpdateRegisteredPluginWindowVisibility not implemented!");
+  return;
+#else
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sPluginWidgetList);
+  sPluginWidgetList->EnumerateRead(RegisteredPluginEnumerator, static_cast<void*>(&aVisibleList));
+#endif
+}
+
 #ifdef DEBUG
 //////////////////////////////////////////////////////////////
 //
 // Convert a GUI event message code to a string.
 // Makes it a lot easier to debug events.
 //
 // See gtk/nsWidget.cpp and windows/nsWindow.cpp
 // for a DebugPrintEvent() function that uses
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -222,16 +222,20 @@ public:
   NS_IMETHOD              RegisterTouchWindow() MOZ_OVERRIDE;
   NS_IMETHOD              UnregisterTouchWindow() MOZ_OVERRIDE;
   NS_IMETHOD_(TextEventDispatcher*) GetTextEventDispatcher() MOZ_OVERRIDE MOZ_FINAL;
 
   void NotifyWindowDestroyed();
   void NotifySizeMoveDone();
   void NotifyWindowMoved(int32_t aX, int32_t aY);
 
+  // Register plugin windows for remote updates from the compositor
+  virtual void RegisterPluginWindowForRemoteUpdates() MOZ_OVERRIDE;
+  virtual void UnregisterPluginWindowForRemoteUpdates() MOZ_OVERRIDE;
+
   // Should be called by derived implementations to notify on system color and
   // theme changes.
   void NotifySysColorChanged();
   void NotifyThemeChanged();
   void NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
                             UIStateChangeType aShowFocusRings);
 
 #ifdef ACCESSIBILITY
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -102,18 +102,18 @@ typedef void* nsNativeWidget;
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x029a269f, 0x8b1a, 0x466b, \
-  { 0x89, 0x61, 0xc9, 0xcd, 0x23, 0x4e, 0x21, 0x27 } };
+{ 0xa7db3e01, 0xb8fe, 0x4122, \
+  { 0xbe, 0xa6, 0x45, 0x6c, 0xdd, 0x85, 0x30, 0x64 } };
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -1390,16 +1390,40 @@ class nsIWidget : public nsISupports {
     /**
      * Appends to aRects the rectangles constituting this widget's clip
      * region. If this widget is not clipped, appends a single rectangle
      * (0, 0, bounds.width, bounds.height).
      */
     virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects) = 0;
 
     /**
+     * Register or unregister native plugin widgets which receive Configuration
+     * data from the content process via the compositor.
+     *
+     * Lookups are used by the main thread via the compositor to lookup widgets
+     * based on a unique window id. On Windows and Linux this is the
+     * NS_NATIVE_PLUGIN_PORT (hwnd/XID). This tracking maintains a reference to
+     * widgets held. Consumers are responsible for removing widgets from this
+     * list.
+     */
+    virtual void RegisterPluginWindowForRemoteUpdates() = 0;
+    virtual void UnregisterPluginWindowForRemoteUpdates() = 0;
+    static nsIWidget* LookupRegisteredPluginWindow(uintptr_t aWindowID);
+
+    /**
+     * Iterates across the list of registered plugin widgets and updates thier
+     * visibility based on which plugins are included in the 'visible' list.
+     *
+     * The compositor knows little about tabs, but it does know which plugin
+     * widgets are currently included in the visible layer tree. It calls this
+     * helper to hide widgets it knows nothing about.
+     */
+    static void UpdateRegisteredPluginWindowVisibility(nsTArray<uintptr_t>& aVisibleList);
+
+    /**
      * Set the shadow style of the window.
      *
      * Ignored on child widgets and on non-Mac platforms.
      */
     NS_IMETHOD SetWindowShadowStyle(int32_t aStyle) = 0;
 
     /*
      * On Mac OS X, this method shows or hides the pill button in the titlebar