Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
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"
30 #include "mozilla/ArrayUtils.h"
31 #include "mozilla/ipc/MessageChannel.h"
32 #include "mozilla/AutoRestore.h"
33 #include "ImageContainer.h"
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;
42 #ifdef MOZ_WIDGET_GTK
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
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
62 #include "nsWindowsDllInterceptor.h"
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;
75 using mozilla::gfx::SharedDIB;
77 #include <windows.h>
78 #include <windowsx.h>
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;
85 static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassProperty");
87 #elif defined(XP_MACOSX)
88 #include <ApplicationServices/ApplicationServices.h>
89 #include "nsCocoaFeatures.h"
90 #include "PluginUtilsOSX.h"
91 #endif // defined(XP_MACOSX)
93 template<>
94 struct RunnableMethodTraits<PluginInstanceChild>
95 {
96 static void RetainCallee(PluginInstanceChild* obj) { }
97 static void ReleaseCallee(PluginInstanceChild* obj) { }
98 };
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 }
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 }
191 int
192 PluginInstanceChild::GetQuirks()
193 {
194 return PluginModuleChild::current()->GetQuirks();
195 }
197 NPError
198 PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
199 NPObject** aObject)
200 {
201 PluginScriptableObjectChild* actor = nullptr;
202 NPError result = NPERR_NO_ERROR;
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;
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;
234 default:
235 NS_NOTREACHED("Don't know what to do with this value type!");
236 }
238 #ifdef DEBUG
239 {
240 NPError currentResult;
241 PPluginScriptableObjectChild* currentActor = nullptr;
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 }
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
264 if (result != NPERR_NO_ERROR) {
265 return result;
266 }
268 NPObject* object = actor->GetObject(false);
269 NS_ASSERTION(object, "Null object?!");
271 *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object);
272 return NPERR_NO_ERROR;
274 }
276 NPError
277 PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
278 void* aValue)
279 {
280 PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar));
281 AssertPluginThread();
283 switch(aVar) {
285 #if defined(MOZ_X11)
286 case NPNVToolkit:
287 *((NPNToolkitType*)aValue) = NPNVGtk2;
288 return NPERR_NO_ERROR;
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;
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 }
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 }
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 }
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 }
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 }
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
381 #ifdef XP_MACOSX
382 case NPNVsupportsCoreGraphicsBool: {
383 *((NPBool*)aValue) = true;
384 return NPERR_NO_ERROR;
385 }
387 case NPNVsupportsCoreAnimationBool: {
388 *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins();
389 return NPERR_NO_ERROR;
390 }
392 case NPNVsupportsInvalidatingCoreAnimationBool: {
393 *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins();
394 return NPERR_NO_ERROR;
395 }
397 case NPNVsupportsCompositingCoreAnimationPluginsBool: {
398 *((NPBool*)aValue) = true;
399 return NPERR_NO_ERROR;
400 }
402 case NPNVsupportsCocoaBool: {
403 *((NPBool*)aValue) = true;
404 return NPERR_NO_ERROR;
405 }
407 #ifndef NP_NO_CARBON
408 case NPNVsupportsCarbonBool: {
409 *((NPBool*)aValue) = false;
410 return NPERR_NO_ERROR;
411 }
412 #endif
414 case NPNVsupportsUpdatedCocoaTextInputBool: {
415 *static_cast<NPBool*>(aValue) = true;
416 return NPERR_NO_ERROR;
417 }
419 #ifndef NP_NO_QUICKDRAW
420 case NPNVsupportsQuickDrawBool: {
421 *((NPBool*)aValue) = false;
422 return NPERR_NO_ERROR;
423 }
424 #endif /* NP_NO_QUICKDRAW */
426 case NPNVcontentsScaleFactor: {
427 *static_cast<double*>(aValue) = mContentsScaleFactor;
428 return NPERR_NO_ERROR;
429 }
430 #endif /* XP_MACOSX */
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
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 }
448 }
450 #ifdef MOZ_WIDGET_COCOA
451 #define DEFAULT_REFRESH_MS 20 // CoreAnimation: 50 FPS
453 void
454 CAUpdate(NPP npp, uint32_t timerID) {
455 static_cast<PluginInstanceChild*>(npp->ndata)->Invalidate();
456 }
458 void
459 PluginInstanceChild::Invalidate()
460 {
461 NPRect windowRect = {0, 0, uint16_t(mWindow.height),
462 uint16_t(mWindow.width)};
464 InvalidateRect(&windowRect);
465 }
466 #endif
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));
474 AssertPluginThread();
476 switch (aVar) {
477 case NPPVpluginWindowBool: {
478 NPError rv;
479 bool windowed = (NPBool) (intptr_t) aValue;
481 if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv))
482 return NPERR_GENERIC_ERROR;
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 }
502 case NPPVpluginTransparentBool: {
503 NPError rv;
504 mIsTransparent = (!!aValue);
506 if (!CallNPN_SetValue_NPPVpluginTransparent(mIsTransparent, &rv))
507 return NPERR_GENERIC_ERROR;
509 return rv;
510 }
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 }
520 case NPPVpluginDrawingModel: {
521 NPError rv;
522 int drawingModel = (int16_t) (intptr_t) aValue;
524 if (!PluginModuleChild::current()->AsyncDrawingAllowed() &&
525 IsDrawingModelAsync(drawingModel)) {
526 return NPERR_GENERIC_ERROR;
527 }
529 CrossProcessMutexHandle handle;
530 OptionalShmem optionalShmem;
531 if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &optionalShmem, &handle, &rv))
532 return NPERR_GENERIC_ERROR;
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;
544 #ifdef XP_MACOSX
545 if (drawingModel == NPDrawingModelCoreAnimation) {
546 mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate);
547 }
548 #endif
550 PLUGIN_LOG_DEBUG((" Plugin requested drawing model id #%i\n",
551 mDrawingModel));
553 return rv;
554 }
556 #ifdef XP_MACOSX
557 case NPPVpluginEventModel: {
558 NPError rv;
559 int eventModel = (int16_t) (intptr_t) aValue;
561 if (!CallNPN_SetValue_NPPVpluginEventModel(eventModel, &rv))
562 return NPERR_GENERIC_ERROR;
563 #if defined(__i386__)
564 mEventModel = static_cast<NPEventModel>(eventModel);
565 #endif
567 PLUGIN_LOG_DEBUG((" Plugin requested event model id # %i\n",
568 eventModel));
570 return rv;
571 }
572 #endif
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 }
582 bool
583 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(
584 bool* wantsAllStreams, NPError* rv)
585 {
586 AssertPluginThread();
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 }
600 bool
601 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(
602 bool* needs, NPError* rv)
603 {
604 AssertPluginThread();
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;
625 #else
627 NS_RUNTIMEABORT("shouldn't be called on non-X11 platforms");
628 return false; // not reached
630 #endif
631 }
633 bool
634 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
635 PPluginScriptableObjectChild** aValue,
636 NPError* aResult)
637 {
638 AssertPluginThread();
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);
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 }
658 NS_ERROR("Failed to get actor!");
659 result = NPERR_GENERIC_ERROR;
660 }
661 else {
662 result = NPERR_GENERIC_ERROR;
663 }
665 *aValue = nullptr;
666 *aResult = result;
667 return true;
668 }
670 bool
671 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId(
672 nsCString* aPlugId,
673 NPError* aResult)
674 {
675 AssertPluginThread();
677 #if MOZ_ACCESSIBILITY_ATK
679 char* plugId = nullptr;
680 NPError result = NPERR_GENERIC_ERROR;
681 if (mPluginIface->getvalue) {
682 result = mPluginIface->getvalue(GetNPP(),
683 NPPVpluginNativeAccessibleAtkPlugId,
684 &plugId);
685 }
687 *aPlugId = nsCString(plugId);
688 *aResult = result;
689 return true;
691 #else
693 NS_RUNTIMEABORT("shouldn't be called on non-ATK platforms");
694 return false;
696 #endif
697 }
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 }
708 NPBool v = value;
709 *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v);
710 return true;
711 }
713 bool
714 PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
715 int16_t* handled)
716 {
717 PLUGIN_LOG_DEBUG_FUNCTION;
718 AssertPluginThread();
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
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 }
736 // Make sure we reset mCurrentEvent in case of an exception
737 AutoRestore<const NPCocoaEvent*> savePreviousEvent(mCurrentEvent);
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
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;
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
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));
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
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
803 return true;
804 }
806 #ifdef XP_MACOSX
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();
817 PaintTracker pt;
819 NPCocoaEvent evcopy = event.event;
820 mContentsScaleFactor = event.contentsScaleFactor;
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);
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 }
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 }
867 *rtnmem = mem;
868 return true;
869 }
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
884 #ifdef XP_MACOSX
886 void CallCGDraw(CGContextRef ref, void* aPluginInstance, nsIntRect aUpdateRect) {
887 PluginInstanceChild* pluginInstance = (PluginInstanceChild*)aPluginInstance;
889 pluginInstance->CGDraw(ref, aUpdateRect);
890 }
892 bool
893 PluginInstanceChild::CGDraw(CGContextRef ref, nsIntRect aUpdateRect) {
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;
904 NPRemoteEvent remoteDrawEvent = {drawEvent};
905 // Signal to AnswerNPP_HandleEvent() not to use this value
906 remoteDrawEvent.contentsScaleFactor = -1.0;
908 int16_t handled;
909 AnswerNPP_HandleEvent(remoteDrawEvent, &handled);
910 return handled == true;
911 }
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();
921 PaintTracker pt;
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 }
933 if (!mCARenderer) {
934 mCARenderer = new nsCARenderer();
935 }
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);
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 }
952 mCARenderer->SetupRenderer(caLayer, mWindow.width, mWindow.height,
953 mContentsScaleFactor,
954 GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ?
955 ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER);
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 }
968 mCARenderer->Render(mWindow.width, mWindow.height,
969 mContentsScaleFactor, nullptr);
971 return true;
973 }
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
986 bool
987 PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
988 {
989 NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
990 "Shouldn't be receiving WindowPosChanged with layer rendering");
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 }
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 }
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));
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
1043 return true;
1044 }
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));
1055 if (!mWindow.window)
1056 return;
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
1066 // We don't have to keep the plug-in window ID any longer.
1067 mWindow.window = nullptr;
1068 }
1069 #endif
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();
1083 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
1084 NS_ASSERTION(mWsInfo.display, "We should have a valid display!");
1086 // The minimum info is sent over IPC to allow this
1087 // code to determine the rest.
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;
1096 mWsInfo.colormap = aWindow.colormap;
1097 int depth;
1098 FindVisualAndDepth(mWsInfo.display, aWindow.visualID,
1099 &mWsInfo.visual, &depth);
1100 mWsInfo.depth = depth;
1102 if (!mWindow.window && mWindow.type == NPWindowTypeWindow) {
1103 CreateWindow(aWindow);
1104 }
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 }
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);
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
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));
1146 if (mPluginIface->setwindow)
1147 (void) mPluginIface->setwindow(&mData, &mWindow);
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 }
1160 if (!CreatePluginWindow())
1161 return false;
1163 ReparentPluginWindow(reinterpret_cast<HWND>(aWindow.window));
1164 SizePluginWindow(aWindow.width, aWindow.height);
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;
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;
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;
1199 default:
1200 NS_NOTREACHED("Bad plugin window type.");
1201 return false;
1202 break;
1203 }
1205 #elif defined(XP_MACOSX)
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;
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 }
1222 if (mPluginIface->setwindow)
1223 (void) mPluginIface->setwindow(&mData, &mWindow);
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
1233 return true;
1234 }
1236 bool
1237 PluginInstanceChild::Initialize()
1238 {
1239 #if (MOZ_WIDGET_GTK == 2)
1240 NPError rv;
1242 if (mWsInfo.display) {
1243 // Already initialized
1244 return false;
1245 }
1247 // Request for windowless plugins is set in newp(), before this call.
1248 if (mWindow.type == NPWindowTypeWindow) {
1249 AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(&mXEmbed, &rv);
1251 // Set up Xt loop for windowed plugins without XEmbed support
1252 if (!mXEmbed) {
1253 xt_client_xloop_create();
1254 }
1255 }
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
1266 return true;
1267 }
1269 #if defined(OS_WIN)
1271 static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
1272 static const TCHAR kPluginInstanceChildProperty[] = TEXT("PluginInstanceChildProperty");
1273 static const TCHAR kFlashThrottleProperty[] = TEXT("MozillaFlashThrottleProperty");
1275 // static
1276 bool
1277 PluginInstanceChild::RegisterWindowClass()
1278 {
1279 static bool alreadyRegistered = false;
1280 if (alreadyRegistered)
1281 return true;
1283 alreadyRegistered = true;
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;
1299 return RegisterClassEx(&wcex) ? true : false;
1300 }
1302 bool
1303 PluginInstanceChild::CreatePluginWindow()
1304 {
1305 // already initialized
1306 if (mPluginWindowHWND)
1307 return true;
1309 if (!RegisterWindowClass())
1310 return false;
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;
1324 // Apparently some plugins require an ASCII WndProc.
1325 SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC,
1326 reinterpret_cast<LONG_PTR>(DefWindowProcA));
1328 return true;
1329 }
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 }
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);
1361 // Do the reparenting.
1362 SetParent(mPluginWindowHWND, hWndParent);
1364 // Make sure we're visible.
1365 ShowWindow(mPluginWindowHWND, SW_SHOWNA);
1366 }
1367 mPluginParentHWND = hWndParent;
1368 }
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 }
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 }
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 }
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 }
1419 NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
1420 NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Self-referential windowproc. Infinite recursion will happen soon.");
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 }
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);
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 }
1458 if (message == WM_KILLFOCUS)
1459 self->CallPluginFocusChange(false);
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 }
1467 NS_ASSERTION(self->mPluginWndProc != PluginWindowProc,
1468 "Self-referential windowproc happened inside our hook proc. "
1469 "Infinite recursion will happen soon.");
1471 LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
1472 lParam);
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 }
1490 if (message == WM_CLOSE)
1491 self->DestroyPluginWindow();
1493 if (message == WM_NCDESTROY)
1494 RemoveProp(hWnd, kPluginInstanceChildProperty);
1496 return res;
1497 }
1499 /* set window long ptr hook for flash */
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 */
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
1535 extern LRESULT CALLBACK
1536 NeuteredWindowProc(HWND hwnd,
1537 UINT uMsg,
1538 WPARAM wParam,
1539 LPARAM lParam);
1541 const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc";
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 }
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);
1582 // Set flash's new subclass to get the result.
1583 LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
1585 // We already checked this in SetWindowLongHookCheck
1586 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
1587 GetProp(hWnd, kPluginInstanceChildProperty));
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 }
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);
1616 // Set flash's new subclass to get the result.
1617 LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
1619 // We already checked this in SetWindowLongHookCheck
1620 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
1621 GetProp(hWnd, kPluginInstanceChildProperty));
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 }
1635 void
1636 PluginInstanceChild::HookSetWindowLongPtr()
1637 {
1638 if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_SETLONGPTR))
1639 return;
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 }
1659 /* windowless track popup menu helpers */
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 }
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 }
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 }
1697 HWND surrogateHwnd = sWinlessPopupSurrogateHWND;
1698 sWinlessPopupSurrogateHWND = nullptr;
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);
1706 DWORD res = sUser32TrackPopupMenuStub(hMenu, uFlags|TPM_RETURNCMD, x, y,
1707 nReserved, surrogateHwnd, prcRect);
1709 if (!isRetCmdCall && res) {
1710 SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(res, 0), 0);
1711 }
1713 return res;
1714 }
1716 void
1717 PluginInstanceChild::InitPopupMenuHook()
1718 {
1719 if (!(GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
1720 sUser32TrackPopupMenuStub)
1721 return;
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 }
1734 void
1735 PluginInstanceChild::CreateWinlessPopupSurrogate()
1736 {
1737 // already initialized
1738 if (mWinlessPopupSurrogateHWND)
1739 return;
1741 HWND hwnd = nullptr;
1742 NPError result;
1743 if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) {
1744 NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed.");
1745 return;
1746 }
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 }
1758 void
1759 PluginInstanceChild::DestroyWinlessPopupSurrogate()
1760 {
1761 if (mWinlessPopupSurrogateHWND)
1762 DestroyWindow(mWinlessPopupSurrogateHWND);
1763 mWinlessPopupSurrogateHWND = nullptr;
1764 }
1766 int16_t
1767 PluginInstanceChild::WinlessHandleEvent(NPEvent& event)
1768 {
1769 if (!mPluginIface->event)
1770 return false;
1772 // Events that might generate nested event dispatch loops need
1773 // special handling during delivery.
1774 int16_t handled;
1776 HWND focusHwnd = nullptr;
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;
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 }
1791 MessageLoop* loop = MessageLoop::current();
1792 AutoRestore<bool> modalLoop(loop->os_modal_loop());
1794 handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
1796 sWinlessPopupSurrogateHWND = nullptr;
1798 if (IsWindow(focusHwnd)) {
1799 SetFocus(focusHwnd);
1800 }
1802 return handled;
1803 }
1805 /* windowless drawing helpers */
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 }
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;
1835 mWindow.window = reinterpret_cast<void*>(mSharedSurfaceDib.GetHDC());
1836 ::SetViewportOrgEx(mSharedSurfaceDib.GetHDC(),
1837 -aWindow.x, -aWindow.y, nullptr);
1839 if (mPluginIface->setwindow)
1840 mPluginIface->setwindow(&mData, &mWindow);
1842 return true;
1843 }
1845 void
1846 PluginInstanceChild::SharedSurfaceRelease()
1847 {
1848 mSharedSurfaceDib.Close();
1849 AlphaExtractCacheRelease();
1850 }
1852 /* double pass cache buffer - (rarely) used in cases where alpha extraction
1853 * occurs for windowless plugins. */
1855 bool
1856 PluginInstanceChild::AlphaExtractCacheSetup()
1857 {
1858 AlphaExtractCacheRelease();
1860 mAlphaExtract.hdc = ::CreateCompatibleDC(nullptr);
1862 if (!mAlphaExtract.hdc)
1863 return false;
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;
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;
1884 DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp));
1885 return true;
1886 }
1888 void
1889 PluginInstanceChild::AlphaExtractCacheRelease()
1890 {
1891 if (mAlphaExtract.bmp)
1892 ::DeleteObject(mAlphaExtract.bmp);
1894 if (mAlphaExtract.hdc)
1895 ::DeleteObject(mAlphaExtract.hdc);
1897 mAlphaExtract.bmp = nullptr;
1898 mAlphaExtract.hdc = nullptr;
1899 }
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 }
1912 int16_t
1913 PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
1914 {
1915 if (!mPluginIface->event)
1916 return false;
1918 RECT* pRect = reinterpret_cast<RECT*>(evcopy.lParam);
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 }
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 }
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);
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 }
1986 /* flash msg throttling helpers */
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.
1995 void
1996 PluginInstanceChild::UnhookWinlessFlashThrottle()
1997 {
1998 // We may have already unhooked
1999 if (!mWinlessThrottleOldWndProc)
2000 return;
2002 WNDPROC tmpProc = mWinlessThrottleOldWndProc;
2003 mWinlessThrottleOldWndProc = nullptr;
2005 NS_ASSERTION(mWinlessHiddenMsgHWND,
2006 "Missing mWinlessHiddenMsgHWND w/subclass set??");
2008 // reset the subclass
2009 SetWindowLongPtr(mWinlessHiddenMsgHWND, GWLP_WNDPROC,
2010 reinterpret_cast<LONG_PTR>(tmpProc));
2012 // Remove our instance prop
2013 RemoveProp(mWinlessHiddenMsgHWND, kFlashThrottleProperty);
2014 mWinlessHiddenMsgHWND = nullptr;
2015 }
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 }
2031 NS_ASSERTION(self->mWinlessThrottleOldWndProc,
2032 "Missing subclass procedure!!");
2034 // Throttle
2035 if (message == WM_USER+1) {
2036 self->FlashThrottleMessage(hWnd, message, wParam, lParam, false);
2037 return 0;
2038 }
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 }
2048 return CallWindowProc(self->mWinlessThrottleOldWndProc,
2049 hWnd, message, wParam, lParam);
2050 }
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 }
2065 wchar_t className[64];
2066 if (!GetClassNameW(hWnd, className, sizeof(className)/sizeof(char16_t)))
2067 return TRUE;
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 }
2091 return TRUE;
2092 }
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 }
2112 WNDPROC
2113 PluginInstanceChild::FlashThrottleAsyncMsg::GetProc()
2114 {
2115 if (mInstance) {
2116 return mWindowed ? mInstance->mPluginWndProc :
2117 mInstance->mWinlessThrottleOldWndProc;
2118 }
2119 return nullptr;
2120 }
2122 void
2123 PluginInstanceChild::FlashThrottleAsyncMsg::Run()
2124 {
2125 RemoveFromAsyncList();
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;
2133 // deliver the event to flash
2134 CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam());
2135 }
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;
2151 {
2152 MutexAutoLock lock(mAsyncCallMutex);
2153 mPendingAsyncCalls.AppendElement(task);
2154 }
2155 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2156 task, kFlashWMUSERMessageThrottleDelayMs);
2157 }
2159 #endif // OS_WIN
2161 bool
2162 PluginInstanceChild::AnswerSetPluginFocus()
2163 {
2164 PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s", FULLFUNCTION));
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 }
2184 bool
2185 PluginInstanceChild::AnswerUpdateWindow()
2186 {
2187 PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s", FULLFUNCTION));
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 }
2204 bool
2205 PluginInstanceChild::RecvNPP_DidComposite()
2206 {
2207 if (mPluginIface->didComposite) {
2208 mPluginIface->didComposite(GetNPP());
2209 }
2210 return true;
2211 }
2213 PPluginScriptableObjectChild*
2214 PluginInstanceChild::AllocPPluginScriptableObjectChild()
2215 {
2216 AssertPluginThread();
2217 return new PluginScriptableObjectChild(Proxy);
2218 }
2220 bool
2221 PluginInstanceChild::DeallocPPluginScriptableObjectChild(
2222 PPluginScriptableObjectChild* aObject)
2223 {
2224 AssertPluginThread();
2225 delete aObject;
2226 return true;
2227 }
2229 bool
2230 PluginInstanceChild::RecvPPluginScriptableObjectConstructor(
2231 PPluginScriptableObjectChild* aActor)
2232 {
2233 AssertPluginThread();
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?!");
2242 actor->InitializeProxy();
2243 NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
2245 return true;
2246 }
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 }
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 }
2284 bool
2285 PluginInstanceChild::DeallocPBrowserStreamChild(PBrowserStreamChild* stream)
2286 {
2287 AssertPluginThread();
2288 delete stream;
2289 return true;
2290 }
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 }
2301 bool
2302 PluginInstanceChild::DeallocPPluginStreamChild(PPluginStreamChild* stream)
2303 {
2304 AssertPluginThread();
2305 delete stream;
2306 return true;
2307 }
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 }
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.");
2328 // reclaim responsibility for deleting ourself
2329 mBrowserStream->mStreamNotify = nullptr;
2330 mBrowserStream = nullptr;
2331 }
2332 }
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?");
2341 mBrowserStream = bs;
2342 }
2344 bool
2345 StreamNotifyChild::Recv__delete__(const NPReason& reason)
2346 {
2347 AssertPluginThread();
2349 if (mBrowserStream)
2350 mBrowserStream->NotifyPending();
2351 else
2352 NPP_URLNotify(reason);
2354 return true;
2355 }
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 }
2368 PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
2369 if (instance->mPluginIface->urlredirectnotify)
2370 instance->mPluginIface->urlredirectnotify(instance->GetNPP(), url.get(), status, mClosure);
2372 return true;
2373 }
2375 void
2376 StreamNotifyChild::NPP_URLNotify(NPReason reason)
2377 {
2378 PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
2380 if (mClosure)
2381 instance->mPluginIface->urlnotify(instance->GetNPP(), mURL.get(),
2382 reason, mClosure);
2383 }
2385 bool
2386 PluginInstanceChild::DeallocPStreamNotifyChild(PStreamNotifyChild* notifyData)
2387 {
2388 AssertPluginThread();
2390 if (!static_cast<StreamNotifyChild*>(notifyData)->mBrowserStream)
2391 delete notifyData;
2392 return true;
2393 }
2395 PluginScriptableObjectChild*
2396 PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
2397 {
2398 AssertPluginThread();
2399 NS_ASSERTION(aObject, "Null pointer!");
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 }
2408 PluginScriptableObjectChild* actor =
2409 PluginModuleChild::current()->GetActorForNPObject(aObject);
2410 if (actor) {
2411 // Plugin-provided object that we've previously wrapped.
2412 return actor;
2413 }
2415 actor = new PluginScriptableObjectChild(LocalObject);
2416 if (!SendPPluginScriptableObjectConstructor(actor)) {
2417 NS_ERROR("Failed to send constructor message!");
2418 return nullptr;
2419 }
2421 actor->InitializeLocal(aObject);
2422 return actor;
2423 }
2425 NPError
2426 PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
2427 NPStream** aStream)
2428 {
2429 AssertPluginThread();
2431 PluginStreamChild* ps = new PluginStreamChild();
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 }
2442 *aStream = &ps->mStream;
2443 return NPERR_NO_ERROR;
2444 }
2446 void
2447 PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow)
2448 {
2449 if (!notifyData) {
2450 return;
2451 }
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 }
2466 NPError
2467 PluginInstanceChild::DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface)
2468 {
2469 AsyncBitmapData* data;
2471 if (!mAsyncBitmaps.Get(aSurface, &data)) {
2472 return NPERR_INVALID_PARAM;
2473 }
2475 DeallocShmem(data->mShmem);
2476 aSurface->bitmap.data = nullptr;
2478 mAsyncBitmaps.Remove(aSurface);
2479 return NPERR_NO_ERROR;
2480 }
2482 bool
2483 PluginInstanceChild::IsAsyncDrawing()
2484 {
2485 return IsDrawingModelAsync(mDrawingModel);
2486 }
2488 NPError
2489 PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
2490 void *initData, NPAsyncSurface *surface)
2491 {
2492 AssertPluginThread();
2494 surface->bitmap.data = nullptr;
2496 if (!IsAsyncDrawing()) {
2497 return NPERR_GENERIC_ERROR;
2498 }
2500 switch (mDrawingModel) {
2501 case NPDrawingModelAsyncBitmapSurface: {
2502 if (mAsyncBitmaps.Get(surface, nullptr)) {
2503 return NPERR_INVALID_PARAM;
2504 }
2506 if (size->width < 0 || size->height < 0) {
2507 return NPERR_INVALID_PARAM;
2508 }
2511 bool result;
2512 NPRemoteAsyncSurface remote;
2514 if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
2515 return NPERR_OUT_OF_MEMORY_ERROR;
2516 }
2518 NS_ABORT_IF_FALSE(remote.data().get_Shmem().IsWritable(),
2519 "Failed to create writable shared memory.");
2521 AsyncBitmapData *data = new AsyncBitmapData;
2522 mAsyncBitmaps.Put(surface, data);
2524 data->mRemotePtr = (void*)remote.hostPtr();
2525 data->mShmem = remote.data().get_Shmem();
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;
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;
2543 if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
2544 return NPERR_OUT_OF_MEMORY_ERROR;
2545 }
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();
2552 return NPERR_NO_ERROR;
2553 }
2554 #endif
2555 }
2557 return NPERR_GENERIC_ERROR;
2558 }
2560 NPError
2561 PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
2562 {
2563 AssertPluginThread();
2565 if (!IsAsyncDrawing()) {
2566 return NPERR_GENERIC_ERROR;
2567 }
2569 switch (mDrawingModel) {
2570 case NPDrawingModelAsyncBitmapSurface: {
2571 AsyncBitmapData *bitmapData;
2573 if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
2574 return NPERR_GENERIC_ERROR;
2575 }
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 }
2587 return DeallocateAsyncBitmapSurface(surface);
2588 }
2589 #ifdef XP_WIN
2590 case NPDrawingModelAsyncWindowsDXGISurface: {
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 }
2602 SendReleaseDXGISharedSurface(surface->sharedHandle);
2603 return NPERR_NO_ERROR;
2604 }
2605 #endif
2606 }
2608 return NPERR_GENERIC_ERROR;
2609 }
2611 void
2612 PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
2613 {
2614 if (!IsAsyncDrawing()) {
2615 return;
2616 }
2618 RemoteImageData *data = mRemoteImageData;
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;
2631 if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
2632 return;
2633 }
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;
2654 data->mWasUpdated = true;
2655 break;
2656 }
2657 #endif
2658 }
2659 }
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 }
2672 void
2673 PluginInstanceChild::DoAsyncRedraw()
2674 {
2675 {
2676 MutexAutoLock autoLock(mAsyncInvalidateMutex);
2677 mAsyncInvalidateTask = nullptr;
2678 }
2680 SendRedrawPlugin();
2681 }
2683 bool
2684 PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
2685 const NPRemoteWindow& aWindow)
2686 {
2687 AssertPluginThread();
2689 NS_ASSERTION(!aWindow.window, "Remote window should be null.");
2691 if (mCurrentAsyncSetWindowTask) {
2692 mCurrentAsyncSetWindowTask->Cancel();
2693 mCurrentAsyncSetWindowTask = nullptr;
2694 }
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);
2707 return true;
2708 }
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));
2719 AssertPluginThread();
2720 NS_ASSERTION(!aWindow.window, "Remote window should be null.");
2721 NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!");
2723 if (aIsAsync) {
2724 if (!mCurrentAsyncSetWindowTask) {
2725 return;
2726 }
2727 mCurrentAsyncSetWindowTask = nullptr;
2728 }
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);
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
2748 if (GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT)
2749 mIsTransparent = true;
2751 mLayersRendering = true;
2752 mSurfaceType = aSurfaceType;
2753 UpdateWindowAttributes(true);
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
2762 if (!mAccumulatedInvalidRect.IsEmpty()) {
2763 AsyncShowPluginFrame();
2764 }
2765 }
2767 static inline gfxRect
2768 GfxFromNsRect(const nsIntRect& aRect)
2769 {
2770 return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
2771 }
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.");
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;
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 }
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 }
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
2818 #ifdef XP_WIN
2819 if (mSurfaceType == gfxSurfaceType::Win32 ||
2820 mSurfaceType == gfxSurfaceType::D2D) {
2821 bool willHaveTransparentPixels = mIsTransparent && !mBackground;
2823 SharedDIBSurface* s = new SharedDIBSurface();
2824 if (!s->Create(reinterpret_cast<HDC>(mWindow.window),
2825 mWindow.width, mWindow.height,
2826 willHaveTransparentPixels))
2827 return false;
2829 mCurrentSurface = s;
2830 return true;
2831 }
2833 NS_RUNTIMEABORT("Shared-memory drawing not expected on Windows.");
2834 #endif
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 }
2842 bool
2843 PluginInstanceChild::MaybeCreatePlatformHelperSurface(void)
2844 {
2845 if (!mCurrentSurface) {
2846 NS_ERROR("Cannot create helper surface without mCurrentSurface");
2847 return false;
2848 }
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;
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 }
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
2898 return true;
2899 }
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);
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 }
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 }
2933 mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
2935 if (mCurrentSurface) {
2936 return true;
2937 }
2939 if (!CreateOptSurface()) {
2940 NS_ERROR("Cannot create optimized surface");
2941 return false;
2942 }
2944 if (!MaybeCreatePlatformHelperSurface()) {
2945 NS_ERROR("Cannot create helper surface");
2946 return false;
2947 }
2949 return true;
2950 #else // XP_MACOSX
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);
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 }
2981 if (mDoubleBufferCARenderer.HasFrontSurface() &&
2982 (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != mWindow.width ||
2983 mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height ||
2984 mDoubleBufferCARenderer.GetContentsScaleFactor() != mContentsScaleFactor)) {
2985 mDoubleBufferCARenderer.ClearFrontSurface();
2986 }
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 }
2998 if (mPluginIface->setwindow)
2999 (void) mPluginIface->setwindow(&mData, &mWindow);
3001 nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height);
3002 mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate);
3003 }
3005 return true;
3006 #endif
3007 }
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;
3030 if (curSurface) {
3031 if (!SharedDIBSurface::IsSharedDIBSurface(curSurface))
3032 NS_RUNTIMEABORT("Expected SharedDIBSurface!");
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
3043 if (!needWindowUpdate) {
3044 return;
3045 }
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
3055 if (IsVisible()) {
3056 // The clip rect is relative to drawable top-left.
3057 nsIntRect clipRect;
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);
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
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
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
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));
3096 if (mPluginIface->setwindow) {
3097 mPluginIface->setwindow(&mData, &mWindow);
3098 }
3099 }
3101 void
3102 PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
3103 gfxASurface* aSurface)
3104 {
3105 UpdateWindowAttributes();
3107 #ifdef MOZ_X11
3108 {
3109 NS_ASSERTION(aSurface->GetType() == gfxSurfaceType::Xlib,
3110 "Non supported platform surface type");
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.");
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 };
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 }
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
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 }
3187 PaintRectToPlatformSurface(plPaintRect, renderSurface);
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 }
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");
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 }
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();
3233 // We always use a temporary "white image"
3234 whiteImage = new gfxImageSurface(targetSize, gfxImageFormat::RGB24);
3235 if (whiteImage->CairoStatus()) {
3236 return;
3237 }
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!");
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 }
3258 // Paint the plugin directly onto the target, with a black
3259 // background
3260 PaintRectToSurface(rect, aSurface, gfxRGBA(0.0, 0.0, 0.0));
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);
3267 #else
3268 // Paint onto white background
3269 whiteImage->SetDeviceOffset(deviceOffset);
3270 PaintRectToSurface(rect, whiteImage, gfxRGBA(1.0, 1.0, 1.0));
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 }
3280 // Paint onto black background
3281 blackImage->SetDeviceOffset(deviceOffset);
3282 PaintRectToSurface(rect, blackImage, gfxRGBA(0.0, 0.0, 0.0));
3283 #endif
3285 NS_ABORT_IF_FALSE(whiteImage && blackImage, "Didn't paint enough!");
3287 // Extract alpha from black and white image and store to black
3288 // image
3289 if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
3290 return;
3291 }
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 }
3304 bool
3305 PluginInstanceChild::CanPaintOnBackground()
3306 {
3307 return (mBackground &&
3308 mCurrentSurface &&
3309 mCurrentSurface->GetSize() == mBackground->GetSize());
3310 }
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 }
3323 AutoRestore<bool> pending(mPendingPluginCall);
3324 mPendingPluginCall = true;
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 }
3338 if (!EnsureCurrentBuffer()) {
3339 return false;
3340 }
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) {
3349 if (!IsVisible()) {
3350 return true;
3351 }
3353 if (!mDoubleBufferCARenderer.HasFrontSurface()) {
3354 NS_ERROR("CARenderer not initialized for rendering");
3355 return false;
3356 }
3358 // Clear accRect here to be able to pass
3359 // test_invalidate_during_plugin_paint test
3360 nsIntRect rect = mAccumulatedInvalidRect;
3361 mAccumulatedInvalidRect.SetEmpty();
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()));
3370 if (mDrawingModel == NPDrawingModelCoreGraphics) {
3371 mozilla::plugins::PluginUtilsOSX::Repaint(mCGLayer, rect);
3372 }
3374 mDoubleBufferCARenderer.Render();
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());
3382 mHasPainted = true;
3384 SurfaceDescriptor returnSurf;
3386 if (!SendShow(r, currSurf, &returnSurf)) {
3387 return false;
3388 }
3390 SwapSurfaces();
3391 return true;
3392 } else {
3393 NS_ERROR("Unsupported drawing model for async layer rendering");
3394 return false;
3395 }
3396 #endif
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");
3402 // Clear accRect here to be able to pass
3403 // test_invalidate_during_plugin_paint test
3404 nsIntRect rect = mAccumulatedInvalidRect;
3405 mAccumulatedInvalidRect.SetEmpty();
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));
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 }
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));
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)"));
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;
3458 PaintRectToSurface(rect, target, gfxRGBA(0.0, 0.0, 0.0, 0.0));
3459 }
3460 mHasPainted = true;
3462 if (temporarilyMakeVisible) {
3463 mWindow.clipRect.right = mWindow.clipRect.bottom = 0;
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));
3470 if (mPluginIface->setwindow) {
3471 mPluginIface->setwindow(&mData, &mWindow);
3472 }
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 }
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);
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 }
3518 // Unused, except to possibly return a shmem to us
3519 SurfaceDescriptor returnSurf;
3521 if (!SendShow(r, currSurf, &returnSurf)) {
3522 return false;
3523 }
3525 SwapSurfaces();
3526 mSurfaceDifferenceRect = rect;
3527 return true;
3528 }
3530 bool
3531 PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
3532 {
3533 if (!mBackSurface)
3534 return false;
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
3549 if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType())
3550 return false;
3552 if (mSurfaceDifferenceRect.IsEmpty())
3553 return true;
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));
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();
3574 return true;
3575 }
3577 void
3578 PluginInstanceChild::InvalidateRectDelayed(void)
3579 {
3580 if (!mCurrentInvalidateTask) {
3581 return;
3582 }
3584 mCurrentInvalidateTask = nullptr;
3585 if (mAccumulatedInvalidRect.IsEmpty()) {
3586 return;
3587 }
3589 if (!ShowPluginFrame()) {
3590 AsyncShowPluginFrame();
3591 }
3592 }
3594 void
3595 PluginInstanceChild::AsyncShowPluginFrame(void)
3596 {
3597 if (mCurrentInvalidateTask) {
3598 return;
3599 }
3601 mCurrentInvalidateTask =
3602 NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed);
3603 MessageLoop::current()->PostTask(FROM_HERE, mCurrentInvalidateTask);
3604 }
3606 void
3607 PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
3608 {
3609 NS_ASSERTION(aInvalidRect, "Null pointer!");
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
3622 if (mLayersRendering) {
3623 nsIntRect r(aInvalidRect->left, aInvalidRect->top,
3624 aInvalidRect->right - aInvalidRect->left,
3625 aInvalidRect->bottom - aInvalidRect->top);
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 }
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 }
3643 bool
3644 PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground,
3645 const nsIntRect& aRect)
3646 {
3647 NS_ABORT_IF_FALSE(mIsTransparent, "Only transparent plugins use backgrounds");
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 }
3666 if (!mBackground) {
3667 return false;
3668 }
3670 gfxIntSize bgSize = mBackground->GetSize();
3671 mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect,
3672 nsIntRect(0, 0, bgSize.width, bgSize.height));
3673 AsyncShowPluginFrame();
3674 return true;
3675 }
3677 // XXX refactor me
3678 mAccumulatedInvalidRect.UnionRect(aRect, mAccumulatedInvalidRect);
3680 // This must be asynchronous, because we may be nested within RPC messages
3681 // which do not expect to receiving paint events.
3682 AsyncShowPluginFrame();
3684 return true;
3685 }
3687 PPluginBackgroundDestroyerChild*
3688 PluginInstanceChild::AllocPPluginBackgroundDestroyerChild()
3689 {
3690 return new PluginBackgroundDestroyerChild();
3691 }
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);
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 }
3717 return PPluginBackgroundDestroyerChild::Send__delete__(aActor);
3718 }
3720 bool
3721 PluginInstanceChild::DeallocPPluginBackgroundDestroyerChild(
3722 PPluginBackgroundDestroyerChild* aActor)
3723 {
3724 delete aActor;
3725 return true;
3726 }
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 }
3738 mTimers.AppendElement(t);
3739 return t->ID();
3740 }
3742 void
3743 PluginInstanceChild::UnscheduleTimer(uint32_t id)
3744 {
3745 if (0 == id)
3746 return;
3748 mTimers.RemoveElement(id, ChildTimer::IDComparator());
3749 }
3751 void
3752 PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData)
3753 {
3754 ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData);
3756 {
3757 MutexAutoLock lock(mAsyncCallMutex);
3758 mPendingAsyncCalls.AppendElement(task);
3759 }
3760 ProcessChild::message_loop()->PostTask(FROM_HERE, task);
3761 }
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);
3770 return PL_DHASH_NEXT;
3771 }
3773 static PLDHashOperator
3774 DeleteObject(DeletingObjectEntry* e, void* userArg)
3775 {
3776 NPObject* o = e->GetKey();
3777 if (!e->mDeleted) {
3778 e->mDeleted = true;
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
3790 PluginModuleChild::DeallocNPObject(o);
3791 }
3793 return PL_DHASH_NEXT;
3794 }
3796 void
3797 PluginInstanceChild::SwapSurfaces()
3798 {
3799 nsRefPtr<gfxASurface> tmpsurf = mCurrentSurface;
3800 #ifdef XP_WIN
3801 PPluginSurfaceChild* tmpactor = mCurrentSurfaceActor;
3802 #endif
3804 mCurrentSurface = mBackSurface;
3805 #ifdef XP_WIN
3806 mCurrentSurfaceActor = mBackSurfaceActor;
3807 #endif
3809 mBackSurface = tmpsurf;
3810 #ifdef XP_WIN
3811 mBackSurfaceActor = tmpactor;
3812 #endif
3814 #ifdef MOZ_WIDGET_COCOA
3815 mDoubleBufferCARenderer.SwapSurfaces();
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())) {
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 }
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 }
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 }
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;
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
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 }
3893 if (mCGLayer) {
3894 mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer);
3895 mCGLayer = nullptr;
3896 }
3898 mDoubleBufferCARenderer.ClearFrontSurface();
3899 mDoubleBufferCARenderer.ClearBackSurface();
3900 #endif
3901 }
3903 PLDHashOperator
3904 PluginInstanceChild::DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg)
3905 {
3906 PluginInstanceChild *inst = static_cast<PluginInstanceChild*>(userArg);
3908 inst->DeallocShmem(data->mShmem);
3910 return PL_DHASH_REMOVE;
3911 }
3913 bool
3914 PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
3915 {
3916 PLUGIN_LOG_DEBUG_METHOD;
3917 AssertPluginThread();
3918 *aResult = NPERR_NO_ERROR;
3920 #if defined(OS_WIN)
3921 SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
3922 #endif
3924 InfallibleTArray<PBrowserStreamChild*> streams;
3925 ManagedPBrowserStreamChild(streams);
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();
3937 mTimers.Clear();
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;
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 }
3961 ClearAllSurfaces();
3963 mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
3964 PluginModuleChild::current()->FindNPObjectsForInstance(this);
3966 mDeletingHash->EnumerateEntries(InvalidateObject, nullptr);
3967 mDeletingHash->EnumerateEntries(DeleteObject, nullptr);
3969 // Null out our cached actors as they should have been killed in the
3970 // PluginInstanceDestroyed call above.
3971 mCachedWindowActor = nullptr;
3972 mCachedElementActor = nullptr;
3974 #if defined(OS_WIN)
3975 SharedSurfaceRelease();
3976 DestroyWinlessPopupSurrogate();
3977 UnhookWinlessFlashThrottle();
3978 DestroyPluginWindow();
3979 #endif
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();
3986 mPendingAsyncCalls.Clear();
3988 if (mAsyncBitmaps.Count()) {
3989 NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!");
3990 mAsyncBitmaps.Enumerate(DeleteSurface, this);
3991 }
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
4002 return true;
4003 }