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 227619 ad862fdf75cd2be6681f713f051ea9150e4f76f5
parent 227618 bcaebd09531ca0c862f92d5e2ff80ffb22741419
child 227620 115f074c9b0d65c1de4b117c0ccdd76b63de4249
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-esr52@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs669200
milestone36.0a1
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