1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "PluginWidgetParent.h"
6 #include "mozilla/dom/TabParent.h"
7 #include "mozilla/dom/ContentParent.h"
8 #include "nsComponentManagerUtils.h"
9 #include "nsWidgetsCID.h"
10 
11 #include "mozilla/Unused.h"
12 #include "mozilla/DebugOnly.h"
13 #include "nsDebug.h"
14 
15 #if defined(MOZ_WIDGET_GTK)
16 #include "nsPluginNativeWindowGtk.h"
17 #endif
18 
19 using namespace mozilla;
20 using namespace mozilla::widget;
21 
22 #define PWLOG(...)
23 //#define PWLOG(...) printf_stderr(__VA_ARGS__)
24 
25 #if defined(XP_WIN)
26 namespace mozilla {
27 namespace dom {
28 // For nsWindow
29 const wchar_t* kPluginWidgetContentParentProperty =
30   L"kPluginWidgetParentProperty";
31 } }
32 #endif
33 
34 namespace mozilla {
35 namespace plugins {
36 
37 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
38 
39 // This macro returns true to prevent an abort in the child process when
40 // ipc message delivery fails.
41 #define ENSURE_CHANNEL {                                      \
42   if (!mWidget) {                                             \
43     NS_WARNING("called on an invalid remote widget.");        \
44     return true;                                              \
45   }                                                           \
46 }
47 
PluginWidgetParent()48 PluginWidgetParent::PluginWidgetParent()
49 {
50   PWLOG("PluginWidgetParent::PluginWidgetParent()\n");
51   MOZ_COUNT_CTOR(PluginWidgetParent);
52 }
53 
~PluginWidgetParent()54 PluginWidgetParent::~PluginWidgetParent()
55 {
56   PWLOG("PluginWidgetParent::~PluginWidgetParent()\n");
57   MOZ_COUNT_DTOR(PluginWidgetParent);
58   // A destroy call can actually get skipped if a widget is associated
59   // with the last out-of-process page, make sure and cleanup any left
60   // over widgets if we have them.
61   KillWidget();
62 }
63 
64 mozilla::dom::TabParent*
GetTabParent()65 PluginWidgetParent::GetTabParent()
66 {
67   return static_cast<mozilla::dom::TabParent*>(Manager());
68 }
69 
70 void
SetParent(nsIWidget * aParent)71 PluginWidgetParent::SetParent(nsIWidget* aParent)
72 {
73   // This will trigger sync send messages to the plugin process window
74   // procedure and a cascade of events to that window related to focus
75   // and activation.
76   if (mWidget && aParent) {
77     mWidget->SetParent(aParent);
78   }
79 }
80 
81 // When plugins run in chrome, nsPluginNativeWindow(Plat) implements platform
82 // specific functionality that wraps plugin widgets. With e10s we currently
83 // bypass this code on Window, and reuse a bit of it on Linux. Content still
84 // makes use of some of the utility functions as well.
85 
86 bool
RecvCreate(nsresult * aResult,uint64_t * aScrollCaptureId,uintptr_t * aPluginInstanceId)87 PluginWidgetParent::RecvCreate(nsresult* aResult, uint64_t* aScrollCaptureId,
88                                uintptr_t* aPluginInstanceId)
89 {
90   PWLOG("PluginWidgetParent::RecvCreate()\n");
91 
92   *aScrollCaptureId = 0;
93   *aPluginInstanceId = 0;
94 
95   mWidget = do_CreateInstance(kWidgetCID, aResult);
96   NS_ASSERTION(NS_SUCCEEDED(*aResult), "widget create failure");
97 
98 #if defined(MOZ_WIDGET_GTK)
99   // We need this currently just for GTK in setting up a socket widget
100   // we can send over to content -> plugin.
101   PLUG_NewPluginNativeWindow((nsPluginNativeWindow**)&mWrapper);
102   if (!mWrapper) {
103     KillWidget();
104     return false;
105   }
106   // Give a copy of this to the widget, which handles some update
107   // work for us.
108   mWidget->SetNativeData(NS_NATIVE_PLUGIN_OBJECT_PTR, (uintptr_t)mWrapper.get());
109 #endif
110 
111   // This returns the top level window widget
112   nsCOMPtr<nsIWidget> parentWidget = GetTabParent()->GetWidget();
113   // If this fails, bail.
114   if (!parentWidget) {
115     *aResult = NS_ERROR_NOT_AVAILABLE;
116     KillWidget();
117     return true;
118   }
119 
120   nsWidgetInitData initData;
121   initData.mWindowType = eWindowType_plugin_ipc_chrome;
122   initData.mUnicode = false;
123   initData.clipChildren = true;
124   initData.clipSiblings = true;
125   *aResult = mWidget->Create(parentWidget.get(), nullptr,
126                              LayoutDeviceIntRect(0, 0, 0, 0), &initData);
127   if (NS_FAILED(*aResult)) {
128     KillWidget();
129     // This should never fail, abort.
130     return false;
131   }
132 
133   mWidget->EnableDragDrop(true);
134 
135 #if defined(MOZ_WIDGET_GTK)
136   // For setup, initially GTK code expects 'window' to hold the parent.
137   mWrapper->window = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
138   DebugOnly<nsresult> drv = mWrapper->CreateXEmbedWindow(false);
139   NS_ASSERTION(NS_SUCCEEDED(drv), "widget call failure");
140   mWrapper->SetAllocation();
141   PWLOG("Plugin XID=%p\n", (void*)mWrapper->window);
142 #elif defined(XP_WIN)
143   DebugOnly<DWORD> winres =
144     ::SetPropW((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW),
145                mozilla::dom::kPluginWidgetContentParentProperty,
146                GetTabParent()->Manager()->AsContentParent());
147   NS_ASSERTION(winres, "SetPropW call failure");
148 
149   *aScrollCaptureId = mWidget->CreateScrollCaptureContainer();
150   *aPluginInstanceId =
151     reinterpret_cast<uintptr_t>(mWidget->GetNativeData(NS_NATIVE_PLUGIN_ID));
152 #endif
153 
154   // This is a special call we make to nsBaseWidget to register this
155   // window as a remote plugin window which is expected to receive
156   // visibility updates from the compositor, which ships this data
157   // over with corresponding layer updates.
158   mWidget->RegisterPluginWindowForRemoteUpdates();
159 
160   return true;
161 }
162 
163 void
KillWidget()164 PluginWidgetParent::KillWidget()
165 {
166   PWLOG("PluginWidgetParent::KillWidget() widget=%p\n", (void*)mWidget.get());
167   if (mWidget) {
168     mWidget->UnregisterPluginWindowForRemoteUpdates();
169     mWidget->Destroy();
170 #if defined(MOZ_WIDGET_GTK)
171     mWidget->SetNativeData(NS_NATIVE_PLUGIN_OBJECT_PTR, (uintptr_t)0);
172     mWrapper = nullptr;
173 #elif defined(XP_WIN)
174     ::RemovePropW((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW),
175                   mozilla::dom::kPluginWidgetContentParentProperty);
176 #endif
177     mWidget = nullptr;
178   }
179 }
180 
181 void
ActorDestroy(ActorDestroyReason aWhy)182 PluginWidgetParent::ActorDestroy(ActorDestroyReason aWhy)
183 {
184   PWLOG("PluginWidgetParent::ActorDestroy(%d)\n", aWhy);
185   KillWidget();
186 }
187 
188 // Called by TabParent's Destroy() in response to an early tear down (Early
189 // in that this is happening before layout in the child has had a chance
190 // to destroy the child widget.) when the tab is closing.
191 void
ParentDestroy()192 PluginWidgetParent::ParentDestroy()
193 {
194   PWLOG("PluginWidgetParent::ParentDestroy()\n");
195 }
196 
197 bool
RecvSetFocus(const bool & aRaise)198 PluginWidgetParent::RecvSetFocus(const bool& aRaise)
199 {
200   ENSURE_CHANNEL;
201   PWLOG("PluginWidgetParent::RecvSetFocus(%d)\n", aRaise);
202   mWidget->SetFocus(aRaise);
203   return true;
204 }
205 
206 bool
RecvGetNativePluginPort(uintptr_t * value)207 PluginWidgetParent::RecvGetNativePluginPort(uintptr_t* value)
208 {
209   ENSURE_CHANNEL;
210 #if defined(MOZ_WIDGET_GTK)
211   *value = (uintptr_t)mWrapper->window;
212   NS_ASSERTION(*value, "no xid??");
213 #else
214   *value = (uintptr_t)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
215   NS_ASSERTION(*value, "no native port??");
216 #endif
217   PWLOG("PluginWidgetParent::RecvGetNativeData() %p\n", (void*)*value);
218   return true;
219 }
220 
221 bool
RecvSetNativeChildWindow(const uintptr_t & aChildWindow)222 PluginWidgetParent::RecvSetNativeChildWindow(const uintptr_t& aChildWindow)
223 {
224 #if defined(XP_WIN)
225   ENSURE_CHANNEL;
226   PWLOG("PluginWidgetParent::RecvSetNativeChildWindow(%p)\n",
227         (void*)aChildWindow);
228   mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, aChildWindow);
229   return true;
230 #else
231   NS_NOTREACHED("PluginWidgetParent::RecvSetNativeChildWindow not implemented!");
232   return false;
233 #endif
234 }
235 
236 } // namespace plugins
237 } // namespace mozilla
238