/src/mozilla-central/dom/plugins/ipc/PluginInstanceChild.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: sw=4 ts=4 et : |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "PluginBackgroundDestroyer.h" |
8 | | #include "PluginInstanceChild.h" |
9 | | #include "PluginModuleChild.h" |
10 | | #include "BrowserStreamChild.h" |
11 | | #include "StreamNotifyChild.h" |
12 | | #include "PluginProcessChild.h" |
13 | | #include "gfxASurface.h" |
14 | | #include "gfxPlatform.h" |
15 | | #include "gfx2DGlue.h" |
16 | | #include "nsNPAPIPluginInstance.h" |
17 | | #include "mozilla/gfx/2D.h" |
18 | | #ifdef MOZ_X11 |
19 | | #include "gfxXlibSurface.h" |
20 | | #endif |
21 | | #ifdef XP_WIN |
22 | | #include "mozilla/D3DMessageUtils.h" |
23 | | #include "mozilla/gfx/SharedDIBSurface.h" |
24 | | #include "nsCrashOnException.h" |
25 | | #include "gfxWindowsPlatform.h" |
26 | | extern const wchar_t* kFlashFullscreenClass; |
27 | | using mozilla::gfx::SharedDIBSurface; |
28 | | #endif |
29 | | #include "gfxSharedImageSurface.h" |
30 | | #include "gfxUtils.h" |
31 | | #include "gfxAlphaRecovery.h" |
32 | | |
33 | | #include "mozilla/ArrayUtils.h" |
34 | | #include "mozilla/BasicEvents.h" |
35 | | #include "mozilla/ipc/MessageChannel.h" |
36 | | #include "mozilla/AutoRestore.h" |
37 | | #include "mozilla/StaticPtr.h" |
38 | | #include "mozilla/UniquePtr.h" |
39 | | #include "ImageContainer.h" |
40 | | |
41 | | using namespace mozilla; |
42 | | using mozilla::ipc::ProcessChild; |
43 | | using namespace mozilla::plugins; |
44 | | using namespace mozilla::layers; |
45 | | using namespace mozilla::gfx; |
46 | | using namespace mozilla::widget; |
47 | | using namespace std; |
48 | | |
49 | | #ifdef MOZ_WIDGET_GTK |
50 | | |
51 | | #include <gtk/gtk.h> |
52 | | #include <gdk/gdkx.h> |
53 | | #include <gdk/gdk.h> |
54 | | #include "gtk2xtbin.h" |
55 | | |
56 | | #elif defined(OS_WIN) |
57 | | |
58 | | #include <windows.h> |
59 | | #include <windowsx.h> |
60 | | |
61 | | #include "mozilla/widget/WinMessages.h" |
62 | | #include "mozilla/widget/WinModifierKeyState.h" |
63 | | #include "mozilla/widget/WinNativeEventData.h" |
64 | | #include "nsWindowsDllInterceptor.h" |
65 | | #include "X11UndefineNone.h" |
66 | | |
67 | | typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, |
68 | | UINT uFlags, |
69 | | int x, |
70 | | int y, |
71 | | int nReserved, |
72 | | HWND hWnd, |
73 | | CONST RECT *prcRect); |
74 | | static WindowsDllInterceptor sUser32Intercept; |
75 | | static HWND sWinlessPopupSurrogateHWND = nullptr; |
76 | | static WindowsDllInterceptor::FuncHookType<User32TrackPopupMenu> sUser32TrackPopupMenuStub; |
77 | | |
78 | | static WindowsDllInterceptor sImm32Intercept; |
79 | | static WindowsDllInterceptor::FuncHookType<decltype(&ImmGetContext)> sImm32ImmGetContextStub; |
80 | | static WindowsDllInterceptor::FuncHookType<decltype(&ImmGetCompositionStringW)> sImm32ImmGetCompositionStringStub; |
81 | | static WindowsDllInterceptor::FuncHookType<decltype(&ImmSetCandidateWindow)> sImm32ImmSetCandidateWindowStub; |
82 | | static WindowsDllInterceptor::FuncHookType<decltype(&ImmNotifyIME)> sImm32ImmNotifyIME; |
83 | | static WindowsDllInterceptor::FuncHookType<decltype(&ImmAssociateContextEx)> sImm32ImmAssociateContextExStub; |
84 | | |
85 | | static PluginInstanceChild* sCurrentPluginInstance = nullptr; |
86 | | static const HIMC sHookIMC = (const HIMC)0xefefefef; |
87 | | |
88 | | using mozilla::gfx::SharedDIB; |
89 | | |
90 | | // Flash WM_USER message delay time for PostDelayedTask. Borrowed |
91 | | // from Chromium's web plugin delegate src. See 'flash msg throttling |
92 | | // helpers' section for details. |
93 | | const int kFlashWMUSERMessageThrottleDelayMs = 5; |
94 | | |
95 | | static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassProperty"); |
96 | | |
97 | | #elif defined(XP_MACOSX) |
98 | | #include <ApplicationServices/ApplicationServices.h> |
99 | | #include "PluginUtilsOSX.h" |
100 | | #endif // defined(XP_MACOSX) |
101 | | |
102 | | /** |
103 | | * We can't use gfxPlatform::CreateDrawTargetForSurface() because calling |
104 | | * gfxPlatform::GetPlatform() instantiates the prefs service, and that's not |
105 | | * allowed from processes other than the main process. So we have our own |
106 | | * version here. |
107 | | */ |
108 | | static RefPtr<DrawTarget> |
109 | | CreateDrawTargetForSurface(gfxASurface *aSurface) |
110 | 0 | { |
111 | 0 | SurfaceFormat format = aSurface->GetSurfaceFormat(); |
112 | 0 | RefPtr<DrawTarget> drawTarget = |
113 | 0 | Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), |
114 | 0 | aSurface->GetSize(), |
115 | 0 | &format); |
116 | 0 | if (!drawTarget) { |
117 | 0 | MOZ_CRASH("CreateDrawTargetForSurface failed in plugin"); |
118 | 0 | } |
119 | 0 | return drawTarget; |
120 | 0 | } |
121 | | |
122 | | bool PluginInstanceChild::sIsIMEComposing = false; |
123 | | |
124 | | PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface, |
125 | | const nsCString& aMimeType, |
126 | | const InfallibleTArray<nsCString>& aNames, |
127 | | const InfallibleTArray<nsCString>& aValues) |
128 | | : mPluginIface(aPluginIface) |
129 | | , mMimeType(aMimeType) |
130 | | , mNames(aNames) |
131 | | , mValues(aValues) |
132 | | #if defined(XP_DARWIN) || defined (XP_WIN) |
133 | | , mContentsScaleFactor(1.0) |
134 | | #endif |
135 | | , mCSSZoomFactor(0.0) |
136 | | , mPostingKeyEvents(0) |
137 | | , mPostingKeyEventsOutdated(0) |
138 | | , mDrawingModel(kDefaultDrawingModel) |
139 | | , mCurrentDirectSurface(nullptr) |
140 | | , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex") |
141 | | , mAsyncInvalidateTask(0) |
142 | | , mCachedWindowActor(nullptr) |
143 | | , mCachedElementActor(nullptr) |
144 | | #if defined(OS_WIN) |
145 | | , mPluginWindowHWND(0) |
146 | | , mPluginWndProc(0) |
147 | | , mPluginParentHWND(0) |
148 | | , mCachedWinlessPluginHWND(0) |
149 | | , mWinlessPopupSurrogateHWND(0) |
150 | | , mWinlessThrottleOldWndProc(0) |
151 | | , mWinlessHiddenMsgHWND(0) |
152 | | #endif // OS_WIN |
153 | | #if defined(MOZ_WIDGET_COCOA) |
154 | | #if defined(__i386__) |
155 | | , mEventModel(NPEventModelCarbon) |
156 | | #endif |
157 | | , mShColorSpace(nullptr) |
158 | | , mShContext(nullptr) |
159 | | , mCGLayer(nullptr) |
160 | | , mCARefreshTimer(0) |
161 | | , mCurrentEvent(nullptr) |
162 | | #endif |
163 | | , mLayersRendering(false) |
164 | | #ifdef XP_WIN |
165 | | , mCurrentSurfaceActor(nullptr) |
166 | | , mBackSurfaceActor(nullptr) |
167 | | #endif |
168 | | , mAccumulatedInvalidRect(0,0,0,0) |
169 | | , mIsTransparent(false) |
170 | | , mSurfaceType(gfxSurfaceType::Max) |
171 | | , mPendingPluginCall(false) |
172 | | , mDoAlphaExtraction(false) |
173 | | , mHasPainted(false) |
174 | | , mSurfaceDifferenceRect(0,0,0,0) |
175 | | , mDestroyed(false) |
176 | | #ifdef XP_WIN |
177 | | , mLastKeyEventConsumed(false) |
178 | | , mLastEnableIMEState(true) |
179 | | #endif // #ifdef XP_WIN |
180 | | , mStackDepth(0) |
181 | 0 | { |
182 | 0 | memset(&mWindow, 0, sizeof(mWindow)); |
183 | 0 | mWindow.type = NPWindowTypeWindow; |
184 | 0 | mData.ndata = (void*) this; |
185 | 0 | mData.pdata = nullptr; |
186 | 0 | #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) |
187 | 0 | mWindow.ws_info = &mWsInfo; |
188 | 0 | memset(&mWsInfo, 0, sizeof(mWsInfo)); |
189 | 0 | #ifdef MOZ_WIDGET_GTK |
190 | 0 | mWsInfo.display = nullptr; |
191 | | #else |
192 | | mWsInfo.display = DefaultXDisplay(); |
193 | | #endif |
194 | | #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX |
195 | | #if defined(OS_WIN) |
196 | | InitPopupMenuHook(); |
197 | | InitImm32Hook(); |
198 | | #endif // OS_WIN |
199 | | } |
200 | | |
201 | | PluginInstanceChild::~PluginInstanceChild() |
202 | 0 | { |
203 | | #if defined(OS_WIN) |
204 | | NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?"); |
205 | | // In the event that we registered for audio device changes, stop. |
206 | | PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome(); |
207 | | if (chromeInstance) { |
208 | | chromeInstance->PluginRequiresAudioDeviceChanges(this, false); |
209 | | } |
210 | | #endif |
211 | | #if defined(MOZ_WIDGET_COCOA) |
212 | | if (mShColorSpace) { |
213 | | ::CGColorSpaceRelease(mShColorSpace); |
214 | | } |
215 | | if (mShContext) { |
216 | | ::CGContextRelease(mShContext); |
217 | | } |
218 | | if (mCGLayer) { |
219 | | PluginUtilsOSX::ReleaseCGLayer(mCGLayer); |
220 | | } |
221 | | if (mDrawingModel == NPDrawingModelCoreAnimation) { |
222 | | UnscheduleTimer(mCARefreshTimer); |
223 | | } |
224 | | #endif |
225 | | } |
226 | | |
227 | | NPError |
228 | | PluginInstanceChild::DoNPP_New() |
229 | 0 | { |
230 | 0 | // unpack the arguments into a C format |
231 | 0 | int argc = mNames.Length(); |
232 | 0 | NS_ASSERTION(argc == (int) mValues.Length(), |
233 | 0 | "argn.length != argv.length"); |
234 | 0 |
|
235 | 0 | UniquePtr<char*[]> argn(new char*[1 + argc]); |
236 | 0 | UniquePtr<char*[]> argv(new char*[1 + argc]); |
237 | 0 | argn[argc] = 0; |
238 | 0 | argv[argc] = 0; |
239 | 0 |
|
240 | 0 | for (int i = 0; i < argc; ++i) { |
241 | 0 | argn[i] = const_cast<char*>(NullableStringGet(mNames[i])); |
242 | 0 | argv[i] = const_cast<char*>(NullableStringGet(mValues[i])); |
243 | 0 | } |
244 | 0 |
|
245 | 0 | NPP npp = GetNPP(); |
246 | 0 |
|
247 | 0 | NPError rv = mPluginIface->newp((char*)NullableStringGet(mMimeType), npp, |
248 | 0 | NP_EMBED, argc, argn.get(), argv.get(), 0); |
249 | 0 | if (NPERR_NO_ERROR != rv) { |
250 | 0 | return rv; |
251 | 0 | } |
252 | 0 | |
253 | 0 | if (!Initialize()) { |
254 | 0 | rv = NPERR_MODULE_LOAD_FAILED_ERROR; |
255 | 0 | } |
256 | 0 | return rv; |
257 | 0 | } |
258 | | |
259 | | int |
260 | | PluginInstanceChild::GetQuirks() |
261 | 0 | { |
262 | 0 | return PluginModuleChild::GetChrome()->GetQuirks(); |
263 | 0 | } |
264 | | |
265 | | NPError |
266 | | PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue, |
267 | | NPObject** aObject) |
268 | 0 | { |
269 | 0 | PluginScriptableObjectChild* actor = nullptr; |
270 | 0 | NPError result = NPERR_NO_ERROR; |
271 | 0 |
|
272 | 0 | switch (aValue) { |
273 | 0 | case NPNVWindowNPObject: |
274 | 0 | if (!(actor = mCachedWindowActor)) { |
275 | 0 | PPluginScriptableObjectChild* actorProtocol; |
276 | 0 | CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result); |
277 | 0 | if (result == NPERR_NO_ERROR) { |
278 | 0 | actor = mCachedWindowActor = |
279 | 0 | static_cast<PluginScriptableObjectChild*>(actorProtocol); |
280 | 0 | NS_ASSERTION(actor, "Null actor!"); |
281 | 0 | PluginModuleChild::sBrowserFuncs.retainobject( |
282 | 0 | actor->GetObject(false)); |
283 | 0 | } |
284 | 0 | } |
285 | 0 | break; |
286 | 0 |
|
287 | 0 | case NPNVPluginElementNPObject: |
288 | 0 | if (!(actor = mCachedElementActor)) { |
289 | 0 | PPluginScriptableObjectChild* actorProtocol; |
290 | 0 | CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol, |
291 | 0 | &result); |
292 | 0 | if (result == NPERR_NO_ERROR) { |
293 | 0 | actor = mCachedElementActor = |
294 | 0 | static_cast<PluginScriptableObjectChild*>(actorProtocol); |
295 | 0 | NS_ASSERTION(actor, "Null actor!"); |
296 | 0 | PluginModuleChild::sBrowserFuncs.retainobject( |
297 | 0 | actor->GetObject(false)); |
298 | 0 | } |
299 | 0 | } |
300 | 0 | break; |
301 | 0 |
|
302 | 0 | default: |
303 | 0 | MOZ_ASSERT_UNREACHABLE("Don't know what to do with this value " |
304 | 0 | "type!"); |
305 | 0 | } |
306 | 0 |
|
307 | | #ifdef DEBUG |
308 | | { |
309 | | NPError currentResult; |
310 | | PPluginScriptableObjectChild* currentActor = nullptr; |
311 | | |
312 | | switch (aValue) { |
313 | | case NPNVWindowNPObject: |
314 | | CallNPN_GetValue_NPNVWindowNPObject(¤tActor, |
315 | | ¤tResult); |
316 | | break; |
317 | | case NPNVPluginElementNPObject: |
318 | | CallNPN_GetValue_NPNVPluginElementNPObject(¤tActor, |
319 | | ¤tResult); |
320 | | break; |
321 | | default: |
322 | | MOZ_ASSERT(false); |
323 | | } |
324 | | |
325 | | // Make sure that the current actor returned by the parent matches our |
326 | | // cached actor! |
327 | | NS_ASSERTION(!currentActor || |
328 | | static_cast<PluginScriptableObjectChild*>(currentActor) == |
329 | | actor, "Cached actor is out of date!"); |
330 | | } |
331 | | #endif |
332 | |
|
333 | 0 | if (result != NPERR_NO_ERROR) { |
334 | 0 | return result; |
335 | 0 | } |
336 | 0 | |
337 | 0 | NPObject* object = actor->GetObject(false); |
338 | 0 | NS_ASSERTION(object, "Null object?!"); |
339 | 0 |
|
340 | 0 | *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object); |
341 | 0 | return NPERR_NO_ERROR; |
342 | 0 |
|
343 | 0 | } |
344 | | |
345 | | NPError |
346 | | PluginInstanceChild::NPN_GetValue(NPNVariable aVar, |
347 | | void* aValue) |
348 | 0 | { |
349 | 0 | PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar)); |
350 | 0 | AssertPluginThread(); |
351 | 0 | AutoStackHelper guard(this); |
352 | 0 |
|
353 | 0 | switch(aVar) { |
354 | 0 |
|
355 | 0 | #if defined(MOZ_X11) |
356 | 0 | case NPNVToolkit: |
357 | 0 | *((NPNToolkitType*)aValue) = NPNVGtk2; |
358 | 0 | return NPERR_NO_ERROR; |
359 | 0 |
|
360 | 0 | case NPNVxDisplay: |
361 | 0 | if (!mWsInfo.display) { |
362 | 0 | // We are called before Initialize() so we have to call it now. |
363 | 0 | if (!Initialize()) { |
364 | 0 | return NPERR_GENERIC_ERROR; |
365 | 0 | } |
366 | 0 | NS_ASSERTION(mWsInfo.display, "We should have a valid display!"); |
367 | 0 | } |
368 | 0 | *(void **)aValue = mWsInfo.display; |
369 | 0 | return NPERR_NO_ERROR; |
370 | 0 |
|
371 | | #elif defined(OS_WIN) |
372 | | case NPNVToolkit: |
373 | | return NPERR_GENERIC_ERROR; |
374 | | #endif |
375 | 0 | case NPNVprivateModeBool: { |
376 | 0 | bool v = false; |
377 | 0 | NPError result; |
378 | 0 | if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) { |
379 | 0 | return NPERR_GENERIC_ERROR; |
380 | 0 | } |
381 | 0 | *static_cast<NPBool*>(aValue) = v; |
382 | 0 | return result; |
383 | 0 | } |
384 | 0 |
|
385 | 0 | case NPNVdocumentOrigin: { |
386 | 0 | nsCString v; |
387 | 0 | NPError result; |
388 | 0 | if (!CallNPN_GetValue_NPNVdocumentOrigin(&v, &result)) { |
389 | 0 | return NPERR_GENERIC_ERROR; |
390 | 0 | } |
391 | 0 | if (result == NPERR_NO_ERROR || |
392 | 0 | (GetQuirks() & |
393 | 0 | QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN)) { |
394 | 0 | *static_cast<char**>(aValue) = ToNewCString(v); |
395 | 0 | } |
396 | 0 | return result; |
397 | 0 | } |
398 | 0 |
|
399 | 0 | case NPNVWindowNPObject: // Intentional fall-through |
400 | 0 | case NPNVPluginElementNPObject: { |
401 | 0 | NPObject* object; |
402 | 0 | NPError result = InternalGetNPObjectForValue(aVar, &object); |
403 | 0 | if (result == NPERR_NO_ERROR) { |
404 | 0 | *((NPObject**)aValue) = object; |
405 | 0 | } |
406 | 0 | return result; |
407 | 0 | } |
408 | 0 |
|
409 | 0 | case NPNVnetscapeWindow: { |
410 | | #ifdef XP_WIN |
411 | | if (mWindow.type == NPWindowTypeDrawable) { |
412 | | if (mCachedWinlessPluginHWND) { |
413 | | *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND; |
414 | | return NPERR_NO_ERROR; |
415 | | } |
416 | | NPError result; |
417 | | if (!CallNPN_GetValue_NPNVnetscapeWindow(&mCachedWinlessPluginHWND, &result)) { |
418 | | return NPERR_GENERIC_ERROR; |
419 | | } |
420 | | *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND; |
421 | | return result; |
422 | | } |
423 | | else { |
424 | | *static_cast<HWND*>(aValue) = mPluginWindowHWND; |
425 | | return NPERR_NO_ERROR; |
426 | | } |
427 | | #elif defined(MOZ_X11) |
428 | | NPError result; |
429 | 0 | CallNPN_GetValue_NPNVnetscapeWindow(static_cast<XID*>(aValue), &result); |
430 | 0 | return result; |
431 | | #else |
432 | | return NPERR_GENERIC_ERROR; |
433 | | #endif |
434 | | } |
435 | 0 |
|
436 | 0 | case NPNVsupportsAsyncBitmapSurfaceBool: { |
437 | 0 | bool value = false; |
438 | 0 | CallNPN_GetValue_SupportsAsyncBitmapSurface(&value); |
439 | 0 | *((NPBool*)aValue) = value; |
440 | 0 | return NPERR_NO_ERROR; |
441 | 0 | } |
442 | 0 |
|
443 | | #ifdef XP_WIN |
444 | | case NPNVsupportsAsyncWindowsDXGISurfaceBool: { |
445 | | bool value = false; |
446 | | CallNPN_GetValue_SupportsAsyncDXGISurface(&value); |
447 | | *((NPBool*)aValue) = value; |
448 | | return NPERR_NO_ERROR; |
449 | | } |
450 | | #endif |
451 | |
|
452 | | #ifdef XP_WIN |
453 | | case NPNVpreferredDXGIAdapter: { |
454 | | DxgiAdapterDesc desc; |
455 | | if (!CallNPN_GetValue_PreferredDXGIAdapter(&desc)) { |
456 | | return NPERR_GENERIC_ERROR; |
457 | | } |
458 | | *reinterpret_cast<DXGI_ADAPTER_DESC*>(aValue) = desc.ToDesc(); |
459 | | return NPERR_NO_ERROR; |
460 | | } |
461 | | #endif |
462 | |
|
463 | | #ifdef XP_MACOSX |
464 | | case NPNVsupportsCoreGraphicsBool: { |
465 | | *((NPBool*)aValue) = true; |
466 | | return NPERR_NO_ERROR; |
467 | | } |
468 | | |
469 | | case NPNVsupportsCoreAnimationBool: { |
470 | | *((NPBool*)aValue) = true; |
471 | | return NPERR_NO_ERROR; |
472 | | } |
473 | | |
474 | | case NPNVsupportsInvalidatingCoreAnimationBool: { |
475 | | *((NPBool*)aValue) = true; |
476 | | return NPERR_NO_ERROR; |
477 | | } |
478 | | |
479 | | case NPNVsupportsCompositingCoreAnimationPluginsBool: { |
480 | | *((NPBool*)aValue) = true; |
481 | | return NPERR_NO_ERROR; |
482 | | } |
483 | | |
484 | | case NPNVsupportsCocoaBool: { |
485 | | *((NPBool*)aValue) = true; |
486 | | return NPERR_NO_ERROR; |
487 | | } |
488 | | |
489 | | #ifndef NP_NO_CARBON |
490 | | case NPNVsupportsCarbonBool: { |
491 | | *((NPBool*)aValue) = false; |
492 | | return NPERR_NO_ERROR; |
493 | | } |
494 | | #endif |
495 | | |
496 | | case NPNVsupportsUpdatedCocoaTextInputBool: { |
497 | | *static_cast<NPBool*>(aValue) = true; |
498 | | return NPERR_NO_ERROR; |
499 | | } |
500 | | |
501 | | #ifndef NP_NO_QUICKDRAW |
502 | | case NPNVsupportsQuickDrawBool: { |
503 | | *((NPBool*)aValue) = false; |
504 | | return NPERR_NO_ERROR; |
505 | | } |
506 | | #endif /* NP_NO_QUICKDRAW */ |
507 | | #endif /* XP_MACOSX */ |
508 | |
|
509 | | #if defined(XP_MACOSX) || defined(XP_WIN) |
510 | | case NPNVcontentsScaleFactor: { |
511 | | *static_cast<double*>(aValue) = mContentsScaleFactor; |
512 | | return NPERR_NO_ERROR; |
513 | | } |
514 | | #endif /* defined(XP_MACOSX) || defined(XP_WIN) */ |
515 | |
|
516 | 0 | case NPNVCSSZoomFactor: { |
517 | 0 | *static_cast<double*>(aValue) = mCSSZoomFactor; |
518 | 0 | return NPERR_NO_ERROR; |
519 | 0 | } |
520 | 0 |
|
521 | | #ifdef DEBUG |
522 | | case NPNVjavascriptEnabledBool: |
523 | | case NPNVasdEnabledBool: |
524 | | case NPNVisOfflineBool: |
525 | | case NPNVSupportsXEmbedBool: |
526 | | case NPNVSupportsWindowless: |
527 | | MOZ_FALLTHROUGH_ASSERT("NPNVariable should be handled in " |
528 | | "PluginModuleChild."); |
529 | | #endif |
530 | |
|
531 | 0 | default: |
532 | 0 | MOZ_LOG(GetPluginLog(), LogLevel::Warning, |
533 | 0 | ("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)", |
534 | 0 | (int) aVar, NPNVariableToString(aVar))); |
535 | 0 | return NPERR_GENERIC_ERROR; |
536 | 0 | } |
537 | 0 | } |
538 | | |
539 | | #ifdef MOZ_WIDGET_COCOA |
540 | | #define DEFAULT_REFRESH_MS 20 // CoreAnimation: 50 FPS |
541 | | |
542 | | void |
543 | | CAUpdate(NPP npp, uint32_t timerID) { |
544 | | static_cast<PluginInstanceChild*>(npp->ndata)->Invalidate(); |
545 | | } |
546 | | |
547 | | void |
548 | | PluginInstanceChild::Invalidate() |
549 | | { |
550 | | NPRect windowRect = {0, 0, uint16_t(mWindow.height), |
551 | | uint16_t(mWindow.width)}; |
552 | | |
553 | | InvalidateRect(&windowRect); |
554 | | } |
555 | | #endif |
556 | | |
557 | | NPError |
558 | | PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue) |
559 | 0 | { |
560 | 0 | MOZ_LOG(GetPluginLog(), LogLevel::Debug, ("%s (aVar=%i, aValue=%p)", |
561 | 0 | FULLFUNCTION, (int) aVar, aValue)); |
562 | 0 |
|
563 | 0 | AssertPluginThread(); |
564 | 0 |
|
565 | 0 | AutoStackHelper guard(this); |
566 | 0 |
|
567 | 0 | switch (aVar) { |
568 | 0 | case NPPVpluginWindowBool: { |
569 | 0 | NPError rv; |
570 | 0 | bool windowed = (NPBool) (intptr_t) aValue; |
571 | 0 |
|
572 | 0 | if (windowed) { |
573 | 0 | return NPERR_GENERIC_ERROR; |
574 | 0 | } |
575 | 0 |
|
576 | 0 | if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv)) |
577 | 0 | return NPERR_GENERIC_ERROR; |
578 | 0 | |
579 | 0 | mWindow.type = NPWindowTypeDrawable; |
580 | 0 | return rv; |
581 | 0 | } |
582 | 0 |
|
583 | 0 | case NPPVpluginTransparentBool: { |
584 | 0 | NPError rv; |
585 | 0 | mIsTransparent = (!!aValue); |
586 | 0 |
|
587 | 0 | if (!CallNPN_SetValue_NPPVpluginTransparent(mIsTransparent, &rv)) |
588 | 0 | return NPERR_GENERIC_ERROR; |
589 | 0 | |
590 | 0 | return rv; |
591 | 0 | } |
592 | 0 |
|
593 | 0 | case NPPVpluginUsesDOMForCursorBool: { |
594 | 0 | NPError rv = NPERR_GENERIC_ERROR; |
595 | 0 | if (!CallNPN_SetValue_NPPVpluginUsesDOMForCursor((NPBool)(intptr_t)aValue, &rv)) { |
596 | 0 | return NPERR_GENERIC_ERROR; |
597 | 0 | } |
598 | 0 | return rv; |
599 | 0 | } |
600 | 0 |
|
601 | 0 | case NPPVpluginDrawingModel: { |
602 | 0 | NPError rv; |
603 | 0 | int drawingModel = (int16_t) (intptr_t) aValue; |
604 | 0 |
|
605 | 0 | if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &rv)) |
606 | 0 | return NPERR_GENERIC_ERROR; |
607 | 0 | |
608 | 0 | mDrawingModel = drawingModel; |
609 | 0 |
|
610 | | #ifdef XP_MACOSX |
611 | | if (drawingModel == NPDrawingModelCoreAnimation) { |
612 | | mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate); |
613 | | } |
614 | | #endif |
615 | |
|
616 | 0 | PLUGIN_LOG_DEBUG((" Plugin requested drawing model id #%i\n", |
617 | 0 | mDrawingModel)); |
618 | 0 |
|
619 | 0 | return rv; |
620 | 0 | } |
621 | 0 |
|
622 | | #ifdef XP_MACOSX |
623 | | case NPPVpluginEventModel: { |
624 | | NPError rv; |
625 | | int eventModel = (int16_t) (intptr_t) aValue; |
626 | | |
627 | | if (!CallNPN_SetValue_NPPVpluginEventModel(eventModel, &rv)) |
628 | | return NPERR_GENERIC_ERROR; |
629 | | #if defined(__i386__) |
630 | | mEventModel = static_cast<NPEventModel>(eventModel); |
631 | | #endif |
632 | | |
633 | | PLUGIN_LOG_DEBUG((" Plugin requested event model id # %i\n", |
634 | | eventModel)); |
635 | | |
636 | | return rv; |
637 | | } |
638 | | #endif |
639 | |
|
640 | 0 | case NPPVpluginIsPlayingAudio: { |
641 | 0 | NPError rv = NPERR_GENERIC_ERROR; |
642 | 0 | if (!CallNPN_SetValue_NPPVpluginIsPlayingAudio((NPBool)(intptr_t)aValue, &rv)) { |
643 | 0 | return NPERR_GENERIC_ERROR; |
644 | 0 | } |
645 | 0 | return rv; |
646 | 0 | } |
647 | 0 |
|
648 | | #ifdef XP_WIN |
649 | | case NPPVpluginRequiresAudioDeviceChanges: { |
650 | | // Many other NPN_SetValue variables are forwarded to our |
651 | | // PluginInstanceParent, which runs on a content process. We |
652 | | // instead forward this message to the PluginModuleParent, which runs |
653 | | // on the chrome process. This is because our audio |
654 | | // API calls should run the chrome proc, not content. |
655 | | NPError rv = NPERR_GENERIC_ERROR; |
656 | | PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome(); |
657 | | if (chromeInstance) { |
658 | | rv = chromeInstance->PluginRequiresAudioDeviceChanges(this, |
659 | | (NPBool)(intptr_t)aValue); |
660 | | } |
661 | | return rv; |
662 | | } |
663 | | #endif |
664 | |
|
665 | 0 | default: |
666 | 0 | MOZ_LOG(GetPluginLog(), LogLevel::Warning, |
667 | 0 | ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)", |
668 | 0 | (int) aVar, NPPVariableToString(aVar))); |
669 | 0 | return NPERR_GENERIC_ERROR; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | mozilla::ipc::IPCResult |
674 | | PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams( |
675 | | bool* wantsAllStreams, NPError* rv) |
676 | 0 | { |
677 | 0 | AssertPluginThread(); |
678 | 0 | AutoStackHelper guard(this); |
679 | 0 |
|
680 | 0 | uint32_t value = 0; |
681 | 0 | if (!mPluginIface->getvalue) { |
682 | 0 | *rv = NPERR_GENERIC_ERROR; |
683 | 0 | } |
684 | 0 | else { |
685 | 0 | *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginWantsAllNetworkStreams, |
686 | 0 | &value); |
687 | 0 | } |
688 | 0 | *wantsAllStreams = value; |
689 | 0 | return IPC_OK(); |
690 | 0 | } |
691 | | |
692 | | mozilla::ipc::IPCResult |
693 | | PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject( |
694 | | PPluginScriptableObjectChild** aValue, |
695 | | NPError* aResult) |
696 | 0 | { |
697 | 0 | AssertPluginThread(); |
698 | 0 | AutoStackHelper guard(this); |
699 | 0 |
|
700 | 0 | NPObject* object = nullptr; |
701 | 0 | NPError result = NPERR_GENERIC_ERROR; |
702 | 0 | if (mPluginIface->getvalue) { |
703 | 0 | result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject, |
704 | 0 | &object); |
705 | 0 | } |
706 | 0 | if (result == NPERR_NO_ERROR && object) { |
707 | 0 | PluginScriptableObjectChild* actor = GetActorForNPObject(object); |
708 | 0 |
|
709 | 0 | // If we get an actor then it has retained. Otherwise we don't need it |
710 | 0 | // any longer. |
711 | 0 | PluginModuleChild::sBrowserFuncs.releaseobject(object); |
712 | 0 | if (actor) { |
713 | 0 | *aValue = actor; |
714 | 0 | *aResult = NPERR_NO_ERROR; |
715 | 0 | return IPC_OK(); |
716 | 0 | } |
717 | 0 |
|
718 | 0 | NS_ERROR("Failed to get actor!"); |
719 | 0 | result = NPERR_GENERIC_ERROR; |
720 | 0 | } |
721 | 0 | else { |
722 | 0 | result = NPERR_GENERIC_ERROR; |
723 | 0 | } |
724 | 0 |
|
725 | 0 | *aValue = nullptr; |
726 | 0 | *aResult = result; |
727 | 0 | return IPC_OK(); |
728 | 0 | } |
729 | | |
730 | | mozilla::ipc::IPCResult |
731 | | PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId( |
732 | | nsCString* aPlugId, |
733 | | NPError* aResult) |
734 | 0 | { |
735 | 0 | AssertPluginThread(); |
736 | 0 | AutoStackHelper guard(this); |
737 | 0 |
|
738 | 0 | #if MOZ_ACCESSIBILITY_ATK |
739 | 0 |
|
740 | 0 | char* plugId = nullptr; |
741 | 0 | NPError result = NPERR_GENERIC_ERROR; |
742 | 0 | if (mPluginIface->getvalue) { |
743 | 0 | result = mPluginIface->getvalue(GetNPP(), |
744 | 0 | NPPVpluginNativeAccessibleAtkPlugId, |
745 | 0 | &plugId); |
746 | 0 | } |
747 | 0 |
|
748 | 0 | *aPlugId = nsCString(plugId); |
749 | 0 | *aResult = result; |
750 | 0 | return IPC_OK(); |
751 | 0 |
|
752 | | #else |
753 | | |
754 | | MOZ_CRASH("shouldn't be called on non-ATK platforms"); |
755 | | |
756 | | #endif |
757 | | } |
758 | | |
759 | | mozilla::ipc::IPCResult |
760 | | PluginInstanceChild::AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value, |
761 | | NPError* result) |
762 | 0 | { |
763 | 0 | if (!mPluginIface->setvalue) { |
764 | 0 | *result = NPERR_GENERIC_ERROR; |
765 | 0 | return IPC_OK(); |
766 | 0 | } |
767 | 0 |
|
768 | 0 | NPBool v = value; |
769 | 0 | *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v); |
770 | 0 | return IPC_OK(); |
771 | 0 | } |
772 | | |
773 | | mozilla::ipc::IPCResult |
774 | | PluginInstanceChild::AnswerNPP_SetValue_NPNVCSSZoomFactor(const double& value, |
775 | | NPError* result) |
776 | 0 | { |
777 | 0 | if (!mPluginIface->setvalue) { |
778 | 0 | *result = NPERR_GENERIC_ERROR; |
779 | 0 | return IPC_OK(); |
780 | 0 | } |
781 | 0 |
|
782 | 0 | mCSSZoomFactor = value; |
783 | 0 | double v = value; |
784 | 0 | *result = mPluginIface->setvalue(GetNPP(), NPNVCSSZoomFactor, &v); |
785 | 0 | return IPC_OK(); |
786 | 0 | } |
787 | | |
788 | | mozilla::ipc::IPCResult |
789 | | PluginInstanceChild::AnswerNPP_SetValue_NPNVmuteAudioBool(const bool& value, |
790 | | NPError* result) |
791 | 0 | { |
792 | 0 | if (!mPluginIface->setvalue) { |
793 | 0 | *result = NPERR_GENERIC_ERROR; |
794 | 0 | return IPC_OK(); |
795 | 0 | } |
796 | 0 |
|
797 | 0 | NPBool v = value; |
798 | 0 | *result = mPluginIface->setvalue(GetNPP(), NPNVmuteAudioBool, &v); |
799 | 0 | return IPC_OK(); |
800 | 0 | } |
801 | | |
802 | | #if defined(XP_WIN) |
803 | | NPError |
804 | | PluginInstanceChild::DefaultAudioDeviceChanged(NPAudioDeviceChangeDetails& details) |
805 | | { |
806 | | if (!mPluginIface->setvalue) { |
807 | | return NPERR_GENERIC_ERROR; |
808 | | } |
809 | | return mPluginIface->setvalue(GetNPP(), NPNVaudioDeviceChangeDetails, (void*)&details); |
810 | | } |
811 | | |
812 | | NPError |
813 | | PluginInstanceChild::AudioDeviceStateChanged(NPAudioDeviceStateChanged& aDeviceState) |
814 | | { |
815 | | if (!mPluginIface->setvalue) { |
816 | | return NPERR_GENERIC_ERROR; |
817 | | } |
818 | | return mPluginIface->setvalue(GetNPP(), NPNVaudioDeviceStateChanged, (void*)&aDeviceState); |
819 | | } |
820 | | #endif |
821 | | |
822 | | mozilla::ipc::IPCResult |
823 | | PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event, |
824 | | int16_t* handled) |
825 | 0 | { |
826 | 0 | PLUGIN_LOG_DEBUG_FUNCTION; |
827 | 0 | AssertPluginThread(); |
828 | 0 | AutoStackHelper guard(this); |
829 | 0 |
|
830 | | #if defined(MOZ_X11) && defined(DEBUG) |
831 | | if (GraphicsExpose == event.event.type) |
832 | | PLUGIN_LOG_DEBUG((" received drawable 0x%lx\n", |
833 | | event.event.xgraphicsexpose.drawable)); |
834 | | #endif |
835 | |
|
836 | | #ifdef XP_MACOSX |
837 | | // Mac OS X does not define an NPEvent structure. It defines more specific types. |
838 | | NPCocoaEvent evcopy = event.event; |
839 | | |
840 | | // Make sure we reset mCurrentEvent in case of an exception |
841 | | AutoRestore<const NPCocoaEvent*> savePreviousEvent(mCurrentEvent); |
842 | | |
843 | | // Track the current event for NPN_PopUpContextMenu. |
844 | | mCurrentEvent = &event.event; |
845 | | #else |
846 | | // Make a copy since we may modify values. |
847 | 0 | NPEvent evcopy = event.event; |
848 | 0 | #endif |
849 | 0 |
|
850 | | #if defined(XP_MACOSX) || defined(XP_WIN) |
851 | | // event.contentsScaleFactor <= 0 is a signal we shouldn't use it, |
852 | | // for example when AnswerNPP_HandleEvent() is called from elsewhere |
853 | | // in the child process (not via rpc code from the parent process). |
854 | | if (event.contentsScaleFactor > 0) { |
855 | | mContentsScaleFactor = event.contentsScaleFactor; |
856 | | } |
857 | | #endif |
858 | |
|
859 | | #ifdef OS_WIN |
860 | | // FIXME/bug 567645: temporarily drop the "dummy event" on the floor |
861 | | if (WM_NULL == evcopy.event) |
862 | | return IPC_OK(); |
863 | | |
864 | | *handled = WinlessHandleEvent(evcopy); |
865 | | return IPC_OK(); |
866 | | #endif |
867 | |
|
868 | 0 | // XXX A previous call to mPluginIface->event might block, e.g. right click |
869 | 0 | // for context menu. Still, we might get here again, calling into the plugin |
870 | 0 | // a second time while it's in the previous call. |
871 | 0 | if (!mPluginIface->event) |
872 | 0 | *handled = false; |
873 | 0 | else |
874 | 0 | *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy)); |
875 | 0 |
|
876 | | #ifdef XP_MACOSX |
877 | | // Release any reference counted objects created in the child process. |
878 | | if (evcopy.type == NPCocoaEventKeyDown || |
879 | | evcopy.type == NPCocoaEventKeyUp) { |
880 | | ::CFRelease((CFStringRef)evcopy.data.key.characters); |
881 | | ::CFRelease((CFStringRef)evcopy.data.key.charactersIgnoringModifiers); |
882 | | } |
883 | | else if (evcopy.type == NPCocoaEventTextInput) { |
884 | | ::CFRelease((CFStringRef)evcopy.data.text.text); |
885 | | } |
886 | | #endif |
887 | |
|
888 | 0 | #ifdef MOZ_X11 |
889 | 0 | if (GraphicsExpose == event.event.type) { |
890 | 0 | // Make sure the X server completes the drawing before the parent |
891 | 0 | // draws on top and destroys the Drawable. |
892 | 0 | // |
893 | 0 | // XSync() waits for the X server to complete. Really this child |
894 | 0 | // process does not need to wait; the parent is the process that needs |
895 | 0 | // to wait. A possibly-slightly-better alternative would be to send |
896 | 0 | // an X event to the parent that the parent would wait for. |
897 | 0 | XSync(mWsInfo.display, False); |
898 | 0 | } |
899 | 0 | #endif |
900 | 0 |
|
901 | 0 | return IPC_OK(); |
902 | 0 | } |
903 | | |
904 | | #ifdef XP_MACOSX |
905 | | |
906 | | mozilla::ipc::IPCResult |
907 | | PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event, |
908 | | Shmem&& mem, |
909 | | int16_t* handled, |
910 | | Shmem* rtnmem) |
911 | | { |
912 | | PLUGIN_LOG_DEBUG_FUNCTION; |
913 | | AssertPluginThread(); |
914 | | AutoStackHelper guard(this); |
915 | | |
916 | | PaintTracker pt; |
917 | | |
918 | | NPCocoaEvent evcopy = event.event; |
919 | | mContentsScaleFactor = event.contentsScaleFactor; |
920 | | |
921 | | if (evcopy.type == NPCocoaEventDrawRect) { |
922 | | int scaleFactor = ceil(mContentsScaleFactor); |
923 | | if (!mShColorSpace) { |
924 | | mShColorSpace = CreateSystemColorSpace(); |
925 | | if (!mShColorSpace) { |
926 | | PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace.")); |
927 | | *handled = false; |
928 | | *rtnmem = mem; |
929 | | return IPC_OK(); |
930 | | } |
931 | | } |
932 | | if (!mShContext) { |
933 | | void* cgContextByte = mem.get<char>(); |
934 | | mShContext = ::CGBitmapContextCreate(cgContextByte, |
935 | | mWindow.width * scaleFactor, |
936 | | mWindow.height * scaleFactor, 8, |
937 | | mWindow.width * 4 * scaleFactor, mShColorSpace, |
938 | | kCGImageAlphaPremultipliedFirst | |
939 | | kCGBitmapByteOrder32Host); |
940 | | |
941 | | if (!mShContext) { |
942 | | PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext.")); |
943 | | *handled = false; |
944 | | *rtnmem = mem; |
945 | | return IPC_OK(); |
946 | | } |
947 | | } |
948 | | CGRect clearRect = ::CGRectMake(0, 0, mWindow.width, mWindow.height); |
949 | | ::CGContextClearRect(mShContext, clearRect); |
950 | | evcopy.data.draw.context = mShContext; |
951 | | } else { |
952 | | PLUGIN_LOG_DEBUG(("Invalid event type for AnswerNNP_HandleEvent_Shmem.")); |
953 | | *handled = false; |
954 | | *rtnmem = mem; |
955 | | return IPC_OK(); |
956 | | } |
957 | | |
958 | | if (!mPluginIface->event) { |
959 | | *handled = false; |
960 | | } else { |
961 | | ::CGContextSaveGState(evcopy.data.draw.context); |
962 | | *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy)); |
963 | | ::CGContextRestoreGState(evcopy.data.draw.context); |
964 | | } |
965 | | |
966 | | *rtnmem = mem; |
967 | | return IPC_OK(); |
968 | | } |
969 | | |
970 | | #else |
971 | | mozilla::ipc::IPCResult |
972 | | PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event, |
973 | | Shmem&& mem, |
974 | | int16_t* handled, |
975 | | Shmem* rtnmem) |
976 | 0 | { |
977 | 0 | MOZ_CRASH("not reached."); |
978 | 0 | *rtnmem = mem; |
979 | 0 | return IPC_OK(); |
980 | 0 | } |
981 | | #endif |
982 | | |
983 | | #ifdef XP_MACOSX |
984 | | |
985 | | void CallCGDraw(CGContextRef ref, void* aPluginInstance, nsIntRect aUpdateRect) { |
986 | | PluginInstanceChild* pluginInstance = (PluginInstanceChild*)aPluginInstance; |
987 | | |
988 | | pluginInstance->CGDraw(ref, aUpdateRect); |
989 | | } |
990 | | |
991 | | bool |
992 | | PluginInstanceChild::CGDraw(CGContextRef ref, nsIntRect aUpdateRect) { |
993 | | |
994 | | NPCocoaEvent drawEvent; |
995 | | drawEvent.type = NPCocoaEventDrawRect; |
996 | | drawEvent.version = 0; |
997 | | drawEvent.data.draw.x = aUpdateRect.x; |
998 | | drawEvent.data.draw.y = aUpdateRect.y; |
999 | | drawEvent.data.draw.width = aUpdateRect.width; |
1000 | | drawEvent.data.draw.height = aUpdateRect.height; |
1001 | | drawEvent.data.draw.context = ref; |
1002 | | |
1003 | | NPRemoteEvent remoteDrawEvent = {drawEvent}; |
1004 | | // Signal to AnswerNPP_HandleEvent() not to use this value |
1005 | | remoteDrawEvent.contentsScaleFactor = -1.0; |
1006 | | |
1007 | | int16_t handled; |
1008 | | AnswerNPP_HandleEvent(remoteDrawEvent, &handled); |
1009 | | return handled == true; |
1010 | | } |
1011 | | |
1012 | | mozilla::ipc::IPCResult |
1013 | | PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, |
1014 | | const uint32_t &surfaceid, |
1015 | | int16_t* handled) |
1016 | | { |
1017 | | PLUGIN_LOG_DEBUG_FUNCTION; |
1018 | | AssertPluginThread(); |
1019 | | AutoStackHelper guard(this); |
1020 | | |
1021 | | PaintTracker pt; |
1022 | | |
1023 | | NPCocoaEvent evcopy = event.event; |
1024 | | mContentsScaleFactor = event.contentsScaleFactor; |
1025 | | RefPtr<MacIOSurface> surf = MacIOSurface::LookupSurface(surfaceid, |
1026 | | mContentsScaleFactor); |
1027 | | if (!surf) { |
1028 | | NS_ERROR("Invalid IOSurface."); |
1029 | | *handled = false; |
1030 | | return IPC_FAIL_NO_REASON(this); |
1031 | | } |
1032 | | |
1033 | | if (!mCARenderer) { |
1034 | | mCARenderer = new nsCARenderer(); |
1035 | | } |
1036 | | |
1037 | | if (evcopy.type == NPCocoaEventDrawRect) { |
1038 | | mCARenderer->AttachIOSurface(surf); |
1039 | | if (!mCARenderer->isInit()) { |
1040 | | void *caLayer = nullptr; |
1041 | | NPError result = mPluginIface->getvalue(GetNPP(), |
1042 | | NPPVpluginCoreAnimationLayer, |
1043 | | &caLayer); |
1044 | | |
1045 | | if (result != NPERR_NO_ERROR || !caLayer) { |
1046 | | PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not " |
1047 | | "provide CALayer.")); |
1048 | | *handled = false; |
1049 | | return IPC_FAIL_NO_REASON(this); |
1050 | | } |
1051 | | |
1052 | | mCARenderer->SetupRenderer(caLayer, mWindow.width, mWindow.height, |
1053 | | mContentsScaleFactor, |
1054 | | GetQuirks() & QUIRK_ALLOW_OFFLINE_RENDERER ? |
1055 | | ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER); |
1056 | | |
1057 | | // Flash needs to have the window set again after this step |
1058 | | if (mPluginIface->setwindow) |
1059 | | (void) mPluginIface->setwindow(&mData, &mWindow); |
1060 | | } |
1061 | | } else { |
1062 | | PLUGIN_LOG_DEBUG(("Invalid event type for " |
1063 | | "AnswerNNP_HandleEvent_IOSurface.")); |
1064 | | *handled = false; |
1065 | | return IPC_FAIL_NO_REASON(this); |
1066 | | } |
1067 | | |
1068 | | mCARenderer->Render(mWindow.width, mWindow.height, |
1069 | | mContentsScaleFactor, nullptr); |
1070 | | |
1071 | | return IPC_OK(); |
1072 | | |
1073 | | } |
1074 | | |
1075 | | #else |
1076 | | mozilla::ipc::IPCResult |
1077 | | PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, |
1078 | | const uint32_t &surfaceid, |
1079 | | int16_t* handled) |
1080 | 0 | { |
1081 | 0 | MOZ_CRASH("NPP_HandleEvent_IOSurface is a OSX-only message"); |
1082 | 0 | } |
1083 | | #endif |
1084 | | |
1085 | | mozilla::ipc::IPCResult |
1086 | | PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event) |
1087 | 0 | { |
1088 | 0 | NS_ASSERTION(!mLayersRendering && !mPendingPluginCall, |
1089 | 0 | "Shouldn't be receiving WindowPosChanged with layer rendering"); |
1090 | 0 |
|
1091 | | #ifdef OS_WIN |
1092 | | int16_t dontcare; |
1093 | | return AnswerNPP_HandleEvent(event, &dontcare); |
1094 | | #else |
1095 | 0 | MOZ_CRASH("WindowPosChanged is a windows-only message"); |
1096 | 0 | #endif |
1097 | 0 | } |
1098 | | |
1099 | | mozilla::ipc::IPCResult |
1100 | | PluginInstanceChild::RecvContentsScaleFactorChanged(const double& aContentsScaleFactor) |
1101 | 0 | { |
1102 | | #if defined(XP_MACOSX) || defined(XP_WIN) |
1103 | | mContentsScaleFactor = aContentsScaleFactor; |
1104 | | #if defined(XP_MACOSX) |
1105 | | if (mShContext) { |
1106 | | // Release the shared context so that it is reallocated |
1107 | | // with the new size. |
1108 | | ::CGContextRelease(mShContext); |
1109 | | mShContext = nullptr; |
1110 | | } |
1111 | | #endif |
1112 | | return IPC_OK(); |
1113 | | #else |
1114 | 0 | MOZ_CRASH("ContentsScaleFactorChanged is an Windows or OSX only message"); |
1115 | 0 | #endif |
1116 | 0 | } |
1117 | | |
1118 | | mozilla::ipc::IPCResult |
1119 | | PluginInstanceChild::AnswerCreateChildPluginWindow(NativeWindowHandle* aChildPluginWindow) |
1120 | 0 | { |
1121 | | #if defined(XP_WIN) |
1122 | | MOZ_ASSERT(!mPluginWindowHWND); |
1123 | | |
1124 | | if (!CreatePluginWindow()) { |
1125 | | return IPC_FAIL_NO_REASON(this); |
1126 | | } |
1127 | | |
1128 | | MOZ_ASSERT(mPluginWindowHWND); |
1129 | | |
1130 | | *aChildPluginWindow = mPluginWindowHWND; |
1131 | | return IPC_OK(); |
1132 | | #else |
1133 | 0 | MOZ_ASSERT_UNREACHABLE("CreateChildPluginWindow not implemented!"); |
1134 | 0 | return IPC_FAIL_NO_REASON(this); |
1135 | 0 | #endif |
1136 | 0 | } |
1137 | | |
1138 | | mozilla::ipc::IPCResult |
1139 | | PluginInstanceChild::RecvCreateChildPopupSurrogate(const NativeWindowHandle& aNetscapeWindow) |
1140 | 0 | { |
1141 | | #if defined(XP_WIN) |
1142 | | mCachedWinlessPluginHWND = aNetscapeWindow; |
1143 | | CreateWinlessPopupSurrogate(); |
1144 | | return IPC_OK(); |
1145 | | #else |
1146 | 0 | MOZ_ASSERT_UNREACHABLE("CreateChildPluginWindow not implemented!"); |
1147 | 0 | return IPC_FAIL_NO_REASON(this); |
1148 | 0 | #endif |
1149 | 0 | } |
1150 | | |
1151 | | mozilla::ipc::IPCResult |
1152 | | PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow) |
1153 | 0 | { |
1154 | 0 | PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%" PRIx64 ", x: %d, y: %d, width: %d, height: %d>)", |
1155 | 0 | FULLFUNCTION, |
1156 | 0 | aWindow.window, |
1157 | 0 | aWindow.x, aWindow.y, |
1158 | 0 | aWindow.width, aWindow.height)); |
1159 | 0 | NS_ASSERTION(!mLayersRendering && !mPendingPluginCall, |
1160 | 0 | "Shouldn't be receiving NPP_SetWindow with layer rendering"); |
1161 | 0 | AssertPluginThread(); |
1162 | 0 | AutoStackHelper guard(this); |
1163 | 0 |
|
1164 | 0 | #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) |
1165 | 0 | NS_ASSERTION(mWsInfo.display, "We should have a valid display!"); |
1166 | 0 |
|
1167 | 0 | // The minimum info is sent over IPC to allow this |
1168 | 0 | // code to determine the rest. |
1169 | 0 |
|
1170 | 0 | mWindow.x = aWindow.x; |
1171 | 0 | mWindow.y = aWindow.y; |
1172 | 0 | mWindow.width = aWindow.width; |
1173 | 0 | mWindow.height = aWindow.height; |
1174 | 0 | mWindow.clipRect = aWindow.clipRect; |
1175 | 0 | mWindow.type = aWindow.type; |
1176 | 0 |
|
1177 | 0 | mWsInfo.colormap = aWindow.colormap; |
1178 | 0 | int depth; |
1179 | 0 | FindVisualAndDepth(mWsInfo.display, aWindow.visualID, |
1180 | 0 | &mWsInfo.visual, &depth); |
1181 | 0 | mWsInfo.depth = depth; |
1182 | 0 |
|
1183 | 0 | PLUGIN_LOG_DEBUG( |
1184 | 0 | ("[InstanceChild][%p] Answer_SetWindow w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>", |
1185 | 0 | this, mWindow.x, mWindow.y, mWindow.width, mWindow.height, |
1186 | 0 | mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom)); |
1187 | 0 |
|
1188 | 0 | if (mPluginIface->setwindow) |
1189 | 0 | (void) mPluginIface->setwindow(&mData, &mWindow); |
1190 | 0 |
|
1191 | | #elif defined(OS_WIN) |
1192 | | switch (aWindow.type) { |
1193 | | case NPWindowTypeWindow: |
1194 | | { |
1195 | | MOZ_ASSERT(mPluginWindowHWND, |
1196 | | "Child plugin window must exist before call to SetWindow"); |
1197 | | |
1198 | | HWND parentHWND = reinterpret_cast<HWND>(aWindow.window); |
1199 | | if (mPluginWindowHWND != parentHWND) { |
1200 | | mPluginParentHWND = parentHWND; |
1201 | | ShowWindow(mPluginWindowHWND, SW_SHOWNA); |
1202 | | } |
1203 | | |
1204 | | SizePluginWindow(aWindow.width, aWindow.height); |
1205 | | |
1206 | | mWindow.window = (void*)mPluginWindowHWND; |
1207 | | mWindow.x = aWindow.x; |
1208 | | mWindow.y = aWindow.y; |
1209 | | mWindow.width = aWindow.width; |
1210 | | mWindow.height = aWindow.height; |
1211 | | mWindow.type = aWindow.type; |
1212 | | mContentsScaleFactor = aWindow.contentsScaleFactor; |
1213 | | |
1214 | | if (mPluginIface->setwindow) { |
1215 | | SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1); |
1216 | | (void) mPluginIface->setwindow(&mData, &mWindow); |
1217 | | WNDPROC wndProc = reinterpret_cast<WNDPROC>( |
1218 | | GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC)); |
1219 | | if (wndProc != PluginWindowProc) { |
1220 | | mPluginWndProc = reinterpret_cast<WNDPROC>( |
1221 | | SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC, |
1222 | | reinterpret_cast<LONG_PTR>(PluginWindowProc))); |
1223 | | NS_ASSERTION(mPluginWndProc != PluginWindowProc, "WTF?"); |
1224 | | } |
1225 | | RemoveProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty); |
1226 | | HookSetWindowLongPtr(); |
1227 | | } |
1228 | | } |
1229 | | break; |
1230 | | |
1231 | | default: |
1232 | | MOZ_ASSERT_UNREACHABLE("Bad plugin window type."); |
1233 | | return IPC_FAIL_NO_REASON(this); |
1234 | | break; |
1235 | | } |
1236 | | |
1237 | | #elif defined(XP_MACOSX) |
1238 | | |
1239 | | mWindow.x = aWindow.x; |
1240 | | mWindow.y = aWindow.y; |
1241 | | mWindow.width = aWindow.width; |
1242 | | mWindow.height = aWindow.height; |
1243 | | mWindow.clipRect = aWindow.clipRect; |
1244 | | mWindow.type = aWindow.type; |
1245 | | mContentsScaleFactor = aWindow.contentsScaleFactor; |
1246 | | |
1247 | | if (mShContext) { |
1248 | | // Release the shared context so that it is reallocated |
1249 | | // with the new size. |
1250 | | ::CGContextRelease(mShContext); |
1251 | | mShContext = nullptr; |
1252 | | } |
1253 | | |
1254 | | if (mPluginIface->setwindow) |
1255 | | (void) mPluginIface->setwindow(&mData, &mWindow); |
1256 | | |
1257 | | #elif defined(ANDROID) |
1258 | | // TODO: Need Android impl |
1259 | | #elif defined(MOZ_WIDGET_UIKIT) |
1260 | | // Don't care |
1261 | | #else |
1262 | | # error Implement me for your OS |
1263 | | #endif |
1264 | |
|
1265 | 0 | return IPC_OK(); |
1266 | 0 | } |
1267 | | |
1268 | | bool |
1269 | | PluginInstanceChild::Initialize() |
1270 | 0 | { |
1271 | 0 | #ifdef MOZ_WIDGET_GTK |
1272 | 0 | if (mWsInfo.display) { |
1273 | 0 | // Already initialized |
1274 | 0 | return true; |
1275 | 0 | } |
1276 | 0 | |
1277 | 0 | // Request for windowless plugins is set in newp(), before this call. |
1278 | 0 | if (mWindow.type == NPWindowTypeWindow) { |
1279 | 0 | return false; |
1280 | 0 | } |
1281 | 0 | |
1282 | 0 | mWsInfo.display = DefaultXDisplay(); |
1283 | 0 | #endif |
1284 | 0 |
|
1285 | | #if defined(XP_MACOSX) && defined(__i386__) |
1286 | | // If an i386 Mac OS X plugin has selected the Carbon event model then |
1287 | | // we have to fail. We do not support putting Carbon event model plugins |
1288 | | // out of process. Note that Carbon is the default model so out of process |
1289 | | // plugins need to actively negotiate something else in order to work |
1290 | | // out of process. |
1291 | | if (EventModel() == NPEventModelCarbon) { |
1292 | | return false; |
1293 | | } |
1294 | | #endif |
1295 | |
|
1296 | 0 | return true; |
1297 | 0 | } |
1298 | | |
1299 | | mozilla::ipc::IPCResult |
1300 | | PluginInstanceChild::RecvHandledWindowedPluginKeyEvent( |
1301 | | const NativeEventData& aKeyEventData, |
1302 | | const bool& aIsConsumed) |
1303 | 0 | { |
1304 | | #if defined(OS_WIN) |
1305 | | const WinNativeKeyEventData* eventData = |
1306 | | static_cast<const WinNativeKeyEventData*>(aKeyEventData); |
1307 | | switch (eventData->mMessage) { |
1308 | | case WM_KEYDOWN: |
1309 | | case WM_SYSKEYDOWN: |
1310 | | case WM_KEYUP: |
1311 | | case WM_SYSKEYUP: |
1312 | | mLastKeyEventConsumed = aIsConsumed; |
1313 | | break; |
1314 | | case WM_CHAR: |
1315 | | case WM_SYSCHAR: |
1316 | | case WM_DEADCHAR: |
1317 | | case WM_SYSDEADCHAR: |
1318 | | // If preceding keydown or keyup event is consumed by the chrome |
1319 | | // process, we should consume WM_*CHAR messages too. |
1320 | | if (mLastKeyEventConsumed) { |
1321 | | return IPC_OK(); |
1322 | | } |
1323 | | default: |
1324 | | MOZ_CRASH("Needs to handle all messages posted to the parent"); |
1325 | | } |
1326 | | #endif // #if defined(OS_WIN) |
1327 | |
|
1328 | 0 | // Unknown key input shouldn't be sent to plugin for security. |
1329 | 0 | // XXX Is this possible if a plugin process which posted the message |
1330 | 0 | // already crashed and this plugin process is recreated? |
1331 | 0 | if (NS_WARN_IF(!mPostingKeyEvents && !mPostingKeyEventsOutdated)) { |
1332 | 0 | return IPC_OK(); |
1333 | 0 | } |
1334 | 0 |
|
1335 | 0 | // If there is outdated posting key events, we should consume the key |
1336 | 0 | // events. |
1337 | 0 | if (mPostingKeyEventsOutdated) { |
1338 | 0 | mPostingKeyEventsOutdated--; |
1339 | 0 | return IPC_OK(); |
1340 | 0 | } |
1341 | 0 |
|
1342 | 0 | mPostingKeyEvents--; |
1343 | 0 |
|
1344 | 0 | // If composition has been started after posting the key event, |
1345 | 0 | // we should discard the event since if we send the event to plugin, |
1346 | 0 | // the plugin may be confused and the result may be broken because |
1347 | 0 | // the event order is shuffled. |
1348 | 0 | if (aIsConsumed || sIsIMEComposing) { |
1349 | 0 | return IPC_OK(); |
1350 | 0 | } |
1351 | 0 |
|
1352 | | #if defined(OS_WIN) |
1353 | | UINT message = 0; |
1354 | | switch (eventData->mMessage) { |
1355 | | case WM_KEYDOWN: |
1356 | | message = MOZ_WM_KEYDOWN; |
1357 | | break; |
1358 | | case WM_SYSKEYDOWN: |
1359 | | message = MOZ_WM_SYSKEYDOWN; |
1360 | | break; |
1361 | | case WM_KEYUP: |
1362 | | message = MOZ_WM_KEYUP; |
1363 | | break; |
1364 | | case WM_SYSKEYUP: |
1365 | | message = MOZ_WM_SYSKEYUP; |
1366 | | break; |
1367 | | case WM_CHAR: |
1368 | | message = MOZ_WM_CHAR; |
1369 | | break; |
1370 | | case WM_SYSCHAR: |
1371 | | message = MOZ_WM_SYSCHAR; |
1372 | | break; |
1373 | | case WM_DEADCHAR: |
1374 | | message = MOZ_WM_DEADCHAR; |
1375 | | break; |
1376 | | case WM_SYSDEADCHAR: |
1377 | | message = MOZ_WM_SYSDEADCHAR; |
1378 | | break; |
1379 | | default: |
1380 | | MOZ_CRASH("Needs to handle all messages posted to the parent"); |
1381 | | } |
1382 | | PluginWindowProcInternal(mPluginWindowHWND, message, |
1383 | | eventData->mWParam, eventData->mLParam); |
1384 | | #endif |
1385 | 0 | return IPC_OK(); |
1386 | 0 | } |
1387 | | |
1388 | | #if defined(OS_WIN) |
1389 | | |
1390 | | static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow"); |
1391 | | static const TCHAR kPluginInstanceChildProperty[] = TEXT("PluginInstanceChildProperty"); |
1392 | | static const TCHAR kFlashThrottleProperty[] = TEXT("MozillaFlashThrottleProperty"); |
1393 | | |
1394 | | // static |
1395 | | bool |
1396 | | PluginInstanceChild::RegisterWindowClass() |
1397 | | { |
1398 | | static bool alreadyRegistered = false; |
1399 | | if (alreadyRegistered) |
1400 | | return true; |
1401 | | |
1402 | | alreadyRegistered = true; |
1403 | | |
1404 | | WNDCLASSEX wcex; |
1405 | | wcex.cbSize = sizeof(WNDCLASSEX); |
1406 | | wcex.style = CS_DBLCLKS; |
1407 | | wcex.lpfnWndProc = DummyWindowProc; |
1408 | | wcex.cbClsExtra = 0; |
1409 | | wcex.cbWndExtra = 0; |
1410 | | wcex.hInstance = GetModuleHandle(nullptr); |
1411 | | wcex.hIcon = 0; |
1412 | | wcex.hCursor = 0; |
1413 | | wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1); |
1414 | | wcex.lpszMenuName = 0; |
1415 | | wcex.lpszClassName = kWindowClassName; |
1416 | | wcex.hIconSm = 0; |
1417 | | |
1418 | | return RegisterClassEx(&wcex) ? true : false; |
1419 | | } |
1420 | | |
1421 | | bool |
1422 | | PluginInstanceChild::CreatePluginWindow() |
1423 | | { |
1424 | | // already initialized |
1425 | | if (mPluginWindowHWND) |
1426 | | return true; |
1427 | | |
1428 | | if (!RegisterWindowClass()) |
1429 | | return false; |
1430 | | |
1431 | | mPluginWindowHWND = |
1432 | | CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING | |
1433 | | WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this! |
1434 | | WS_EX_RIGHTSCROLLBAR, |
1435 | | kWindowClassName, 0, |
1436 | | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, |
1437 | | 0, 0, nullptr, 0, GetModuleHandle(nullptr), 0); |
1438 | | if (!mPluginWindowHWND) |
1439 | | return false; |
1440 | | if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this)) |
1441 | | return false; |
1442 | | |
1443 | | // Apparently some plugins require an ASCII WndProc. |
1444 | | SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC, |
1445 | | reinterpret_cast<LONG_PTR>(DefWindowProcA)); |
1446 | | |
1447 | | return true; |
1448 | | } |
1449 | | |
1450 | | void |
1451 | | PluginInstanceChild::DestroyPluginWindow() |
1452 | | { |
1453 | | if (mPluginWindowHWND) { |
1454 | | // Unsubclass the window. |
1455 | | WNDPROC wndProc = reinterpret_cast<WNDPROC>( |
1456 | | GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC)); |
1457 | | // Removed prior to SetWindowLongPtr, see HookSetWindowLongPtr. |
1458 | | RemoveProp(mPluginWindowHWND, kPluginInstanceChildProperty); |
1459 | | if (wndProc == PluginWindowProc) { |
1460 | | NS_ASSERTION(mPluginWndProc, "Should have old proc here!"); |
1461 | | SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC, |
1462 | | reinterpret_cast<LONG_PTR>(mPluginWndProc)); |
1463 | | mPluginWndProc = 0; |
1464 | | } |
1465 | | DestroyWindow(mPluginWindowHWND); |
1466 | | mPluginWindowHWND = 0; |
1467 | | } |
1468 | | } |
1469 | | |
1470 | | void |
1471 | | PluginInstanceChild::SizePluginWindow(int width, |
1472 | | int height) |
1473 | | { |
1474 | | if (mPluginWindowHWND) { |
1475 | | mPluginSize.x = width; |
1476 | | mPluginSize.y = height; |
1477 | | SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height, |
1478 | | SWP_NOZORDER | SWP_NOREPOSITION); |
1479 | | } |
1480 | | } |
1481 | | |
1482 | | // See chromium's webplugin_delegate_impl.cc for explanation of this function. |
1483 | | // static |
1484 | | LRESULT CALLBACK |
1485 | | PluginInstanceChild::DummyWindowProc(HWND hWnd, |
1486 | | UINT message, |
1487 | | WPARAM wParam, |
1488 | | LPARAM lParam) |
1489 | | { |
1490 | | return CallWindowProc(DefWindowProc, hWnd, message, wParam, lParam); |
1491 | | } |
1492 | | |
1493 | | // static |
1494 | | LRESULT CALLBACK |
1495 | | PluginInstanceChild::PluginWindowProc(HWND hWnd, |
1496 | | UINT message, |
1497 | | WPARAM wParam, |
1498 | | LPARAM lParam) |
1499 | | { |
1500 | | return mozilla::CallWindowProcCrashProtected(PluginWindowProcInternal, hWnd, message, wParam, lParam); |
1501 | | } |
1502 | | |
1503 | | // static |
1504 | | LRESULT CALLBACK |
1505 | | PluginInstanceChild::PluginWindowProcInternal(HWND hWnd, |
1506 | | UINT message, |
1507 | | WPARAM wParam, |
1508 | | LPARAM lParam) |
1509 | | { |
1510 | | NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(), |
1511 | | "Failed to prevent a nonqueued message from running!"); |
1512 | | PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>( |
1513 | | GetProp(hWnd, kPluginInstanceChildProperty)); |
1514 | | if (!self) { |
1515 | | MOZ_ASSERT_UNREACHABLE("Badness!"); |
1516 | | return 0; |
1517 | | } |
1518 | | |
1519 | | NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!"); |
1520 | | NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Self-referential windowproc. Infinite recursion will happen soon."); |
1521 | | |
1522 | | bool isIMECompositionMessage = false; |
1523 | | switch (message) { |
1524 | | // Adobe's shockwave positions the plugin window relative to the browser |
1525 | | // frame when it initializes. With oopp disabled, this wouldn't have an |
1526 | | // effect. With oopp, GeckoPluginWindow is a child of the parent plugin |
1527 | | // window, so the move offsets the child within the parent. Generally |
1528 | | // we don't want plugins moving or sizing our window, so we prevent |
1529 | | // these changes here. |
1530 | | case WM_WINDOWPOSCHANGING: { |
1531 | | WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lParam); |
1532 | | if (pos && |
1533 | | (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE))) { |
1534 | | pos->x = pos->y = 0; |
1535 | | pos->cx = self->mPluginSize.x; |
1536 | | pos->cy = self->mPluginSize.y; |
1537 | | LRESULT res = CallWindowProc(self->mPluginWndProc, |
1538 | | hWnd, message, wParam, lParam); |
1539 | | pos->x = pos->y = 0; |
1540 | | pos->cx = self->mPluginSize.x; |
1541 | | pos->cy = self->mPluginSize.y; |
1542 | | return res; |
1543 | | } |
1544 | | break; |
1545 | | } |
1546 | | |
1547 | | case WM_SETFOCUS: |
1548 | | // If this gets focus, ensure that there is no pending key events. |
1549 | | // Even if there were, we should ignore them for performance reason. |
1550 | | // Although, such case shouldn't occur. |
1551 | | NS_WARNING_ASSERTION(self->mPostingKeyEvents == 0, |
1552 | | "pending events"); |
1553 | | self->mPostingKeyEvents = 0; |
1554 | | self->mLastKeyEventConsumed = false; |
1555 | | break; |
1556 | | |
1557 | | case WM_KEYDOWN: |
1558 | | case WM_SYSKEYDOWN: |
1559 | | case WM_KEYUP: |
1560 | | case WM_SYSKEYUP: |
1561 | | if (self->MaybePostKeyMessage(message, wParam, lParam)) { |
1562 | | // If PreHandleKeyMessage() posts the message to the parent |
1563 | | // process, we need to wait RecvOnKeyEventHandledBeforePlugin() |
1564 | | // to be called. |
1565 | | return 0; // Consume current message temporarily. |
1566 | | } |
1567 | | break; |
1568 | | |
1569 | | case MOZ_WM_KEYDOWN: |
1570 | | message = WM_KEYDOWN; |
1571 | | break; |
1572 | | case MOZ_WM_SYSKEYDOWN: |
1573 | | message = WM_SYSKEYDOWN; |
1574 | | break; |
1575 | | case MOZ_WM_KEYUP: |
1576 | | message = WM_KEYUP; |
1577 | | break; |
1578 | | case MOZ_WM_SYSKEYUP: |
1579 | | message = WM_SYSKEYUP; |
1580 | | break; |
1581 | | case MOZ_WM_CHAR: |
1582 | | message = WM_CHAR; |
1583 | | break; |
1584 | | case MOZ_WM_SYSCHAR: |
1585 | | message = WM_SYSCHAR; |
1586 | | break; |
1587 | | case MOZ_WM_DEADCHAR: |
1588 | | message = WM_DEADCHAR; |
1589 | | break; |
1590 | | case MOZ_WM_SYSDEADCHAR: |
1591 | | message = WM_SYSDEADCHAR; |
1592 | | break; |
1593 | | |
1594 | | case WM_IME_STARTCOMPOSITION: |
1595 | | isIMECompositionMessage = true; |
1596 | | sIsIMEComposing = true; |
1597 | | break; |
1598 | | case WM_IME_ENDCOMPOSITION: |
1599 | | isIMECompositionMessage = true; |
1600 | | sIsIMEComposing = false; |
1601 | | break; |
1602 | | case WM_IME_COMPOSITION: |
1603 | | isIMECompositionMessage = true; |
1604 | | // XXX Some old IME may not send WM_IME_COMPOSITION_START or |
1605 | | // WM_IME_COMPSOITION_END properly. So, we need to check |
1606 | | // WM_IME_COMPSOITION and if it includes commit string. |
1607 | | sIsIMEComposing = !(lParam & GCS_RESULTSTR); |
1608 | | break; |
1609 | | |
1610 | | // The plugin received keyboard focus, let the parent know so the dom |
1611 | | // is up to date. |
1612 | | case WM_MOUSEACTIVATE: |
1613 | | self->CallPluginFocusChange(true); |
1614 | | break; |
1615 | | } |
1616 | | |
1617 | | // When a composition is committed, there may be pending key |
1618 | | // events which were posted to the parent process before starting |
1619 | | // the composition. Then, we shouldn't handle it since they are |
1620 | | // now outdated. |
1621 | | if (isIMECompositionMessage && !sIsIMEComposing) { |
1622 | | self->mPostingKeyEventsOutdated += self->mPostingKeyEvents; |
1623 | | self->mPostingKeyEvents = 0; |
1624 | | } |
1625 | | |
1626 | | // Prevent lockups due to plugins making rpc calls when the parent |
1627 | | // is making a synchronous SendMessage call to the child window. Add |
1628 | | // more messages as needed. |
1629 | | if ((InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { |
1630 | | switch(message) { |
1631 | | case WM_CHILDACTIVATE: |
1632 | | case WM_KILLFOCUS: |
1633 | | ReplyMessage(0); |
1634 | | break; |
1635 | | } |
1636 | | } |
1637 | | |
1638 | | if (message == WM_KILLFOCUS) { |
1639 | | self->CallPluginFocusChange(false); |
1640 | | } |
1641 | | |
1642 | | if (message == WM_USER+1 && |
1643 | | (self->GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) { |
1644 | | self->FlashThrottleMessage(hWnd, message, wParam, lParam, true); |
1645 | | return 0; |
1646 | | } |
1647 | | |
1648 | | NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, |
1649 | | "Self-referential windowproc happened inside our hook proc. " |
1650 | | "Infinite recursion will happen soon."); |
1651 | | |
1652 | | LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam, |
1653 | | lParam); |
1654 | | |
1655 | | // Make sure capture is released by the child on mouse events. Fixes a |
1656 | | // problem with flash full screen mode mouse input. Appears to be |
1657 | | // caused by a bug in flash, since we are not setting the capture |
1658 | | // on the window. |
1659 | | if (message == WM_LBUTTONDOWN && |
1660 | | self->GetQuirks() & QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) { |
1661 | | wchar_t szClass[26]; |
1662 | | HWND hwnd = GetForegroundWindow(); |
1663 | | if (hwnd && GetClassNameW(hwnd, szClass, |
1664 | | sizeof(szClass)/sizeof(char16_t)) && |
1665 | | !wcscmp(szClass, kFlashFullscreenClass)) { |
1666 | | ReleaseCapture(); |
1667 | | SetFocus(hwnd); |
1668 | | } |
1669 | | } |
1670 | | |
1671 | | if (message == WM_CLOSE) { |
1672 | | self->DestroyPluginWindow(); |
1673 | | } |
1674 | | |
1675 | | if (message == WM_NCDESTROY) { |
1676 | | RemoveProp(hWnd, kPluginInstanceChildProperty); |
1677 | | } |
1678 | | |
1679 | | return res; |
1680 | | } |
1681 | | |
1682 | | bool |
1683 | | PluginInstanceChild::ShouldPostKeyMessage(UINT message, |
1684 | | WPARAM wParam, |
1685 | | LPARAM lParam) |
1686 | | { |
1687 | | // If there is a composition, we shouldn't post the key message to the |
1688 | | // parent process because we cannot handle IME messages asynchronously. |
1689 | | // Therefore, if we posted key events to the parent process, the event |
1690 | | // order of the posted key events and IME events are shuffled. |
1691 | | if (sIsIMEComposing) { |
1692 | | return false; |
1693 | | } |
1694 | | |
1695 | | // If there are some pending keyboard events which are not handled in |
1696 | | // the parent process, we should post the message for avoiding to shuffle |
1697 | | // the key event order. |
1698 | | if (mPostingKeyEvents) { |
1699 | | return true; |
1700 | | } |
1701 | | |
1702 | | // If we are not waiting calls of RecvOnKeyEventHandledBeforePlugin(), |
1703 | | // we don't need to post WM_*CHAR messages. |
1704 | | switch (message) { |
1705 | | case WM_CHAR: |
1706 | | case WM_SYSCHAR: |
1707 | | case WM_DEADCHAR: |
1708 | | case WM_SYSDEADCHAR: |
1709 | | return false; |
1710 | | } |
1711 | | |
1712 | | // Otherwise, we should post key message which might match with a |
1713 | | // shortcut key. |
1714 | | ModifierKeyState modifierState; |
1715 | | if (!modifierState.MaybeMatchShortcutKey()) { |
1716 | | // For better UX, we shouldn't use IPC when user tries to |
1717 | | // input character(s). |
1718 | | return false; |
1719 | | } |
1720 | | |
1721 | | // Ignore modifier key events and keys already handled by IME. |
1722 | | switch (wParam) { |
1723 | | case VK_SHIFT: |
1724 | | case VK_CONTROL: |
1725 | | case VK_MENU: |
1726 | | case VK_LWIN: |
1727 | | case VK_RWIN: |
1728 | | case VK_CAPITAL: |
1729 | | case VK_NUMLOCK: |
1730 | | case VK_SCROLL: |
1731 | | // Following virtual keycodes shouldn't come with WM_(SYS)KEY* message |
1732 | | // but check it for avoiding unnecessary cross process communication. |
1733 | | case VK_LSHIFT: |
1734 | | case VK_RSHIFT: |
1735 | | case VK_LCONTROL: |
1736 | | case VK_RCONTROL: |
1737 | | case VK_LMENU: |
1738 | | case VK_RMENU: |
1739 | | case VK_PROCESSKEY: |
1740 | | case VK_PACKET: |
1741 | | case 0xFF: // 0xFF could be sent with unidentified key by the layout. |
1742 | | return false; |
1743 | | default: |
1744 | | break; |
1745 | | } |
1746 | | return true; |
1747 | | } |
1748 | | |
1749 | | bool |
1750 | | PluginInstanceChild::MaybePostKeyMessage(UINT message, |
1751 | | WPARAM wParam, |
1752 | | LPARAM lParam) |
1753 | | { |
1754 | | if (!ShouldPostKeyMessage(message, wParam, lParam)) { |
1755 | | return false; |
1756 | | } |
1757 | | |
1758 | | ModifierKeyState modifierState; |
1759 | | WinNativeKeyEventData winNativeKeyData(message, wParam, lParam, |
1760 | | modifierState); |
1761 | | NativeEventData nativeKeyData; |
1762 | | nativeKeyData.Copy(winNativeKeyData); |
1763 | | if (NS_WARN_IF(!SendOnWindowedPluginKeyEvent(nativeKeyData))) { |
1764 | | return false; |
1765 | | } |
1766 | | |
1767 | | mPostingKeyEvents++; |
1768 | | return true; |
1769 | | } |
1770 | | |
1771 | | /* set window long ptr hook for flash */ |
1772 | | |
1773 | | /* |
1774 | | * Flash will reset the subclass of our widget at various times. |
1775 | | * (Notably when entering and exiting full screen mode.) This |
1776 | | * occurs independent of the main plugin window event procedure. |
1777 | | * We trap these subclass calls to prevent our subclass hook from |
1778 | | * getting dropped. |
1779 | | * Note, ascii versions can be nixed once flash versions < 10.1 |
1780 | | * are considered obsolete. |
1781 | | */ |
1782 | | |
1783 | | #ifdef _WIN64 |
1784 | | typedef LONG_PTR |
1785 | | (WINAPI *User32SetWindowLongPtrA)(HWND hWnd, |
1786 | | int nIndex, |
1787 | | LONG_PTR dwNewLong); |
1788 | | typedef LONG_PTR |
1789 | | (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, |
1790 | | int nIndex, |
1791 | | LONG_PTR dwNewLong); |
1792 | | static WindowsDllInterceptor::FuncHookType<User32SetWindowLongPtrA> sUser32SetWindowLongAHookStub; |
1793 | | static WindowsDllInterceptor::FuncHookType<User32SetWindowLongPtrW> sUser32SetWindowLongWHookStub; |
1794 | | #else |
1795 | | typedef LONG |
1796 | | (WINAPI *User32SetWindowLongA)(HWND hWnd, |
1797 | | int nIndex, |
1798 | | LONG dwNewLong); |
1799 | | typedef LONG |
1800 | | (WINAPI *User32SetWindowLongW)(HWND hWnd, |
1801 | | int nIndex, |
1802 | | LONG dwNewLong); |
1803 | | static WindowsDllInterceptor::FuncHookType<User32SetWindowLongA> sUser32SetWindowLongAHookStub; |
1804 | | static WindowsDllInterceptor::FuncHookType<User32SetWindowLongW> sUser32SetWindowLongWHookStub; |
1805 | | #endif |
1806 | | |
1807 | | extern LRESULT CALLBACK |
1808 | | NeuteredWindowProc(HWND hwnd, |
1809 | | UINT uMsg, |
1810 | | WPARAM wParam, |
1811 | | LPARAM lParam); |
1812 | | |
1813 | | const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc"; |
1814 | | |
1815 | | // static |
1816 | | bool |
1817 | | PluginInstanceChild::SetWindowLongHookCheck(HWND hWnd, |
1818 | | int nIndex, |
1819 | | LONG_PTR newLong) |
1820 | | { |
1821 | | // Let this go through if it's not a subclass |
1822 | | if (nIndex != GWLP_WNDPROC || |
1823 | | // if it's not a subclassed plugin window |
1824 | | !GetProp(hWnd, kPluginInstanceChildProperty) || |
1825 | | // if we're not disabled |
1826 | | GetProp(hWnd, kPluginIgnoreSubclassProperty) || |
1827 | | // if the subclass is set to a known procedure |
1828 | | newLong == reinterpret_cast<LONG_PTR>(PluginWindowProc) || |
1829 | | newLong == reinterpret_cast<LONG_PTR>(NeuteredWindowProc) || |
1830 | | newLong == reinterpret_cast<LONG_PTR>(DefWindowProcA) || |
1831 | | newLong == reinterpret_cast<LONG_PTR>(DefWindowProcW) || |
1832 | | // if the subclass is a WindowsMessageLoop subclass restore |
1833 | | GetProp(hWnd, kOldWndProcProp)) |
1834 | | return true; |
1835 | | // prevent the subclass |
1836 | | return false; |
1837 | | } |
1838 | | |
1839 | | #ifdef _WIN64 |
1840 | | LONG_PTR WINAPI |
1841 | | PluginInstanceChild::SetWindowLongPtrAHook(HWND hWnd, |
1842 | | int nIndex, |
1843 | | LONG_PTR newLong) |
1844 | | #else |
1845 | | LONG WINAPI |
1846 | | PluginInstanceChild::SetWindowLongAHook(HWND hWnd, |
1847 | | int nIndex, |
1848 | | LONG newLong) |
1849 | | #endif |
1850 | | { |
1851 | | if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) |
1852 | | return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); |
1853 | | |
1854 | | // Set flash's new subclass to get the result. |
1855 | | LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); |
1856 | | |
1857 | | // We already checked this in SetWindowLongHookCheck |
1858 | | PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>( |
1859 | | GetProp(hWnd, kPluginInstanceChildProperty)); |
1860 | | |
1861 | | // Hook our subclass back up, just like we do on setwindow. |
1862 | | WNDPROC currentProc = |
1863 | | reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC)); |
1864 | | if (currentProc != PluginWindowProc) { |
1865 | | self->mPluginWndProc = |
1866 | | reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex, |
1867 | | reinterpret_cast<LONG_PTR>(PluginWindowProc))); |
1868 | | NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!"); |
1869 | | } |
1870 | | return proc; |
1871 | | } |
1872 | | |
1873 | | #ifdef _WIN64 |
1874 | | LONG_PTR WINAPI |
1875 | | PluginInstanceChild::SetWindowLongPtrWHook(HWND hWnd, |
1876 | | int nIndex, |
1877 | | LONG_PTR newLong) |
1878 | | #else |
1879 | | LONG WINAPI |
1880 | | PluginInstanceChild::SetWindowLongWHook(HWND hWnd, |
1881 | | int nIndex, |
1882 | | LONG newLong) |
1883 | | #endif |
1884 | | { |
1885 | | if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) |
1886 | | return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); |
1887 | | |
1888 | | // Set flash's new subclass to get the result. |
1889 | | LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); |
1890 | | |
1891 | | // We already checked this in SetWindowLongHookCheck |
1892 | | PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>( |
1893 | | GetProp(hWnd, kPluginInstanceChildProperty)); |
1894 | | |
1895 | | // Hook our subclass back up, just like we do on setwindow. |
1896 | | WNDPROC currentProc = |
1897 | | reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC)); |
1898 | | if (currentProc != PluginWindowProc) { |
1899 | | self->mPluginWndProc = |
1900 | | reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex, |
1901 | | reinterpret_cast<LONG_PTR>(PluginWindowProc))); |
1902 | | NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!"); |
1903 | | } |
1904 | | return proc; |
1905 | | } |
1906 | | |
1907 | | void |
1908 | | PluginInstanceChild::HookSetWindowLongPtr() |
1909 | | { |
1910 | | if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR)) { |
1911 | | return; |
1912 | | } |
1913 | | |
1914 | | sUser32Intercept.Init("user32.dll"); |
1915 | | #ifdef _WIN64 |
1916 | | sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongPtrA", |
1917 | | &SetWindowLongPtrAHook); |
1918 | | sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongPtrW", |
1919 | | &SetWindowLongPtrWHook); |
1920 | | #else |
1921 | | sUser32SetWindowLongAHookStub.Set(sUser32Intercept, "SetWindowLongA", |
1922 | | &SetWindowLongAHook); |
1923 | | sUser32SetWindowLongWHookStub.Set(sUser32Intercept, "SetWindowLongW", |
1924 | | &SetWindowLongWHook); |
1925 | | #endif |
1926 | | } |
1927 | | |
1928 | | /* windowless track popup menu helpers */ |
1929 | | |
1930 | | BOOL |
1931 | | WINAPI |
1932 | | PluginInstanceChild::TrackPopupHookProc(HMENU hMenu, |
1933 | | UINT uFlags, |
1934 | | int x, |
1935 | | int y, |
1936 | | int nReserved, |
1937 | | HWND hWnd, |
1938 | | CONST RECT *prcRect) |
1939 | | { |
1940 | | if (!sUser32TrackPopupMenuStub) { |
1941 | | NS_ERROR("TrackPopupMenu stub isn't set! Badness!"); |
1942 | | return 0; |
1943 | | } |
1944 | | |
1945 | | // Only change the parent when we know this is a context on the plugin |
1946 | | // surface within the browser. Prevents resetting the parent on child ui |
1947 | | // displayed by plugins that have working parent-child relationships. |
1948 | | wchar_t szClass[21]; |
1949 | | bool haveClass = GetClassNameW(hWnd, szClass, ArrayLength(szClass)); |
1950 | | if (!haveClass || |
1951 | | (wcscmp(szClass, L"MozillaWindowClass") && |
1952 | | wcscmp(szClass, L"SWFlash_Placeholder"))) { |
1953 | | // Unrecognized parent |
1954 | | return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved, |
1955 | | hWnd, prcRect); |
1956 | | } |
1957 | | |
1958 | | // Called on an unexpected event, warn. |
1959 | | if (!sWinlessPopupSurrogateHWND) { |
1960 | | NS_WARNING( |
1961 | | "Untraced TrackPopupHookProc call! Menu might not work right!"); |
1962 | | return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved, |
1963 | | hWnd, prcRect); |
1964 | | } |
1965 | | |
1966 | | HWND surrogateHwnd = sWinlessPopupSurrogateHWND; |
1967 | | sWinlessPopupSurrogateHWND = nullptr; |
1968 | | |
1969 | | // Popups that don't use TPM_RETURNCMD expect a final command message |
1970 | | // when an item is selected and the context closes. Since we replace |
1971 | | // the parent, we need to forward this back to the real parent so it |
1972 | | // can act on the menu item selected. |
1973 | | bool isRetCmdCall = (uFlags & TPM_RETURNCMD); |
1974 | | |
1975 | | DWORD res = sUser32TrackPopupMenuStub(hMenu, uFlags|TPM_RETURNCMD, x, y, |
1976 | | nReserved, surrogateHwnd, prcRect); |
1977 | | |
1978 | | if (!isRetCmdCall && res) { |
1979 | | SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(res, 0), 0); |
1980 | | } |
1981 | | |
1982 | | return res; |
1983 | | } |
1984 | | |
1985 | | void |
1986 | | PluginInstanceChild::InitPopupMenuHook() |
1987 | | { |
1988 | | if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK)) { |
1989 | | return; |
1990 | | } |
1991 | | |
1992 | | // Note, once WindowsDllInterceptor is initialized for a module, |
1993 | | // it remains initialized for that particular module for it's |
1994 | | // lifetime. Additional instances are needed if other modules need |
1995 | | // to be hooked. |
1996 | | sUser32Intercept.Init("user32.dll"); |
1997 | | sUser32TrackPopupMenuStub.Set(sUser32Intercept, "TrackPopupMenu", |
1998 | | &TrackPopupHookProc); |
1999 | | } |
2000 | | |
2001 | | void |
2002 | | PluginInstanceChild::CreateWinlessPopupSurrogate() |
2003 | | { |
2004 | | // already initialized |
2005 | | if (mWinlessPopupSurrogateHWND) |
2006 | | return; |
2007 | | |
2008 | | mWinlessPopupSurrogateHWND = |
2009 | | CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_POPUP, |
2010 | | 0, 0, 0, 0, nullptr, 0, GetModuleHandle(nullptr), 0); |
2011 | | if (!mWinlessPopupSurrogateHWND) { |
2012 | | NS_ERROR("CreateWindowEx failed for winless placeholder!"); |
2013 | | return; |
2014 | | } |
2015 | | |
2016 | | SendSetNetscapeWindowAsParent(mWinlessPopupSurrogateHWND); |
2017 | | } |
2018 | | |
2019 | | // static |
2020 | | HIMC |
2021 | | PluginInstanceChild::ImmGetContextProc(HWND aWND) |
2022 | | { |
2023 | | if (!sCurrentPluginInstance) { |
2024 | | return sImm32ImmGetContextStub(aWND); |
2025 | | } |
2026 | | |
2027 | | wchar_t szClass[21]; |
2028 | | int haveClass = GetClassNameW(aWND, szClass, ArrayLength(szClass)); |
2029 | | if (!haveClass || wcscmp(szClass, L"SWFlash_PlaceholderX")) { |
2030 | | NS_WARNING("We cannot recongnize hooked window class"); |
2031 | | return sImm32ImmGetContextStub(aWND); |
2032 | | } |
2033 | | |
2034 | | return sHookIMC; |
2035 | | } |
2036 | | |
2037 | | // static |
2038 | | LONG |
2039 | | PluginInstanceChild::ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex, |
2040 | | LPVOID aBuf, DWORD aLen) |
2041 | | { |
2042 | | if (aIMC != sHookIMC) { |
2043 | | return sImm32ImmGetCompositionStringStub(aIMC, aIndex, aBuf, aLen); |
2044 | | } |
2045 | | if (!sCurrentPluginInstance) { |
2046 | | return IMM_ERROR_GENERAL; |
2047 | | } |
2048 | | AutoTArray<uint8_t, 16> dist; |
2049 | | int32_t length = 0; // IMM_ERROR_NODATA |
2050 | | sCurrentPluginInstance->SendGetCompositionString(aIndex, &dist, &length); |
2051 | | if (length == IMM_ERROR_NODATA || length == IMM_ERROR_GENERAL) { |
2052 | | return length; |
2053 | | } |
2054 | | |
2055 | | if (aBuf && aLen >= static_cast<DWORD>(length)) { |
2056 | | memcpy(aBuf, dist.Elements(), length); |
2057 | | } |
2058 | | return length; |
2059 | | } |
2060 | | |
2061 | | // staitc |
2062 | | BOOL |
2063 | | PluginInstanceChild::ImmSetCandidateWindowProc(HIMC aIMC, LPCANDIDATEFORM aForm) |
2064 | | { |
2065 | | if (aIMC != sHookIMC) { |
2066 | | return sImm32ImmSetCandidateWindowStub(aIMC, aForm); |
2067 | | } |
2068 | | |
2069 | | if (!sCurrentPluginInstance || |
2070 | | aForm->dwIndex != 0) { |
2071 | | return FALSE; |
2072 | | } |
2073 | | |
2074 | | CandidateWindowPosition position; |
2075 | | position.mPoint.x = aForm->ptCurrentPos.x; |
2076 | | position.mPoint.y = aForm->ptCurrentPos.y; |
2077 | | position.mExcludeRect = !!(aForm->dwStyle & CFS_EXCLUDE); |
2078 | | if (position.mExcludeRect) { |
2079 | | position.mRect.x = aForm->rcArea.left; |
2080 | | position.mRect.y = aForm->rcArea.top; |
2081 | | position.mRect.width = aForm->rcArea.right - aForm->rcArea.left; |
2082 | | position.mRect.height = aForm->rcArea.bottom - aForm->rcArea.top; |
2083 | | } |
2084 | | |
2085 | | sCurrentPluginInstance->SendSetCandidateWindow(position); |
2086 | | return TRUE; |
2087 | | } |
2088 | | |
2089 | | // static |
2090 | | BOOL |
2091 | | PluginInstanceChild::ImmNotifyIME(HIMC aIMC, DWORD aAction, DWORD aIndex, |
2092 | | DWORD aValue) |
2093 | | { |
2094 | | if (aIMC != sHookIMC) { |
2095 | | return sImm32ImmNotifyIME(aIMC, aAction, aIndex, aValue); |
2096 | | } |
2097 | | |
2098 | | // We only supports NI_COMPOSITIONSTR because Flash uses it only |
2099 | | if (!sCurrentPluginInstance || |
2100 | | aAction != NI_COMPOSITIONSTR || |
2101 | | (aIndex != CPS_COMPLETE && aIndex != CPS_CANCEL)) { |
2102 | | return FALSE; |
2103 | | } |
2104 | | |
2105 | | sCurrentPluginInstance->SendRequestCommitOrCancel(aAction == CPS_COMPLETE); |
2106 | | return TRUE; |
2107 | | } |
2108 | | |
2109 | | // static |
2110 | | BOOL |
2111 | | PluginInstanceChild::ImmAssociateContextExProc(HWND hWND, HIMC hImc, |
2112 | | DWORD dwFlags) |
2113 | | { |
2114 | | PluginInstanceChild* self = sCurrentPluginInstance; |
2115 | | if (!self) { |
2116 | | // If ImmAssociateContextEx calls unexpected window message, |
2117 | | // we can use child instance object from window property if available. |
2118 | | self = reinterpret_cast<PluginInstanceChild*>( |
2119 | | GetProp(hWND, kFlashThrottleProperty)); |
2120 | | NS_WARNING_ASSERTION(self, "Cannot find PluginInstanceChild"); |
2121 | | } |
2122 | | |
2123 | | // HIMC is always nullptr on Flash's windowless |
2124 | | if (!hImc && self) { |
2125 | | // Store the last IME state since Flash may call ImmAssociateContextEx |
2126 | | // before taking focus. |
2127 | | self->mLastEnableIMEState = !!(dwFlags & IACE_DEFAULT); |
2128 | | self->SendEnableIME(self->mLastEnableIMEState); |
2129 | | } |
2130 | | return sImm32ImmAssociateContextExStub(hWND, hImc, dwFlags); |
2131 | | } |
2132 | | |
2133 | | void |
2134 | | PluginInstanceChild::InitImm32Hook() |
2135 | | { |
2136 | | if (!(GetQuirks() & QUIRK_WINLESS_HOOK_IME)) { |
2137 | | return; |
2138 | | } |
2139 | | |
2140 | | // When using windowless plugin, IMM API won't work due ot OOP. |
2141 | | // |
2142 | | // ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't |
2143 | | // need to hook this. |
2144 | | |
2145 | | sImm32Intercept.Init("imm32.dll"); |
2146 | | sImm32ImmGetContextStub.Set(sImm32Intercept, "ImmGetContext", |
2147 | | &ImmGetContextProc); |
2148 | | sImm32ImmGetCompositionStringStub.Set(sImm32Intercept, |
2149 | | "ImmGetCompositionStringW", |
2150 | | &ImmGetCompositionStringProc); |
2151 | | sImm32ImmSetCandidateWindowStub.Set(sImm32Intercept, |
2152 | | "ImmSetCandidateWindow", |
2153 | | &ImmSetCandidateWindowProc); |
2154 | | sImm32ImmNotifyIME.Set(sImm32Intercept, "ImmNotifyIME", &ImmNotifyIME); |
2155 | | sImm32ImmAssociateContextExStub.Set(sImm32Intercept, "ImmAssociateContextEx", |
2156 | | &ImmAssociateContextExProc); |
2157 | | } |
2158 | | |
2159 | | void |
2160 | | PluginInstanceChild::DestroyWinlessPopupSurrogate() |
2161 | | { |
2162 | | if (mWinlessPopupSurrogateHWND) |
2163 | | DestroyWindow(mWinlessPopupSurrogateHWND); |
2164 | | mWinlessPopupSurrogateHWND = nullptr; |
2165 | | } |
2166 | | |
2167 | | int16_t |
2168 | | PluginInstanceChild::WinlessHandleEvent(NPEvent& event) |
2169 | | { |
2170 | | if (!mPluginIface->event) |
2171 | | return false; |
2172 | | |
2173 | | // Events that might generate nested event dispatch loops need |
2174 | | // special handling during delivery. |
2175 | | int16_t handled; |
2176 | | |
2177 | | HWND focusHwnd = nullptr; |
2178 | | |
2179 | | // TrackPopupMenu will fail if the parent window is not associated with |
2180 | | // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate |
2181 | | // parent created in the child process. |
2182 | | if ((GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default? |
2183 | | (event.event == WM_RBUTTONDOWN || // flash |
2184 | | event.event == WM_RBUTTONUP)) { // silverlight |
2185 | | sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND; |
2186 | | |
2187 | | // A little trick scrounged from chromium's code - set the focus |
2188 | | // to our surrogate parent so keyboard nav events go to the menu. |
2189 | | focusHwnd = SetFocus(mWinlessPopupSurrogateHWND); |
2190 | | } |
2191 | | |
2192 | | AutoRestore<PluginInstanceChild *> pluginInstance(sCurrentPluginInstance); |
2193 | | if (event.event == WM_IME_STARTCOMPOSITION || |
2194 | | event.event == WM_IME_COMPOSITION || |
2195 | | event.event == WM_LBUTTONDOWN || |
2196 | | event.event == WM_KILLFOCUS) { |
2197 | | sCurrentPluginInstance = this; |
2198 | | } |
2199 | | |
2200 | | MessageLoop* loop = MessageLoop::current(); |
2201 | | AutoRestore<bool> modalLoop(loop->os_modal_loop()); |
2202 | | |
2203 | | handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&event)); |
2204 | | |
2205 | | sWinlessPopupSurrogateHWND = nullptr; |
2206 | | |
2207 | | if (IsWindow(focusHwnd)) { |
2208 | | SetFocus(focusHwnd); |
2209 | | } |
2210 | | |
2211 | | // This is hack of Flash's behaviour. |
2212 | | // |
2213 | | // When moving focus from chrome to plugin by mouse click, Gecko sends |
2214 | | // mouse message (such as WM_LBUTTONDOWN etc) at first, then sends |
2215 | | // WM_SETFOCUS. But Flash will call ImmAssociateContextEx on WM_LBUTTONDOWN |
2216 | | // even if it doesn't receive WM_SETFOCUS. |
2217 | | // |
2218 | | // In this situation, after sending mouse message, content process will be |
2219 | | // activated and set input context with PLUGIN. So after activating |
2220 | | // content process, we have to set current IME state again. |
2221 | | |
2222 | | if (event.event == WM_SETFOCUS) { |
2223 | | // When focus is changed from chrome process to plugin process, |
2224 | | // Flash may call ImmAssociateContextEx before receiving WM_SETFOCUS. |
2225 | | SendEnableIME(mLastEnableIMEState); |
2226 | | } else if (event.event == WM_KILLFOCUS) { |
2227 | | // Flash always calls ImmAssociateContextEx by taking focus. |
2228 | | // Although this flag doesn't have to be reset, I add it for safety. |
2229 | | mLastEnableIMEState = true; |
2230 | | } |
2231 | | |
2232 | | return handled; |
2233 | | } |
2234 | | |
2235 | | /* flash msg throttling helpers */ |
2236 | | |
2237 | | // Flash has the unfortunate habit of flooding dispatch loops with custom |
2238 | | // windowing events they use for timing. We throttle these by dropping the |
2239 | | // delivery priority below any other event, including pending ipc io |
2240 | | // notifications. We do this for both windowed and windowless controls. |
2241 | | // Note flash's windowless msg window can last longer than our instance, |
2242 | | // so we try to unhook when the window is destroyed and in NPP_Destroy. |
2243 | | |
2244 | | void |
2245 | | PluginInstanceChild::UnhookWinlessFlashThrottle() |
2246 | | { |
2247 | | // We may have already unhooked |
2248 | | if (!mWinlessThrottleOldWndProc) |
2249 | | return; |
2250 | | |
2251 | | WNDPROC tmpProc = mWinlessThrottleOldWndProc; |
2252 | | mWinlessThrottleOldWndProc = nullptr; |
2253 | | |
2254 | | NS_ASSERTION(mWinlessHiddenMsgHWND, |
2255 | | "Missing mWinlessHiddenMsgHWND w/subclass set??"); |
2256 | | |
2257 | | // reset the subclass |
2258 | | SetWindowLongPtr(mWinlessHiddenMsgHWND, GWLP_WNDPROC, |
2259 | | reinterpret_cast<LONG_PTR>(tmpProc)); |
2260 | | |
2261 | | // Remove our instance prop |
2262 | | RemoveProp(mWinlessHiddenMsgHWND, kFlashThrottleProperty); |
2263 | | mWinlessHiddenMsgHWND = nullptr; |
2264 | | } |
2265 | | |
2266 | | // static |
2267 | | LRESULT CALLBACK |
2268 | | PluginInstanceChild::WinlessHiddenFlashWndProc(HWND hWnd, |
2269 | | UINT message, |
2270 | | WPARAM wParam, |
2271 | | LPARAM lParam) |
2272 | | { |
2273 | | PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>( |
2274 | | GetProp(hWnd, kFlashThrottleProperty)); |
2275 | | if (!self) { |
2276 | | MOZ_ASSERT_UNREACHABLE("Badness!"); |
2277 | | return 0; |
2278 | | } |
2279 | | |
2280 | | NS_ASSERTION(self->mWinlessThrottleOldWndProc, |
2281 | | "Missing subclass procedure!!"); |
2282 | | |
2283 | | // Throttle |
2284 | | if (message == WM_USER+1) { |
2285 | | self->FlashThrottleMessage(hWnd, message, wParam, lParam, false); |
2286 | | return 0; |
2287 | | } |
2288 | | |
2289 | | // Unhook |
2290 | | if (message == WM_CLOSE || message == WM_NCDESTROY) { |
2291 | | WNDPROC tmpProc = self->mWinlessThrottleOldWndProc; |
2292 | | self->UnhookWinlessFlashThrottle(); |
2293 | | LRESULT res = CallWindowProc(tmpProc, hWnd, message, wParam, lParam); |
2294 | | return res; |
2295 | | } |
2296 | | |
2297 | | return CallWindowProc(self->mWinlessThrottleOldWndProc, |
2298 | | hWnd, message, wParam, lParam); |
2299 | | } |
2300 | | |
2301 | | // Enumerate all thread windows looking for flash's hidden message window. |
2302 | | // Once we find it, sub class it so we can throttle user msgs. |
2303 | | // static |
2304 | | BOOL CALLBACK |
2305 | | PluginInstanceChild::EnumThreadWindowsCallback(HWND hWnd, |
2306 | | LPARAM aParam) |
2307 | | { |
2308 | | PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(aParam); |
2309 | | if (!self) { |
2310 | | MOZ_ASSERT_UNREACHABLE("Enum befuddled!"); |
2311 | | return FALSE; |
2312 | | } |
2313 | | |
2314 | | wchar_t className[64]; |
2315 | | if (!GetClassNameW(hWnd, className, sizeof(className)/sizeof(char16_t))) |
2316 | | return TRUE; |
2317 | | |
2318 | | if (!wcscmp(className, L"SWFlash_PlaceholderX")) { |
2319 | | WNDPROC oldWndProc = |
2320 | | reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC)); |
2321 | | // Only set this if we haven't already. |
2322 | | if (oldWndProc != WinlessHiddenFlashWndProc) { |
2323 | | if (self->mWinlessThrottleOldWndProc) { |
2324 | | NS_WARNING("mWinlessThrottleWndProc already set???"); |
2325 | | return FALSE; |
2326 | | } |
2327 | | // Subsclass and store self as a property |
2328 | | self->mWinlessHiddenMsgHWND = hWnd; |
2329 | | self->mWinlessThrottleOldWndProc = |
2330 | | reinterpret_cast<WNDPROC>(SetWindowLongPtr(hWnd, GWLP_WNDPROC, |
2331 | | reinterpret_cast<LONG_PTR>(WinlessHiddenFlashWndProc))); |
2332 | | SetProp(hWnd, kFlashThrottleProperty, self); |
2333 | | NS_ASSERTION(self->mWinlessThrottleOldWndProc, |
2334 | | "SetWindowLongPtr failed?!"); |
2335 | | } |
2336 | | // Return no matter what once we find the right window. |
2337 | | return FALSE; |
2338 | | } |
2339 | | |
2340 | | return TRUE; |
2341 | | } |
2342 | | |
2343 | | void |
2344 | | PluginInstanceChild::SetupFlashMsgThrottle() |
2345 | | { |
2346 | | if (mWindow.type == NPWindowTypeDrawable) { |
2347 | | // Search for the flash hidden message window and subclass it. Only |
2348 | | // search for flash windows belonging to our ui thread! |
2349 | | if (mWinlessThrottleOldWndProc) |
2350 | | return; |
2351 | | EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsCallback, |
2352 | | reinterpret_cast<LPARAM>(this)); |
2353 | | } |
2354 | | else { |
2355 | | // Already setup through quirks and the subclass. |
2356 | | return; |
2357 | | } |
2358 | | } |
2359 | | |
2360 | | WNDPROC |
2361 | | PluginInstanceChild::FlashThrottleMsg::GetProc() |
2362 | | { |
2363 | | if (mInstance) { |
2364 | | return mWindowed ? mInstance->mPluginWndProc : |
2365 | | mInstance->mWinlessThrottleOldWndProc; |
2366 | | } |
2367 | | return nullptr; |
2368 | | } |
2369 | | |
2370 | | NS_IMETHODIMP |
2371 | | PluginInstanceChild::FlashThrottleMsg::Run() |
2372 | | { |
2373 | | if (!mInstance) { |
2374 | | return NS_OK; |
2375 | | } |
2376 | | |
2377 | | mInstance->mPendingFlashThrottleMsgs.RemoveElement(this); |
2378 | | |
2379 | | // GetProc() checks mInstance, and pulls the procedure from |
2380 | | // PluginInstanceChild. We don't transport sub-class procedure |
2381 | | // ptrs around in FlashThrottleMsg msgs. |
2382 | | if (!GetProc()) |
2383 | | return NS_OK; |
2384 | | |
2385 | | // deliver the event to flash |
2386 | | CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam()); |
2387 | | return NS_OK; |
2388 | | } |
2389 | | |
2390 | | nsresult |
2391 | | PluginInstanceChild::FlashThrottleMsg::Cancel() |
2392 | | { |
2393 | | MOZ_ASSERT(mInstance); |
2394 | | mInstance = nullptr; |
2395 | | return NS_OK; |
2396 | | } |
2397 | | |
2398 | | void |
2399 | | PluginInstanceChild::FlashThrottleMessage(HWND aWnd, |
2400 | | UINT aMsg, |
2401 | | WPARAM aWParam, |
2402 | | LPARAM aLParam, |
2403 | | bool isWindowed) |
2404 | | { |
2405 | | // We save a reference to the FlashThrottleMsg so we can cancel it in |
2406 | | // Destroy if it's still alive. |
2407 | | RefPtr<FlashThrottleMsg> task = |
2408 | | new FlashThrottleMsg(this, aWnd, aMsg, aWParam, aLParam, isWindowed); |
2409 | | |
2410 | | mPendingFlashThrottleMsgs.AppendElement(task); |
2411 | | |
2412 | | MessageLoop::current()->PostDelayedTask(task.forget(), |
2413 | | kFlashWMUSERMessageThrottleDelayMs); |
2414 | | } |
2415 | | |
2416 | | #endif // OS_WIN |
2417 | | |
2418 | | mozilla::ipc::IPCResult |
2419 | | PluginInstanceChild::AnswerSetPluginFocus() |
2420 | 0 | { |
2421 | 0 | MOZ_LOG(GetPluginLog(), LogLevel::Debug, ("%s", FULLFUNCTION)); |
2422 | 0 |
|
2423 | | #if defined(OS_WIN) |
2424 | | // Parent is letting us know the dom set focus to the plugin. Note, |
2425 | | // focus can change during transit in certain edge cases, for example |
2426 | | // when a button click brings up a full screen window. Since we send |
2427 | | // this in response to a WM_SETFOCUS event on our parent, the parent |
2428 | | // should have focus when we receive this. If not, ignore the call. |
2429 | | if (::GetFocus() == mPluginWindowHWND) |
2430 | | return IPC_OK(); |
2431 | | ::SetFocus(mPluginWindowHWND); |
2432 | | return IPC_OK(); |
2433 | | #else |
2434 | 0 | MOZ_ASSERT_UNREACHABLE("AnswerSetPluginFocus not implemented!"); |
2435 | 0 | return IPC_FAIL_NO_REASON(this); |
2436 | 0 | #endif |
2437 | 0 | } |
2438 | | |
2439 | | mozilla::ipc::IPCResult |
2440 | | PluginInstanceChild::AnswerUpdateWindow() |
2441 | 0 | { |
2442 | 0 | MOZ_LOG(GetPluginLog(), LogLevel::Debug, ("%s", FULLFUNCTION)); |
2443 | 0 |
|
2444 | | #if defined(OS_WIN) |
2445 | | if (mPluginWindowHWND) { |
2446 | | RECT rect; |
2447 | | if (GetUpdateRect(GetParent(mPluginWindowHWND), &rect, FALSE)) { |
2448 | | ::InvalidateRect(mPluginWindowHWND, &rect, FALSE); |
2449 | | } |
2450 | | UpdateWindow(mPluginWindowHWND); |
2451 | | } |
2452 | | return IPC_OK(); |
2453 | | #else |
2454 | 0 | MOZ_ASSERT_UNREACHABLE("AnswerUpdateWindow not implemented!"); |
2455 | 0 | return IPC_FAIL_NO_REASON(this); |
2456 | 0 | #endif |
2457 | 0 | } |
2458 | | |
2459 | | mozilla::ipc::IPCResult |
2460 | | PluginInstanceChild::RecvNPP_DidComposite() |
2461 | 0 | { |
2462 | 0 | if (mPluginIface->didComposite) { |
2463 | 0 | mPluginIface->didComposite(GetNPP()); |
2464 | 0 | } |
2465 | 0 | return IPC_OK(); |
2466 | 0 | } |
2467 | | |
2468 | | PPluginScriptableObjectChild* |
2469 | | PluginInstanceChild::AllocPPluginScriptableObjectChild() |
2470 | 0 | { |
2471 | 0 | AssertPluginThread(); |
2472 | 0 | return new PluginScriptableObjectChild(Proxy); |
2473 | 0 | } |
2474 | | |
2475 | | bool |
2476 | | PluginInstanceChild::DeallocPPluginScriptableObjectChild( |
2477 | | PPluginScriptableObjectChild* aObject) |
2478 | 0 | { |
2479 | 0 | AssertPluginThread(); |
2480 | 0 | delete aObject; |
2481 | 0 | return true; |
2482 | 0 | } |
2483 | | |
2484 | | mozilla::ipc::IPCResult |
2485 | | PluginInstanceChild::RecvPPluginScriptableObjectConstructor( |
2486 | | PPluginScriptableObjectChild* aActor) |
2487 | 0 | { |
2488 | 0 | AssertPluginThread(); |
2489 | 0 |
|
2490 | 0 | // This is only called in response to the parent process requesting the |
2491 | 0 | // creation of an actor. This actor will represent an NPObject that is |
2492 | 0 | // created by the browser and returned to the plugin. |
2493 | 0 | PluginScriptableObjectChild* actor = |
2494 | 0 | static_cast<PluginScriptableObjectChild*>(aActor); |
2495 | 0 | NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!"); |
2496 | 0 |
|
2497 | 0 | actor->InitializeProxy(); |
2498 | 0 | NS_ASSERTION(actor->GetObject(false), "Actor should have an object!"); |
2499 | 0 |
|
2500 | 0 | return IPC_OK(); |
2501 | 0 | } |
2502 | | |
2503 | | mozilla::ipc::IPCResult |
2504 | | PluginInstanceChild::RecvPBrowserStreamConstructor( |
2505 | | PBrowserStreamChild* aActor, |
2506 | | const nsCString& url, |
2507 | | const uint32_t& length, |
2508 | | const uint32_t& lastmodified, |
2509 | | PStreamNotifyChild* notifyData, |
2510 | | const nsCString& headers) |
2511 | 0 | { |
2512 | 0 | return IPC_OK(); |
2513 | 0 | } |
2514 | | |
2515 | | NPError |
2516 | | PluginInstanceChild::DoNPP_NewStream(BrowserStreamChild* actor, |
2517 | | const nsCString& mimeType, |
2518 | | const bool& seekable, |
2519 | | uint16_t* stype) |
2520 | 0 | { |
2521 | 0 | AssertPluginThread(); |
2522 | 0 | AutoStackHelper guard(this); |
2523 | 0 | NPError rv = actor->StreamConstructed(mimeType, seekable, stype); |
2524 | 0 | return rv; |
2525 | 0 | } |
2526 | | |
2527 | | mozilla::ipc::IPCResult |
2528 | | PluginInstanceChild::AnswerNPP_NewStream(PBrowserStreamChild* actor, |
2529 | | const nsCString& mimeType, |
2530 | | const bool& seekable, |
2531 | | NPError* rv, |
2532 | | uint16_t* stype) |
2533 | 0 | { |
2534 | 0 | *rv = DoNPP_NewStream(static_cast<BrowserStreamChild*>(actor), mimeType, |
2535 | 0 | seekable, stype); |
2536 | 0 | return IPC_OK(); |
2537 | 0 | } |
2538 | | |
2539 | | PBrowserStreamChild* |
2540 | | PluginInstanceChild::AllocPBrowserStreamChild(const nsCString& url, |
2541 | | const uint32_t& length, |
2542 | | const uint32_t& lastmodified, |
2543 | | PStreamNotifyChild* notifyData, |
2544 | | const nsCString& headers) |
2545 | 0 | { |
2546 | 0 | AssertPluginThread(); |
2547 | 0 | return new BrowserStreamChild(this, url, length, lastmodified, |
2548 | 0 | static_cast<StreamNotifyChild*>(notifyData), |
2549 | 0 | headers); |
2550 | 0 | } |
2551 | | |
2552 | | bool |
2553 | | PluginInstanceChild::DeallocPBrowserStreamChild(PBrowserStreamChild* stream) |
2554 | 0 | { |
2555 | 0 | AssertPluginThread(); |
2556 | 0 | delete stream; |
2557 | 0 | return true; |
2558 | 0 | } |
2559 | | |
2560 | | |
2561 | | PStreamNotifyChild* |
2562 | | PluginInstanceChild::AllocPStreamNotifyChild(const nsCString& url, |
2563 | | const nsCString& target, |
2564 | | const bool& post, |
2565 | | const nsCString& buffer, |
2566 | | const bool& file, |
2567 | | NPError* result) |
2568 | 0 | { |
2569 | 0 | AssertPluginThread(); |
2570 | 0 | MOZ_CRASH("not reached"); |
2571 | 0 | return nullptr; |
2572 | 0 | } |
2573 | | |
2574 | | void |
2575 | | StreamNotifyChild::ActorDestroy(ActorDestroyReason why) |
2576 | 0 | { |
2577 | 0 | if (AncestorDeletion == why && mBrowserStream) { |
2578 | 0 | NS_ERROR("Pending NPP_URLNotify not called when closing an instance."); |
2579 | 0 |
|
2580 | 0 | // reclaim responsibility for deleting ourself |
2581 | 0 | mBrowserStream->mStreamNotify = nullptr; |
2582 | 0 | mBrowserStream = nullptr; |
2583 | 0 | } |
2584 | 0 | } |
2585 | | |
2586 | | void |
2587 | | StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs) |
2588 | 0 | { |
2589 | 0 | NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?"); |
2590 | 0 |
|
2591 | 0 | mBrowserStream = bs; |
2592 | 0 | } |
2593 | | |
2594 | | mozilla::ipc::IPCResult |
2595 | | StreamNotifyChild::Recv__delete__(const NPReason& reason) |
2596 | 0 | { |
2597 | 0 | AssertPluginThread(); |
2598 | 0 |
|
2599 | 0 | if (mBrowserStream) |
2600 | 0 | mBrowserStream->NotifyPending(); |
2601 | 0 | else |
2602 | 0 | NPP_URLNotify(reason); |
2603 | 0 |
|
2604 | 0 | return IPC_OK(); |
2605 | 0 | } |
2606 | | |
2607 | | mozilla::ipc::IPCResult |
2608 | | StreamNotifyChild::RecvRedirectNotify(const nsCString& url, const int32_t& status) |
2609 | 0 | { |
2610 | 0 | // NPP_URLRedirectNotify requires a non-null closure. Since core logic |
2611 | 0 | // assumes that all out-of-process notify streams have non-null closure |
2612 | 0 | // data it will assume that the plugin was notified at this point and |
2613 | 0 | // expect a response otherwise the redirect will hang indefinitely. |
2614 | 0 | if (!mClosure) { |
2615 | 0 | SendRedirectNotifyResponse(false); |
2616 | 0 | } |
2617 | 0 |
|
2618 | 0 | PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager()); |
2619 | 0 | if (instance->mPluginIface->urlredirectnotify) |
2620 | 0 | instance->mPluginIface->urlredirectnotify(instance->GetNPP(), url.get(), status, mClosure); |
2621 | 0 |
|
2622 | 0 | return IPC_OK(); |
2623 | 0 | } |
2624 | | |
2625 | | void |
2626 | | StreamNotifyChild::NPP_URLNotify(NPReason reason) |
2627 | 0 | { |
2628 | 0 | PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager()); |
2629 | 0 |
|
2630 | 0 | if (mClosure) |
2631 | 0 | instance->mPluginIface->urlnotify(instance->GetNPP(), mURL.get(), |
2632 | 0 | reason, mClosure); |
2633 | 0 | } |
2634 | | |
2635 | | bool |
2636 | | PluginInstanceChild::DeallocPStreamNotifyChild(PStreamNotifyChild* notifyData) |
2637 | 0 | { |
2638 | 0 | AssertPluginThread(); |
2639 | 0 |
|
2640 | 0 | if (!static_cast<StreamNotifyChild*>(notifyData)->mBrowserStream) |
2641 | 0 | delete notifyData; |
2642 | 0 | return true; |
2643 | 0 | } |
2644 | | |
2645 | | PluginScriptableObjectChild* |
2646 | | PluginInstanceChild::GetActorForNPObject(NPObject* aObject) |
2647 | 0 | { |
2648 | 0 | AssertPluginThread(); |
2649 | 0 | NS_ASSERTION(aObject, "Null pointer!"); |
2650 | 0 |
|
2651 | 0 | if (aObject->_class == PluginScriptableObjectChild::GetClass()) { |
2652 | 0 | // One of ours! It's a browser-provided object. |
2653 | 0 | ChildNPObject* object = static_cast<ChildNPObject*>(aObject); |
2654 | 0 | NS_ASSERTION(object->parent, "Null actor!"); |
2655 | 0 | return object->parent; |
2656 | 0 | } |
2657 | 0 |
|
2658 | 0 | PluginScriptableObjectChild* actor = |
2659 | 0 | PluginScriptableObjectChild::GetActorForNPObject(aObject); |
2660 | 0 | if (actor) { |
2661 | 0 | // Plugin-provided object that we've previously wrapped. |
2662 | 0 | return actor; |
2663 | 0 | } |
2664 | 0 | |
2665 | 0 | actor = new PluginScriptableObjectChild(LocalObject); |
2666 | 0 | if (!SendPPluginScriptableObjectConstructor(actor)) { |
2667 | 0 | NS_ERROR("Failed to send constructor message!"); |
2668 | 0 | return nullptr; |
2669 | 0 | } |
2670 | 0 |
|
2671 | 0 | actor->InitializeLocal(aObject); |
2672 | 0 | return actor; |
2673 | 0 | } |
2674 | | |
2675 | | void |
2676 | | PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow) |
2677 | 0 | { |
2678 | 0 | if (!notifyData) { |
2679 | 0 | return; |
2680 | 0 | } |
2681 | 0 | |
2682 | 0 | InfallibleTArray<PStreamNotifyChild*> notifyStreams; |
2683 | 0 | ManagedPStreamNotifyChild(notifyStreams); |
2684 | 0 | uint32_t notifyStreamCount = notifyStreams.Length(); |
2685 | 0 | for (uint32_t i = 0; i < notifyStreamCount; i++) { |
2686 | 0 | StreamNotifyChild* sn = static_cast<StreamNotifyChild*>(notifyStreams[i]); |
2687 | 0 | if (sn->mClosure == notifyData) { |
2688 | 0 | sn->SendRedirectNotifyResponse(static_cast<bool>(allow)); |
2689 | 0 | return; |
2690 | 0 | } |
2691 | 0 | } |
2692 | 0 | NS_ASSERTION(false, "Couldn't find stream for redirect response!"); |
2693 | 0 | } |
2694 | | |
2695 | | bool |
2696 | | PluginInstanceChild::IsUsingDirectDrawing() |
2697 | 0 | { |
2698 | 0 | return IsDrawingModelDirect(mDrawingModel); |
2699 | 0 | } |
2700 | | |
2701 | | PluginInstanceChild::DirectBitmap::DirectBitmap(PluginInstanceChild* aOwner, const Shmem& shmem, |
2702 | | const IntSize& size, uint32_t stride, SurfaceFormat format) |
2703 | | : mOwner(aOwner), |
2704 | | mShmem(shmem), |
2705 | | mFormat(format), |
2706 | | mSize(size), |
2707 | | mStride(stride) |
2708 | 0 | { |
2709 | 0 | } |
2710 | | |
2711 | | PluginInstanceChild::DirectBitmap::~DirectBitmap() |
2712 | 0 | { |
2713 | 0 | mOwner->DeallocShmem(mShmem); |
2714 | 0 | } |
2715 | | |
2716 | | static inline SurfaceFormat |
2717 | | NPImageFormatToSurfaceFormat(NPImageFormat aFormat) |
2718 | 0 | { |
2719 | 0 | switch (aFormat) { |
2720 | 0 | case NPImageFormatBGRA32: |
2721 | 0 | return SurfaceFormat::B8G8R8A8; |
2722 | 0 | case NPImageFormatBGRX32: |
2723 | 0 | return SurfaceFormat::B8G8R8X8; |
2724 | 0 | default: |
2725 | 0 | MOZ_ASSERT_UNREACHABLE("unknown NPImageFormat"); |
2726 | 0 | return SurfaceFormat::UNKNOWN; |
2727 | 0 | } |
2728 | 0 | } |
2729 | | |
2730 | | static inline gfx::IntRect |
2731 | | NPRectToIntRect(const NPRect& in) |
2732 | 0 | { |
2733 | 0 | return IntRect(in.left, in.top, in.right - in.left, in.bottom - in.top); |
2734 | 0 | } |
2735 | | |
2736 | | NPError |
2737 | | PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format, |
2738 | | void *initData, NPAsyncSurface *surface) |
2739 | 0 | { |
2740 | 0 | AssertPluginThread(); |
2741 | 0 | AutoStackHelper guard(this); |
2742 | 0 |
|
2743 | 0 | if (!IsUsingDirectDrawing()) { |
2744 | 0 | return NPERR_INVALID_PARAM; |
2745 | 0 | } |
2746 | 0 | if (format != NPImageFormatBGRA32 && format != NPImageFormatBGRX32) { |
2747 | 0 | return NPERR_INVALID_PARAM; |
2748 | 0 | } |
2749 | 0 |
|
2750 | 0 | PodZero(surface); |
2751 | 0 |
|
2752 | 0 | // NPAPI guarantees that the SetCurrentAsyncSurface call will release the |
2753 | 0 | // previous surface if it was different. However, no functionality exists |
2754 | 0 | // within content to synchronize a non-shadow-layers transaction with the |
2755 | 0 | // compositor. |
2756 | 0 | // |
2757 | 0 | // To get around this, we allocate two surfaces: a child copy, which we |
2758 | 0 | // hand off to the plugin, and a parent copy, which we will hand off to |
2759 | 0 | // the compositor. Each call to SetCurrentAsyncSurface will copy the |
2760 | 0 | // invalid region from the child surface to its parent. |
2761 | 0 | switch (mDrawingModel) { |
2762 | 0 | case NPDrawingModelAsyncBitmapSurface: { |
2763 | 0 | // Validate that the caller does not expect initial data to be set. |
2764 | 0 | if (initData) { |
2765 | 0 | return NPERR_INVALID_PARAM; |
2766 | 0 | } |
2767 | 0 |
|
2768 | 0 | // Validate that we're not double-allocating a surface. |
2769 | 0 | RefPtr<DirectBitmap> holder; |
2770 | 0 | if (mDirectBitmaps.Get(surface, getter_AddRefs(holder))) { |
2771 | 0 | return NPERR_INVALID_PARAM; |
2772 | 0 | } |
2773 | 0 |
|
2774 | 0 | SurfaceFormat mozformat = NPImageFormatToSurfaceFormat(format); |
2775 | 0 | int32_t bytesPerPixel = BytesPerPixel(mozformat); |
2776 | 0 |
|
2777 | 0 | if (size->width <= 0 || size->height <= 0) { |
2778 | 0 | return NPERR_INVALID_PARAM; |
2779 | 0 | } |
2780 | 0 |
|
2781 | 0 | CheckedInt<uint32_t> nbytes = SafeBytesForBitmap(size->width, size->height, bytesPerPixel); |
2782 | 0 | if (!nbytes.isValid()) { |
2783 | 0 | return NPERR_INVALID_PARAM; |
2784 | 0 | } |
2785 | 0 |
|
2786 | 0 | Shmem shmem; |
2787 | 0 | if (!AllocUnsafeShmem(nbytes.value(), SharedMemory::TYPE_BASIC, &shmem)) { |
2788 | 0 | return NPERR_OUT_OF_MEMORY_ERROR; |
2789 | 0 | } |
2790 | 0 | MOZ_ASSERT(shmem.Size<uint8_t>() == nbytes.value()); |
2791 | 0 |
|
2792 | 0 | surface->version = 0; |
2793 | 0 | surface->size = *size; |
2794 | 0 | surface->format = format; |
2795 | 0 | surface->bitmap.data = shmem.get<unsigned char>(); |
2796 | 0 | surface->bitmap.stride = size->width * bytesPerPixel; |
2797 | 0 |
|
2798 | 0 | // Hold the shmem alive until Finalize() is called or this actor dies. |
2799 | 0 | holder = new DirectBitmap(this, shmem, |
2800 | 0 | IntSize(size->width, size->height), |
2801 | 0 | surface->bitmap.stride, mozformat); |
2802 | 0 | mDirectBitmaps.Put(surface, holder); |
2803 | 0 | return NPERR_NO_ERROR; |
2804 | 0 | } |
2805 | | #if defined(XP_WIN) |
2806 | | case NPDrawingModelAsyncWindowsDXGISurface: { |
2807 | | // Validate that the caller does not expect initial data to be set. |
2808 | | if (initData) { |
2809 | | return NPERR_INVALID_PARAM; |
2810 | | } |
2811 | | |
2812 | | // Validate that we're not double-allocating a surface. |
2813 | | WindowsHandle handle = 0; |
2814 | | if (mDxgiSurfaces.Get(surface, &handle)) { |
2815 | | return NPERR_INVALID_PARAM; |
2816 | | } |
2817 | | |
2818 | | NPError error = NPERR_NO_ERROR; |
2819 | | SurfaceFormat mozformat = NPImageFormatToSurfaceFormat(format); |
2820 | | if (!SendInitDXGISurface(mozformat, |
2821 | | IntSize(size->width, size->height), |
2822 | | &handle, |
2823 | | &error)) |
2824 | | { |
2825 | | return NPERR_GENERIC_ERROR; |
2826 | | } |
2827 | | if (error != NPERR_NO_ERROR) { |
2828 | | return error; |
2829 | | } |
2830 | | |
2831 | | surface->version = 0; |
2832 | | surface->size = *size; |
2833 | | surface->format = format; |
2834 | | surface->sharedHandle = reinterpret_cast<HANDLE>(handle); |
2835 | | |
2836 | | mDxgiSurfaces.Put(surface, handle); |
2837 | | return NPERR_NO_ERROR; |
2838 | | } |
2839 | | #endif |
2840 | 0 | default: |
2841 | 0 | MOZ_ASSERT_UNREACHABLE("unknown drawing model"); |
2842 | 0 | } |
2843 | 0 |
|
2844 | 0 | return NPERR_INVALID_PARAM; |
2845 | 0 | } |
2846 | | |
2847 | | NPError |
2848 | | PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface) |
2849 | 0 | { |
2850 | 0 | AssertPluginThread(); |
2851 | 0 |
|
2852 | 0 | if (!IsUsingDirectDrawing()) { |
2853 | 0 | return NPERR_GENERIC_ERROR; |
2854 | 0 | } |
2855 | 0 |
|
2856 | 0 | switch (mDrawingModel) { |
2857 | 0 | case NPDrawingModelAsyncBitmapSurface: { |
2858 | 0 | RefPtr<DirectBitmap> bitmap; |
2859 | 0 | if (!mDirectBitmaps.Get(surface, getter_AddRefs(bitmap))) { |
2860 | 0 | return NPERR_INVALID_PARAM; |
2861 | 0 | } |
2862 | 0 |
|
2863 | 0 | PodZero(surface); |
2864 | 0 | mDirectBitmaps.Remove(surface); |
2865 | 0 | return NPERR_NO_ERROR; |
2866 | 0 | } |
2867 | | #if defined(XP_WIN) |
2868 | | case NPDrawingModelAsyncWindowsDXGISurface: { |
2869 | | WindowsHandle handle; |
2870 | | if (!mDxgiSurfaces.Get(surface, &handle)) { |
2871 | | return NPERR_INVALID_PARAM; |
2872 | | } |
2873 | | |
2874 | | SendFinalizeDXGISurface(handle); |
2875 | | mDxgiSurfaces.Remove(surface); |
2876 | | return NPERR_NO_ERROR; |
2877 | | } |
2878 | | #endif |
2879 | 0 | default: |
2880 | 0 | MOZ_ASSERT_UNREACHABLE("unknown drawing model"); |
2881 | 0 | } |
2882 | 0 |
|
2883 | 0 | return NPERR_INVALID_PARAM; |
2884 | 0 | } |
2885 | | |
2886 | | void |
2887 | | PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) |
2888 | 0 | { |
2889 | 0 | AssertPluginThread(); |
2890 | 0 |
|
2891 | 0 | if (!IsUsingDirectDrawing()) { |
2892 | 0 | return; |
2893 | 0 | } |
2894 | 0 | |
2895 | 0 | mCurrentDirectSurface = surface; |
2896 | 0 |
|
2897 | 0 | if (!surface) { |
2898 | 0 | SendRevokeCurrentDirectSurface(); |
2899 | 0 | return; |
2900 | 0 | } |
2901 | 0 | |
2902 | 0 | switch (mDrawingModel) { |
2903 | 0 | case NPDrawingModelAsyncBitmapSurface: { |
2904 | 0 | RefPtr<DirectBitmap> bitmap; |
2905 | 0 | if (!mDirectBitmaps.Get(surface, getter_AddRefs(bitmap))) { |
2906 | 0 | return; |
2907 | 0 | } |
2908 | 0 | |
2909 | 0 | IntRect dirty = changed |
2910 | 0 | ? NPRectToIntRect(*changed) |
2911 | 0 | : IntRect(IntPoint(0, 0), bitmap->mSize); |
2912 | 0 |
|
2913 | 0 | // Need a holder since IPDL zaps the object for mysterious reasons. |
2914 | 0 | Shmem shmemHolder = bitmap->mShmem; |
2915 | 0 | SendShowDirectBitmap(shmemHolder, bitmap->mFormat, bitmap->mStride, bitmap->mSize, dirty); |
2916 | 0 | break; |
2917 | 0 | } |
2918 | | #if defined(XP_WIN) |
2919 | | case NPDrawingModelAsyncWindowsDXGISurface: { |
2920 | | WindowsHandle handle; |
2921 | | if (!mDxgiSurfaces.Get(surface, &handle)) { |
2922 | | return; |
2923 | | } |
2924 | | |
2925 | | IntRect dirty = changed |
2926 | | ? NPRectToIntRect(*changed) |
2927 | | : IntRect(IntPoint(0, 0), IntSize(surface->size.width, surface->size.height)); |
2928 | | |
2929 | | SendShowDirectDXGISurface(handle, dirty); |
2930 | | break; |
2931 | | } |
2932 | | #endif |
2933 | 0 | default: |
2934 | 0 | MOZ_ASSERT_UNREACHABLE("unknown drawing model"); |
2935 | 0 | } |
2936 | 0 | } |
2937 | | |
2938 | | void |
2939 | | PluginInstanceChild::DoAsyncRedraw() |
2940 | 0 | { |
2941 | 0 | { |
2942 | 0 | MutexAutoLock autoLock(mAsyncInvalidateMutex); |
2943 | 0 | mAsyncInvalidateTask = nullptr; |
2944 | 0 | } |
2945 | 0 |
|
2946 | 0 | SendRedrawPlugin(); |
2947 | 0 | } |
2948 | | |
2949 | | mozilla::ipc::IPCResult |
2950 | | PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType, |
2951 | | const NPRemoteWindow& aWindow) |
2952 | 0 | { |
2953 | 0 | AssertPluginThread(); |
2954 | 0 |
|
2955 | 0 | AutoStackHelper guard(this); |
2956 | 0 | NS_ASSERTION(!aWindow.window, "Remote window should be null."); |
2957 | 0 |
|
2958 | 0 | if (mCurrentAsyncSetWindowTask) { |
2959 | 0 | mCurrentAsyncSetWindowTask->Cancel(); |
2960 | 0 | mCurrentAsyncSetWindowTask = nullptr; |
2961 | 0 | } |
2962 | 0 |
|
2963 | 0 | // We shouldn't process this now because it may be received within a nested |
2964 | 0 | // RPC call, and both Flash and Java don't expect to receive setwindow calls |
2965 | 0 | // at arbitrary times. |
2966 | 0 | mCurrentAsyncSetWindowTask = |
2967 | 0 | NewNonOwningCancelableRunnableMethod<gfxSurfaceType, |
2968 | 0 | NPRemoteWindow, |
2969 | 0 | bool>( |
2970 | 0 | "plugins::PluginInstanceChild::DoAsyncSetWindow", |
2971 | 0 | this, |
2972 | 0 | &PluginInstanceChild::DoAsyncSetWindow, |
2973 | 0 | aSurfaceType, |
2974 | 0 | aWindow, |
2975 | 0 | true); |
2976 | 0 | RefPtr<Runnable> addrefedTask = mCurrentAsyncSetWindowTask; |
2977 | 0 | MessageLoop::current()->PostTask(addrefedTask.forget()); |
2978 | 0 |
|
2979 | 0 | return IPC_OK(); |
2980 | 0 | } |
2981 | | |
2982 | | void |
2983 | | PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType, |
2984 | | const NPRemoteWindow& aWindow, |
2985 | | bool aIsAsync) |
2986 | 0 | { |
2987 | 0 | PLUGIN_LOG_DEBUG( |
2988 | 0 | ("[InstanceChild][%p] AsyncSetWindow to <x=%d,y=%d, w=%d,h=%d>", |
2989 | 0 | this, aWindow.x, aWindow.y, aWindow.width, aWindow.height)); |
2990 | 0 |
|
2991 | 0 | AssertPluginThread(); |
2992 | 0 | NS_ASSERTION(!aWindow.window, "Remote window should be null."); |
2993 | 0 | NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!"); |
2994 | 0 |
|
2995 | 0 | if (aIsAsync) { |
2996 | 0 | if (!mCurrentAsyncSetWindowTask) { |
2997 | 0 | return; |
2998 | 0 | } |
2999 | 0 | mCurrentAsyncSetWindowTask = nullptr; |
3000 | 0 | } |
3001 | 0 |
|
3002 | 0 | mWindow.window = nullptr; |
3003 | 0 | if (mWindow.width != aWindow.width || mWindow.height != aWindow.height || |
3004 | 0 | mWindow.clipRect.top != aWindow.clipRect.top || |
3005 | 0 | mWindow.clipRect.left != aWindow.clipRect.left || |
3006 | 0 | mWindow.clipRect.bottom != aWindow.clipRect.bottom || |
3007 | 0 | mWindow.clipRect.right != aWindow.clipRect.right) |
3008 | 0 | mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height); |
3009 | 0 |
|
3010 | 0 | mWindow.x = aWindow.x; |
3011 | 0 | mWindow.y = aWindow.y; |
3012 | 0 | mWindow.width = aWindow.width; |
3013 | 0 | mWindow.height = aWindow.height; |
3014 | 0 | mWindow.clipRect = aWindow.clipRect; |
3015 | 0 | mWindow.type = aWindow.type; |
3016 | | #if defined(XP_MACOSX) || defined(XP_WIN) |
3017 | | mContentsScaleFactor = aWindow.contentsScaleFactor; |
3018 | | #endif |
3019 | |
|
3020 | 0 | mLayersRendering = true; |
3021 | 0 | mSurfaceType = aSurfaceType; |
3022 | 0 | UpdateWindowAttributes(true); |
3023 | 0 |
|
3024 | | #ifdef XP_WIN |
3025 | | if (GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) |
3026 | | SetupFlashMsgThrottle(); |
3027 | | #endif |
3028 | |
|
3029 | 0 | if (!mAccumulatedInvalidRect.IsEmpty()) { |
3030 | 0 | AsyncShowPluginFrame(); |
3031 | 0 | } |
3032 | 0 | } |
3033 | | |
3034 | | bool |
3035 | | PluginInstanceChild::CreateOptSurface(void) |
3036 | 0 | { |
3037 | 0 | MOZ_ASSERT(mSurfaceType != gfxSurfaceType::Max, |
3038 | 0 | "Need a valid surface type here"); |
3039 | 0 | NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync."); |
3040 | 0 |
|
3041 | 0 | // Use an opaque surface unless we're transparent and *don't* have |
3042 | 0 | // a background to source from. |
3043 | 0 | gfxImageFormat format = |
3044 | 0 | (mIsTransparent && !mBackground) ? SurfaceFormat::A8R8G8B8_UINT32 : |
3045 | 0 | SurfaceFormat::X8R8G8B8_UINT32; |
3046 | 0 |
|
3047 | 0 | #ifdef MOZ_X11 |
3048 | 0 | Display* dpy = mWsInfo.display; |
3049 | 0 | Screen* screen = DefaultScreenOfDisplay(dpy); |
3050 | 0 | if (format == SurfaceFormat::X8R8G8B8_UINT32 && |
3051 | 0 | DefaultDepth(dpy, DefaultScreen(dpy)) == 16) { |
3052 | 0 | format = SurfaceFormat::R5G6B5_UINT16; |
3053 | 0 | } |
3054 | 0 |
|
3055 | 0 | if (mSurfaceType == gfxSurfaceType::Xlib) { |
3056 | 0 | if (!mIsTransparent || mBackground) { |
3057 | 0 | Visual* defaultVisual = DefaultVisualOfScreen(screen); |
3058 | 0 | mCurrentSurface = |
3059 | 0 | gfxXlibSurface::Create(screen, defaultVisual, |
3060 | 0 | IntSize(mWindow.width, mWindow.height)); |
3061 | 0 | return mCurrentSurface != nullptr; |
3062 | 0 | } |
3063 | 0 | |
3064 | 0 | XRenderPictFormat* xfmt = XRenderFindStandardFormat(dpy, PictStandardARGB32); |
3065 | 0 | if (!xfmt) { |
3066 | 0 | NS_ERROR("Need X falback surface, but FindRenderFormat failed"); |
3067 | 0 | return false; |
3068 | 0 | } |
3069 | 0 | mCurrentSurface = |
3070 | 0 | gfxXlibSurface::Create(screen, xfmt, |
3071 | 0 | IntSize(mWindow.width, mWindow.height)); |
3072 | 0 | return mCurrentSurface != nullptr; |
3073 | 0 | } |
3074 | 0 | #endif |
3075 | 0 | |
3076 | | #ifdef XP_WIN |
3077 | | if (mSurfaceType == gfxSurfaceType::Win32) { |
3078 | | bool willHaveTransparentPixels = mIsTransparent && !mBackground; |
3079 | | |
3080 | | SharedDIBSurface* s = new SharedDIBSurface(); |
3081 | | if (!s->Create(reinterpret_cast<HDC>(mWindow.window), |
3082 | | mWindow.width, mWindow.height, |
3083 | | willHaveTransparentPixels)) |
3084 | | return false; |
3085 | | |
3086 | | mCurrentSurface = s; |
3087 | | return true; |
3088 | | } |
3089 | | |
3090 | | MOZ_CRASH("Shared-memory drawing not expected on Windows."); |
3091 | | #endif |
3092 | | |
3093 | 0 | // Make common shmem implementation working for any platform |
3094 | 0 | mCurrentSurface = |
3095 | 0 | gfxSharedImageSurface::CreateUnsafe(this, IntSize(mWindow.width, mWindow.height), format); |
3096 | 0 | return !!mCurrentSurface; |
3097 | 0 | } |
3098 | | |
3099 | | bool |
3100 | | PluginInstanceChild::MaybeCreatePlatformHelperSurface(void) |
3101 | 0 | { |
3102 | 0 | if (!mCurrentSurface) { |
3103 | 0 | NS_ERROR("Cannot create helper surface without mCurrentSurface"); |
3104 | 0 | return false; |
3105 | 0 | } |
3106 | 0 |
|
3107 | 0 | #ifdef MOZ_X11 |
3108 | 0 | bool supportNonDefaultVisual = false; |
3109 | 0 | Screen* screen = DefaultScreenOfDisplay(mWsInfo.display); |
3110 | 0 | Visual* defaultVisual = DefaultVisualOfScreen(screen); |
3111 | 0 | Visual* visual = nullptr; |
3112 | 0 | Colormap colormap = 0; |
3113 | 0 | mDoAlphaExtraction = false; |
3114 | 0 | bool createHelperSurface = false; |
3115 | 0 |
|
3116 | 0 | if (mCurrentSurface->GetType() == gfxSurfaceType::Xlib) { |
3117 | 0 | static_cast<gfxXlibSurface*>(mCurrentSurface.get())-> |
3118 | 0 | GetColormapAndVisual(&colormap, &visual); |
3119 | 0 | // Create helper surface if layer surface visual not same as default |
3120 | 0 | // and we don't support non-default visual rendering |
3121 | 0 | if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) { |
3122 | 0 | createHelperSurface = true; |
3123 | 0 | visual = defaultVisual; |
3124 | 0 | mDoAlphaExtraction = mIsTransparent; |
3125 | 0 | } |
3126 | 0 | } else if (mCurrentSurface->GetType() == gfxSurfaceType::Image) { |
3127 | 0 | // For image layer surface we should always create helper surface |
3128 | 0 | createHelperSurface = true; |
3129 | 0 | // Check if we can create helper surface with non-default visual |
3130 | 0 | visual = gfxXlibSurface::FindVisual(screen, |
3131 | 0 | static_cast<gfxImageSurface*>(mCurrentSurface.get())->Format()); |
3132 | 0 | if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) { |
3133 | 0 | visual = defaultVisual; |
3134 | 0 | mDoAlphaExtraction = mIsTransparent; |
3135 | 0 | } |
3136 | 0 | } |
3137 | 0 |
|
3138 | 0 | if (createHelperSurface) { |
3139 | 0 | if (!visual) { |
3140 | 0 | NS_ERROR("Need X falback surface, but visual failed"); |
3141 | 0 | return false; |
3142 | 0 | } |
3143 | 0 | mHelperSurface = |
3144 | 0 | gfxXlibSurface::Create(screen, visual, |
3145 | 0 | mCurrentSurface->GetSize()); |
3146 | 0 | if (!mHelperSurface) { |
3147 | 0 | NS_WARNING("Fail to create create helper surface"); |
3148 | 0 | return false; |
3149 | 0 | } |
3150 | 0 | } |
3151 | | #elif defined(XP_WIN) |
3152 | | mDoAlphaExtraction = mIsTransparent && !mBackground; |
3153 | | #endif |
3154 | | |
3155 | 0 | return true; |
3156 | 0 | } |
3157 | | |
3158 | | bool |
3159 | | PluginInstanceChild::EnsureCurrentBuffer(void) |
3160 | 0 | { |
3161 | 0 | #ifndef XP_DARWIN |
3162 | 0 | nsIntRect toInvalidate(0, 0, 0, 0); |
3163 | 0 | IntSize winSize = IntSize(mWindow.width, mWindow.height); |
3164 | 0 |
|
3165 | 0 | if (mBackground && mBackground->GetSize() != winSize) { |
3166 | 0 | // It would be nice to keep the old background here, but doing |
3167 | 0 | // so can lead to cases in which we permanently keep the old |
3168 | 0 | // background size. |
3169 | 0 | mBackground = nullptr; |
3170 | 0 | toInvalidate.UnionRect(toInvalidate, |
3171 | 0 | nsIntRect(0, 0, winSize.width, winSize.height)); |
3172 | 0 | } |
3173 | 0 |
|
3174 | 0 | if (mCurrentSurface) { |
3175 | 0 | IntSize surfSize = mCurrentSurface->GetSize(); |
3176 | 0 | if (winSize != surfSize || |
3177 | 0 | (mBackground && !CanPaintOnBackground()) || |
3178 | 0 | (mBackground && |
3179 | 0 | gfxContentType::COLOR != mCurrentSurface->GetContentType()) || |
3180 | 0 | (!mBackground && mIsTransparent && |
3181 | 0 | gfxContentType::COLOR == mCurrentSurface->GetContentType())) { |
3182 | 0 | // Don't try to use an old, invalid DC. |
3183 | 0 | mWindow.window = nullptr; |
3184 | 0 | ClearCurrentSurface(); |
3185 | 0 | toInvalidate.UnionRect(toInvalidate, |
3186 | 0 | nsIntRect(0, 0, winSize.width, winSize.height)); |
3187 | 0 | } |
3188 | 0 | } |
3189 | 0 |
|
3190 | 0 | mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate); |
3191 | 0 |
|
3192 | 0 | if (mCurrentSurface) { |
3193 | 0 | return true; |
3194 | 0 | } |
3195 | 0 | |
3196 | 0 | if (!CreateOptSurface()) { |
3197 | 0 | NS_ERROR("Cannot create optimized surface"); |
3198 | 0 | return false; |
3199 | 0 | } |
3200 | 0 |
|
3201 | 0 | if (!MaybeCreatePlatformHelperSurface()) { |
3202 | 0 | NS_ERROR("Cannot create helper surface"); |
3203 | 0 | return false; |
3204 | 0 | } |
3205 | | #elif defined(XP_MACOSX) |
3206 | | |
3207 | | if (!mDoubleBufferCARenderer.HasCALayer()) { |
3208 | | void *caLayer = nullptr; |
3209 | | if (mDrawingModel == NPDrawingModelCoreGraphics) { |
3210 | | if (!mCGLayer) { |
3211 | | caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, |
3212 | | this, |
3213 | | mContentsScaleFactor); |
3214 | | |
3215 | | if (!caLayer) { |
3216 | | PLUGIN_LOG_DEBUG(("GetCGLayer failed.")); |
3217 | | return false; |
3218 | | } |
3219 | | } |
3220 | | mCGLayer = caLayer; |
3221 | | } else { |
3222 | | NPError result = mPluginIface->getvalue(GetNPP(), |
3223 | | NPPVpluginCoreAnimationLayer, |
3224 | | &caLayer); |
3225 | | if (result != NPERR_NO_ERROR || !caLayer) { |
3226 | | PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not " |
3227 | | "provide CALayer.")); |
3228 | | return false; |
3229 | | } |
3230 | | } |
3231 | | mDoubleBufferCARenderer.SetCALayer(caLayer); |
3232 | | } |
3233 | | |
3234 | | if (mDoubleBufferCARenderer.HasFrontSurface() && |
3235 | | (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != mWindow.width || |
3236 | | mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height || |
3237 | | mDoubleBufferCARenderer.GetContentsScaleFactor() != mContentsScaleFactor)) { |
3238 | | mDoubleBufferCARenderer.ClearFrontSurface(); |
3239 | | } |
3240 | | |
3241 | | if (!mDoubleBufferCARenderer.HasFrontSurface()) { |
3242 | | bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface( |
3243 | | mWindow.width, mWindow.height, mContentsScaleFactor, |
3244 | | GetQuirks() & QUIRK_ALLOW_OFFLINE_RENDERER ? |
3245 | | ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER); |
3246 | | if (!allocSurface) { |
3247 | | PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface")); |
3248 | | return false; |
3249 | | } |
3250 | | |
3251 | | if (mPluginIface->setwindow) |
3252 | | (void) mPluginIface->setwindow(&mData, &mWindow); |
3253 | | |
3254 | | nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height); |
3255 | | mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate); |
3256 | | } |
3257 | | #endif |
3258 | | |
3259 | 0 | return true; |
3260 | 0 | } |
3261 | | |
3262 | | void |
3263 | | PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow) |
3264 | 0 | { |
3265 | 0 | #if defined(MOZ_X11) || defined(XP_WIN) |
3266 | 0 | RefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface; |
3267 | 0 | #endif // Only used within MOZ_X11 or XP_WIN blocks. Unused variable otherwise |
3268 | 0 | bool needWindowUpdate = aForceSetWindow; |
3269 | 0 | #ifdef MOZ_X11 |
3270 | 0 | Visual* visual = nullptr; |
3271 | 0 | Colormap colormap = 0; |
3272 | 0 | if (curSurface && curSurface->GetType() == gfxSurfaceType::Xlib) { |
3273 | 0 | static_cast<gfxXlibSurface*>(curSurface.get())-> |
3274 | 0 | GetColormapAndVisual(&colormap, &visual); |
3275 | 0 | if (visual != mWsInfo.visual || colormap != mWsInfo.colormap) { |
3276 | 0 | mWsInfo.visual = visual; |
3277 | 0 | mWsInfo.colormap = colormap; |
3278 | 0 | needWindowUpdate = true; |
3279 | 0 | } |
3280 | 0 | } |
3281 | 0 | #endif // MOZ_X11 |
3282 | | #ifdef XP_WIN |
3283 | | HDC dc = nullptr; |
3284 | | |
3285 | | if (curSurface) { |
3286 | | if (!SharedDIBSurface::IsSharedDIBSurface(curSurface)) |
3287 | | MOZ_CRASH("Expected SharedDIBSurface!"); |
3288 | | |
3289 | | SharedDIBSurface* dibsurf = static_cast<SharedDIBSurface*>(curSurface.get()); |
3290 | | dc = dibsurf->GetHDC(); |
3291 | | } |
3292 | | if (mWindow.window != dc) { |
3293 | | mWindow.window = dc; |
3294 | | needWindowUpdate = true; |
3295 | | } |
3296 | | #endif // XP_WIN |
3297 | |
|
3298 | 0 | if (!needWindowUpdate) { |
3299 | 0 | return; |
3300 | 0 | } |
3301 | 0 | |
3302 | 0 | #ifndef XP_MACOSX |
3303 | 0 | // Adjusting the window isn't needed for OSX |
3304 | 0 | #ifndef XP_WIN |
3305 | 0 | // On Windows, we translate the device context, in order for the window |
3306 | 0 | // origin to be correct. |
3307 | 0 | mWindow.x = mWindow.y = 0; |
3308 | 0 | #endif |
3309 | 0 |
|
3310 | 0 | if (IsVisible()) { |
3311 | 0 | // The clip rect is relative to drawable top-left. |
3312 | 0 | nsIntRect clipRect; |
3313 | 0 |
|
3314 | 0 | // Don't ask the plugin to draw outside the drawable. The clip rect |
3315 | 0 | // is in plugin coordinates, not window coordinates. |
3316 | 0 | // This also ensures that the unsigned clip rectangle offsets won't be -ve. |
3317 | 0 | clipRect.SetRect(0, 0, mWindow.width, mWindow.height); |
3318 | 0 |
|
3319 | 0 | mWindow.clipRect.left = 0; |
3320 | 0 | mWindow.clipRect.top = 0; |
3321 | 0 | mWindow.clipRect.right = clipRect.XMost(); |
3322 | 0 | mWindow.clipRect.bottom = clipRect.YMost(); |
3323 | 0 | } |
3324 | 0 | #endif // XP_MACOSX |
3325 | 0 |
|
3326 | | #ifdef XP_WIN |
3327 | | // Windowless plugins on Windows need a WM_WINDOWPOSCHANGED event to update |
3328 | | // their location... or at least Flash does: Silverlight uses the |
3329 | | // window.x/y passed to NPP_SetWindow |
3330 | | |
3331 | | if (mPluginIface->event) { |
3332 | | // width and height are stored as units, but narrow to ints here |
3333 | | MOZ_RELEASE_ASSERT(mWindow.width <= INT_MAX); |
3334 | | MOZ_RELEASE_ASSERT(mWindow.height <= INT_MAX); |
3335 | | |
3336 | | WINDOWPOS winpos = { |
3337 | | 0, 0, |
3338 | | mWindow.x, mWindow.y, |
3339 | | (int32_t)mWindow.width, (int32_t)mWindow.height, |
3340 | | 0 |
3341 | | }; |
3342 | | NPEvent pluginEvent = { |
3343 | | WM_WINDOWPOSCHANGED, 0, |
3344 | | (LPARAM) &winpos |
3345 | | }; |
3346 | | mPluginIface->event(&mData, &pluginEvent); |
3347 | | } |
3348 | | #endif |
3349 | |
|
3350 | 0 | PLUGIN_LOG_DEBUG( |
3351 | 0 | ("[InstanceChild][%p] UpdateWindow w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>", |
3352 | 0 | this, mWindow.x, mWindow.y, mWindow.width, mWindow.height, |
3353 | 0 | mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom)); |
3354 | 0 |
|
3355 | 0 | if (mPluginIface->setwindow) { |
3356 | 0 | mPluginIface->setwindow(&mData, &mWindow); |
3357 | 0 | } |
3358 | 0 | } |
3359 | | |
3360 | | void |
3361 | | PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect, |
3362 | | gfxASurface* aSurface) |
3363 | 0 | { |
3364 | 0 | UpdateWindowAttributes(); |
3365 | 0 |
|
3366 | 0 | // We should not send an async surface if we're using direct rendering. |
3367 | 0 | MOZ_ASSERT(!IsUsingDirectDrawing()); |
3368 | 0 |
|
3369 | 0 | #ifdef MOZ_X11 |
3370 | 0 | { |
3371 | 0 | NS_ASSERTION(aSurface->GetType() == gfxSurfaceType::Xlib, |
3372 | 0 | "Non supported platform surface type"); |
3373 | 0 |
|
3374 | 0 | NPEvent pluginEvent; |
3375 | 0 | XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose; |
3376 | 0 | exposeEvent.type = GraphicsExpose; |
3377 | 0 | exposeEvent.display = mWsInfo.display; |
3378 | 0 | exposeEvent.drawable = static_cast<gfxXlibSurface*>(aSurface)->XDrawable(); |
3379 | 0 | exposeEvent.x = aRect.x; |
3380 | 0 | exposeEvent.y = aRect.y; |
3381 | 0 | exposeEvent.width = aRect.width; |
3382 | 0 | exposeEvent.height = aRect.height; |
3383 | 0 | exposeEvent.count = 0; |
3384 | 0 | // information not set: |
3385 | 0 | exposeEvent.serial = 0; |
3386 | 0 | exposeEvent.send_event = False; |
3387 | 0 | exposeEvent.major_code = 0; |
3388 | 0 | exposeEvent.minor_code = 0; |
3389 | 0 | mPluginIface->event(&mData, reinterpret_cast<void*>(&exposeEvent)); |
3390 | 0 | } |
3391 | | #elif defined(XP_WIN) |
3392 | | NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(aSurface), |
3393 | | "Expected (SharedDIB) image surface."); |
3394 | | |
3395 | | // This rect is in the window coordinate space. aRect is in the plugin |
3396 | | // coordinate space. |
3397 | | RECT rect = { |
3398 | | mWindow.x + aRect.x, |
3399 | | mWindow.y + aRect.y, |
3400 | | mWindow.x + aRect.XMost(), |
3401 | | mWindow.y + aRect.YMost() |
3402 | | }; |
3403 | | NPEvent paintEvent = { |
3404 | | WM_PAINT, |
3405 | | uintptr_t(mWindow.window), |
3406 | | intptr_t(&rect) |
3407 | | }; |
3408 | | |
3409 | | ::SetViewportOrgEx((HDC) mWindow.window, -mWindow.x, -mWindow.y, nullptr); |
3410 | | ::SelectClipRgn((HDC) mWindow.window, nullptr); |
3411 | | ::IntersectClipRect((HDC) mWindow.window, rect.left, rect.top, rect.right, rect.bottom); |
3412 | | mPluginIface->event(&mData, reinterpret_cast<void*>(&paintEvent)); |
3413 | | #else |
3414 | | MOZ_CRASH("Surface type not implemented."); |
3415 | | #endif |
3416 | | } |
3417 | | |
3418 | | void |
3419 | | PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect, |
3420 | | gfxASurface* aSurface, |
3421 | | const Color& aColor) |
3422 | 0 | { |
3423 | 0 | // Render using temporary X surface, with copy to image surface |
3424 | 0 | nsIntRect plPaintRect(aRect); |
3425 | 0 | RefPtr<gfxASurface> renderSurface = aSurface; |
3426 | 0 | #ifdef MOZ_X11 |
3427 | 0 | if (mIsTransparent && (GetQuirks() & QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) { |
3428 | 0 | // Work around a bug in Flash up to 10.1 d51 at least, where expose event |
3429 | 0 | // top left coordinates within the plugin-rect and not at the drawable |
3430 | 0 | // origin are misinterpreted. (We can move the top left coordinate |
3431 | 0 | // provided it is within the clipRect.), see bug 574583 |
3432 | 0 | plPaintRect.SetRect(0, 0, aRect.XMost(), aRect.YMost()); |
3433 | 0 | } |
3434 | 0 | if (mHelperSurface) { |
3435 | 0 | // On X11 we can paint to non Xlib surface only with HelperSurface |
3436 | 0 | renderSurface = mHelperSurface; |
3437 | 0 | } |
3438 | 0 | #endif |
3439 | 0 |
|
3440 | 0 | if (mIsTransparent && !CanPaintOnBackground()) { |
3441 | 0 | RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(renderSurface); |
3442 | 0 | gfx::Rect rect(plPaintRect.x, plPaintRect.y, |
3443 | 0 | plPaintRect.width, plPaintRect.height); |
3444 | 0 | // Moz2D treats OP_SOURCE operations as unbounded, so we need to |
3445 | 0 | // clip to the rect that we want to fill: |
3446 | 0 | dt->PushClipRect(rect); |
3447 | 0 | dt->FillRect(rect, ColorPattern(aColor), // aColor is already a device color |
3448 | 0 | DrawOptions(1.f, CompositionOp::OP_SOURCE)); |
3449 | 0 | dt->PopClip(); |
3450 | 0 | dt->Flush(); |
3451 | 0 | } |
3452 | 0 |
|
3453 | 0 | PaintRectToPlatformSurface(plPaintRect, renderSurface); |
3454 | 0 |
|
3455 | 0 | if (renderSurface != aSurface) { |
3456 | 0 | RefPtr<DrawTarget> dt; |
3457 | 0 | if (aSurface == mCurrentSurface && |
3458 | 0 | aSurface->GetType() == gfxSurfaceType::Image && |
3459 | 0 | aSurface->GetSurfaceFormat() == SurfaceFormat::B8G8R8X8) { |
3460 | 0 | gfxImageSurface* imageSurface = static_cast<gfxImageSurface*>(aSurface); |
3461 | 0 | // Bug 1196927 - Reinterpret target surface as BGRA to fill alpha with opaque. |
3462 | 0 | // Certain backends (i.e. Skia) may not truly support BGRX formats, so they must |
3463 | 0 | // be emulated by filling the alpha channel opaque as if it was BGRA data. Cairo |
3464 | 0 | // leaves the alpha zeroed out for BGRX, so we cause Cairo to fill it as opaque |
3465 | 0 | // by handling the copy target as a BGRA surface. |
3466 | 0 | dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, |
3467 | 0 | imageSurface->Data(), |
3468 | 0 | imageSurface->GetSize(), |
3469 | 0 | imageSurface->Stride(), |
3470 | 0 | SurfaceFormat::B8G8R8A8); |
3471 | 0 | } else { |
3472 | 0 | // Copy helper surface content to target |
3473 | 0 | dt = CreateDrawTargetForSurface(aSurface); |
3474 | 0 | } |
3475 | 0 | if (dt && dt->IsValid()) { |
3476 | 0 | RefPtr<SourceSurface> surface = |
3477 | 0 | gfxPlatform::GetSourceSurfaceForSurface(dt, renderSurface); |
3478 | 0 | dt->CopySurface(surface, aRect, aRect.TopLeft()); |
3479 | 0 | } else { |
3480 | 0 | gfxWarning() << "PluginInstanceChild::PaintRectToSurface failure"; |
3481 | 0 | } |
3482 | 0 | } |
3483 | 0 | } |
3484 | | |
3485 | | void |
3486 | | PluginInstanceChild::PaintRectWithAlphaExtraction(const nsIntRect& aRect, |
3487 | | gfxASurface* aSurface) |
3488 | 0 | { |
3489 | 0 | MOZ_ASSERT(aSurface->GetContentType() == gfxContentType::COLOR_ALPHA, |
3490 | 0 | "Refusing to pointlessly recover alpha"); |
3491 | 0 |
|
3492 | 0 | nsIntRect rect(aRect); |
3493 | 0 | // If |aSurface| can be used to paint and can have alpha values |
3494 | 0 | // recovered directly to it, do that to save a tmp surface and |
3495 | 0 | // copy. |
3496 | 0 | bool useSurfaceSubimageForBlack = false; |
3497 | 0 | if (gfxSurfaceType::Image == aSurface->GetType()) { |
3498 | 0 | gfxImageSurface* surfaceAsImage = |
3499 | 0 | static_cast<gfxImageSurface*>(aSurface); |
3500 | 0 | useSurfaceSubimageForBlack = |
3501 | 0 | (surfaceAsImage->Format() == SurfaceFormat::A8R8G8B8_UINT32); |
3502 | 0 | // If we're going to use a subimage, nudge the rect so that we |
3503 | 0 | // can use optimal alpha recovery. If we're not using a |
3504 | 0 | // subimage, the temporaries should automatically get |
3505 | 0 | // fast-path alpha recovery so we don't need to do anything. |
3506 | 0 | if (useSurfaceSubimageForBlack) { |
3507 | 0 | rect = |
3508 | 0 | gfxAlphaRecovery::AlignRectForSubimageRecovery(aRect, |
3509 | 0 | surfaceAsImage); |
3510 | 0 | } |
3511 | 0 | } |
3512 | 0 |
|
3513 | 0 | RefPtr<gfxImageSurface> whiteImage; |
3514 | 0 | RefPtr<gfxImageSurface> blackImage; |
3515 | 0 | gfxRect targetRect(rect.x, rect.y, rect.width, rect.height); |
3516 | 0 | IntSize targetSize(rect.width, rect.height); |
3517 | 0 | gfxPoint deviceOffset = -targetRect.TopLeft(); |
3518 | 0 |
|
3519 | 0 | // We always use a temporary "white image" |
3520 | 0 | whiteImage = new gfxImageSurface(targetSize, SurfaceFormat::X8R8G8B8_UINT32); |
3521 | 0 | if (whiteImage->CairoStatus()) { |
3522 | 0 | return; |
3523 | 0 | } |
3524 | 0 | |
3525 | | #ifdef XP_WIN |
3526 | | // On windows, we need an HDC and so can't paint directly to |
3527 | | // vanilla image surfaces. Bifurcate this painting code so that |
3528 | | // we don't accidentally attempt that. |
3529 | | if (!SharedDIBSurface::IsSharedDIBSurface(aSurface)) |
3530 | | MOZ_CRASH("Expected SharedDIBSurface!"); |
3531 | | |
3532 | | // Paint the plugin directly onto the target, with a white |
3533 | | // background and copy the result |
3534 | | PaintRectToSurface(rect, aSurface, Color(1.f, 1.f, 1.f)); |
3535 | | { |
3536 | | RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(whiteImage); |
3537 | | RefPtr<SourceSurface> surface = |
3538 | | gfxPlatform::GetSourceSurfaceForSurface(dt, aSurface); |
3539 | | dt->CopySurface(surface, rect, IntPoint()); |
3540 | | } |
3541 | | |
3542 | | // Paint the plugin directly onto the target, with a black |
3543 | | // background |
3544 | | PaintRectToSurface(rect, aSurface, Color(0.f, 0.f, 0.f)); |
3545 | | |
3546 | | // Don't copy the result, just extract a subimage so that we can |
3547 | | // recover alpha directly into the target |
3548 | | gfxImageSurface *image = static_cast<gfxImageSurface*>(aSurface); |
3549 | | blackImage = image->GetSubimage(targetRect); |
3550 | | |
3551 | | #else |
3552 | | // Paint onto white background |
3553 | 0 | whiteImage->SetDeviceOffset(deviceOffset); |
3554 | 0 | PaintRectToSurface(rect, whiteImage, Color(1.f, 1.f, 1.f)); |
3555 | 0 |
|
3556 | 0 | if (useSurfaceSubimageForBlack) { |
3557 | 0 | gfxImageSurface *surface = static_cast<gfxImageSurface*>(aSurface); |
3558 | 0 | blackImage = surface->GetSubimage(targetRect); |
3559 | 0 | } else { |
3560 | 0 | blackImage = new gfxImageSurface(targetSize, |
3561 | 0 | SurfaceFormat::A8R8G8B8_UINT32); |
3562 | 0 | } |
3563 | 0 |
|
3564 | 0 | // Paint onto black background |
3565 | 0 | blackImage->SetDeviceOffset(deviceOffset); |
3566 | 0 | PaintRectToSurface(rect, blackImage, Color(0.f, 0.f, 0.f)); |
3567 | 0 | #endif |
3568 | 0 |
|
3569 | 0 | MOZ_ASSERT(whiteImage && blackImage, "Didn't paint enough!"); |
3570 | 0 |
|
3571 | 0 | // Extract alpha from black and white image and store to black |
3572 | 0 | // image |
3573 | 0 | if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) { |
3574 | 0 | return; |
3575 | 0 | } |
3576 | 0 | |
3577 | 0 | // If we had to use a temporary black surface, copy the pixels |
3578 | 0 | // with alpha back to the target |
3579 | 0 | if (!useSurfaceSubimageForBlack) { |
3580 | 0 | RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(aSurface); |
3581 | 0 | RefPtr<SourceSurface> surface = |
3582 | 0 | gfxPlatform::GetSourceSurfaceForSurface(dt, blackImage); |
3583 | 0 | dt->CopySurface(surface, |
3584 | 0 | IntRect(0, 0, rect.width, rect.height), |
3585 | 0 | rect.TopLeft()); |
3586 | 0 | } |
3587 | 0 | } |
3588 | | |
3589 | | bool |
3590 | | PluginInstanceChild::CanPaintOnBackground() |
3591 | 0 | { |
3592 | 0 | return (mBackground && |
3593 | 0 | mCurrentSurface && |
3594 | 0 | mCurrentSurface->GetSize() == mBackground->GetSize()); |
3595 | 0 | } |
3596 | | |
3597 | | bool |
3598 | | PluginInstanceChild::ShowPluginFrame() |
3599 | 0 | { |
3600 | 0 | // mLayersRendering can be false if we somehow get here without |
3601 | 0 | // receiving AsyncSetWindow() first. mPendingPluginCall is our |
3602 | 0 | // re-entrancy guard; we can't paint while nested inside another |
3603 | 0 | // paint. |
3604 | 0 | if (!mLayersRendering || mPendingPluginCall) { |
3605 | 0 | return false; |
3606 | 0 | } |
3607 | 0 | |
3608 | 0 | // We should not attempt to asynchronously show the plugin if we're using |
3609 | 0 | // direct rendering. |
3610 | 0 | MOZ_ASSERT(!IsUsingDirectDrawing()); |
3611 | 0 |
|
3612 | 0 | AutoRestore<bool> pending(mPendingPluginCall); |
3613 | 0 | mPendingPluginCall = true; |
3614 | 0 |
|
3615 | 0 | bool temporarilyMakeVisible = !IsVisible() && !mHasPainted; |
3616 | 0 | if (temporarilyMakeVisible && mWindow.width && mWindow.height) { |
3617 | 0 | mWindow.clipRect.right = mWindow.width; |
3618 | 0 | mWindow.clipRect.bottom = mWindow.height; |
3619 | 0 | } else if (!IsVisible()) { |
3620 | 0 | // If we're not visible, don't bother painting a <0,0,0,0> |
3621 | 0 | // rect. If we're eventually made visible, the visibility |
3622 | 0 | // change will invalidate our window. |
3623 | 0 | ClearCurrentSurface(); |
3624 | 0 | return true; |
3625 | 0 | } |
3626 | 0 | |
3627 | 0 | if (!EnsureCurrentBuffer()) { |
3628 | 0 | return false; |
3629 | 0 | } |
3630 | 0 | |
3631 | | #ifdef MOZ_WIDGET_COCOA |
3632 | | // We can't use the thebes code with CoreAnimation so we will |
3633 | | // take a different code path. |
3634 | | if (mDrawingModel == NPDrawingModelCoreAnimation || |
3635 | | mDrawingModel == NPDrawingModelInvalidatingCoreAnimation || |
3636 | | mDrawingModel == NPDrawingModelCoreGraphics) { |
3637 | | |
3638 | | if (!IsVisible()) { |
3639 | | return true; |
3640 | | } |
3641 | | |
3642 | | if (!mDoubleBufferCARenderer.HasFrontSurface()) { |
3643 | | NS_ERROR("CARenderer not initialized for rendering"); |
3644 | | return false; |
3645 | | } |
3646 | | |
3647 | | // Clear accRect here to be able to pass |
3648 | | // test_invalidate_during_plugin_paint test |
3649 | | nsIntRect rect = mAccumulatedInvalidRect; |
3650 | | mAccumulatedInvalidRect.SetEmpty(); |
3651 | | |
3652 | | // Fix up old invalidations that might have been made when our |
3653 | | // surface was a different size |
3654 | | rect.IntersectRect(rect, |
3655 | | nsIntRect(0, 0, |
3656 | | mDoubleBufferCARenderer.GetFrontSurfaceWidth(), |
3657 | | mDoubleBufferCARenderer.GetFrontSurfaceHeight())); |
3658 | | |
3659 | | if (mDrawingModel == NPDrawingModelCoreGraphics) { |
3660 | | mozilla::plugins::PluginUtilsOSX::Repaint(mCGLayer, rect); |
3661 | | } |
3662 | | |
3663 | | mDoubleBufferCARenderer.Render(); |
3664 | | |
3665 | | NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x, |
3666 | | (uint16_t)rect.YMost(), (uint16_t)rect.XMost() }; |
3667 | | SurfaceDescriptor currSurf; |
3668 | | currSurf = IOSurfaceDescriptor(mDoubleBufferCARenderer.GetFrontSurfaceID(), |
3669 | | mDoubleBufferCARenderer.GetContentsScaleFactor()); |
3670 | | |
3671 | | mHasPainted = true; |
3672 | | |
3673 | | SurfaceDescriptor returnSurf; |
3674 | | |
3675 | | if (!SendShow(r, currSurf, &returnSurf)) { |
3676 | | return false; |
3677 | | } |
3678 | | |
3679 | | SwapSurfaces(); |
3680 | | return true; |
3681 | | } else { |
3682 | | NS_ERROR("Unsupported drawing model for async layer rendering"); |
3683 | | return false; |
3684 | | } |
3685 | | #endif |
3686 | | |
3687 | 0 | NS_ASSERTION(mWindow.width == uint32_t(mWindow.clipRect.right - mWindow.clipRect.left) && |
3688 | 0 | mWindow.height == uint32_t(mWindow.clipRect.bottom - mWindow.clipRect.top), |
3689 | 0 | "Clip rect should be same size as window when using layers"); |
3690 | 0 |
|
3691 | 0 | // Clear accRect here to be able to pass |
3692 | 0 | // test_invalidate_during_plugin_paint test |
3693 | 0 | nsIntRect rect = mAccumulatedInvalidRect; |
3694 | 0 | mAccumulatedInvalidRect.SetEmpty(); |
3695 | 0 |
|
3696 | 0 | // Fix up old invalidations that might have been made when our |
3697 | 0 | // surface was a different size |
3698 | 0 | IntSize surfaceSize = mCurrentSurface->GetSize(); |
3699 | 0 | rect.IntersectRect(rect, |
3700 | 0 | nsIntRect(0, 0, surfaceSize.width, surfaceSize.height)); |
3701 | 0 |
|
3702 | 0 | if (!ReadbackDifferenceRect(rect)) { |
3703 | 0 | // We couldn't read back the pixels that differ between the |
3704 | 0 | // current surface and last, so we have to invalidate the |
3705 | 0 | // entire window. |
3706 | 0 | rect.SetRect(0, 0, mWindow.width, mWindow.height); |
3707 | 0 | } |
3708 | 0 |
|
3709 | 0 | bool haveTransparentPixels = |
3710 | 0 | gfxContentType::COLOR_ALPHA == mCurrentSurface->GetContentType(); |
3711 | 0 | PLUGIN_LOG_DEBUG( |
3712 | 0 | ("[InstanceChild][%p] Painting%s <x=%d,y=%d, w=%d,h=%d> on surface <w=%d,h=%d>", |
3713 | 0 | this, haveTransparentPixels ? " with alpha" : "", |
3714 | 0 | rect.x, rect.y, rect.width, rect.height, |
3715 | 0 | mCurrentSurface->GetSize().width, mCurrentSurface->GetSize().height)); |
3716 | 0 |
|
3717 | 0 | if (CanPaintOnBackground()) { |
3718 | 0 | PLUGIN_LOG_DEBUG((" (on background)")); |
3719 | 0 | // Source the background pixels ... |
3720 | 0 | { |
3721 | 0 | RefPtr<gfxASurface> surface = |
3722 | 0 | mHelperSurface ? mHelperSurface : mCurrentSurface; |
3723 | 0 | RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(surface); |
3724 | 0 | RefPtr<SourceSurface> backgroundSurface = |
3725 | 0 | gfxPlatform::GetSourceSurfaceForSurface(dt, mBackground); |
3726 | 0 | dt->CopySurface(backgroundSurface, rect, rect.TopLeft()); |
3727 | 0 | } |
3728 | 0 | // ... and hand off to the plugin |
3729 | 0 | // BEWARE: mBackground may die during this call |
3730 | 0 | PaintRectToSurface(rect, mCurrentSurface, Color()); |
3731 | 0 | } else if (!temporarilyMakeVisible && mDoAlphaExtraction) { |
3732 | 0 | // We don't want to pay the expense of alpha extraction for |
3733 | 0 | // phony paints. |
3734 | 0 | PLUGIN_LOG_DEBUG((" (with alpha recovery)")); |
3735 | 0 | PaintRectWithAlphaExtraction(rect, mCurrentSurface); |
3736 | 0 | } else { |
3737 | 0 | PLUGIN_LOG_DEBUG((" (onto opaque surface)")); |
3738 | 0 |
|
3739 | 0 | // If we're on a platform that needs helper surfaces for |
3740 | 0 | // plugins, and we're forcing a throwaway paint of a |
3741 | 0 | // wmode=transparent plugin, then make sure to use the helper |
3742 | 0 | // surface here. |
3743 | 0 | RefPtr<gfxASurface> target = |
3744 | 0 | (temporarilyMakeVisible && mHelperSurface) ? |
3745 | 0 | mHelperSurface : mCurrentSurface; |
3746 | 0 |
|
3747 | 0 | PaintRectToSurface(rect, target, Color()); |
3748 | 0 | } |
3749 | 0 | mHasPainted = true; |
3750 | 0 |
|
3751 | 0 | if (temporarilyMakeVisible) { |
3752 | 0 | mWindow.clipRect.right = mWindow.clipRect.bottom = 0; |
3753 | 0 |
|
3754 | 0 | PLUGIN_LOG_DEBUG( |
3755 | 0 | ("[InstanceChild][%p] Undoing temporary clipping w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>", |
3756 | 0 | this, mWindow.x, mWindow.y, mWindow.width, mWindow.height, |
3757 | 0 | mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom)); |
3758 | 0 |
|
3759 | 0 | if (mPluginIface->setwindow) { |
3760 | 0 | mPluginIface->setwindow(&mData, &mWindow); |
3761 | 0 | } |
3762 | 0 |
|
3763 | 0 | // Skip forwarding the results of the phony paint to the |
3764 | 0 | // browser. We may have painted a transparent plugin using |
3765 | 0 | // the opaque-plugin path, which can result in wrong pixels. |
3766 | 0 | // We also don't want to pay the expense of forwarding the |
3767 | 0 | // surface for plugins that might really be invisible. |
3768 | 0 | mAccumulatedInvalidRect.SetRect(0, 0, mWindow.width, mWindow.height); |
3769 | 0 | return true; |
3770 | 0 | } |
3771 | 0 |
|
3772 | 0 | NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x, |
3773 | 0 | (uint16_t)rect.YMost(), (uint16_t)rect.XMost() }; |
3774 | 0 | SurfaceDescriptor currSurf; |
3775 | 0 | #ifdef MOZ_X11 |
3776 | 0 | if (mCurrentSurface->GetType() == gfxSurfaceType::Xlib) { |
3777 | 0 | gfxXlibSurface *xsurf = static_cast<gfxXlibSurface*>(mCurrentSurface.get()); |
3778 | 0 | currSurf = SurfaceDescriptorX11(xsurf); |
3779 | 0 | // Need to sync all pending x-paint requests |
3780 | 0 | // before giving drawable to another process |
3781 | 0 | XSync(mWsInfo.display, False); |
3782 | 0 | } else |
3783 | 0 | #endif |
3784 | | #ifdef XP_WIN |
3785 | | if (SharedDIBSurface::IsSharedDIBSurface(mCurrentSurface)) { |
3786 | | SharedDIBSurface* s = static_cast<SharedDIBSurface*>(mCurrentSurface.get()); |
3787 | | if (!mCurrentSurfaceActor) { |
3788 | | base::SharedMemoryHandle handle = nullptr; |
3789 | | s->ShareToProcess(OtherPid(), &handle); |
3790 | | |
3791 | | mCurrentSurfaceActor = |
3792 | | SendPPluginSurfaceConstructor(handle, |
3793 | | mCurrentSurface->GetSize(), |
3794 | | haveTransparentPixels); |
3795 | | } |
3796 | | currSurf = mCurrentSurfaceActor; |
3797 | | s->Flush(); |
3798 | | } else |
3799 | | #endif |
3800 | 0 | if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) { |
3801 | 0 | currSurf = static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem(); |
3802 | 0 | } else { |
3803 | 0 | MOZ_CRASH("Surface type is not remotable"); |
3804 | 0 | return false; |
3805 | 0 | } |
3806 | 0 | |
3807 | 0 | // Unused, except to possibly return a shmem to us |
3808 | 0 | SurfaceDescriptor returnSurf; |
3809 | 0 |
|
3810 | 0 | if (!SendShow(r, currSurf, &returnSurf)) { |
3811 | 0 | return false; |
3812 | 0 | } |
3813 | 0 | |
3814 | 0 | SwapSurfaces(); |
3815 | 0 | mSurfaceDifferenceRect = rect; |
3816 | 0 | return true; |
3817 | 0 | } |
3818 | | |
3819 | | bool |
3820 | | PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect) |
3821 | 0 | { |
3822 | 0 | if (!mBackSurface) |
3823 | 0 | return false; |
3824 | 0 | |
3825 | 0 | // We can read safely from XSurface,SharedDIBSurface and Unsafe SharedMemory, |
3826 | 0 | // because PluginHost is not able to modify that surface |
3827 | 0 | #if defined(MOZ_X11) |
3828 | 0 | if (mBackSurface->GetType() != gfxSurfaceType::Xlib && |
3829 | 0 | !gfxSharedImageSurface::IsSharedImage(mBackSurface)) |
3830 | 0 | return false; |
3831 | | #elif defined(XP_WIN) |
3832 | | if (!SharedDIBSurface::IsSharedDIBSurface(mBackSurface)) |
3833 | | return false; |
3834 | | #endif |
3835 | | |
3836 | 0 | #if defined(MOZ_X11) || defined(XP_WIN) |
3837 | 0 | if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType()) |
3838 | 0 | return false; |
3839 | 0 | |
3840 | 0 | if (mSurfaceDifferenceRect.IsEmpty()) |
3841 | 0 | return true; |
3842 | 0 | |
3843 | 0 | PLUGIN_LOG_DEBUG( |
3844 | 0 | ("[InstanceChild][%p] Reading back part of <x=%d,y=%d, w=%d,h=%d>", |
3845 | 0 | this, mSurfaceDifferenceRect.x, mSurfaceDifferenceRect.y, |
3846 | 0 | mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height)); |
3847 | 0 |
|
3848 | 0 | // Read back previous content |
3849 | 0 | RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(mCurrentSurface); |
3850 | 0 | RefPtr<SourceSurface> source = |
3851 | 0 | gfxPlatform::GetSourceSurfaceForSurface(dt, mBackSurface); |
3852 | 0 | // Subtract from mSurfaceDifferenceRect area which is overlapping with rect |
3853 | 0 | nsIntRegion result; |
3854 | 0 | result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect)); |
3855 | 0 | for (auto iter = result.RectIter(); !iter.Done(); iter.Next()) { |
3856 | 0 | const nsIntRect& r = iter.Get(); |
3857 | 0 | dt->CopySurface(source, r, r.TopLeft()); |
3858 | 0 | } |
3859 | 0 |
|
3860 | 0 | return true; |
3861 | | #else |
3862 | | return false; |
3863 | | #endif |
3864 | | } |
3865 | | |
3866 | | void |
3867 | | PluginInstanceChild::InvalidateRectDelayed(void) |
3868 | 0 | { |
3869 | 0 | if (!mCurrentInvalidateTask) { |
3870 | 0 | return; |
3871 | 0 | } |
3872 | 0 | |
3873 | 0 | mCurrentInvalidateTask = nullptr; |
3874 | 0 |
|
3875 | 0 | // When this method is run asynchronously, we can end up switching to |
3876 | 0 | // direct drawing before while we wait to run. In that case, bail. |
3877 | 0 | if (IsUsingDirectDrawing()) { |
3878 | 0 | return; |
3879 | 0 | } |
3880 | 0 | |
3881 | 0 | if (mAccumulatedInvalidRect.IsEmpty()) { |
3882 | 0 | return; |
3883 | 0 | } |
3884 | 0 | |
3885 | 0 | if (!ShowPluginFrame()) { |
3886 | 0 | AsyncShowPluginFrame(); |
3887 | 0 | } |
3888 | 0 | } |
3889 | | |
3890 | | void |
3891 | | PluginInstanceChild::AsyncShowPluginFrame(void) |
3892 | 0 | { |
3893 | 0 | if (mCurrentInvalidateTask) { |
3894 | 0 | return; |
3895 | 0 | } |
3896 | 0 | |
3897 | 0 | // When the plugin is using direct surfaces to draw, it is not driving |
3898 | 0 | // paints via paint events - it will drive painting via its own events |
3899 | 0 | // and/or DidComposite callbacks. |
3900 | 0 | if (IsUsingDirectDrawing()) { |
3901 | 0 | return; |
3902 | 0 | } |
3903 | 0 | |
3904 | 0 | mCurrentInvalidateTask = NewNonOwningCancelableRunnableMethod( |
3905 | 0 | "plugins::PluginInstanceChild::InvalidateRectDelayed", |
3906 | 0 | this, |
3907 | 0 | &PluginInstanceChild::InvalidateRectDelayed); |
3908 | 0 | RefPtr<Runnable> addrefedTask = mCurrentInvalidateTask; |
3909 | 0 | MessageLoop::current()->PostTask(addrefedTask.forget()); |
3910 | 0 | } |
3911 | | |
3912 | | void |
3913 | | PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect) |
3914 | 0 | { |
3915 | 0 | NS_ASSERTION(aInvalidRect, "Null pointer!"); |
3916 | 0 |
|
3917 | | #ifdef OS_WIN |
3918 | | // Invalidate and draw locally for windowed plugins. |
3919 | | if (mWindow.type == NPWindowTypeWindow) { |
3920 | | NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!"); |
3921 | | RECT rect = { aInvalidRect->left, aInvalidRect->top, |
3922 | | aInvalidRect->right, aInvalidRect->bottom }; |
3923 | | ::InvalidateRect(mPluginWindowHWND, &rect, FALSE); |
3924 | | return; |
3925 | | } |
3926 | | #endif |
3927 | |
|
3928 | 0 | if (IsUsingDirectDrawing()) { |
3929 | 0 | NS_ASSERTION(false, "Should not call InvalidateRect() in direct surface mode!"); |
3930 | 0 | return; |
3931 | 0 | } |
3932 | 0 |
|
3933 | 0 | if (mLayersRendering) { |
3934 | 0 | nsIntRect r(aInvalidRect->left, aInvalidRect->top, |
3935 | 0 | aInvalidRect->right - aInvalidRect->left, |
3936 | 0 | aInvalidRect->bottom - aInvalidRect->top); |
3937 | 0 |
|
3938 | 0 | mAccumulatedInvalidRect.UnionRect(r, mAccumulatedInvalidRect); |
3939 | 0 | // If we are able to paint and invalidate sent, then reset |
3940 | 0 | // accumulated rectangle |
3941 | 0 | AsyncShowPluginFrame(); |
3942 | 0 | return; |
3943 | 0 | } |
3944 | 0 | |
3945 | 0 | // If we were going to use layers rendering but it's not set up |
3946 | 0 | // yet, and the plugin happens to call this first, we'll forward |
3947 | 0 | // the invalidation to the browser. It's unclear whether |
3948 | 0 | // non-layers plugins need this rect forwarded when their window |
3949 | 0 | // width or height is 0, which it would be for layers plugins |
3950 | 0 | // before their first SetWindow(). |
3951 | 0 | SendNPN_InvalidateRect(*aInvalidRect); |
3952 | 0 | } |
3953 | | |
3954 | | mozilla::ipc::IPCResult |
3955 | | PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground, |
3956 | | const nsIntRect& aRect) |
3957 | 0 | { |
3958 | 0 | MOZ_ASSERT(mIsTransparent, "Only transparent plugins use backgrounds"); |
3959 | 0 |
|
3960 | 0 | if (!mBackground) { |
3961 | 0 | // XXX refactor me |
3962 | 0 | switch (aBackground.type()) { |
3963 | 0 | #ifdef MOZ_X11 |
3964 | 0 | case SurfaceDescriptor::TSurfaceDescriptorX11: { |
3965 | 0 | mBackground = aBackground.get_SurfaceDescriptorX11().OpenForeign(); |
3966 | 0 | break; |
3967 | 0 | } |
3968 | 0 | #endif |
3969 | 0 | case SurfaceDescriptor::TShmem: { |
3970 | 0 | mBackground = gfxSharedImageSurface::Open(aBackground.get_Shmem()); |
3971 | 0 | break; |
3972 | 0 | } |
3973 | 0 | default: |
3974 | 0 | MOZ_CRASH("Unexpected background surface descriptor"); |
3975 | 0 | } |
3976 | 0 |
|
3977 | 0 | if (!mBackground) { |
3978 | 0 | return IPC_FAIL_NO_REASON(this); |
3979 | 0 | } |
3980 | 0 |
|
3981 | 0 | IntSize bgSize = mBackground->GetSize(); |
3982 | 0 | mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, |
3983 | 0 | nsIntRect(0, 0, bgSize.width, bgSize.height)); |
3984 | 0 | AsyncShowPluginFrame(); |
3985 | 0 | return IPC_OK(); |
3986 | 0 | } |
3987 | 0 |
|
3988 | 0 | // XXX refactor me |
3989 | 0 | mAccumulatedInvalidRect.UnionRect(aRect, mAccumulatedInvalidRect); |
3990 | 0 |
|
3991 | 0 | // This must be asynchronous, because we may be nested within RPC messages |
3992 | 0 | // which do not expect to receiving paint events. |
3993 | 0 | AsyncShowPluginFrame(); |
3994 | 0 |
|
3995 | 0 | return IPC_OK(); |
3996 | 0 | } |
3997 | | |
3998 | | PPluginBackgroundDestroyerChild* |
3999 | | PluginInstanceChild::AllocPPluginBackgroundDestroyerChild() |
4000 | 0 | { |
4001 | 0 | return new PluginBackgroundDestroyerChild(); |
4002 | 0 | } |
4003 | | |
4004 | | mozilla::ipc::IPCResult |
4005 | | PluginInstanceChild::RecvPPluginBackgroundDestroyerConstructor( |
4006 | | PPluginBackgroundDestroyerChild* aActor) |
4007 | 0 | { |
4008 | 0 | // Our background changed, so we have to invalidate the area |
4009 | 0 | // painted with the old background. If the background was |
4010 | 0 | // destroyed because we have a new background, then we expect to |
4011 | 0 | // be notified of that "soon", before processing the asynchronous |
4012 | 0 | // invalidation here. If we're *not* getting a new background, |
4013 | 0 | // our current front surface is stale and we want to repaint |
4014 | 0 | // "soon" so that we can hand the browser back a surface with |
4015 | 0 | // alpha values. (We should be notified of that invalidation soon |
4016 | 0 | // too, but we don't assume that here.) |
4017 | 0 | if (mBackground) { |
4018 | 0 | IntSize bgsize = mBackground->GetSize(); |
4019 | 0 | mAccumulatedInvalidRect.UnionRect( |
4020 | 0 | nsIntRect(0, 0, bgsize.width, bgsize.height), mAccumulatedInvalidRect); |
4021 | 0 |
|
4022 | 0 | // NB: we don't have to XSync here because only ShowPluginFrame() |
4023 | 0 | // uses mBackground, and it always XSyncs after finishing. |
4024 | 0 | mBackground = nullptr; |
4025 | 0 | AsyncShowPluginFrame(); |
4026 | 0 | } |
4027 | 0 |
|
4028 | 0 | if (!PPluginBackgroundDestroyerChild::Send__delete__(aActor)) { |
4029 | 0 | return IPC_FAIL_NO_REASON(this); |
4030 | 0 | } |
4031 | 0 | return IPC_OK(); |
4032 | 0 | } |
4033 | | |
4034 | | bool |
4035 | | PluginInstanceChild::DeallocPPluginBackgroundDestroyerChild( |
4036 | | PPluginBackgroundDestroyerChild* aActor) |
4037 | 0 | { |
4038 | 0 | delete aActor; |
4039 | 0 | return true; |
4040 | 0 | } |
4041 | | |
4042 | | uint32_t |
4043 | | PluginInstanceChild::ScheduleTimer(uint32_t interval, bool repeat, |
4044 | | TimerFunc func) |
4045 | 0 | { |
4046 | 0 | auto* t = new ChildTimer(this, interval, repeat, func); |
4047 | 0 | if (0 == t->ID()) { |
4048 | 0 | delete t; |
4049 | 0 | return 0; |
4050 | 0 | } |
4051 | 0 | |
4052 | 0 | mTimers.AppendElement(t); |
4053 | 0 | return t->ID(); |
4054 | 0 | } |
4055 | | |
4056 | | void |
4057 | | PluginInstanceChild::UnscheduleTimer(uint32_t id) |
4058 | 0 | { |
4059 | 0 | if (0 == id) |
4060 | 0 | return; |
4061 | 0 | |
4062 | 0 | mTimers.RemoveElement(id, ChildTimer::IDComparator()); |
4063 | 0 | } |
4064 | | |
4065 | | void |
4066 | | PluginInstanceChild::SwapSurfaces() |
4067 | 0 | { |
4068 | 0 | RefPtr<gfxASurface> tmpsurf = mCurrentSurface; |
4069 | | #ifdef XP_WIN |
4070 | | PPluginSurfaceChild* tmpactor = mCurrentSurfaceActor; |
4071 | | #endif |
4072 | |
|
4073 | 0 | mCurrentSurface = mBackSurface; |
4074 | | #ifdef XP_WIN |
4075 | | mCurrentSurfaceActor = mBackSurfaceActor; |
4076 | | #endif |
4077 | |
|
4078 | 0 | mBackSurface = tmpsurf; |
4079 | | #ifdef XP_WIN |
4080 | | mBackSurfaceActor = tmpactor; |
4081 | | #endif |
4082 | |
|
4083 | | #ifdef MOZ_WIDGET_COCOA |
4084 | | mDoubleBufferCARenderer.SwapSurfaces(); |
4085 | | |
4086 | | // Outdated back surface... not usable anymore due to changed plugin size. |
4087 | | // Dropping obsolete surface |
4088 | | if (mDoubleBufferCARenderer.HasFrontSurface() && |
4089 | | mDoubleBufferCARenderer.HasBackSurface() && |
4090 | | (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != |
4091 | | mDoubleBufferCARenderer.GetBackSurfaceWidth() || |
4092 | | mDoubleBufferCARenderer.GetFrontSurfaceHeight() != |
4093 | | mDoubleBufferCARenderer.GetBackSurfaceHeight() || |
4094 | | mDoubleBufferCARenderer.GetFrontSurfaceContentsScaleFactor() != |
4095 | | mDoubleBufferCARenderer.GetBackSurfaceContentsScaleFactor())) { |
4096 | | |
4097 | | mDoubleBufferCARenderer.ClearFrontSurface(); |
4098 | | } |
4099 | | #else |
4100 | 0 | if (mCurrentSurface && mBackSurface && |
4101 | 0 | (mCurrentSurface->GetSize() != mBackSurface->GetSize() || |
4102 | 0 | mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) { |
4103 | 0 | ClearCurrentSurface(); |
4104 | 0 | } |
4105 | 0 | #endif |
4106 | 0 | } |
4107 | | |
4108 | | void |
4109 | | PluginInstanceChild::ClearCurrentSurface() |
4110 | 0 | { |
4111 | 0 | mCurrentSurface = nullptr; |
4112 | | #ifdef MOZ_WIDGET_COCOA |
4113 | | if (mDoubleBufferCARenderer.HasFrontSurface()) { |
4114 | | mDoubleBufferCARenderer.ClearFrontSurface(); |
4115 | | } |
4116 | | #endif |
4117 | | #ifdef XP_WIN |
4118 | | if (mCurrentSurfaceActor) { |
4119 | | PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor); |
4120 | | mCurrentSurfaceActor = nullptr; |
4121 | | } |
4122 | | #endif |
4123 | | mHelperSurface = nullptr; |
4124 | 0 | } |
4125 | | |
4126 | | void |
4127 | | PluginInstanceChild::ClearAllSurfaces() |
4128 | 0 | { |
4129 | 0 | if (mBackSurface) { |
4130 | 0 | // Get last surface back, and drop it |
4131 | 0 | SurfaceDescriptor temp = null_t(); |
4132 | 0 | NPRect r = { 0, 0, 1, 1 }; |
4133 | 0 | SendShow(r, temp, &temp); |
4134 | 0 | } |
4135 | 0 |
|
4136 | 0 | if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) |
4137 | 0 | DeallocShmem(static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem()); |
4138 | 0 | if (gfxSharedImageSurface::IsSharedImage(mBackSurface)) |
4139 | 0 | DeallocShmem(static_cast<gfxSharedImageSurface*>(mBackSurface.get())->GetShmem()); |
4140 | 0 | mCurrentSurface = nullptr; |
4141 | 0 | mBackSurface = nullptr; |
4142 | 0 |
|
4143 | | #ifdef XP_WIN |
4144 | | if (mCurrentSurfaceActor) { |
4145 | | PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor); |
4146 | | mCurrentSurfaceActor = nullptr; |
4147 | | } |
4148 | | if (mBackSurfaceActor) { |
4149 | | PPluginSurfaceChild::Send__delete__(mBackSurfaceActor); |
4150 | | mBackSurfaceActor = nullptr; |
4151 | | } |
4152 | | #endif |
4153 | |
|
4154 | | #ifdef MOZ_WIDGET_COCOA |
4155 | | if (mDoubleBufferCARenderer.HasBackSurface()) { |
4156 | | // Get last surface back, and drop it |
4157 | | SurfaceDescriptor temp = null_t(); |
4158 | | NPRect r = { 0, 0, 1, 1 }; |
4159 | | SendShow(r, temp, &temp); |
4160 | | } |
4161 | | |
4162 | | if (mCGLayer) { |
4163 | | mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer); |
4164 | | mCGLayer = nullptr; |
4165 | | } |
4166 | | |
4167 | | mDoubleBufferCARenderer.ClearFrontSurface(); |
4168 | | mDoubleBufferCARenderer.ClearBackSurface(); |
4169 | | #endif |
4170 | | } |
4171 | | |
4172 | | static void |
4173 | | InvalidateObjects(nsTHashtable<DeletingObjectEntry>& aEntries) |
4174 | 0 | { |
4175 | 0 | for (auto iter = aEntries.Iter(); !iter.Done(); iter.Next()) { |
4176 | 0 | DeletingObjectEntry* e = iter.Get(); |
4177 | 0 | NPObject* o = e->GetKey(); |
4178 | 0 | if (!e->mDeleted && o->_class && o->_class->invalidate) { |
4179 | 0 | o->_class->invalidate(o); |
4180 | 0 | } |
4181 | 0 | } |
4182 | 0 | } |
4183 | | |
4184 | | static void |
4185 | | DeleteObjects(nsTHashtable<DeletingObjectEntry>& aEntries) |
4186 | 0 | { |
4187 | 0 | for (auto iter = aEntries.Iter(); !iter.Done(); iter.Next()) { |
4188 | 0 | DeletingObjectEntry* e = iter.Get(); |
4189 | 0 | NPObject* o = e->GetKey(); |
4190 | 0 | if (!e->mDeleted) { |
4191 | 0 | e->mDeleted = true; |
4192 | 0 |
|
4193 | | #ifdef NS_BUILD_REFCNT_LOGGING |
4194 | | { |
4195 | | int32_t refcnt = o->referenceCount; |
4196 | | while (refcnt) { |
4197 | | --refcnt; |
4198 | | NS_LOG_RELEASE(o, refcnt, "NPObject"); |
4199 | | } |
4200 | | } |
4201 | | #endif |
4202 | |
|
4203 | 0 | PluginModuleChild::DeallocNPObject(o); |
4204 | 0 | } |
4205 | 0 | } |
4206 | 0 | } |
4207 | | |
4208 | | void |
4209 | | PluginInstanceChild::Destroy() |
4210 | 0 | { |
4211 | 0 | if (mDestroyed) { |
4212 | 0 | return; |
4213 | 0 | } |
4214 | 0 | if (mStackDepth != 0) { |
4215 | 0 | MOZ_CRASH("Destroying plugin instance on the stack."); |
4216 | 0 | } |
4217 | 0 | mDestroyed = true; |
4218 | 0 |
|
4219 | | #if defined(OS_WIN) |
4220 | | SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1); |
4221 | | #endif |
4222 | |
|
4223 | 0 | InfallibleTArray<PBrowserStreamChild*> streams; |
4224 | 0 | ManagedPBrowserStreamChild(streams); |
4225 | 0 |
|
4226 | 0 | // First make sure none of these streams become deleted |
4227 | 0 | for (uint32_t i = 0; i < streams.Length(); ) { |
4228 | 0 | if (static_cast<BrowserStreamChild*>(streams[i])->InstanceDying()) |
4229 | 0 | ++i; |
4230 | 0 | else |
4231 | 0 | streams.RemoveElementAt(i); |
4232 | 0 | } |
4233 | 0 | for (uint32_t i = 0; i < streams.Length(); ++i) |
4234 | 0 | static_cast<BrowserStreamChild*>(streams[i])->FinishDelivery(); |
4235 | 0 |
|
4236 | 0 | mTimers.Clear(); |
4237 | 0 |
|
4238 | 0 | // NPP_Destroy() should be a synchronization point for plugin threads |
4239 | 0 | // calling NPN_AsyncCall: after this function returns, they are no longer |
4240 | 0 | // allowed to make async calls on this instance. |
4241 | 0 | static_cast<PluginModuleChild *>(Manager())->NPP_Destroy(this); |
4242 | 0 | mData.ndata = 0; |
4243 | 0 |
|
4244 | 0 | if (mCurrentInvalidateTask) { |
4245 | 0 | mCurrentInvalidateTask->Cancel(); |
4246 | 0 | mCurrentInvalidateTask = nullptr; |
4247 | 0 | } |
4248 | 0 | if (mCurrentAsyncSetWindowTask) { |
4249 | 0 | mCurrentAsyncSetWindowTask->Cancel(); |
4250 | 0 | mCurrentAsyncSetWindowTask = nullptr; |
4251 | 0 | } |
4252 | 0 | { |
4253 | 0 | MutexAutoLock autoLock(mAsyncInvalidateMutex); |
4254 | 0 | if (mAsyncInvalidateTask) { |
4255 | 0 | mAsyncInvalidateTask->Cancel(); |
4256 | 0 | mAsyncInvalidateTask = nullptr; |
4257 | 0 | } |
4258 | 0 | } |
4259 | 0 |
|
4260 | 0 | ClearAllSurfaces(); |
4261 | 0 | mDirectBitmaps.Clear(); |
4262 | 0 |
|
4263 | 0 | mDeletingHash = new nsTHashtable<DeletingObjectEntry>; |
4264 | 0 | PluginScriptableObjectChild::NotifyOfInstanceShutdown(this); |
4265 | 0 |
|
4266 | 0 | InvalidateObjects(*mDeletingHash); |
4267 | 0 | DeleteObjects(*mDeletingHash); |
4268 | 0 |
|
4269 | 0 | // Null out our cached actors as they should have been killed in the |
4270 | 0 | // PluginInstanceDestroyed call above. |
4271 | 0 | mCachedWindowActor = nullptr; |
4272 | 0 | mCachedElementActor = nullptr; |
4273 | 0 |
|
4274 | | #if defined(OS_WIN) |
4275 | | DestroyWinlessPopupSurrogate(); |
4276 | | UnhookWinlessFlashThrottle(); |
4277 | | DestroyPluginWindow(); |
4278 | | |
4279 | | for (uint32_t i = 0; i < mPendingFlashThrottleMsgs.Length(); ++i) { |
4280 | | mPendingFlashThrottleMsgs[i]->Cancel(); |
4281 | | } |
4282 | | mPendingFlashThrottleMsgs.Clear(); |
4283 | | #endif |
4284 | | } |
4285 | | |
4286 | | mozilla::ipc::IPCResult |
4287 | | PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult) |
4288 | 0 | { |
4289 | 0 | PLUGIN_LOG_DEBUG_METHOD; |
4290 | 0 | AssertPluginThread(); |
4291 | 0 | *aResult = NPERR_NO_ERROR; |
4292 | 0 |
|
4293 | 0 | Destroy(); |
4294 | 0 |
|
4295 | 0 | return IPC_OK(); |
4296 | 0 | } |
4297 | | |
4298 | | void |
4299 | | PluginInstanceChild::ActorDestroy(ActorDestroyReason why) |
4300 | 0 | { |
4301 | | #ifdef XP_WIN |
4302 | | // ClearAllSurfaces() should not try to send anything after ActorDestroy. |
4303 | | mCurrentSurfaceActor = nullptr; |
4304 | | mBackSurfaceActor = nullptr; |
4305 | | #endif |
4306 | |
|
4307 | 0 | Destroy(); |
4308 | 0 | } |