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