Bug 669200 - On the child side implement a suitable nsIWidget wrapper for PPluginWidget based on PuppetWidget. r=billm
authorJim Mathies <jmathies@mozilla.com>
Wed, 12 Nov 2014 14:59:20 -0600
changeset 239676 ad862fdf75cd2be6681f713f051ea9150e4f76f5
parent 239675 bcaebd09531ca0c862f92d5e2ff80ffb22741419
child 239677 115f074c9b0d65c1de4b117c0ccdd76b63de4249
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs669200
milestone36.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 669200 - On the child side implement a suitable nsIWidget wrapper for PPluginWidget based on PuppetWidget. r=billm
dom/ipc/TabChild.cpp
widget/PluginWidgetProxy.cpp
widget/PluginWidgetProxy.h
widget/moz.build
widget/nsIWidget.h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3133,18 +3133,23 @@ TabChild::CreatePluginWidget(nsIWidget* 
     return nullptr;
   }
   nsCOMPtr<nsIWidget> pluginWidget = nsIWidget::CreatePluginProxyWidget(this, child);
   if (!pluginWidget) {
     NS_ERROR("couldn't create PluginWidgetProxy");
     return nullptr;
   }
 
-  nsresult rv = pluginWidget->Create(aParent, 0, nsIntRect(nsIntPoint(0, 0),
-                                     nsIntSize(0, 0)), nullptr, nullptr);
+  nsWidgetInitData initData;
+  initData.mWindowType = eWindowType_plugin_ipc_content;
+  initData.mUnicode = false;
+  initData.clipChildren = true;
+  initData.clipSiblings = true;
+  nsresult rv = pluginWidget->Create(aParent, nullptr, nsIntRect(nsIntPoint(0, 0),
+                                     nsIntSize(0, 0)), nullptr, &initData);
   if (NS_FAILED(rv)) {
     NS_WARNING("Creating native plugin widget on the chrome side failed.");
   }
   return pluginWidget.forget();
 }
 
 TabChildGlobal::TabChildGlobal(TabChildBase* aTabChild)
 : mTabChild(aTabChild)
new file mode 100644
--- /dev/null
+++ b/widget/PluginWidgetProxy.cpp
@@ -0,0 +1,206 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PluginWidgetProxy.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/plugins/PluginWidgetChild.h"
+#include "nsDebug.h"
+
+#define PWLOG(...)
+// #define PWLOG(...) printf_stderr(__VA_ARGS__)
+
+/* static */
+already_AddRefed<nsIWidget>
+nsIWidget::CreatePluginProxyWidget(TabChild* aTabChild,
+                                   mozilla::plugins::PluginWidgetChild* aActor)
+{
+  nsCOMPtr<nsIWidget> widget =
+    new mozilla::widget::PluginWidgetProxy(aTabChild, aActor);
+  return widget.forget();
+}
+
+namespace mozilla {
+namespace widget {
+
+NS_IMPL_ISUPPORTS_INHERITED(PluginWidgetProxy, PuppetWidget, nsIWidget)
+
+#define ENSURE_CHANNEL do {                                   \
+  if (!mActor) {                                              \
+    NS_WARNING("called on an invalid channel.");              \
+    return NS_ERROR_FAILURE;                                  \
+  }                                                           \
+} while (0)
+
+PluginWidgetProxy::PluginWidgetProxy(dom::TabChild* aTabChild,
+                                     mozilla::plugins::PluginWidgetChild* aActor) :
+  PuppetWidget(aTabChild),
+  mActor(aActor)
+{
+  // See ChannelDestroyed() in the header
+  mActor->mWidget = this;
+}
+
+PluginWidgetProxy::~PluginWidgetProxy()
+{
+  PWLOG("PluginWidgetProxy::~PluginWidgetProxy()\n");
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Create(nsIWidget*        aParent,
+                          nsNativeWidget    aNativeParent,
+                          const nsIntRect&  aRect,
+                          nsDeviceContext*  aContext,
+                          nsWidgetInitData* aInitData)
+{
+  ENSURE_CHANNEL;
+  PWLOG("PluginWidgetProxy::Create()\n");
+
+  if (!mActor->SendCreate()) {
+    NS_WARNING("failed to create chrome widget, plugins won't paint.");
+  }
+
+  BaseCreate(aParent, aRect, aContext, aInitData);
+
+  mBounds = aRect;
+  mEnabled = true;
+  mVisible = true;
+
+  mActor->SendResize(mBounds);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::SetParent(nsIWidget* aNewParent)
+{
+  mParent = aNewParent;
+
+  nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
+  nsIWidget* parent = GetParent();
+  if (parent) {
+    parent->RemoveChild(this);
+  }
+  if (aNewParent) {
+    aNewParent->AddChild(this);
+  }
+  return NS_OK;
+}
+
+nsIWidget*
+PluginWidgetProxy::GetParent(void)
+{
+  return mParent.get();
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Destroy()
+{
+  PWLOG("PluginWidgetProxy::Destroy()\n");
+
+  if (mActor) {
+    mActor->SendShow(false);
+    mActor->SendDestroy();
+    mActor->mWidget = nullptr;
+    mActor->Send__delete__(mActor);
+    mActor = nullptr;
+  }
+
+  return PuppetWidget::Destroy();
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Show(bool aState)
+{
+  ENSURE_CHANNEL;
+  mActor->SendShow(aState);
+  mVisible = aState;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Invalidate(const nsIntRect& aRect)
+{
+  ENSURE_CHANNEL;
+  mActor->SendInvalidate(aRect);
+  return NS_OK;
+}
+
+void*
+PluginWidgetProxy::GetNativeData(uint32_t aDataType)
+{
+  if (!mActor) {
+    return nullptr;
+  }
+  switch (aDataType) {
+    case NS_NATIVE_PLUGIN_PORT:
+    case NS_NATIVE_WINDOW:
+    case NS_NATIVE_SHAREABLE_WINDOW:
+      break;
+    default:
+      NS_WARNING("PluginWidgetProxy::GetNativeData received request for unsupported data type.");
+      return nullptr;
+  }
+  uintptr_t value = 0;
+  mActor->SendGetNativePluginPort(&value);
+  return (void*)value;
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Resize(double aWidth, double aHeight, bool aRepaint)
+{
+  ENSURE_CHANNEL;
+  PWLOG("PluginWidgetProxy::Resize(%0.2f, %0.2f, %d)\n", aWidth, aHeight, aRepaint);
+  nsIntRect oldBounds = mBounds;
+  mBounds.SizeTo(nsIntSize(NSToIntRound(aWidth), NSToIntRound(aHeight)));
+  mActor->SendResize(mBounds);
+  if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) {
+    mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Resize(double aX, double aY, double aWidth,
+                          double aHeight, bool aRepaint)
+{
+  nsresult rv = Move(aX, aY);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return Resize(aWidth, aHeight, aRepaint);
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::Move(double aX, double aY)
+{
+  ENSURE_CHANNEL;
+  PWLOG("PluginWidgetProxy::Move(%0.2f, %0.2f)\n", aX, aY);
+  mActor->SendMove(aX, aY);
+  if (mAttachedWidgetListener) {
+    mAttachedWidgetListener->WindowMoved(this, aX, aY);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PluginWidgetProxy::SetFocus(bool aRaise)
+{
+  ENSURE_CHANNEL;
+  PWLOG("PluginWidgetProxy::SetFocus(%d)\n", aRaise);
+  mActor->SendSetFocus(aRaise);
+  return NS_OK;
+}
+
+nsresult
+PluginWidgetProxy::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+                                       bool aIntersectWithExisting)
+{
+  ENSURE_CHANNEL;
+  mActor->SendSetWindowClipRegion(aRects, aIntersectWithExisting);
+  nsBaseWidget::SetWindowClipRegion(aRects, aIntersectWithExisting);
+  return NS_OK;
+}
+
+}  // namespace widget
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/PluginWidgetProxy.h
@@ -0,0 +1,79 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_widget_RemotePlugin_h__
+#define mozilla_widget_RemotePlugin_h__
+
+#include "PuppetWidget.h"
+#include "mozilla/dom/TabChild.h"
+
+/*
+ * PluginWidgetProxy is a nsIWidget wrapper we hand around in plugin and layout
+ * code. It wraps a native widget it creates in the chrome process. Since this
+ * is for plugins, only a limited set of the widget apis need to be overridden,
+ * the rest of the implementation is in PuppetWidget or nsBaseWidget.
+ */
+
+namespace mozilla {
+namespace plugins {
+class PluginWidgetChild;
+}
+namespace widget {
+
+class PluginWidgetProxy MOZ_FINAL : public PuppetWidget
+{
+public:
+  explicit PluginWidgetProxy(dom::TabChild* aTabChild,
+                             mozilla::plugins::PluginWidgetChild* aChannel);
+
+protected:
+  virtual ~PluginWidgetProxy();
+
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIWidget
+  NS_IMETHOD Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
+                    const nsIntRect& aRect, nsDeviceContext* aContext,
+                    nsWidgetInitData* aInitData = nullptr) MOZ_OVERRIDE;
+  NS_IMETHOD Destroy() MOZ_OVERRIDE;
+  NS_IMETHOD Show(bool aState) MOZ_OVERRIDE;
+  NS_IMETHOD Invalidate(const nsIntRect& aRect) MOZ_OVERRIDE;
+  NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint) MOZ_OVERRIDE;
+  NS_IMETHOD Resize(double aX, double aY, double aWidth,
+                    double aHeight, bool aRepaint)  MOZ_OVERRIDE;
+  NS_IMETHOD Move(double aX, double aY) MOZ_OVERRIDE;
+  NS_IMETHOD SetFocus(bool aRaise = false) MOZ_OVERRIDE;
+  NS_IMETHOD SetParent(nsIWidget* aNewParent) MOZ_OVERRIDE;
+
+  virtual nsIWidget* GetParent(void) MOZ_OVERRIDE;
+  virtual void* GetNativeData(uint32_t aDataType) MOZ_OVERRIDE;
+  virtual nsresult SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+                                       bool aIntersectWithExisting) MOZ_OVERRIDE;
+
+  // nsBaseWidget
+  virtual nsTransparencyMode GetTransparencyMode() MOZ_OVERRIDE
+  { return eTransparencyOpaque; }
+
+public:
+  /**
+   * When tabs are closed PPluginWidget can terminate before plugin code is
+   * finished tearing us down. When this happens plugin calls over mActor
+   * fail triggering an abort in the content process. To protect against this
+   * the connection tells us when it is torn down here so we can avoid making
+   * calls while content finishes tearing us down.
+   */
+  void ChannelDestroyed() { mActor = nullptr; }
+
+private:
+  // Our connection with the chrome widget, created on PBrowser.
+  mozilla::plugins::PluginWidgetChild* mActor;
+  // PuppetWidget does not implement parent apis, but we need
+  // them for plugin widgets.
+  nsCOMPtr<nsIWidget> mParent;
+};
+
+}  // namespace widget
+}  // namespace mozilla
+#endif
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -102,16 +102,17 @@ EXPORTS += [
     'nsIDeviceContextSpec.h',
     'nsIPluginWidget.h',
     'nsIRollupListener.h',
     'nsIWidget.h',
     'nsIWidgetListener.h',
     'nsPrintOptionsImpl.h',
     'nsWidgetInitData.h',
     'nsWidgetsCID.h',
+    'PluginWidgetProxy.h',
     'PuppetWidget.h',
 ]
 
 EXPORTS.mozilla += [
     'BasicEvents.h',
     'CommandList.h',
     'ContentEvents.h',
     'EventClassList.h',
@@ -147,16 +148,17 @@ UNIFIED_SOURCES += [
     'nsPrimitiveHelpers.cpp',
     'nsPrintOptionsImpl.cpp',
     'nsPrintSession.cpp',
     'nsPrintSettingsImpl.cpp',
     'nsScreenManagerProxy.cpp',
     'nsShmImage.cpp',
     'nsTransferable.cpp',
     'nsXPLookAndFeel.cpp',
+    'PluginWidgetProxy.cpp',
     'PuppetWidget.cpp',
     'ScreenProxy.cpp',
     'SharedWidgetUtils.cpp',
     'VsyncDispatcher.cpp',
     'WidgetEventImpl.cpp',
     'WidgetUtils.cpp',
 ]
 
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -33,16 +33,19 @@ class   nsIContent;
 class   ViewWrapper;
 class   nsIWidgetListener;
 class   nsIntRegion;
 
 namespace mozilla {
 namespace dom {
 class TabChild;
 }
+namespace plugins {
+class PluginWidgetChild;
+}
 namespace layers {
 class Composer2D;
 class CompositorChild;
 class LayerManager;
 class LayerManagerComposite;
 class PLayerTransactionChild;
 }
 namespace gfx {
@@ -2034,16 +2037,26 @@ public:
      *
      * This function is called "Create" to match CreateInstance().
      * The returned widget must still be nsIWidget::Create()d.
      */
     static already_AddRefed<nsIWidget>
     CreatePuppetWidget(TabChild* aTabChild);
 
     /**
+     * Allocate and return a "plugin proxy widget", a subclass of PuppetWidget
+     * used in wrapping a PPluginWidget connection for remote widgets. Note
+     * this call creates the base object, it does not create the widget. Use
+     * nsIWidget's Create to do this.
+     */
+    static already_AddRefed<nsIWidget>
+    CreatePluginProxyWidget(TabChild* aTabChild,
+                            mozilla::plugins::PluginWidgetChild* aActor);
+
+    /**
      * Reparent this widget's native widget.
      * @param aNewParent the native widget of aNewParent is the new native
      *                   parent widget
      */
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) = 0;
 
     /**
      * Return the internal format of the default framebuffer for this