Bug 630697 - Flash crash [@ _SEH_prolog ]; r=bsmedberg a=blocking-final+
[mozilla-central.git] / dom / plugins / PluginInstanceChild.cpp
blob48dbf5a84a601df2e6d9c5e36eaee1012f6d892f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 et :
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Plugin App.
18 * The Initial Developer of the Original Code is
19 * Chris Jones <jones.chris.g@gmail.com>
20 * Portions created by the Initial Developer are Copyright (C) 2009
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Jim Mathies <jmathies@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "PluginInstanceChild.h"
41 #include "PluginModuleChild.h"
42 #include "BrowserStreamChild.h"
43 #include "PluginStreamChild.h"
44 #include "StreamNotifyChild.h"
45 #include "PluginProcessChild.h"
46 #include "gfxASurface.h"
47 #include "gfxContext.h"
48 #ifdef MOZ_X11
49 #include "gfxXlibSurface.h"
50 #endif
51 #ifdef XP_WIN
52 #include "mozilla/gfx/SharedDIBSurface.h"
54 using mozilla::gfx::SharedDIBSurface;
55 #endif
56 #include "gfxSharedImageSurface.h"
57 #include "gfxUtils.h"
58 #include "gfxAlphaRecovery.h"
60 #include "mozilla/ipc/SyncChannel.h"
62 using mozilla::ipc::ProcessChild;
63 using namespace mozilla::plugins;
65 #ifdef MOZ_WIDGET_GTK2
67 #include <gtk/gtk.h>
68 #include <gdk/gdkx.h>
69 #include <gdk/gdk.h>
70 #include "gtk2xtbin.h"
72 #elif defined(MOZ_WIDGET_QT)
73 #include <QX11Info>
74 #elif defined(OS_WIN)
75 #ifndef WM_MOUSEHWHEEL
76 #define WM_MOUSEHWHEEL 0x020E
77 #endif
79 #include "nsWindowsDllInterceptor.h"
81 typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu,
82 UINT uFlags,
83 int x,
84 int y,
85 int nReserved,
86 HWND hWnd,
87 CONST RECT *prcRect);
88 static WindowsDllInterceptor sUser32Intercept;
89 static HWND sWinlessPopupSurrogateHWND = NULL;
90 static User32TrackPopupMenu sUser32TrackPopupMenuStub = NULL;
92 using mozilla::gfx::SharedDIB;
94 #include <windows.h>
95 #include <windowsx.h>
97 // Flash WM_USER message delay time for PostDelayedTask. Borrowed
98 // from Chromium's web plugin delegate src. See 'flash msg throttling
99 // helpers' section for details.
100 const int kFlashWMUSERMessageThrottleDelayMs = 5;
102 static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassProperty");
104 #elif defined(XP_MACOSX)
105 #include <ApplicationServices/ApplicationServices.h>
106 #endif // defined(XP_MACOSX)
108 template<>
109 struct RunnableMethodTraits<PluginInstanceChild>
111 static void RetainCallee(PluginInstanceChild* obj) { }
112 static void ReleaseCallee(PluginInstanceChild* obj) { }
115 PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
116 : mPluginIface(aPluginIface)
117 , mCachedWindowActor(nsnull)
118 , mCachedElementActor(nsnull)
119 #if defined(OS_WIN)
120 , mPluginWindowHWND(0)
121 , mPluginWndProc(0)
122 , mPluginParentHWND(0)
123 , mCachedWinlessPluginHWND(0)
124 , mWinlessPopupSurrogateHWND(0)
125 , mWinlessThrottleOldWndProc(0)
126 , mWinlessHiddenMsgHWND(0)
127 , mMouseHook(NULL)
128 #endif // OS_WIN
129 , mAsyncCallMutex("PluginInstanceChild::mAsyncCallMutex")
130 #if defined(OS_MACOSX)
131 #if defined(__i386__)
132 , mEventModel(NPEventModelCarbon)
133 #endif
134 , mShColorSpace(nsnull)
135 , mShContext(nsnull)
136 , mDrawingModel(NPDrawingModelCoreGraphics)
137 , mCurrentEvent(nsnull)
138 #endif
139 , mLayersRendering(false)
140 #ifdef XP_WIN
141 , mCurrentSurfaceActor(NULL)
142 , mBackSurfaceActor(NULL)
143 #endif
144 , mAccumulatedInvalidRect(0,0,0,0)
145 , mIsTransparent(false)
146 , mSurfaceType(gfxASurface::SurfaceTypeMax)
147 , mCurrentInvalidateTask(nsnull)
148 , mCurrentAsyncSetWindowTask(nsnull)
149 , mPendingPluginCall(false)
150 , mDoAlphaExtraction(false)
151 , mHasPainted(false)
152 , mSurfaceDifferenceRect(0,0,0,0)
153 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
154 , mMaemoImageRendering(PR_FALSE)
155 #endif
157 memset(&mWindow, 0, sizeof(mWindow));
158 mData.ndata = (void*) this;
159 mData.pdata = nsnull;
160 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
161 mWindow.ws_info = &mWsInfo;
162 memset(&mWsInfo, 0, sizeof(mWsInfo));
163 mWsInfo.display = DefaultXDisplay();
164 #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
165 #if defined(OS_WIN)
166 memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
167 #endif // OS_WIN
168 #if defined(OS_WIN)
169 InitPopupMenuHook();
170 HookSystemParametersInfo();
171 #endif // OS_WIN
172 #ifdef MOZ_X11
173 // Maemo flash can render plugin with any provided rectangle and not require this quirk.
174 #ifndef MOZ_PLATFORM_MAEMO
175 const char *description = NULL;
176 mPluginIface->getvalue(GetNPP(), NPPVpluginDescriptionString,
177 &description);
178 if (description) {
179 NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
180 if (StringBeginsWith(nsDependentCString(description), flash10Head)) {
181 PluginModuleChild::current()->AddQuirk(PluginModuleChild::QUIRK_FLASH_EXPOSE_COORD_TRANSLATION);
184 #endif
185 #endif
188 PluginInstanceChild::~PluginInstanceChild()
190 #if defined(OS_WIN)
191 NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?");
192 #endif
193 #if defined(OS_MACOSX)
194 if (mShColorSpace) {
195 ::CGColorSpaceRelease(mShColorSpace);
197 if (mShContext) {
198 ::CGContextRelease(mShContext);
200 #endif
204 PluginInstanceChild::GetQuirks()
206 return PluginModuleChild::current()->GetQuirks();
209 NPError
210 PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
211 NPObject** aObject)
213 PluginScriptableObjectChild* actor;
214 NPError result = NPERR_NO_ERROR;
216 switch (aValue) {
217 case NPNVWindowNPObject:
218 if (!(actor = mCachedWindowActor)) {
219 PPluginScriptableObjectChild* actorProtocol;
220 CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result);
221 if (result == NPERR_NO_ERROR) {
222 actor = mCachedWindowActor =
223 static_cast<PluginScriptableObjectChild*>(actorProtocol);
224 NS_ASSERTION(actor, "Null actor!");
225 PluginModuleChild::sBrowserFuncs.retainobject(
226 actor->GetObject(false));
229 break;
231 case NPNVPluginElementNPObject:
232 if (!(actor = mCachedElementActor)) {
233 PPluginScriptableObjectChild* actorProtocol;
234 CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol,
235 &result);
236 if (result == NPERR_NO_ERROR) {
237 actor = mCachedElementActor =
238 static_cast<PluginScriptableObjectChild*>(actorProtocol);
239 NS_ASSERTION(actor, "Null actor!");
240 PluginModuleChild::sBrowserFuncs.retainobject(
241 actor->GetObject(false));
244 break;
246 default:
247 NS_NOTREACHED("Don't know what to do with this value type!");
250 #ifdef DEBUG
252 NPError currentResult;
253 PPluginScriptableObjectChild* currentActor;
255 switch (aValue) {
256 case NPNVWindowNPObject:
257 CallNPN_GetValue_NPNVWindowNPObject(&currentActor,
258 &currentResult);
259 break;
260 case NPNVPluginElementNPObject:
261 CallNPN_GetValue_NPNVPluginElementNPObject(&currentActor,
262 &currentResult);
263 break;
264 default:
265 NS_NOTREACHED("Don't know what to do with this value type!");
268 // Make sure that the current actor returned by the parent matches our
269 // cached actor!
270 NS_ASSERTION(static_cast<PluginScriptableObjectChild*>(currentActor) ==
271 actor, "Cached actor is out of date!");
272 NS_ASSERTION(currentResult == result, "Results don't match?!");
274 #endif
276 if (result != NPERR_NO_ERROR) {
277 return result;
280 NPObject* object = actor->GetObject(false);
281 NS_ASSERTION(object, "Null object?!");
283 *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object);
284 return NPERR_NO_ERROR;
288 NPError
289 PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
290 void* aValue)
292 PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar));
293 AssertPluginThread();
295 switch(aVar) {
297 case NPNVSupportsWindowless:
298 #if defined(OS_LINUX) || defined(OS_WIN)
299 *((NPBool*)aValue) = true;
300 #else
301 *((NPBool*)aValue) = false;
302 #endif
303 return NPERR_NO_ERROR;
305 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
306 case NPNVSupportsWindowlessLocal: {
307 #ifdef MOZ_WIDGET_QT
308 const char *graphicsSystem = PR_GetEnv("MOZ_QT_GRAPHICSSYSTEM");
309 // we should set local rendering to false in order to render X-Plugin
310 // there is no possibility to change it later on maemo5 platform
311 mMaemoImageRendering = (!(graphicsSystem && !strcmp(graphicsSystem, "native")));
312 #endif
313 *((NPBool*)aValue) = mMaemoImageRendering;
314 return NPERR_NO_ERROR;
316 #endif
317 #if defined(OS_LINUX)
318 case NPNVSupportsXEmbedBool:
319 *((NPBool*)aValue) = true;
320 return NPERR_NO_ERROR;
322 case NPNVToolkit:
323 *((NPNToolkitType*)aValue) = NPNVGtk2;
324 return NPERR_NO_ERROR;
326 #elif defined(OS_WIN)
327 case NPNVToolkit:
328 return NPERR_GENERIC_ERROR;
329 #endif
330 case NPNVjavascriptEnabledBool: {
331 bool v = false;
332 NPError result;
333 if (!CallNPN_GetValue_NPNVjavascriptEnabledBool(&v, &result)) {
334 return NPERR_GENERIC_ERROR;
336 *static_cast<NPBool*>(aValue) = v;
337 return result;
340 case NPNVisOfflineBool: {
341 bool v = false;
342 NPError result;
343 if (!CallNPN_GetValue_NPNVisOfflineBool(&v, &result)) {
344 return NPERR_GENERIC_ERROR;
346 *static_cast<NPBool*>(aValue) = v;
347 return result;
350 case NPNVprivateModeBool: {
351 bool v = false;
352 NPError result;
353 if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) {
354 return NPERR_GENERIC_ERROR;
356 *static_cast<NPBool*>(aValue) = v;
357 return result;
360 case NPNVWindowNPObject: // Intentional fall-through
361 case NPNVPluginElementNPObject: {
362 NPObject* object;
363 NPError result = InternalGetNPObjectForValue(aVar, &object);
364 if (result == NPERR_NO_ERROR) {
365 *((NPObject**)aValue) = object;
367 return result;
370 case NPNVnetscapeWindow: {
371 #ifdef XP_WIN
372 if (mWindow.type == NPWindowTypeDrawable) {
373 if (mCachedWinlessPluginHWND) {
374 *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND;
375 return NPERR_NO_ERROR;
377 NPError result;
378 if (!CallNPN_GetValue_NPNVnetscapeWindow(&mCachedWinlessPluginHWND, &result)) {
379 return NPERR_GENERIC_ERROR;
381 *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND;
382 return result;
384 else {
385 *static_cast<HWND*>(aValue) = mPluginWindowHWND;
386 return NPERR_NO_ERROR;
388 #elif defined(MOZ_X11)
389 NPError result;
390 CallNPN_GetValue_NPNVnetscapeWindow(static_cast<XID*>(aValue), &result);
391 return result;
392 #else
393 return NPERR_GENERIC_ERROR;
394 #endif
397 #ifdef XP_MACOSX
398 case NPNVsupportsCoreGraphicsBool: {
399 *((NPBool*)aValue) = true;
400 return NPERR_NO_ERROR;
403 case NPNVsupportsCoreAnimationBool: {
404 *((NPBool*)aValue) = true;
405 return NPERR_NO_ERROR;
408 case NPNVsupportsInvalidatingCoreAnimationBool: {
409 *((NPBool*)aValue) = true;
410 return NPERR_NO_ERROR;
413 case NPNVsupportsCocoaBool: {
414 *((NPBool*)aValue) = true;
415 return NPERR_NO_ERROR;
418 #ifndef NP_NO_CARBON
419 case NPNVsupportsCarbonBool: {
420 *((NPBool*)aValue) = false;
421 return NPERR_NO_ERROR;
423 #endif
425 case NPNVsupportsUpdatedCocoaTextInputBool: {
426 *static_cast<NPBool*>(aValue) = true;
427 return NPERR_NO_ERROR;
430 #ifndef NP_NO_QUICKDRAW
431 case NPNVsupportsQuickDrawBool: {
432 *((NPBool*)aValue) = false;
433 return NPERR_NO_ERROR;
435 #endif /* NP_NO_QUICKDRAW */
436 #endif /* XP_MACOSX */
438 default:
439 PR_LOG(gPluginLog, PR_LOG_WARNING,
440 ("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)",
441 (int) aVar, NPNVariableToString(aVar)));
442 return NPERR_GENERIC_ERROR;
448 NPError
449 PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
451 PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s (aVar=%i, aValue=%p)",
452 FULLFUNCTION, (int) aVar, aValue));
454 AssertPluginThread();
456 switch (aVar) {
457 case NPPVpluginWindowBool: {
458 NPError rv;
459 bool windowed = (NPBool) (intptr_t) aValue;
461 if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv))
462 return NPERR_GENERIC_ERROR;
464 return rv;
467 case NPPVpluginTransparentBool: {
468 NPError rv;
469 mIsTransparent = (!!aValue);
471 if (!CallNPN_SetValue_NPPVpluginTransparent(mIsTransparent, &rv))
472 return NPERR_GENERIC_ERROR;
474 return rv;
477 #ifdef XP_MACOSX
478 case NPPVpluginDrawingModel: {
479 NPError rv;
480 int drawingModel = (int16) (intptr_t) aValue;
482 if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &rv))
483 return NPERR_GENERIC_ERROR;
484 mDrawingModel = drawingModel;
486 return rv;
489 case NPPVpluginEventModel: {
490 NPError rv;
491 int eventModel = (int16) (intptr_t) aValue;
493 if (!CallNPN_SetValue_NPPVpluginEventModel(eventModel, &rv))
494 return NPERR_GENERIC_ERROR;
495 #if defined(__i386__)
496 mEventModel = static_cast<NPEventModel>(eventModel);
497 #endif
499 return rv;
501 #endif
503 default:
504 PR_LOG(gPluginLog, PR_LOG_WARNING,
505 ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)",
506 (int) aVar, NPPVariableToString(aVar)));
507 return NPERR_GENERIC_ERROR;
511 bool
512 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(
513 bool* needs, NPError* rv)
515 AssertPluginThread();
517 #ifdef MOZ_X11
518 // The documentation on the types for many variables in NP(N|P)_GetValue
519 // is vague. Often boolean values are NPBool (1 byte), but
520 // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins
521 // treats NPPVpluginNeedsXEmbed as PRBool (int), and
522 // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|.
523 // thus we can't use NPBool for needsXEmbed, or the three bytes above
524 // it on the stack would get clobbered. so protect with the larger PRBool.
525 PRBool needsXEmbed = 0;
526 if (!mPluginIface->getvalue) {
527 *rv = NPERR_GENERIC_ERROR;
529 else {
530 *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginNeedsXEmbed,
531 &needsXEmbed);
533 *needs = needsXEmbed;
534 return true;
536 #else
538 NS_RUNTIMEABORT("shouldn't be called on non-X11 platforms");
539 return false; // not reached
541 #endif
544 bool
545 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
546 PPluginScriptableObjectChild** aValue,
547 NPError* aResult)
549 AssertPluginThread();
551 NPObject* object = nsnull;
552 NPError result = NPERR_GENERIC_ERROR;
553 if (mPluginIface->getvalue) {
554 result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject,
555 &object);
557 if (result == NPERR_NO_ERROR && object) {
558 PluginScriptableObjectChild* actor = GetActorForNPObject(object);
560 // If we get an actor then it has retained. Otherwise we don't need it
561 // any longer.
562 PluginModuleChild::sBrowserFuncs.releaseobject(object);
563 if (actor) {
564 *aValue = actor;
565 *aResult = NPERR_NO_ERROR;
566 return true;
569 NS_ERROR("Failed to get actor!");
570 result = NPERR_GENERIC_ERROR;
572 else {
573 result = NPERR_GENERIC_ERROR;
576 *aValue = nsnull;
577 *aResult = result;
578 return true;
581 bool
582 PluginInstanceChild::AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value,
583 NPError* result)
585 if (!mPluginIface->setvalue) {
586 *result = NPERR_GENERIC_ERROR;
587 return true;
590 NPBool v = value;
591 *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v);
592 return true;
595 bool
596 PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
597 int16_t* handled)
599 PLUGIN_LOG_DEBUG_FUNCTION;
600 AssertPluginThread();
602 #if defined(MOZ_X11) && defined(DEBUG)
603 if (GraphicsExpose == event.event.type)
604 PLUGIN_LOG_DEBUG((" received drawable 0x%lx\n",
605 event.event.xgraphicsexpose.drawable));
606 #endif
608 #ifdef XP_MACOSX
609 // Mac OS X does not define an NPEvent structure. It defines more specific types.
610 NPCocoaEvent evcopy = event.event;
612 // Make sure we reset mCurrentEvent in case of an exception
613 AutoRestore<const NPCocoaEvent*> savePreviousEvent(mCurrentEvent);
615 // Track the current event for NPN_PopUpContextMenu.
616 mCurrentEvent = &event.event;
617 #else
618 // Make a copy since we may modify values.
619 NPEvent evcopy = event.event;
620 #endif
622 #ifdef OS_WIN
623 // FIXME/bug 567645: temporarily drop the "dummy event" on the floor
624 if (WM_NULL == evcopy.event)
625 return true;
627 // Painting for win32. SharedSurfacePaint handles everything.
628 if (mWindow.type == NPWindowTypeDrawable) {
629 if (evcopy.event == WM_PAINT) {
630 *handled = SharedSurfacePaint(evcopy);
631 return true;
633 else if (DoublePassRenderingEvent() == evcopy.event) {
634 // We'll render to mSharedSurfaceDib first, then render to a cached bitmap
635 // we store locally. The two passes are for alpha extraction, so the second
636 // pass must be to a flat white surface in order for things to work.
637 mAlphaExtract.doublePass = RENDER_BACK_ONE;
638 *handled = true;
639 return true;
642 *handled = WinlessHandleEvent(evcopy);
643 return true;
644 #endif
646 // XXX A previous call to mPluginIface->event might block, e.g. right click
647 // for context menu. Still, we might get here again, calling into the plugin
648 // a second time while it's in the previous call.
649 if (!mPluginIface->event)
650 *handled = false;
651 else
652 *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
654 #ifdef XP_MACOSX
655 // Release any reference counted objects created in the child process.
656 if (evcopy.type == NPCocoaEventKeyDown ||
657 evcopy.type == NPCocoaEventKeyUp) {
658 ::CFRelease((CFStringRef)evcopy.data.key.characters);
659 ::CFRelease((CFStringRef)evcopy.data.key.charactersIgnoringModifiers);
661 else if (evcopy.type == NPCocoaEventTextInput) {
662 ::CFRelease((CFStringRef)evcopy.data.text.text);
664 #endif
666 #ifdef MOZ_X11
667 if (GraphicsExpose == event.event.type) {
668 // Make sure the X server completes the drawing before the parent
669 // draws on top and destroys the Drawable.
671 // XSync() waits for the X server to complete. Really this child
672 // process does not need to wait; the parent is the process that needs
673 // to wait. A possibly-slightly-better alternative would be to send
674 // an X event to the parent that the parent would wait for.
675 XSync(mWsInfo.display, False);
677 #endif
679 return true;
682 #ifdef XP_MACOSX
684 bool
685 PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
686 Shmem& mem,
687 int16_t* handled,
688 Shmem* rtnmem)
690 PLUGIN_LOG_DEBUG_FUNCTION;
691 AssertPluginThread();
693 PaintTracker pt;
695 NPCocoaEvent evcopy = event.event;
697 if (evcopy.type == NPCocoaEventDrawRect) {
698 if (!mShColorSpace) {
699 mShColorSpace = CreateSystemColorSpace();
700 if (!mShColorSpace) {
701 PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
702 *handled = false;
703 *rtnmem = mem;
704 return true;
707 if (!mShContext) {
708 void* cgContextByte = mem.get<char>();
709 mShContext = ::CGBitmapContextCreate(cgContextByte,
710 mWindow.width, mWindow.height, 8,
711 mWindow.width * 4, mShColorSpace,
712 kCGImageAlphaPremultipliedFirst |
713 kCGBitmapByteOrder32Host);
715 if (!mShContext) {
716 PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext."));
717 *handled = false;
718 *rtnmem = mem;
719 return true;
722 CGRect clearRect = ::CGRectMake(0, 0, mWindow.width, mWindow.height);
723 ::CGContextClearRect(mShContext, clearRect);
724 evcopy.data.draw.context = mShContext;
725 } else {
726 PLUGIN_LOG_DEBUG(("Invalid event type for AnswerNNP_HandleEvent_Shmem."));
727 *handled = false;
728 *rtnmem = mem;
729 return true;
732 if (!mPluginIface->event) {
733 *handled = false;
734 } else {
735 ::CGContextSaveGState(evcopy.data.draw.context);
736 *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
737 ::CGContextRestoreGState(evcopy.data.draw.context);
740 *rtnmem = mem;
741 return true;
744 #else
745 bool
746 PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
747 Shmem& mem,
748 int16_t* handled,
749 Shmem* rtnmem)
751 NS_RUNTIMEABORT("not reached.");
752 *rtnmem = mem;
753 return true;
755 #endif
757 #ifdef XP_MACOSX
758 bool
759 PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event,
760 const uint32_t &surfaceid,
761 int16_t* handled)
763 PLUGIN_LOG_DEBUG_FUNCTION;
764 AssertPluginThread();
766 PaintTracker pt;
768 NPCocoaEvent evcopy = event.event;
769 nsIOSurface* surf = nsIOSurface::LookupSurface(surfaceid);
770 if (!surf) {
771 NS_ERROR("Invalid IOSurface.");
772 *handled = false;
773 return false;
776 if (evcopy.type == NPCocoaEventDrawRect) {
777 mCARenderer.AttachIOSurface(surf);
778 if (!mCARenderer.isInit()) {
779 void *caLayer = nsnull;
780 NPError result = mPluginIface->getvalue(GetNPP(),
781 NPPVpluginCoreAnimationLayer,
782 &caLayer);
783 if (result != NPERR_NO_ERROR || !caLayer) {
784 PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not "
785 "provide CALayer."));
786 *handled = false;
787 return false;
789 mCARenderer.SetupRenderer(caLayer, mWindow.width, mWindow.height);
790 // Flash needs to have the window set again after this step
791 if (mPluginIface->setwindow)
792 (void) mPluginIface->setwindow(&mData, &mWindow);
794 } else {
795 PLUGIN_LOG_DEBUG(("Invalid event type for "
796 "AnswerNNP_HandleEvent_IOSurface."));
797 *handled = false;
798 return false;
801 mCARenderer.Render(mWindow.width, mWindow.height, nsnull);
803 return true;
807 #else
808 bool
809 PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event,
810 const uint32_t &surfaceid,
811 int16_t* handled)
813 NS_RUNTIMEABORT("NPP_HandleEvent_IOSurface is a OSX-only message");
814 return false;
816 #endif
818 bool
819 PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
821 NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
822 "Shouldn't be receiving WindowPosChanged with layer rendering");
824 #ifdef OS_WIN
825 int16_t dontcare;
826 return AnswerNPP_HandleEvent(event, &dontcare);
827 #else
828 NS_RUNTIMEABORT("WindowPosChanged is a windows-only message");
829 return false;
830 #endif
834 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
835 static bool
836 XVisualIDToInfo(Display* aDisplay, VisualID aVisualID,
837 Visual** aVisual, unsigned int* aDepth)
839 if (aVisualID == None) {
840 *aVisual = NULL;
841 *aDepth = 0;
842 return true;
845 const Screen* screen = DefaultScreenOfDisplay(aDisplay);
847 for (int d = 0; d < screen->ndepths; d++) {
848 Depth *d_info = &screen->depths[d];
849 for (int v = 0; v < d_info->nvisuals; v++) {
850 Visual* visual = &d_info->visuals[v];
851 if (visual->visualid == aVisualID) {
852 *aVisual = visual;
853 *aDepth = d_info->depth;
854 return true;
859 NS_ERROR("VisualID not on Screen.");
860 return false;
862 #endif
864 bool
865 PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
867 PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
868 FULLFUNCTION,
869 aWindow.window,
870 aWindow.x, aWindow.y,
871 aWindow.width, aWindow.height));
872 NS_ASSERTION(!mLayersRendering && !mPendingPluginCall,
873 "Shouldn't be receiving NPP_SetWindow with layer rendering");
874 AssertPluginThread();
876 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
877 // The minimum info is sent over IPC to allow this
878 // code to determine the rest.
880 mWindow.window = reinterpret_cast<void*>(aWindow.window);
881 mWindow.x = aWindow.x;
882 mWindow.y = aWindow.y;
883 mWindow.width = aWindow.width;
884 mWindow.height = aWindow.height;
885 mWindow.clipRect = aWindow.clipRect;
886 mWindow.type = aWindow.type;
888 mWsInfo.colormap = aWindow.colormap;
889 if (!XVisualIDToInfo(mWsInfo.display, aWindow.visualID,
890 &mWsInfo.visual, &mWsInfo.depth))
891 return false;
893 #ifdef MOZ_WIDGET_GTK2
894 if (gtk_check_version(2,18,7) != NULL) { // older
895 if (aWindow.type == NPWindowTypeWindow) {
896 GdkWindow* socket_window = gdk_window_lookup(aWindow.window);
897 if (socket_window) {
898 // A GdkWindow for the socket already exists. Need to
899 // workaround https://bugzilla.gnome.org/show_bug.cgi?id=607061
900 // See wrap_gtk_plug_embedded in PluginModuleChild.cpp.
901 g_object_set_data(G_OBJECT(socket_window),
902 "moz-existed-before-set-window",
903 GUINT_TO_POINTER(1));
907 if (aWindow.visualID != None
908 && gtk_check_version(2, 12, 10) != NULL) { // older
909 // Workaround for a bug in Gtk+ (prior to 2.12.10) where deleting
910 // a foreign GdkColormap will also free the XColormap.
911 // http://git.gnome.org/browse/gtk+/log/gdk/x11/gdkcolor-x11.c?id=GTK_2_12_10
912 GdkVisual *gdkvisual = gdkx_visual_get(aWindow.visualID);
913 GdkColormap *gdkcolor =
914 gdk_x11_colormap_foreign_new(gdkvisual, aWindow.colormap);
916 if (g_object_get_data(G_OBJECT(gdkcolor), "moz-have-extra-ref")) {
917 // We already have a ref to keep the object alive.
918 g_object_unref(gdkcolor);
919 } else {
920 // leak and mark as already leaked
921 g_object_set_data(G_OBJECT(gdkcolor),
922 "moz-have-extra-ref", GUINT_TO_POINTER(1));
926 #endif
928 if (mPluginIface->setwindow)
929 (void) mPluginIface->setwindow(&mData, &mWindow);
931 #elif defined(OS_WIN)
932 switch (aWindow.type) {
933 case NPWindowTypeWindow:
935 if (!CreatePluginWindow())
936 return false;
938 ReparentPluginWindow((HWND)aWindow.window);
939 SizePluginWindow(aWindow.width, aWindow.height);
941 mWindow.window = (void*)mPluginWindowHWND;
942 mWindow.x = aWindow.x;
943 mWindow.y = aWindow.y;
944 mWindow.width = aWindow.width;
945 mWindow.height = aWindow.height;
946 mWindow.type = aWindow.type;
948 if (mPluginIface->setwindow) {
949 SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
950 (void) mPluginIface->setwindow(&mData, &mWindow);
951 WNDPROC wndProc = reinterpret_cast<WNDPROC>(
952 GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
953 if (wndProc != PluginWindowProc) {
954 mPluginWndProc = reinterpret_cast<WNDPROC>(
955 SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
956 reinterpret_cast<LONG_PTR>(PluginWindowProc)));
958 RemoveProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty);
959 HookSetWindowLongPtr();
962 break;
964 case NPWindowTypeDrawable:
965 mWindow.type = aWindow.type;
966 if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK)
967 CreateWinlessPopupSurrogate();
968 if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
969 SetupFlashMsgThrottle();
970 return SharedSurfaceSetWindow(aWindow);
971 break;
973 default:
974 NS_NOTREACHED("Bad plugin window type.");
975 return false;
976 break;
979 #elif defined(XP_MACOSX)
981 mWindow.x = aWindow.x;
982 mWindow.y = aWindow.y;
983 mWindow.width = aWindow.width;
984 mWindow.height = aWindow.height;
985 mWindow.clipRect = aWindow.clipRect;
986 mWindow.type = aWindow.type;
988 if (mShContext) {
989 // Release the shared context so that it is reallocated
990 // with the new size.
991 ::CGContextRelease(mShContext);
992 mShContext = nsnull;
995 if (mPluginIface->setwindow)
996 (void) mPluginIface->setwindow(&mData, &mWindow);
998 #elif defined(ANDROID)
999 # warning Need Android impl
1000 #else
1001 # error Implement me for your OS
1002 #endif
1004 return true;
1007 bool
1008 PluginInstanceChild::Initialize()
1010 return true;
1013 #if defined(OS_WIN)
1015 static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
1016 static const TCHAR kPluginInstanceChildProperty[] = TEXT("PluginInstanceChildProperty");
1017 static const TCHAR kFlashThrottleProperty[] = TEXT("MozillaFlashThrottleProperty");
1019 // static
1020 bool
1021 PluginInstanceChild::RegisterWindowClass()
1023 static bool alreadyRegistered = false;
1024 if (alreadyRegistered)
1025 return true;
1027 alreadyRegistered = true;
1029 WNDCLASSEX wcex;
1030 wcex.cbSize = sizeof(WNDCLASSEX);
1031 wcex.style = CS_DBLCLKS;
1032 wcex.lpfnWndProc = DummyWindowProc;
1033 wcex.cbClsExtra = 0;
1034 wcex.cbWndExtra = 0;
1035 wcex.hInstance = GetModuleHandle(NULL);
1036 wcex.hIcon = 0;
1037 wcex.hCursor = 0;
1038 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
1039 wcex.lpszMenuName = 0;
1040 wcex.lpszClassName = kWindowClassName;
1041 wcex.hIconSm = 0;
1043 return RegisterClassEx(&wcex) ? true : false;
1046 static inline void
1047 HandleMouseCapture(HWND aWnd, UINT aMessage)
1049 // Make sure capture is released by the child on mouse events. Fixes a
1050 // problem with flash full screen mode mouse input. Appears to be
1051 // caused by a bug in flash, since we are not setting the capture
1052 // on the window. (In non-oopp land, we would set and release via
1053 // widget for other reasons.)
1054 switch (aMessage) {
1055 case WM_LBUTTONDOWN:
1056 case WM_MBUTTONDOWN:
1057 case WM_RBUTTONDOWN:
1058 SetCapture(aWnd);
1059 break;
1060 case WM_LBUTTONUP:
1061 case WM_MBUTTONUP:
1062 case WM_RBUTTONUP:
1063 ReleaseCapture();
1064 break;
1068 LRESULT CALLBACK MouseHookProc(int code,
1069 WPARAM wParam,
1070 LPARAM lParam)
1072 if (code == HC_ACTION) {
1073 MOUSEHOOKSTRUCT* hookStruct =
1074 reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam);
1075 if (hookStruct)
1076 HandleMouseCapture(hookStruct->hwnd, wParam);
1079 return CallNextHookEx(NULL, code, wParam, lParam);
1082 bool
1083 PluginInstanceChild::CreatePluginWindow()
1085 // already initialized
1086 if (mPluginWindowHWND)
1087 return true;
1089 if (!RegisterWindowClass())
1090 return false;
1092 mPluginWindowHWND =
1093 CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING |
1094 WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this!
1095 WS_EX_RIGHTSCROLLBAR,
1096 kWindowClassName, 0,
1097 WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0,
1098 0, 0, NULL, 0, GetModuleHandle(NULL), 0);
1099 if (!mPluginWindowHWND)
1100 return false;
1101 if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this))
1102 return false;
1104 // Apparently some plugins require an ASCII WndProc.
1105 SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC,
1106 reinterpret_cast<LONG_PTR>(DefWindowProcA));
1108 // Mouse capture hook for flash full screen capture bug
1109 if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_MOUSE_CAPTURE) {
1110 mMouseHook = SetWindowsHookEx(WH_MOUSE, MouseHookProc, NULL,
1111 GetCurrentThreadId());
1113 return true;
1116 void
1117 PluginInstanceChild::DestroyPluginWindow()
1119 if (mPluginWindowHWND) {
1120 // Unsubclass the window.
1121 WNDPROC wndProc = reinterpret_cast<WNDPROC>(
1122 GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
1123 // Removed prior to SetWindowLongPtr, see HookSetWindowLongPtr.
1124 RemoveProp(mPluginWindowHWND, kPluginInstanceChildProperty);
1125 if (wndProc == PluginWindowProc) {
1126 NS_ASSERTION(mPluginWndProc, "Should have old proc here!");
1127 SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
1128 reinterpret_cast<LONG_PTR>(mPluginWndProc));
1129 mPluginWndProc = 0;
1131 DestroyWindow(mPluginWindowHWND);
1132 mPluginWindowHWND = 0;
1135 if (mMouseHook) {
1136 UnhookWindowsHookEx(mMouseHook);
1137 mMouseHook = NULL;
1141 void
1142 PluginInstanceChild::ReparentPluginWindow(HWND hWndParent)
1144 if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
1145 // Fix the child window's style to be a child window.
1146 LONG_PTR style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
1147 style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
1148 style &= ~WS_POPUP;
1149 SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
1151 // Do the reparenting.
1152 SetParent(mPluginWindowHWND, hWndParent);
1154 // Make sure we're visible.
1155 ShowWindow(mPluginWindowHWND, SW_SHOWNA);
1157 mPluginParentHWND = hWndParent;
1160 void
1161 PluginInstanceChild::SizePluginWindow(int width,
1162 int height)
1164 if (mPluginWindowHWND) {
1165 mPluginSize.x = width;
1166 mPluginSize.y = height;
1167 SetWindowPos(mPluginWindowHWND, NULL, 0, 0, width, height,
1168 SWP_NOZORDER | SWP_NOREPOSITION);
1172 // See chromium's webplugin_delegate_impl.cc for explanation of this function.
1173 // static
1174 LRESULT CALLBACK
1175 PluginInstanceChild::DummyWindowProc(HWND hWnd,
1176 UINT message,
1177 WPARAM wParam,
1178 LPARAM lParam)
1180 return CallWindowProc(DefWindowProc, hWnd, message, wParam, lParam);
1183 // static
1184 LRESULT CALLBACK
1185 PluginInstanceChild::PluginWindowProc(HWND hWnd,
1186 UINT message,
1187 WPARAM wParam,
1188 LPARAM lParam)
1190 NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
1191 "Failed to prevent a nonqueued message from running!");
1192 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
1193 GetProp(hWnd, kPluginInstanceChildProperty));
1194 if (!self) {
1195 NS_NOTREACHED("Badness!");
1196 return 0;
1199 NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
1201 // Adobe's shockwave positions the plugin window relative to the browser
1202 // frame when it initializes. With oopp disabled, this wouldn't have an
1203 // effect. With oopp, GeckoPluginWindow is a child of the parent plugin
1204 // window, so the move offsets the child within the parent. Generally
1205 // we don't want plugins moving or sizing our window, so we prevent these
1206 // changes here.
1207 if (message == WM_WINDOWPOSCHANGING) {
1208 WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lParam);
1209 if (pos && (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE))) {
1210 pos->x = pos->y = 0;
1211 pos->cx = self->mPluginSize.x;
1212 pos->cy = self->mPluginSize.y;
1213 LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
1214 lParam);
1215 pos->x = pos->y = 0;
1216 pos->cx = self->mPluginSize.x;
1217 pos->cy = self->mPluginSize.y;
1218 return res;
1222 // The plugin received keyboard focus, let the parent know so the dom is up to date.
1223 if (message == WM_MOUSEACTIVATE)
1224 self->CallPluginFocusChange(true);
1226 // Prevent lockups due to plugins making rpc calls when the parent
1227 // is making a synchronous SendMessage call to the child window. Add
1228 // more messages as needed.
1229 if ((InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
1230 switch(message) {
1231 case WM_KILLFOCUS:
1232 case WM_MOUSEHWHEEL:
1233 case WM_MOUSEWHEEL:
1234 case WM_HSCROLL:
1235 case WM_VSCROLL:
1236 ReplyMessage(0);
1237 break;
1241 if (message == WM_KILLFOCUS)
1242 self->CallPluginFocusChange(false);
1244 if (message == WM_USER+1 &&
1245 (self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) {
1246 self->FlashThrottleMessage(hWnd, message, wParam, lParam, true);
1247 return 0;
1250 HandleMouseCapture(hWnd, message);
1252 LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
1253 lParam);
1255 if (message == WM_CLOSE)
1256 self->DestroyPluginWindow();
1258 if (message == WM_NCDESTROY)
1259 RemoveProp(hWnd, kPluginInstanceChildProperty);
1261 return res;
1264 /* system parameters info hook for flash */
1266 typedef BOOL (WINAPI *User32SystemParametersInfoW)(UINT uiAction,
1267 UINT uiParam,
1268 PVOID pvParam,
1269 UINT fWinIni);
1271 static User32SystemParametersInfoW sUser32SystemParametersInfoWStub = NULL;
1273 static BOOL WINAPI User32SystemParametersInfoHook(UINT uiAction,
1274 UINT uiParam,
1275 PVOID pvParam,
1276 UINT fWinIni)
1278 if (!sUser32SystemParametersInfoWStub) {
1279 NS_NOTREACHED("sUser32SystemParametersInfoWStub not set??");
1280 return FALSE;
1283 // Tell them cleartype is disabled, so they don't mess with
1284 // the alpha channel in our buffers.
1285 if (uiAction == SPI_GETFONTSMOOTHINGTYPE && pvParam) {
1286 *((UINT*)(pvParam)) = FE_FONTSMOOTHINGSTANDARD;
1287 return TRUE;
1290 return sUser32SystemParametersInfoWStub(uiAction, uiParam, pvParam, fWinIni);
1293 void
1294 PluginInstanceChild::HookSystemParametersInfo()
1296 if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_MASK_CLEARTYPE_SETTINGS))
1297 return;
1298 if (sUser32SystemParametersInfoWStub)
1299 return;
1300 sUser32Intercept.Init("gdi32.dll");
1301 sUser32Intercept.AddHook("SystemParametersInfoW", User32SystemParametersInfoHook,
1302 (void**) &sUser32SystemParametersInfoWStub);
1305 /* set window long ptr hook for flash */
1308 * Flash will reset the subclass of our widget at various times.
1309 * (Notably when entering and exiting full screen mode.) This
1310 * occurs independent of the main plugin window event procedure.
1311 * We trap these subclass calls to prevent our subclass hook from
1312 * getting dropped.
1313 * Note, ascii versions can be nixed once flash versions < 10.1
1314 * are considered obsolete.
1317 #ifdef _WIN64
1318 typedef LONG_PTR
1319 (WINAPI *User32SetWindowLongPtrA)(HWND hWnd,
1320 int nIndex,
1321 LONG_PTR dwNewLong);
1322 typedef LONG_PTR
1323 (WINAPI *User32SetWindowLongPtrW)(HWND hWnd,
1324 int nIndex,
1325 LONG_PTR dwNewLong);
1326 static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = NULL;
1327 static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = NULL;
1328 #else
1329 typedef LONG
1330 (WINAPI *User32SetWindowLongA)(HWND hWnd,
1331 int nIndex,
1332 LONG dwNewLong);
1333 typedef LONG
1334 (WINAPI *User32SetWindowLongW)(HWND hWnd,
1335 int nIndex,
1336 LONG dwNewLong);
1337 static User32SetWindowLongA sUser32SetWindowLongAHookStub = NULL;
1338 static User32SetWindowLongW sUser32SetWindowLongWHookStub = NULL;
1339 #endif
1341 extern LRESULT CALLBACK
1342 NeuteredWindowProc(HWND hwnd,
1343 UINT uMsg,
1344 WPARAM wParam,
1345 LPARAM lParam);
1347 const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc";
1349 // static
1350 PRBool
1351 PluginInstanceChild::SetWindowLongHookCheck(HWND hWnd,
1352 int nIndex,
1353 LONG_PTR newLong)
1355 // Let this go through if it's not a subclass
1356 if (nIndex != GWLP_WNDPROC ||
1357 // if it's not a subclassed plugin window
1358 !GetProp(hWnd, kPluginInstanceChildProperty) ||
1359 // if we're not disabled
1360 GetProp(hWnd, kPluginIgnoreSubclassProperty) ||
1361 // if the subclass is set to a known procedure
1362 newLong == reinterpret_cast<LONG_PTR>(PluginWindowProc) ||
1363 newLong == reinterpret_cast<LONG_PTR>(NeuteredWindowProc) ||
1364 newLong == reinterpret_cast<LONG_PTR>(DefWindowProcA) ||
1365 newLong == reinterpret_cast<LONG_PTR>(DefWindowProcW) ||
1366 // if the subclass is a WindowsMessageLoop subclass restore
1367 GetProp(hWnd, kOldWndProcProp))
1368 return PR_TRUE;
1369 // prevent the subclass
1370 return PR_FALSE;
1373 #ifdef _WIN64
1374 LONG_PTR WINAPI
1375 PluginInstanceChild::SetWindowLongPtrAHook(HWND hWnd,
1376 int nIndex,
1377 LONG_PTR newLong)
1378 #else
1379 LONG WINAPI
1380 PluginInstanceChild::SetWindowLongAHook(HWND hWnd,
1381 int nIndex,
1382 LONG newLong)
1383 #endif
1385 if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
1386 return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
1388 // Set flash's new subclass to get the result.
1389 LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
1391 // We already checked this in SetWindowLongHookCheck
1392 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
1393 GetProp(hWnd, kPluginInstanceChildProperty));
1395 // Hook our subclass back up, just like we do on setwindow.
1396 WNDPROC currentProc =
1397 reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
1398 if (currentProc != PluginWindowProc) {
1399 self->mPluginWndProc =
1400 reinterpret_cast<WNDPROC>(sUser32SetWindowLongAHookStub(hWnd, nIndex,
1401 reinterpret_cast<LONG_PTR>(PluginWindowProc)));
1403 return proc;
1406 #ifdef _WIN64
1407 LONG_PTR WINAPI
1408 PluginInstanceChild::SetWindowLongPtrWHook(HWND hWnd,
1409 int nIndex,
1410 LONG_PTR newLong)
1411 #else
1412 LONG WINAPI
1413 PluginInstanceChild::SetWindowLongWHook(HWND hWnd,
1414 int nIndex,
1415 LONG newLong)
1416 #endif
1418 if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
1419 return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
1421 // Set flash's new subclass to get the result.
1422 LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
1424 // We already checked this in SetWindowLongHookCheck
1425 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
1426 GetProp(hWnd, kPluginInstanceChildProperty));
1428 // Hook our subclass back up, just like we do on setwindow.
1429 WNDPROC currentProc =
1430 reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
1431 if (currentProc != PluginWindowProc) {
1432 self->mPluginWndProc =
1433 reinterpret_cast<WNDPROC>(sUser32SetWindowLongAHookStub(hWnd, nIndex,
1434 reinterpret_cast<LONG_PTR>(PluginWindowProc)));
1436 return proc;
1439 void
1440 PluginInstanceChild::HookSetWindowLongPtr()
1442 #ifdef _WIN64
1443 // XXX WindowsDllInterceptor doesn't support hooks
1444 // in 64-bit builds, disabling this code for now.
1445 return;
1446 #endif
1448 if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_SETLONGPTR))
1449 return;
1451 sUser32Intercept.Init("user32.dll");
1452 #ifdef _WIN64
1453 sUser32Intercept.AddHook("SetWindowLongPtrA", SetWindowLongPtrAHook,
1454 (void**) &sUser32SetWindowLongAHookStub);
1455 sUser32Intercept.AddHook("SetWindowLongPtrW", SetWindowLongPtrWHook,
1456 (void**) &sUser32SetWindowLongWHookStub);
1457 #else
1458 sUser32Intercept.AddHook("SetWindowLongA", SetWindowLongAHook,
1459 (void**) &sUser32SetWindowLongAHookStub);
1460 sUser32Intercept.AddHook("SetWindowLongW", SetWindowLongWHook,
1461 (void**) &sUser32SetWindowLongWHookStub);
1462 #endif
1465 /* windowless track popup menu helpers */
1467 BOOL
1468 WINAPI
1469 PluginInstanceChild::TrackPopupHookProc(HMENU hMenu,
1470 UINT uFlags,
1471 int x,
1472 int y,
1473 int nReserved,
1474 HWND hWnd,
1475 CONST RECT *prcRect)
1477 if (!sUser32TrackPopupMenuStub) {
1478 NS_ERROR("TrackPopupMenu stub isn't set! Badness!");
1479 return 0;
1482 // Only change the parent when we know this is a context on the plugin
1483 // surface within the browser. Prevents resetting the parent on child ui
1484 // displayed by plugins that have working parent-child relationships.
1485 PRUnichar szClass[21];
1486 bool haveClass = GetClassNameW(hWnd, szClass, NS_ARRAY_LENGTH(szClass));
1487 if (!haveClass ||
1488 (wcscmp(szClass, L"MozillaWindowClass") &&
1489 wcscmp(szClass, L"SWFlash_Placeholder"))) {
1490 // Unrecognized parent
1491 return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved,
1492 hWnd, prcRect);
1495 // Called on an unexpected event, warn.
1496 if (!sWinlessPopupSurrogateHWND) {
1497 NS_WARNING(
1498 "Untraced TrackPopupHookProc call! Menu might not work right!");
1499 return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved,
1500 hWnd, prcRect);
1503 HWND surrogateHwnd = sWinlessPopupSurrogateHWND;
1504 sWinlessPopupSurrogateHWND = NULL;
1506 // Popups that don't use TPM_RETURNCMD expect a final command message
1507 // when an item is selected and the context closes. Since we replace
1508 // the parent, we need to forward this back to the real parent so it
1509 // can act on the menu item selected.
1510 bool isRetCmdCall = (uFlags & TPM_RETURNCMD);
1512 // A little trick scrounged from chromium's code - set the focus
1513 // to our surrogate parent so keyboard nav events go to the menu.
1514 HWND focusHwnd = SetFocus(surrogateHwnd);
1515 DWORD res = sUser32TrackPopupMenuStub(hMenu, uFlags|TPM_RETURNCMD, x, y,
1516 nReserved, surrogateHwnd, prcRect);
1517 if (IsWindow(focusHwnd)) {
1518 SetFocus(focusHwnd);
1521 if (!isRetCmdCall && res) {
1522 SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(res, 0), 0);
1525 return res;
1528 void
1529 PluginInstanceChild::InitPopupMenuHook()
1531 if (!(GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
1532 sUser32TrackPopupMenuStub)
1533 return;
1535 // Note, once WindowsDllInterceptor is initialized for a module,
1536 // it remains initialized for that particular module for it's
1537 // lifetime. Additional instances are needed if other modules need
1538 // to be hooked.
1539 sUser32Intercept.Init("user32.dll");
1540 sUser32Intercept.AddHook("TrackPopupMenu", TrackPopupHookProc,
1541 (void**) &sUser32TrackPopupMenuStub);
1544 void
1545 PluginInstanceChild::CreateWinlessPopupSurrogate()
1547 // already initialized
1548 if (mWinlessPopupSurrogateHWND)
1549 return;
1551 HWND hwnd = NULL;
1552 NPError result;
1553 if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) {
1554 NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed.");
1555 return;
1558 mWinlessPopupSurrogateHWND =
1559 CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", NULL, WS_CHILD, 0, 0,
1560 0, 0, hwnd, 0, GetModuleHandle(NULL), 0);
1561 if (!mWinlessPopupSurrogateHWND) {
1562 NS_ERROR("CreateWindowEx failed for winless placeholder!");
1563 return;
1565 return;
1568 void
1569 PluginInstanceChild::DestroyWinlessPopupSurrogate()
1571 if (mWinlessPopupSurrogateHWND)
1572 DestroyWindow(mWinlessPopupSurrogateHWND);
1573 mWinlessPopupSurrogateHWND = NULL;
1576 /* windowless handle event helpers */
1578 static bool
1579 NeedsNestedEventCoverage(UINT msg)
1581 // Events we assume some sort of modal ui *might* be generated.
1582 switch (msg) {
1583 case WM_LBUTTONUP:
1584 case WM_RBUTTONUP:
1585 case WM_MBUTTONUP:
1586 case WM_LBUTTONDOWN:
1587 case WM_RBUTTONDOWN:
1588 case WM_MBUTTONDOWN:
1589 case WM_CONTEXTMENU:
1590 return true;
1592 return false;
1595 static bool
1596 IsMouseInputEvent(UINT msg)
1598 switch (msg) {
1599 case WM_MOUSEMOVE:
1600 case WM_LBUTTONUP:
1601 case WM_RBUTTONUP:
1602 case WM_MBUTTONUP:
1603 case WM_LBUTTONDOWN:
1604 case WM_RBUTTONDOWN:
1605 case WM_MBUTTONDOWN:
1606 case WM_LBUTTONDBLCLK:
1607 case WM_MBUTTONDBLCLK:
1608 case WM_RBUTTONDBLCLK:
1609 return true;
1611 return false;
1614 int16_t
1615 PluginInstanceChild::WinlessHandleEvent(NPEvent& event)
1617 if (!mPluginIface->event)
1618 return false;
1620 if (!NeedsNestedEventCoverage(event.event)) {
1621 return mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
1624 // Events that might generate nested event dispatch loops need
1625 // special handling during delivery.
1626 int16_t handled;
1628 // TrackPopupMenu will fail if the parent window is not associated with
1629 // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate
1630 // parent created in the child process.
1631 if ((GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default?
1632 (event.event == WM_RBUTTONDOWN || // flash
1633 event.event == WM_RBUTTONUP)) { // silverlight
1634 sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND;
1637 handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
1639 sWinlessPopupSurrogateHWND = NULL;
1641 return handled;
1644 /* windowless drawing helpers */
1646 bool
1647 PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow)
1649 // If the surfaceHandle is empty, parent is telling us we can reuse our cached
1650 // memory surface and hdc. Otherwise, we need to reset, usually due to a
1651 // expanding plugin port size.
1652 if (!aWindow.surfaceHandle) {
1653 if (!mSharedSurfaceDib.IsValid()) {
1654 return false;
1657 else {
1658 // Attach to the new shared surface parent handed us.
1659 if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle,
1660 aWindow.width, aWindow.height, false)))
1661 return false;
1662 // Free any alpha extraction resources if needed. This will be reset
1663 // the next time it's used.
1664 AlphaExtractCacheRelease();
1667 // NPRemoteWindow's origin is the origin of our shared dib.
1668 mWindow.x = aWindow.x;
1669 mWindow.y = aWindow.y;
1670 mWindow.width = aWindow.width;
1671 mWindow.height = aWindow.height;
1672 mWindow.type = aWindow.type;
1674 mWindow.window = reinterpret_cast<void*>(mSharedSurfaceDib.GetHDC());
1675 ::SetViewportOrgEx(mSharedSurfaceDib.GetHDC(), -aWindow.x, -aWindow.y, NULL);
1677 if (mPluginIface->setwindow)
1678 mPluginIface->setwindow(&mData, &mWindow);
1680 return true;
1683 void
1684 PluginInstanceChild::SharedSurfaceRelease()
1686 mSharedSurfaceDib.Close();
1687 AlphaExtractCacheRelease();
1690 /* double pass cache buffer - (rarely) used in cases where alpha extraction
1691 * occurs for windowless plugins. */
1693 bool
1694 PluginInstanceChild::AlphaExtractCacheSetup()
1696 AlphaExtractCacheRelease();
1698 mAlphaExtract.hdc = ::CreateCompatibleDC(NULL);
1700 if (!mAlphaExtract.hdc)
1701 return false;
1703 BITMAPINFOHEADER bmih;
1704 memset((void*)&bmih, 0, sizeof(BITMAPINFOHEADER));
1705 bmih.biSize = sizeof(BITMAPINFOHEADER);
1706 bmih.biWidth = mWindow.width;
1707 bmih.biHeight = mWindow.height;
1708 bmih.biPlanes = 1;
1709 bmih.biBitCount = 32;
1710 bmih.biCompression = BI_RGB;
1712 void* ppvBits = nsnull;
1713 mAlphaExtract.bmp = ::CreateDIBSection(mAlphaExtract.hdc,
1714 (BITMAPINFO*)&bmih,
1715 DIB_RGB_COLORS,
1716 (void**)&ppvBits,
1717 NULL,
1718 (unsigned long)sizeof(BITMAPINFOHEADER));
1719 if (!mAlphaExtract.bmp)
1720 return false;
1722 DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp));
1723 return true;
1726 void
1727 PluginInstanceChild::AlphaExtractCacheRelease()
1729 if (mAlphaExtract.bmp)
1730 ::DeleteObject(mAlphaExtract.bmp);
1732 if (mAlphaExtract.hdc)
1733 ::DeleteObject(mAlphaExtract.hdc);
1735 mAlphaExtract.bmp = NULL;
1736 mAlphaExtract.hdc = NULL;
1739 void
1740 PluginInstanceChild::UpdatePaintClipRect(RECT* aRect)
1742 if (aRect) {
1743 // Update the clip rect on our internal hdc
1744 HRGN clip = ::CreateRectRgnIndirect(aRect);
1745 ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip);
1746 ::DeleteObject(clip);
1750 int16_t
1751 PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
1753 if (!mPluginIface->event)
1754 return false;
1756 RECT* pRect = reinterpret_cast<RECT*>(evcopy.lParam);
1758 switch(mAlphaExtract.doublePass) {
1759 case RENDER_NATIVE:
1760 // pass the internal hdc to the plugin
1761 UpdatePaintClipRect(pRect);
1762 evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
1763 return mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
1764 break;
1765 case RENDER_BACK_ONE:
1766 // Handle a double pass render used in alpha extraction for transparent
1767 // plugins. (See nsObjectFrame and gfxWindowsNativeDrawing for details.)
1768 // We render twice, once to the shared dib, and once to a cache which
1769 // we copy back on a second paint. These paints can't be spread across
1770 // multiple rpc messages as delays cause animation frame changes.
1771 if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) {
1772 mAlphaExtract.doublePass = RENDER_NATIVE;
1773 return false;
1776 // See gfxWindowsNativeDrawing, color order doesn't have to match.
1777 UpdatePaintClipRect(pRect);
1778 ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
1779 evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
1780 if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
1781 mAlphaExtract.doublePass = RENDER_NATIVE;
1782 return false;
1785 // Copy to cache. We render to shared dib so we don't have to call
1786 // setwindow between calls (flash issue).
1787 ::BitBlt(mAlphaExtract.hdc,
1788 pRect->left,
1789 pRect->top,
1790 pRect->right - pRect->left,
1791 pRect->bottom - pRect->top,
1792 mSharedSurfaceDib.GetHDC(),
1793 pRect->left,
1794 pRect->top,
1795 SRCCOPY);
1797 ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
1798 if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
1799 mAlphaExtract.doublePass = RENDER_NATIVE;
1800 return false;
1802 mAlphaExtract.doublePass = RENDER_BACK_TWO;
1803 return true;
1804 break;
1805 case RENDER_BACK_TWO:
1806 // copy our cached surface back
1807 UpdatePaintClipRect(pRect);
1808 ::BitBlt(mSharedSurfaceDib.GetHDC(),
1809 pRect->left,
1810 pRect->top,
1811 pRect->right - pRect->left,
1812 pRect->bottom - pRect->top,
1813 mAlphaExtract.hdc,
1814 pRect->left,
1815 pRect->top,
1816 SRCCOPY);
1817 mAlphaExtract.doublePass = RENDER_NATIVE;
1818 return true;
1819 break;
1821 return false;
1824 /* flash msg throttling helpers */
1826 // Flash has the unfortunate habit of flooding dispatch loops with custom
1827 // windowing events they use for timing. We throttle these by dropping the
1828 // delivery priority below any other event, including pending ipc io
1829 // notifications. We do this for both windowed and windowless controls.
1830 // Note flash's windowless msg window can last longer than our instance,
1831 // so we try to unhook when the window is destroyed and in NPP_Destroy.
1833 void
1834 PluginInstanceChild::UnhookWinlessFlashThrottle()
1836 // We may have already unhooked
1837 if (!mWinlessThrottleOldWndProc)
1838 return;
1840 WNDPROC tmpProc = mWinlessThrottleOldWndProc;
1841 mWinlessThrottleOldWndProc = nsnull;
1843 NS_ASSERTION(mWinlessHiddenMsgHWND,
1844 "Missing mWinlessHiddenMsgHWND w/subclass set??");
1846 // reset the subclass
1847 SetWindowLongPtr(mWinlessHiddenMsgHWND, GWLP_WNDPROC,
1848 reinterpret_cast<LONG_PTR>(tmpProc));
1850 // Remove our instance prop
1851 RemoveProp(mWinlessHiddenMsgHWND, kFlashThrottleProperty);
1852 mWinlessHiddenMsgHWND = nsnull;
1855 // static
1856 LRESULT CALLBACK
1857 PluginInstanceChild::WinlessHiddenFlashWndProc(HWND hWnd,
1858 UINT message,
1859 WPARAM wParam,
1860 LPARAM lParam)
1862 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
1863 GetProp(hWnd, kFlashThrottleProperty));
1864 if (!self) {
1865 NS_NOTREACHED("Badness!");
1866 return 0;
1869 NS_ASSERTION(self->mWinlessThrottleOldWndProc,
1870 "Missing subclass procedure!!");
1872 // Throttle
1873 if (message == WM_USER+1) {
1874 self->FlashThrottleMessage(hWnd, message, wParam, lParam, false);
1875 return 0;
1878 // Unhook
1879 if (message == WM_CLOSE || message == WM_NCDESTROY) {
1880 WNDPROC tmpProc = self->mWinlessThrottleOldWndProc;
1881 self->UnhookWinlessFlashThrottle();
1882 LRESULT res = CallWindowProc(tmpProc, hWnd, message, wParam, lParam);
1883 return res;
1886 return CallWindowProc(self->mWinlessThrottleOldWndProc,
1887 hWnd, message, wParam, lParam);
1890 // Enumerate all thread windows looking for flash's hidden message window.
1891 // Once we find it, sub class it so we can throttle user msgs.
1892 // static
1893 BOOL CALLBACK
1894 PluginInstanceChild::EnumThreadWindowsCallback(HWND hWnd,
1895 LPARAM aParam)
1897 PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(aParam);
1898 if (!self) {
1899 NS_NOTREACHED("Enum befuddled!");
1900 return FALSE;
1903 PRUnichar className[64];
1904 if (!GetClassNameW(hWnd, className, sizeof(className)/sizeof(PRUnichar)))
1905 return TRUE;
1907 if (!wcscmp(className, L"SWFlash_PlaceholderX")) {
1908 WNDPROC oldWndProc =
1909 reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
1910 // Only set this if we haven't already.
1911 if (oldWndProc != WinlessHiddenFlashWndProc) {
1912 if (self->mWinlessThrottleOldWndProc) {
1913 NS_WARNING("mWinlessThrottleWndProc already set???");
1914 return FALSE;
1916 // Subsclass and store self as a property
1917 self->mWinlessHiddenMsgHWND = hWnd;
1918 self->mWinlessThrottleOldWndProc =
1919 reinterpret_cast<WNDPROC>(SetWindowLongPtr(hWnd, GWLP_WNDPROC,
1920 reinterpret_cast<LONG_PTR>(WinlessHiddenFlashWndProc)));
1921 SetProp(hWnd, kFlashThrottleProperty, self);
1922 NS_ASSERTION(self->mWinlessThrottleOldWndProc,
1923 "SetWindowLongPtr failed?!");
1925 // Return no matter what once we find the right window.
1926 return FALSE;
1929 return TRUE;
1933 void
1934 PluginInstanceChild::SetupFlashMsgThrottle()
1936 if (mWindow.type == NPWindowTypeDrawable) {
1937 // Search for the flash hidden message window and subclass it. Only
1938 // search for flash windows belonging to our ui thread!
1939 if (mWinlessThrottleOldWndProc)
1940 return;
1941 EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsCallback,
1942 reinterpret_cast<LPARAM>(this));
1944 else {
1945 // Already setup through quirks and the subclass.
1946 return;
1950 WNDPROC
1951 PluginInstanceChild::FlashThrottleAsyncMsg::GetProc()
1953 if (mInstance) {
1954 return mWindowed ? mInstance->mPluginWndProc :
1955 mInstance->mWinlessThrottleOldWndProc;
1957 return nsnull;
1960 void
1961 PluginInstanceChild::FlashThrottleAsyncMsg::Run()
1963 RemoveFromAsyncList();
1965 // GetProc() checks mInstance, and pulls the procedure from
1966 // PluginInstanceChild. We don't transport sub-class procedure
1967 // ptrs around in FlashThrottleAsyncMsg msgs.
1968 if (!GetProc())
1969 return;
1971 // deliver the event to flash
1972 CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam());
1975 void
1976 PluginInstanceChild::FlashThrottleMessage(HWND aWnd,
1977 UINT aMsg,
1978 WPARAM aWParam,
1979 LPARAM aLParam,
1980 bool isWindowed)
1982 // We reuse ChildAsyncCall so we get the cancelation work
1983 // that's done in Destroy.
1984 FlashThrottleAsyncMsg* task = new FlashThrottleAsyncMsg(this,
1985 aWnd, aMsg, aWParam, aLParam, isWindowed);
1986 if (!task)
1987 return;
1990 MutexAutoLock lock(mAsyncCallMutex);
1991 mPendingAsyncCalls.AppendElement(task);
1993 MessageLoop::current()->PostDelayedTask(FROM_HERE,
1994 task, kFlashWMUSERMessageThrottleDelayMs);
1997 #endif // OS_WIN
1999 bool
2000 PluginInstanceChild::AnswerSetPluginFocus()
2002 PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s", FULLFUNCTION));
2004 #if defined(OS_WIN)
2005 // Parent is letting us know something set focus to the plugin.
2006 if (::GetFocus() == mPluginWindowHWND)
2007 return true;
2008 ::SetFocus(mPluginWindowHWND);
2009 return true;
2010 #else
2011 NS_NOTREACHED("PluginInstanceChild::AnswerSetPluginFocus not implemented!");
2012 return false;
2013 #endif
2016 bool
2017 PluginInstanceChild::AnswerUpdateWindow()
2019 PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s", FULLFUNCTION));
2021 #if defined(OS_WIN)
2022 if (mPluginWindowHWND) {
2023 RECT rect;
2024 if (GetUpdateRect(GetParent(mPluginWindowHWND), &rect, FALSE)) {
2025 ::InvalidateRect(mPluginWindowHWND, &rect, FALSE);
2027 UpdateWindow(mPluginWindowHWND);
2029 return true;
2030 #else
2031 NS_NOTREACHED("PluginInstanceChild::AnswerUpdateWindow not implemented!");
2032 return false;
2033 #endif
2036 PPluginScriptableObjectChild*
2037 PluginInstanceChild::AllocPPluginScriptableObject()
2039 AssertPluginThread();
2040 return new PluginScriptableObjectChild(Proxy);
2043 bool
2044 PluginInstanceChild::DeallocPPluginScriptableObject(
2045 PPluginScriptableObjectChild* aObject)
2047 AssertPluginThread();
2048 delete aObject;
2049 return true;
2052 bool
2053 PluginInstanceChild::RecvPPluginScriptableObjectConstructor(
2054 PPluginScriptableObjectChild* aActor)
2056 AssertPluginThread();
2058 // This is only called in response to the parent process requesting the
2059 // creation of an actor. This actor will represent an NPObject that is
2060 // created by the browser and returned to the plugin.
2061 PluginScriptableObjectChild* actor =
2062 static_cast<PluginScriptableObjectChild*>(aActor);
2063 NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
2065 actor->InitializeProxy();
2066 NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
2068 return true;
2071 bool
2072 PluginInstanceChild::AnswerPBrowserStreamConstructor(
2073 PBrowserStreamChild* aActor,
2074 const nsCString& url,
2075 const uint32_t& length,
2076 const uint32_t& lastmodified,
2077 PStreamNotifyChild* notifyData,
2078 const nsCString& headers,
2079 const nsCString& mimeType,
2080 const bool& seekable,
2081 NPError* rv,
2082 uint16_t* stype)
2084 AssertPluginThread();
2085 *rv = static_cast<BrowserStreamChild*>(aActor)
2086 ->StreamConstructed(mimeType, seekable, stype);
2087 return true;
2090 PBrowserStreamChild*
2091 PluginInstanceChild::AllocPBrowserStream(const nsCString& url,
2092 const uint32_t& length,
2093 const uint32_t& lastmodified,
2094 PStreamNotifyChild* notifyData,
2095 const nsCString& headers,
2096 const nsCString& mimeType,
2097 const bool& seekable,
2098 NPError* rv,
2099 uint16_t *stype)
2101 AssertPluginThread();
2102 return new BrowserStreamChild(this, url, length, lastmodified,
2103 static_cast<StreamNotifyChild*>(notifyData),
2104 headers, mimeType, seekable, rv, stype);
2107 bool
2108 PluginInstanceChild::DeallocPBrowserStream(PBrowserStreamChild* stream)
2110 AssertPluginThread();
2111 delete stream;
2112 return true;
2115 PPluginStreamChild*
2116 PluginInstanceChild::AllocPPluginStream(const nsCString& mimeType,
2117 const nsCString& target,
2118 NPError* result)
2120 NS_RUNTIMEABORT("not callable");
2121 return NULL;
2124 bool
2125 PluginInstanceChild::DeallocPPluginStream(PPluginStreamChild* stream)
2127 AssertPluginThread();
2128 delete stream;
2129 return true;
2132 PStreamNotifyChild*
2133 PluginInstanceChild::AllocPStreamNotify(const nsCString& url,
2134 const nsCString& target,
2135 const bool& post,
2136 const nsCString& buffer,
2137 const bool& file,
2138 NPError* result)
2140 AssertPluginThread();
2141 NS_RUNTIMEABORT("not reached");
2142 return NULL;
2145 void
2146 StreamNotifyChild::ActorDestroy(ActorDestroyReason why)
2148 if (AncestorDeletion == why && mBrowserStream) {
2149 NS_ERROR("Pending NPP_URLNotify not called when closing an instance.");
2151 // reclaim responsibility for deleting ourself
2152 mBrowserStream->mStreamNotify = NULL;
2153 mBrowserStream = NULL;
2158 void
2159 StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs)
2161 NS_ASSERTION(bs, "Shouldn't be null");
2162 NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?");
2164 mBrowserStream = bs;
2167 bool
2168 StreamNotifyChild::Recv__delete__(const NPReason& reason)
2170 AssertPluginThread();
2172 if (mBrowserStream)
2173 mBrowserStream->NotifyPending();
2174 else
2175 NPP_URLNotify(reason);
2177 return true;
2180 bool
2181 StreamNotifyChild::RecvRedirectNotify(const nsCString& url, const int32_t& status)
2183 // NPP_URLRedirectNotify requires a non-null closure. Since core logic
2184 // assumes that all out-of-process notify streams have non-null closure
2185 // data it will assume that the plugin was notified at this point and
2186 // expect a response otherwise the redirect will hang indefinitely.
2187 if (!mClosure) {
2188 SendRedirectNotifyResponse(false);
2191 PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
2192 if (instance->mPluginIface->urlredirectnotify)
2193 instance->mPluginIface->urlredirectnotify(instance->GetNPP(), url.get(), status, mClosure);
2195 return true;
2198 void
2199 StreamNotifyChild::NPP_URLNotify(NPReason reason)
2201 PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
2203 if (mClosure)
2204 instance->mPluginIface->urlnotify(instance->GetNPP(), mURL.get(),
2205 reason, mClosure);
2208 bool
2209 PluginInstanceChild::DeallocPStreamNotify(PStreamNotifyChild* notifyData)
2211 AssertPluginThread();
2213 if (!static_cast<StreamNotifyChild*>(notifyData)->mBrowserStream)
2214 delete notifyData;
2215 return true;
2218 PluginScriptableObjectChild*
2219 PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
2221 AssertPluginThread();
2222 NS_ASSERTION(aObject, "Null pointer!");
2224 if (aObject->_class == PluginScriptableObjectChild::GetClass()) {
2225 // One of ours! It's a browser-provided object.
2226 ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
2227 NS_ASSERTION(object->parent, "Null actor!");
2228 return object->parent;
2231 PluginScriptableObjectChild* actor =
2232 PluginModuleChild::current()->GetActorForNPObject(aObject);
2233 if (actor) {
2234 // Plugin-provided object that we've previously wrapped.
2235 return actor;
2238 actor = new PluginScriptableObjectChild(LocalObject);
2239 if (!SendPPluginScriptableObjectConstructor(actor)) {
2240 NS_ERROR("Failed to send constructor message!");
2241 return nsnull;
2244 actor->InitializeLocal(aObject);
2245 return actor;
2248 NPError
2249 PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
2250 NPStream** aStream)
2252 AssertPluginThread();
2254 PluginStreamChild* ps = new PluginStreamChild();
2256 NPError result;
2257 CallPPluginStreamConstructor(ps, nsDependentCString(aMIMEType),
2258 NullableString(aWindow), &result);
2259 if (NPERR_NO_ERROR != result) {
2260 *aStream = NULL;
2261 PPluginStreamChild::Call__delete__(ps, NPERR_GENERIC_ERROR, true);
2262 return result;
2265 *aStream = &ps->mStream;
2266 return NPERR_NO_ERROR;
2269 void
2270 PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow)
2272 if (!notifyData) {
2273 return;
2276 InfallibleTArray<PStreamNotifyChild*> notifyStreams;
2277 ManagedPStreamNotifyChild(notifyStreams);
2278 PRUint32 notifyStreamCount = notifyStreams.Length();
2279 for (PRUint32 i = 0; i < notifyStreamCount; i++) {
2280 StreamNotifyChild* sn = static_cast<StreamNotifyChild*>(notifyStreams[i]);
2281 if (sn->mClosure == notifyData) {
2282 sn->SendRedirectNotifyResponse(static_cast<bool>(allow));
2283 return;
2286 NS_ASSERTION(PR_FALSE, "Couldn't find stream for redirect response!");
2289 bool
2290 PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
2291 const NPRemoteWindow& aWindow)
2293 AssertPluginThread();
2295 NS_ASSERTION(!aWindow.window, "Remote window should be null.");
2297 if (mCurrentAsyncSetWindowTask) {
2298 mCurrentAsyncSetWindowTask->Cancel();
2299 mCurrentAsyncSetWindowTask = nsnull;
2302 if (mPendingPluginCall) {
2303 // We shouldn't process this now. Run it later.
2304 mCurrentAsyncSetWindowTask =
2305 NewRunnableMethod<PluginInstanceChild,
2306 void (PluginInstanceChild::*)(const gfxSurfaceType&, const NPRemoteWindow&, bool),
2307 gfxSurfaceType, NPRemoteWindow, bool>
2308 (this, &PluginInstanceChild::DoAsyncSetWindow,
2309 aSurfaceType, aWindow, true);
2310 MessageLoop::current()->PostTask(FROM_HERE, mCurrentAsyncSetWindowTask);
2311 } else {
2312 DoAsyncSetWindow(aSurfaceType, aWindow, false);
2315 return true;
2318 void
2319 PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
2320 const NPRemoteWindow& aWindow,
2321 bool aIsAsync)
2323 AssertPluginThread();
2324 NS_ASSERTION(!aWindow.window, "Remote window should be null.");
2325 NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!");
2327 if (aIsAsync) {
2328 if (!mCurrentAsyncSetWindowTask) {
2329 return;
2331 mCurrentAsyncSetWindowTask = nsnull;
2334 mWindow.window = NULL;
2335 if (mWindow.width != aWindow.width || mWindow.height != aWindow.height) {
2336 ClearCurrentSurface();
2337 mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
2339 if (mWindow.clipRect.top != aWindow.clipRect.top ||
2340 mWindow.clipRect.left != aWindow.clipRect.left ||
2341 mWindow.clipRect.bottom != aWindow.clipRect.bottom ||
2342 mWindow.clipRect.right != aWindow.clipRect.right)
2343 mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
2345 mWindow.x = aWindow.x;
2346 mWindow.y = aWindow.y;
2347 mWindow.width = aWindow.width;
2348 mWindow.height = aWindow.height;
2349 mWindow.clipRect = aWindow.clipRect;
2350 mWindow.type = aWindow.type;
2352 if (GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT)
2353 mIsTransparent = true;
2355 mLayersRendering = true;
2356 mSurfaceType = aSurfaceType;
2357 UpdateWindowAttributes(true);
2359 #ifdef XP_WIN
2360 if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK)
2361 CreateWinlessPopupSurrogate();
2362 if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
2363 SetupFlashMsgThrottle();
2364 #endif
2366 if (!mAccumulatedInvalidRect.IsEmpty()) {
2367 AsyncShowPluginFrame();
2371 static inline gfxRect
2372 GfxFromNsRect(const nsIntRect& aRect)
2374 return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
2377 bool
2378 PluginInstanceChild::CreateOptSurface(void)
2380 NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
2382 nsRefPtr<gfxASurface> retsurf;
2383 gfxASurface::gfxImageFormat format =
2384 mIsTransparent ? gfxASurface::ImageFormatARGB32 :
2385 gfxASurface::ImageFormatRGB24;
2387 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
2388 // On Maemo 5, we must send the Visibility event to activate the plugin
2389 if (mMaemoImageRendering) {
2390 NPEvent pluginEvent;
2391 XVisibilityEvent& visibilityEvent = pluginEvent.xvisibility;
2392 visibilityEvent.type = VisibilityNotify;
2393 visibilityEvent.display = 0;
2394 visibilityEvent.state = VisibilityUnobscured;
2395 mPluginIface->event(&mData, reinterpret_cast<void*>(&pluginEvent));
2397 #endif
2398 #ifdef MOZ_X11
2399 Display* dpy = mWsInfo.display;
2400 Screen* screen = DefaultScreenOfDisplay(dpy);
2401 if (format == gfxASurface::ImageFormatRGB24 &&
2402 DefaultDepth(dpy, DefaultScreen(dpy)) == 16) {
2403 format = gfxASurface::ImageFormatRGB16_565;
2406 if (mSurfaceType == gfxASurface::SurfaceTypeXlib) {
2407 XRenderPictFormat* xfmt = gfxXlibSurface::FindRenderFormat(dpy, format);
2408 if (!xfmt) {
2409 NS_ERROR("Need X falback surface, but FindRenderFormat failed");
2410 return false;
2412 mCurrentSurface =
2413 gfxXlibSurface::Create(screen, xfmt,
2414 gfxIntSize(mWindow.width,
2415 mWindow.height));
2416 return mCurrentSurface != nsnull;
2418 #endif
2420 #ifdef XP_WIN
2421 if (mSurfaceType == gfxASurface::SurfaceTypeWin32 ||
2422 mSurfaceType == gfxASurface::SurfaceTypeD2D) {
2424 SharedDIBSurface* s = new SharedDIBSurface();
2425 if (!s->Create(reinterpret_cast<HDC>(mWindow.window),
2426 mWindow.width, mWindow.height, mIsTransparent))
2427 return false;
2429 mCurrentSurface = s;
2430 return true;
2433 NS_RUNTIMEABORT("Shared-memory drawing not expected on Windows.");
2434 #endif
2436 // Make common shmem implementation working for any platform
2437 mCurrentSurface =
2438 gfxSharedImageSurface::CreateUnsafe(this, gfxIntSize(mWindow.width, mWindow.height), format);
2439 return !!mCurrentSurface;
2442 bool
2443 PluginInstanceChild::MaybeCreatePlatformHelperSurface(void)
2445 if (!mCurrentSurface) {
2446 NS_ERROR("Cannot create helper surface without mCurrentSurface");
2447 return false;
2450 #ifdef MOZ_PLATFORM_MAEMO
2451 // On maemo plugins support non-default visual rendering
2452 bool supportNonDefaultVisual = true;
2453 #else
2454 bool supportNonDefaultVisual = false;
2455 #endif
2456 #ifdef MOZ_X11
2457 Screen* screen = DefaultScreenOfDisplay(mWsInfo.display);
2458 Visual* defaultVisual = DefaultVisualOfScreen(screen);
2459 Visual* visual = nsnull;
2460 Colormap colormap = 0;
2461 mDoAlphaExtraction = false;
2462 bool createHelperSurface = false;
2464 if (mCurrentSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
2465 static_cast<gfxXlibSurface*>(mCurrentSurface.get())->
2466 GetColormapAndVisual(&colormap, &visual);
2467 // Create helper surface if layer surface visual not same as default
2468 // and we don't support non-default visual rendering
2469 if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) {
2470 createHelperSurface = true;
2471 visual = defaultVisual;
2472 mDoAlphaExtraction = mIsTransparent;
2474 } else if (mCurrentSurface->GetType() == gfxASurface::SurfaceTypeImage) {
2475 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
2476 if (mMaemoImageRendering) {
2477 // No helper surface needed, when mMaemoImageRendering is TRUE.
2478 // we can rendering directly into image memory
2479 // with NPImageExpose Maemo5 NPAPI
2480 return PR_TRUE;
2482 #endif
2483 // For image layer surface we should always create helper surface
2484 createHelperSurface = true;
2485 // Check if we can create helper surface with non-default visual
2486 visual = gfxXlibSurface::FindVisual(screen,
2487 static_cast<gfxImageSurface*>(mCurrentSurface.get())->Format());
2488 if (visual && defaultVisual != visual && !supportNonDefaultVisual) {
2489 visual = defaultVisual;
2490 mDoAlphaExtraction = mIsTransparent;
2494 if (createHelperSurface) {
2495 if (!visual) {
2496 NS_ERROR("Need X falback surface, but visual failed");
2497 return false;
2499 mHelperSurface =
2500 gfxXlibSurface::Create(screen, visual,
2501 mCurrentSurface->GetSize());
2502 if (!mHelperSurface) {
2503 NS_WARNING("Fail to create create helper surface");
2504 return false;
2507 #endif
2509 return true;
2512 bool
2513 PluginInstanceChild::EnsureCurrentBuffer(void)
2515 if (mCurrentSurface) {
2516 return true;
2519 if (!mWindow.width || !mWindow.height) {
2520 return false;
2523 if (!CreateOptSurface()) {
2524 NS_ERROR("Cannot create optimized surface");
2525 return false;
2528 if (!MaybeCreatePlatformHelperSurface()) {
2529 NS_ERROR("Cannot create helper surface");
2530 return false;
2533 return true;
2536 void
2537 PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
2539 nsRefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface;
2540 bool needWindowUpdate = aForceSetWindow;
2541 #ifdef MOZ_X11
2542 Visual* visual = nsnull;
2543 Colormap colormap = 0;
2544 if (curSurface && curSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
2545 static_cast<gfxXlibSurface*>(curSurface.get())->
2546 GetColormapAndVisual(&colormap, &visual);
2547 if (visual != mWsInfo.visual || colormap != mWsInfo.colormap) {
2548 mWsInfo.visual = visual;
2549 mWsInfo.colormap = colormap;
2550 needWindowUpdate = true;
2553 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
2554 else if (curSurface && curSurface->GetType() == gfxASurface::SurfaceTypeImage
2555 && mMaemoImageRendering) {
2556 // For maemo5 we need to setup window/colormap to 0
2557 // and specify depth of image surface
2558 gfxImageSurface* img = static_cast<gfxImageSurface*>(curSurface.get());
2559 if (mWindow.window ||
2560 mWsInfo.depth != gfxUtils::ImageFormatToDepth(img->Format()) ||
2561 mWsInfo.colormap) {
2562 mWindow.window = nsnull;
2563 mWsInfo.depth = gfxUtils::ImageFormatToDepth(img->Format());
2564 mWsInfo.colormap = 0;
2565 needWindowUpdate = PR_TRUE;
2568 #endif // MAEMO
2569 #endif // MOZ_X11
2570 #ifdef XP_WIN
2571 HDC dc = NULL;
2573 if (curSurface) {
2574 NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(curSurface),
2575 "Expected (SharedDIB) image surface.");
2577 SharedDIBSurface* dibsurf = static_cast<SharedDIBSurface*>(curSurface.get());
2578 dc = dibsurf->GetHDC();
2580 if (mWindow.window != dc) {
2581 mWindow.window = dc;
2582 needWindowUpdate = true;
2584 #endif // XP_WIN
2586 if (!needWindowUpdate) {
2587 return;
2590 #ifndef XP_WIN
2591 // On Windows, we translate the device context, in order for the window
2592 // origin to be correct.
2593 mWindow.x = mWindow.y = 0;
2594 #endif
2596 if (IsVisible()) {
2597 // The clip rect is relative to drawable top-left.
2598 nsIntRect clipRect;
2600 // Don't ask the plugin to draw outside the drawable. The clip rect
2601 // is in plugin coordinates, not window coordinates.
2602 // This also ensures that the unsigned clip rectangle offsets won't be -ve.
2603 clipRect.SetRect(0, 0, mWindow.width, mWindow.height);
2605 mWindow.clipRect.left = 0;
2606 mWindow.clipRect.top = 0;
2607 mWindow.clipRect.right = clipRect.XMost();
2608 mWindow.clipRect.bottom = clipRect.YMost();
2611 #ifdef XP_WIN
2612 // Windowless plugins on Windows need a WM_WINDOWPOSCHANGED event to update
2613 // their location... or at least Flash does: Silverlight uses the
2614 // window.x/y passed to NPP_SetWindow
2616 if (mPluginIface->event) {
2617 WINDOWPOS winpos = {
2618 0, 0,
2619 mWindow.x, mWindow.y,
2620 mWindow.width, mWindow.height,
2623 NPEvent pluginEvent = {
2624 WM_WINDOWPOSCHANGED, 0,
2625 (LPARAM) &winpos
2627 mPluginIface->event(&mData, &pluginEvent);
2629 #endif
2631 if (mPluginIface->setwindow) {
2632 mPluginIface->setwindow(&mData, &mWindow);
2636 void
2637 PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
2638 gfxASurface* aSurface)
2640 bool temporarilyMakeVisible = !IsVisible() && !mHasPainted;
2641 if (temporarilyMakeVisible) {
2642 mWindow.clipRect.right = mWindow.width;
2643 mWindow.clipRect.bottom = mWindow.height;
2646 UpdateWindowAttributes();
2648 #ifdef MOZ_X11
2649 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
2650 // On maemo5 we do support Image rendering NPAPI
2651 if (mMaemoImageRendering &&
2652 aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
2653 aSurface->Flush();
2654 gfxImageSurface* image = static_cast<gfxImageSurface*>(aSurface);
2655 NPImageExpose imgExp;
2656 imgExp.depth = gfxUtils::ImageFormatToDepth(image->Format());
2657 imgExp.x = aRect.x;
2658 imgExp.y = aRect.y;
2659 imgExp.width = aRect.width;
2660 imgExp.height = aRect.height;
2661 imgExp.stride = image->Stride();
2662 imgExp.data = (char *)image->Data();
2663 imgExp.dataSize.width = image->Width();
2664 imgExp.dataSize.height = image->Height();
2665 imgExp.translateX = 0;
2666 imgExp.translateY = 0;
2667 imgExp.scaleX = 1;
2668 imgExp.scaleY = 1;
2669 NPEvent pluginEvent;
2670 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
2671 exposeEvent.type = GraphicsExpose;
2672 exposeEvent.display = 0;
2673 // Store imageExpose structure pointer as drawable member
2674 exposeEvent.drawable = (Drawable)&imgExp;
2675 exposeEvent.x = imgExp.x;
2676 exposeEvent.y = imgExp.y;
2677 exposeEvent.width = imgExp.width;
2678 exposeEvent.height = imgExp.height;
2679 exposeEvent.count = 0;
2680 // information not set:
2681 exposeEvent.serial = 0;
2682 exposeEvent.send_event = False;
2683 exposeEvent.major_code = 0;
2684 exposeEvent.minor_code = 0;
2685 mPluginIface->event(&mData, reinterpret_cast<void*>(&exposeEvent));
2686 } else
2687 #endif
2689 NS_ASSERTION(aSurface->GetType() == gfxASurface::SurfaceTypeXlib,
2690 "Non supported platform surface type");
2692 NPEvent pluginEvent;
2693 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
2694 exposeEvent.type = GraphicsExpose;
2695 exposeEvent.display = mWsInfo.display;
2696 exposeEvent.drawable = static_cast<gfxXlibSurface*>(aSurface)->XDrawable();
2697 exposeEvent.x = aRect.x;
2698 exposeEvent.y = aRect.y;
2699 exposeEvent.width = aRect.width;
2700 exposeEvent.height = aRect.height;
2701 exposeEvent.count = 0;
2702 // information not set:
2703 exposeEvent.serial = 0;
2704 exposeEvent.send_event = False;
2705 exposeEvent.major_code = 0;
2706 exposeEvent.minor_code = 0;
2707 mPluginIface->event(&mData, reinterpret_cast<void*>(&exposeEvent));
2709 #elif defined(XP_WIN)
2710 NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(aSurface),
2711 "Expected (SharedDIB) image surface.");
2713 // This rect is in the window coordinate space. aRect is in the plugin
2714 // coordinate space.
2715 RECT rect = {
2716 mWindow.x + aRect.x,
2717 mWindow.y + aRect.y,
2718 mWindow.x + aRect.XMost(),
2719 mWindow.y + aRect.YMost()
2721 NPEvent paintEvent = {
2722 WM_PAINT,
2723 uintptr_t(mWindow.window),
2724 uintptr_t(&rect)
2727 ::SetViewportOrgEx((HDC) mWindow.window, -mWindow.x, -mWindow.y, NULL);
2728 ::SelectClipRgn((HDC) mWindow.window, NULL);
2729 ::IntersectClipRect((HDC) mWindow.window, rect.left, rect.top, rect.right, rect.bottom);
2730 mPluginIface->event(&mData, reinterpret_cast<void*>(&paintEvent));
2731 #else
2732 NS_RUNTIMEABORT("Surface type not implemented.");
2733 #endif
2735 if (temporarilyMakeVisible) {
2736 mWindow.clipRect.right = mWindow.clipRect.bottom = 0;
2738 if (mPluginIface->setwindow) {
2739 mPluginIface->setwindow(&mData, &mWindow);
2744 void
2745 PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect,
2746 gfxASurface* aSurface,
2747 const gfxRGBA& aColor)
2749 // Render using temporary X surface, with copy to image surface
2750 nsIntRect plPaintRect(aRect);
2751 nsRefPtr<gfxASurface> renderSurface = aSurface;
2752 #ifdef MOZ_X11
2753 if (mIsTransparent && (GetQuirks() & PluginModuleChild::QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) {
2754 // Work around a bug in Flash up to 10.1 d51 at least, where expose event
2755 // top left coordinates within the plugin-rect and not at the drawable
2756 // origin are misinterpreted. (We can move the top left coordinate
2757 // provided it is within the clipRect.), see bug 574583
2758 plPaintRect.SetRect(0, 0, aRect.XMost(), aRect.YMost());
2760 if (renderSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
2761 // On X11 we can paint to non Xlib surface only with HelperSurface
2762 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
2763 // Don't use mHelperSurface if surface is image and mMaemoImageRendering is TRUE
2764 if (!mMaemoImageRendering ||
2765 renderSurface->GetType() != gfxASurface::SurfaceTypeImage)
2766 #endif
2767 renderSurface = mHelperSurface;
2769 #endif
2771 if (mIsTransparent) {
2772 // Clear surface content for transparent rendering
2773 nsRefPtr<gfxContext> ctx = new gfxContext(renderSurface);
2774 ctx->SetColor(aColor);
2775 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
2776 ctx->Rectangle(GfxFromNsRect(plPaintRect));
2777 ctx->Fill();
2780 PaintRectToPlatformSurface(plPaintRect, renderSurface);
2782 if (renderSurface != aSurface) {
2783 // Copy helper surface content to target
2784 nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
2785 ctx->SetSource(renderSurface);
2786 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
2787 ctx->Rectangle(GfxFromNsRect(aRect));
2788 ctx->Fill();
2792 void
2793 PluginInstanceChild::PaintRectWithAlphaExtraction(const nsIntRect& aRect,
2794 gfxASurface* aSurface)
2796 // Paint onto black image
2797 bool needImageSurface = true;
2798 nsRefPtr<gfxImageSurface> blackImage;
2799 gfxIntSize clipSize(aRect.width, aRect.height);
2800 gfxPoint deviceOffset(-aRect.x, -aRect.y);
2801 // Try to re-use existing image surface, and avoid one copy
2802 if (aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
2803 gfxImageSurface *surface = static_cast<gfxImageSurface*>(aSurface);
2804 if (surface->Format() == gfxASurface::ImageFormatARGB32) {
2805 needImageSurface = false;
2806 blackImage = surface->GetSubimage(GfxFromNsRect(aRect));
2809 // otherwise create new helper surface
2810 if (needImageSurface) {
2811 blackImage = new gfxImageSurface(clipSize, gfxASurface::ImageFormatARGB32);
2814 // Paint to black image
2815 blackImage->SetDeviceOffset(deviceOffset);
2816 PaintRectToSurface(aRect, blackImage, gfxRGBA(0.0, 0.0, 0.0));
2818 // Paint onto white image
2819 nsRefPtr<gfxImageSurface> whiteImage =
2820 new gfxImageSurface(clipSize, gfxASurface::ImageFormatRGB24);
2822 whiteImage->SetDeviceOffset(deviceOffset);
2823 PaintRectToSurface(aRect, whiteImage, gfxRGBA(1.0, 1.0, 1.0));
2825 // Extract Alpha from black and white image and store to black Image
2826 gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
2827 if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage, nsnull)) {
2828 return;
2831 if (needImageSurface) {
2832 nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
2833 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
2834 ctx->SetSource(blackImage);
2835 ctx->Rectangle(GfxFromNsRect(aRect));
2836 ctx->Fill();
2840 bool
2841 PluginInstanceChild::ShowPluginFrame()
2843 if (mPendingPluginCall) {
2844 return false;
2847 AutoRestore<bool> pending(mPendingPluginCall);
2848 mPendingPluginCall = true;
2850 if (!EnsureCurrentBuffer()) {
2851 return false;
2854 // Make expose rect not bigger than clip rect
2855 mAccumulatedInvalidRect.IntersectRect(mAccumulatedInvalidRect,
2856 nsIntRect(mWindow.clipRect.left, mWindow.clipRect.top,
2857 mWindow.clipRect.right - mWindow.clipRect.left,
2858 mWindow.clipRect.bottom - mWindow.clipRect.top));
2860 // Clear accRect here to be able to pass
2861 // test_invalidate_during_plugin_paint test
2862 nsIntRect rect = mAccumulatedInvalidRect;
2863 mAccumulatedInvalidRect.Empty();
2865 if (!ReadbackDifferenceRect(rect)) {
2866 // Just repaint whole plugin, because we cannot read back from Shmem which is owned by another process
2867 rect.SetRect(0, 0, mWindow.width, mWindow.height);
2870 if (mDoAlphaExtraction) {
2871 PaintRectWithAlphaExtraction(rect, mCurrentSurface);
2872 } else {
2873 PaintRectToSurface(rect, mCurrentSurface, gfxRGBA(0.0, 0.0, 0.0, 0.0));
2875 mHasPainted = true;
2877 NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x,
2878 (uint16_t)rect.YMost(), (uint16_t)rect.XMost() };
2879 SurfaceDescriptor currSurf;
2880 #ifdef MOZ_X11
2881 if (mCurrentSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
2882 gfxXlibSurface *xsurf = static_cast<gfxXlibSurface*>(mCurrentSurface.get());
2883 currSurf = SurfaceDescriptorX11(xsurf->XDrawable(), xsurf->XRenderFormat()->id,
2884 mCurrentSurface->GetSize());
2885 // Need to sync all pending x-paint requests
2886 // before giving drawable to another process
2887 XSync(mWsInfo.display, False);
2888 } else
2889 #endif
2890 #ifdef XP_WIN
2891 if (SharedDIBSurface::IsSharedDIBSurface(mCurrentSurface)) {
2892 SharedDIBSurface* s = static_cast<SharedDIBSurface*>(mCurrentSurface.get());
2893 if (!mCurrentSurfaceActor) {
2894 base::SharedMemoryHandle handle = NULL;
2895 s->ShareToProcess(PluginModuleChild::current()->OtherProcess(), &handle);
2897 mCurrentSurfaceActor =
2898 SendPPluginSurfaceConstructor(handle,
2899 mCurrentSurface->GetSize(),
2900 mIsTransparent);
2902 currSurf = mCurrentSurfaceActor;
2903 s->Flush();
2904 } else
2905 #endif
2906 if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) {
2907 currSurf = static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem();
2908 } else {
2909 NS_RUNTIMEABORT("Surface type is not remotable");
2910 return false;
2913 // Unused, except to possibly return a shmem to us
2914 SurfaceDescriptor returnSurf;
2916 if (!SendShow(r, currSurf, &returnSurf)) {
2917 return false;
2920 SwapSurfaces();
2921 mSurfaceDifferenceRect = rect;
2922 return true;
2925 bool
2926 PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
2928 if (!mBackSurface)
2929 return false;
2931 // We can read safely from XSurface,SharedDIBSurface and Unsafe SharedMemory,
2932 // because PluginHost is not able to modify that surface
2933 #if defined(MOZ_X11)
2934 if (mBackSurface->GetType() != gfxASurface::SurfaceTypeXlib &&
2935 !gfxSharedImageSurface::IsSharedImage(mBackSurface))
2936 return false;
2937 #elif defined(XP_WIN)
2938 if (!SharedDIBSurface::IsSharedDIBSurface(mBackSurface))
2939 return false;
2940 #else
2941 return false;
2942 #endif
2944 if (mSurfaceDifferenceRect.IsEmpty())
2945 return true;
2947 // Read back previous content
2948 nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface);
2949 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
2950 ctx->SetSource(mBackSurface);
2951 // Subtract from mSurfaceDifferenceRect area which is overlapping with rect
2952 nsIntRegion result;
2953 result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect));
2954 nsIntRegionRectIterator iter(result);
2955 const nsIntRect* r;
2956 while ((r = iter.Next()) != nsnull) {
2957 ctx->Rectangle(GfxFromNsRect(*r));
2959 ctx->Fill();
2961 return true;
2964 void
2965 PluginInstanceChild::InvalidateRectDelayed(void)
2967 if (!mCurrentInvalidateTask) {
2968 return;
2971 mCurrentInvalidateTask = nsnull;
2972 if (mAccumulatedInvalidRect.IsEmpty() || (mHasPainted && !IsVisible())) {
2973 return;
2976 if (!ShowPluginFrame()) {
2977 AsyncShowPluginFrame();
2981 void
2982 PluginInstanceChild::AsyncShowPluginFrame(void)
2984 if (mCurrentInvalidateTask || (mHasPainted && !IsVisible())) {
2985 return;
2988 mCurrentInvalidateTask =
2989 NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed);
2990 MessageLoop::current()->PostTask(FROM_HERE, mCurrentInvalidateTask);
2993 void
2994 PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
2996 NS_ASSERTION(aInvalidRect, "Null pointer!");
2998 #ifdef OS_WIN
2999 // Invalidate and draw locally for windowed plugins.
3000 if (mWindow.type == NPWindowTypeWindow) {
3001 NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!");
3002 RECT rect = { aInvalidRect->left, aInvalidRect->top,
3003 aInvalidRect->right, aInvalidRect->bottom };
3004 ::InvalidateRect(mPluginWindowHWND, &rect, FALSE);
3005 return;
3007 #endif
3009 if (mLayersRendering) {
3010 nsIntRect r(aInvalidRect->left, aInvalidRect->top,
3011 aInvalidRect->right - aInvalidRect->left,
3012 aInvalidRect->bottom - aInvalidRect->top);
3014 mAccumulatedInvalidRect.UnionRect(r, mAccumulatedInvalidRect);
3015 // If we are able to paint and invalidate sent, then reset
3016 // accumulated rectangle
3017 AsyncShowPluginFrame();
3018 return;
3020 SendNPN_InvalidateRect(*aInvalidRect);
3023 uint32_t
3024 PluginInstanceChild::ScheduleTimer(uint32_t interval, bool repeat,
3025 TimerFunc func)
3027 ChildTimer* t = new ChildTimer(this, interval, repeat, func);
3028 if (0 == t->ID()) {
3029 delete t;
3030 return 0;
3033 mTimers.AppendElement(t);
3034 return t->ID();
3037 void
3038 PluginInstanceChild::UnscheduleTimer(uint32_t id)
3040 if (0 == id)
3041 return;
3043 mTimers.RemoveElement(id, ChildTimer::IDComparator());
3046 void
3047 PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData)
3049 ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData);
3052 MutexAutoLock lock(mAsyncCallMutex);
3053 mPendingAsyncCalls.AppendElement(task);
3055 ProcessChild::message_loop()->PostTask(FROM_HERE, task);
3058 static PLDHashOperator
3059 InvalidateObject(DeletingObjectEntry* e, void* userArg)
3061 NPObject* o = e->GetKey();
3062 if (!e->mDeleted && o->_class && o->_class->invalidate)
3063 o->_class->invalidate(o);
3065 return PL_DHASH_NEXT;
3068 static PLDHashOperator
3069 DeleteObject(DeletingObjectEntry* e, void* userArg)
3071 NPObject* o = e->GetKey();
3072 if (!e->mDeleted) {
3073 e->mDeleted = true;
3075 #ifdef NS_BUILD_REFCNT_LOGGING
3077 int32_t refcnt = o->referenceCount;
3078 while (refcnt) {
3079 --refcnt;
3080 NS_LOG_RELEASE(o, refcnt, "NPObject");
3083 #endif
3085 PluginModuleChild::DeallocNPObject(o);
3088 return PL_DHASH_NEXT;
3091 void
3092 PluginInstanceChild::SwapSurfaces()
3094 nsRefPtr<gfxASurface> tmpsurf = mCurrentSurface;
3095 #ifdef XP_WIN
3096 PPluginSurfaceChild* tmpactor = mCurrentSurfaceActor;
3097 #endif
3099 mCurrentSurface = mBackSurface;
3100 #ifdef XP_WIN
3101 mCurrentSurfaceActor = mBackSurfaceActor;
3102 #endif
3104 mBackSurface = tmpsurf;
3105 #ifdef XP_WIN
3106 mBackSurfaceActor = tmpactor;
3107 #endif
3109 // Outdated back surface... not usable anymore due to changed plugin size.
3110 // Dropping obsolete surface
3111 if (mCurrentSurface && mBackSurface &&
3112 mCurrentSurface->GetSize() != mBackSurface->GetSize()) {
3113 mCurrentSurface = nsnull;
3114 #ifdef XP_WIN
3115 if (mCurrentSurfaceActor) {
3116 PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
3117 mCurrentSurfaceActor = NULL;
3119 #endif
3123 void
3124 PluginInstanceChild::ClearCurrentSurface()
3126 mCurrentSurface = nsnull;
3127 #ifdef XP_WIN
3128 if (mCurrentSurfaceActor) {
3129 PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
3130 mCurrentSurfaceActor = NULL;
3132 #endif
3133 mHelperSurface = nsnull;
3136 void
3137 PluginInstanceChild::ClearAllSurfaces()
3139 if (mBackSurface) {
3140 // Get last surface back, and drop it
3141 SurfaceDescriptor temp = null_t();
3142 NPRect r = { 0, 0, 1, 1 };
3143 SendShow(r, temp, &temp);
3145 if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface))
3146 DeallocShmem(static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem());
3147 if (gfxSharedImageSurface::IsSharedImage(mBackSurface))
3148 DeallocShmem(static_cast<gfxSharedImageSurface*>(mBackSurface.get())->GetShmem());
3149 mCurrentSurface = nsnull;
3150 mBackSurface = nsnull;
3152 #ifdef XP_WIN
3153 if (mCurrentSurfaceActor) {
3154 PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor);
3155 mCurrentSurfaceActor = NULL;
3157 if (mBackSurfaceActor) {
3158 PPluginSurfaceChild::Send__delete__(mBackSurfaceActor);
3159 mBackSurfaceActor = NULL;
3161 #endif
3164 bool
3165 PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
3167 PLUGIN_LOG_DEBUG_METHOD;
3168 AssertPluginThread();
3170 #if defined(OS_WIN)
3171 SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1);
3172 #endif
3174 InfallibleTArray<PBrowserStreamChild*> streams;
3175 ManagedPBrowserStreamChild(streams);
3177 // First make sure none of these streams become deleted
3178 for (PRUint32 i = 0; i < streams.Length(); ) {
3179 if (static_cast<BrowserStreamChild*>(streams[i])->InstanceDying())
3180 ++i;
3181 else
3182 streams.RemoveElementAt(i);
3184 for (PRUint32 i = 0; i < streams.Length(); ++i)
3185 static_cast<BrowserStreamChild*>(streams[i])->FinishDelivery();
3187 mTimers.Clear();
3188 if (mCurrentInvalidateTask) {
3189 mCurrentInvalidateTask->Cancel();
3190 mCurrentInvalidateTask = nsnull;
3192 if (mCurrentAsyncSetWindowTask) {
3193 mCurrentAsyncSetWindowTask->Cancel();
3194 mCurrentAsyncSetWindowTask = nsnull;
3197 // NPP_Destroy() should be a synchronization point for plugin threads
3198 // calling NPN_AsyncCall: after this function returns, they are no longer
3199 // allowed to make async calls on this instance.
3200 PluginModuleChild::current()->NPP_Destroy(this);
3201 mData.ndata = 0;
3203 ClearAllSurfaces();
3205 mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
3206 mDeletingHash->Init();
3207 PluginModuleChild::current()->FindNPObjectsForInstance(this);
3209 mDeletingHash->EnumerateEntries(InvalidateObject, NULL);
3210 mDeletingHash->EnumerateEntries(DeleteObject, NULL);
3212 // Null out our cached actors as they should have been killed in the
3213 // PluginInstanceDestroyed call above.
3214 mCachedWindowActor = nsnull;
3215 mCachedElementActor = nsnull;
3217 #if defined(OS_WIN)
3218 SharedSurfaceRelease();
3219 DestroyWinlessPopupSurrogate();
3220 UnhookWinlessFlashThrottle();
3221 DestroyPluginWindow();
3222 #endif
3224 // Pending async calls are discarded, not delivered. This matches the
3225 // in-process behavior.
3226 for (PRUint32 i = 0; i < mPendingAsyncCalls.Length(); ++i)
3227 mPendingAsyncCalls[i]->Cancel();
3229 mPendingAsyncCalls.Clear();
3231 return true;