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