Fix regexp match pair end-index == -1 assumption. (r=dmandelin, a=blocker b=605754)
[mozilla-central.git] / dom / plugins / PluginInstanceParent.cpp
blob2048bfca694ec872bf1ab7247dd5c21f70120820
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 "PluginInstanceParent.h"
42 #include "BrowserStreamParent.h"
43 #include "PluginModuleParent.h"
44 #include "PluginStreamParent.h"
45 #include "StreamNotifyParent.h"
46 #include "npfunctions.h"
47 #include "nsAutoPtr.h"
48 #include "mozilla/unused.h"
49 #include "gfxASurface.h"
50 #include "gfxContext.h"
51 #include "gfxPlatform.h"
52 #include "gfxSharedImageSurface.h"
53 #ifdef MOZ_X11
54 #include "gfxXlibSurface.h"
55 #endif
56 #include "gfxContext.h"
57 #include "gfxColor.h"
58 #include "gfxUtils.h"
60 #if defined(OS_WIN)
61 #include <windowsx.h>
62 #include "mozilla/gfx/SharedDIBSurface.h"
64 using mozilla::gfx::SharedDIBSurface;
66 // Plugin focus event for widget.
67 extern const PRUnichar* kOOPPPluginFocusEventId;
68 UINT gOOPPPluginFocusEvent =
69 RegisterWindowMessage(kOOPPPluginFocusEventId);
70 extern const PRUnichar* kFlashFullscreenClass;
71 UINT gOOPPSpinNativeLoopEvent =
72 RegisterWindowMessage(L"SyncChannel Spin Inner Loop Message");
73 UINT gOOPPStopNativeLoopEvent =
74 RegisterWindowMessage(L"SyncChannel Stop Inner Loop Message");
75 #elif defined(MOZ_WIDGET_GTK2)
76 #include <gdk/gdk.h>
77 #elif defined(XP_MACOSX)
78 #include <ApplicationServices/ApplicationServices.h>
79 #endif // defined(XP_MACOSX)
81 using namespace mozilla::plugins;
83 PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
84 NPP npp,
85 const nsCString& aMimeType,
86 const NPNetscapeFuncs* npniface)
87 : mParent(parent)
88 , mNPP(npp)
89 , mNPNIface(npniface)
90 , mWindowType(NPWindowTypeWindow)
91 #if defined(OS_WIN)
92 , mPluginHWND(NULL)
93 , mPluginWndProc(NULL)
94 , mNestedEventState(false)
95 #endif // defined(XP_WIN)
96 , mQuirks(0)
97 #if defined(XP_MACOSX)
98 , mShWidth(0)
99 , mShHeight(0)
100 , mShColorSpace(nsnull)
101 , mDrawingModel(NPDrawingModelCoreGraphics)
102 , mIOSurface(nsnull)
103 #endif
105 InitQuirksModes(aMimeType);
108 void
109 PluginInstanceParent::InitQuirksModes(const nsCString& aMimeType)
111 #ifdef OS_MACOSX
112 NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash");
113 // Flash sends us Invalidate events so we will use those
114 // instead of the refresh timer.
115 if (!FindInReadable(flash, aMimeType)) {
116 mQuirks |= COREANIMATION_REFRESH_TIMER;
118 #endif
121 PluginInstanceParent::~PluginInstanceParent()
123 if (mNPP)
124 mNPP->pdata = NULL;
126 #if defined(OS_WIN)
127 NS_ASSERTION(!(mPluginHWND || mPluginWndProc),
128 "Subclass was not reset correctly before the dtor was reached!");
129 #endif
130 #if defined(OS_MACOSX)
131 if (mShWidth != 0 && mShHeight != 0) {
132 DeallocShmem(mShSurface);
134 if (mShColorSpace)
135 ::CGColorSpaceRelease(mShColorSpace);
136 if (mIOSurface)
137 delete mIOSurface;
138 if (mDrawingModel == NPDrawingModelCoreAnimation) {
139 mParent->RemoveFromRefreshTimer(this);
141 #endif
144 bool
145 PluginInstanceParent::Init()
147 return !!mScriptableObjects.Init();
150 namespace {
152 PLDHashOperator
153 ActorCollect(const void* aKey,
154 PluginScriptableObjectParent* aData,
155 void* aUserData)
157 nsTArray<PluginScriptableObjectParent*>* objects =
158 reinterpret_cast<nsTArray<PluginScriptableObjectParent*>*>(aUserData);
159 return objects->AppendElement(aData) ? PL_DHASH_NEXT : PL_DHASH_STOP;
162 } // anonymous namespace
164 void
165 PluginInstanceParent::ActorDestroy(ActorDestroyReason why)
167 #if defined(OS_WIN)
168 if (why == AbnormalShutdown) {
169 // If the plugin process crashes, this is the only
170 // chance we get to destroy resources.
171 SharedSurfaceRelease();
172 UnsubclassPluginWindow();
174 #endif
175 // After this method, the data backing the remote surface may no
176 // longer be calid. The X surface may be destroyed, or the shared
177 // memory backing this surface may no longer be valid. The right
178 // way to inform the nsObjectFrame that the surface is no longer
179 // valid is with an invalidate call.
180 if (mFrontSurface) {
181 mFrontSurface = NULL;
182 const NPRect rect = {0, 0, 0, 0};
183 RecvNPN_InvalidateRect(rect);
184 #ifdef MOZ_X11
185 XSync(DefaultXDisplay(), False);
186 #endif
190 NPError
191 PluginInstanceParent::Destroy()
193 NPError retval;
194 if (!CallNPP_Destroy(&retval))
195 retval = NPERR_GENERIC_ERROR;
197 #if defined(OS_WIN)
198 SharedSurfaceRelease();
199 UnsubclassPluginWindow();
200 #endif
202 return retval;
205 PBrowserStreamParent*
206 PluginInstanceParent::AllocPBrowserStream(const nsCString& url,
207 const uint32_t& length,
208 const uint32_t& lastmodified,
209 PStreamNotifyParent* notifyData,
210 const nsCString& headers,
211 const nsCString& mimeType,
212 const bool& seekable,
213 NPError* rv,
214 uint16_t *stype)
216 NS_RUNTIMEABORT("Not reachable");
217 return NULL;
220 bool
221 PluginInstanceParent::DeallocPBrowserStream(PBrowserStreamParent* stream)
223 delete stream;
224 return true;
227 PPluginStreamParent*
228 PluginInstanceParent::AllocPPluginStream(const nsCString& mimeType,
229 const nsCString& target,
230 NPError* result)
232 return new PluginStreamParent(this, mimeType, target, result);
235 bool
236 PluginInstanceParent::DeallocPPluginStream(PPluginStreamParent* stream)
238 delete stream;
239 return true;
242 bool
243 PluginInstanceParent::AnswerNPN_GetValue_NPNVjavascriptEnabledBool(
244 bool* value,
245 NPError* result)
247 NPBool v;
248 *result = mNPNIface->getvalue(mNPP, NPNVjavascriptEnabledBool, &v);
249 *value = v;
250 return true;
253 bool
254 PluginInstanceParent::AnswerNPN_GetValue_NPNVisOfflineBool(bool* value,
255 NPError* result)
257 NPBool v;
258 *result = mNPNIface->getvalue(mNPP, NPNVisOfflineBool, &v);
259 *value = v;
260 return true;
263 bool
264 PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
265 NPError* result)
267 #ifdef XP_WIN
268 HWND id;
269 #elif defined(MOZ_X11)
270 XID id;
271 #elif defined(XP_MACOSX)
272 intptr_t id;
273 #elif defined(ANDROID)
274 #warning Need Android impl
275 int id;
276 #else
277 #warning Implement me
278 #endif
280 *result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow, &id);
281 *value = id;
282 return true;
285 bool
286 PluginInstanceParent::InternalGetValueForNPObject(
287 NPNVariable aVariable,
288 PPluginScriptableObjectParent** aValue,
289 NPError* aResult)
291 NPObject* npobject;
292 NPError result = mNPNIface->getvalue(mNPP, aVariable, (void*)&npobject);
293 if (result == NPERR_NO_ERROR) {
294 NS_ASSERTION(npobject, "Shouldn't return null and NPERR_NO_ERROR!");
296 PluginScriptableObjectParent* actor = GetActorForNPObject(npobject);
297 mNPNIface->releaseobject(npobject);
298 if (actor) {
299 *aValue = actor;
300 *aResult = NPERR_NO_ERROR;
301 return true;
304 NS_ERROR("Failed to get actor!");
305 result = NPERR_GENERIC_ERROR;
308 *aValue = nsnull;
309 *aResult = result;
310 return true;
313 bool
314 PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
315 PPluginScriptableObjectParent** aValue,
316 NPError* aResult)
318 return InternalGetValueForNPObject(NPNVWindowNPObject, aValue, aResult);
321 bool
322 PluginInstanceParent::AnswerNPN_GetValue_NPNVPluginElementNPObject(
323 PPluginScriptableObjectParent** aValue,
324 NPError* aResult)
326 return InternalGetValueForNPObject(NPNVPluginElementNPObject, aValue,
327 aResult);
330 bool
331 PluginInstanceParent::AnswerNPN_GetValue_NPNVprivateModeBool(bool* value,
332 NPError* result)
334 NPBool v;
335 *result = mNPNIface->getvalue(mNPP, NPNVprivateModeBool, &v);
336 *value = v;
337 return true;
340 bool
341 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
342 const bool& windowed, NPError* result)
344 NPBool isWindowed = windowed;
345 *result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
346 (void*)isWindowed);
347 return true;
350 bool
351 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginTransparent(
352 const bool& transparent, NPError* result)
354 NPBool isTransparent = transparent;
355 *result = mNPNIface->setvalue(mNPP, NPPVpluginTransparentBool,
356 (void*)isTransparent);
357 return true;
360 bool
361 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
362 const int& drawingModel, NPError* result)
364 #ifdef XP_MACOSX
365 if (drawingModel == NPDrawingModelCoreAnimation ||
366 drawingModel == NPDrawingModelInvalidatingCoreAnimation) {
367 // We need to request CoreGraphics otherwise
368 // the nsObjectFrame will try to draw a CALayer
369 // that can not be shared across process.
370 mDrawingModel = drawingModel;
371 *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
372 (void*)NPDrawingModelCoreGraphics);
373 if (drawingModel == NPDrawingModelCoreAnimation &&
374 mQuirks & COREANIMATION_REFRESH_TIMER) {
375 mParent->AddToRefreshTimer(this);
377 } else {
378 mDrawingModel = drawingModel;
379 *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
380 (void*)drawingModel);
382 return true;
383 #else
384 *result = NPERR_GENERIC_ERROR;
385 return true;
386 #endif
389 bool
390 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
391 const int& eventModel, NPError* result)
393 #ifdef XP_MACOSX
394 *result = mNPNIface->setvalue(mNPP, NPPVpluginEventModel,
395 (void*)eventModel);
396 return true;
397 #else
398 *result = NPERR_GENERIC_ERROR;
399 return true;
400 #endif
403 bool
404 PluginInstanceParent::AnswerNPN_GetURL(const nsCString& url,
405 const nsCString& target,
406 NPError* result)
408 *result = mNPNIface->geturl(mNPP,
409 NullableStringGet(url),
410 NullableStringGet(target));
411 return true;
414 bool
415 PluginInstanceParent::AnswerNPN_PostURL(const nsCString& url,
416 const nsCString& target,
417 const nsCString& buffer,
418 const bool& file,
419 NPError* result)
421 *result = mNPNIface->posturl(mNPP, url.get(), NullableStringGet(target),
422 buffer.Length(), buffer.get(), file);
423 return true;
426 PStreamNotifyParent*
427 PluginInstanceParent::AllocPStreamNotify(const nsCString& url,
428 const nsCString& target,
429 const bool& post,
430 const nsCString& buffer,
431 const bool& file,
432 NPError* result)
434 return new StreamNotifyParent();
437 bool
438 PluginInstanceParent::AnswerPStreamNotifyConstructor(PStreamNotifyParent* actor,
439 const nsCString& url,
440 const nsCString& target,
441 const bool& post,
442 const nsCString& buffer,
443 const bool& file,
444 NPError* result)
446 bool streamDestroyed = false;
447 static_cast<StreamNotifyParent*>(actor)->
448 SetDestructionFlag(&streamDestroyed);
450 if (!post) {
451 *result = mNPNIface->geturlnotify(mNPP,
452 NullableStringGet(url),
453 NullableStringGet(target),
454 actor);
456 else {
457 *result = mNPNIface->posturlnotify(mNPP,
458 NullableStringGet(url),
459 NullableStringGet(target),
460 buffer.Length(),
461 NullableStringGet(buffer),
462 file, actor);
465 if (!streamDestroyed) {
466 static_cast<StreamNotifyParent*>(actor)->ClearDestructionFlag();
467 if (*result != NPERR_NO_ERROR)
468 return PStreamNotifyParent::Send__delete__(actor,
469 NPERR_GENERIC_ERROR);
472 return true;
475 bool
476 PluginInstanceParent::DeallocPStreamNotify(PStreamNotifyParent* notifyData)
478 delete notifyData;
479 return true;
482 bool
483 PluginInstanceParent::RecvNPN_InvalidateRect(const NPRect& rect)
485 mNPNIface->invalidaterect(mNPP, const_cast<NPRect*>(&rect));
486 return true;
489 bool
490 PluginInstanceParent::RecvShow(const NPRect& updatedRect,
491 const SurfaceDescriptor& newSurface,
492 SurfaceDescriptor* prevSurface)
494 nsRefPtr<gfxASurface> surface;
495 if (newSurface.type() == SurfaceDescriptor::TShmem) {
496 if (!newSurface.get_Shmem().IsReadable()) {
497 NS_WARNING("back surface not readable");
498 return false;
500 surface = new gfxSharedImageSurface(newSurface.get_Shmem());
502 #ifdef MOZ_X11
503 else if (newSurface.type() == SurfaceDescriptor::TSurfaceDescriptorX11) {
504 SurfaceDescriptorX11 xdesc = newSurface.get_SurfaceDescriptorX11();
505 XRenderPictFormat pf;
506 pf.id = xdesc.xrenderPictID();
507 XRenderPictFormat *incFormat =
508 XRenderFindFormat(DefaultXDisplay(), PictFormatID, &pf, 0);
509 surface =
510 new gfxXlibSurface(DefaultScreenOfDisplay(DefaultXDisplay()),
511 xdesc.XID(), incFormat, xdesc.size());
513 #endif
514 #ifdef XP_WIN
515 else if (newSurface.type() == SurfaceDescriptor::TSurfaceDescriptorWin) {
516 SurfaceDescriptorWin windesc = newSurface.get_SurfaceDescriptorWin();
517 SharedDIBSurface* dibsurf = new SharedDIBSurface();
518 if (dibsurf->Attach(windesc.handle(), windesc.size().width, windesc.size().height, windesc.transparent()))
519 surface = dibsurf;
521 #endif
523 #ifdef MOZ_X11
524 if (mFrontSurface &&
525 mFrontSurface->GetType() == gfxASurface::SurfaceTypeXlib)
526 XSync(DefaultXDisplay(), False);
527 #endif
529 if (mFrontSurface && gfxSharedImageSurface::IsSharedImage(mFrontSurface))
530 *prevSurface = static_cast<gfxSharedImageSurface*>(mFrontSurface.get())->GetShmem();
531 else
532 *prevSurface = null_t();
534 mFrontSurface = surface;
535 RecvNPN_InvalidateRect(updatedRect);
537 return true;
540 nsresult
541 PluginInstanceParent::AsyncSetWindow(NPWindow* aWindow)
543 NPRemoteWindow window;
544 mWindowType = aWindow->type;
545 window.window = reinterpret_cast<unsigned long>(aWindow->window);
546 window.x = aWindow->x;
547 window.y = aWindow->y;
548 window.width = aWindow->width;
549 window.height = aWindow->height;
550 window.clipRect = aWindow->clipRect;
551 window.type = aWindow->type;
552 if (!SendAsyncSetWindow(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(),
553 window))
554 return NS_ERROR_FAILURE;
556 return NS_OK;
559 nsresult
560 PluginInstanceParent::GetSurface(gfxASurface** aSurface)
562 if (mFrontSurface) {
563 NS_ADDREF(*aSurface = mFrontSurface);
564 return NS_OK;
566 return NS_ERROR_NOT_AVAILABLE;
569 NPError
570 PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
572 PLUGIN_LOG_DEBUG(("%s (aWindow=%p)", FULLFUNCTION, (void*) aWindow));
574 NS_ENSURE_TRUE(aWindow, NPERR_GENERIC_ERROR);
576 NPRemoteWindow window;
577 mWindowType = aWindow->type;
579 #if defined(OS_WIN)
580 // On windowless controls, reset the shared memory surface as needed.
581 if (mWindowType == NPWindowTypeDrawable) {
582 // SharedSurfaceSetWindow will take care of NPRemoteWindow.
583 if (!SharedSurfaceSetWindow(aWindow, window)) {
584 return NPERR_OUT_OF_MEMORY_ERROR;
587 else {
588 SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
590 window.window = reinterpret_cast<unsigned long>(aWindow->window);
591 window.x = aWindow->x;
592 window.y = aWindow->y;
593 window.width = aWindow->width;
594 window.height = aWindow->height;
595 window.type = aWindow->type;
597 #else
598 window.window = reinterpret_cast<unsigned long>(aWindow->window);
599 window.x = aWindow->x;
600 window.y = aWindow->y;
601 window.width = aWindow->width;
602 window.height = aWindow->height;
603 window.clipRect = aWindow->clipRect; // MacOS specific
604 window.type = aWindow->type;
605 #endif
607 #if defined(XP_MACOSX)
608 if (mShWidth != window.width || mShHeight != window.height) {
609 if (mDrawingModel == NPDrawingModelCoreAnimation ||
610 mDrawingModel == NPDrawingModelInvalidatingCoreAnimation) {
611 if (mIOSurface) {
612 delete mIOSurface;
614 mIOSurface = nsIOSurface::CreateIOSurface(window.width, window.height);
615 } else if (mShWidth * mShHeight != window.width * window.height) {
616 if (mShWidth != 0 && mShHeight != 0) {
617 DeallocShmem(mShSurface);
618 mShWidth = 0;
619 mShHeight = 0;
622 if (window.width != 0 && window.height != 0) {
623 if (!AllocShmem(window.width * window.height*4,
624 SharedMemory::TYPE_BASIC, &mShSurface)) {
625 PLUGIN_LOG_DEBUG(("Shared memory could not be allocated."));
626 return NPERR_GENERIC_ERROR;
630 mShWidth = window.width;
631 mShHeight = window.height;
633 #endif
635 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
636 const NPSetWindowCallbackStruct* ws_info =
637 static_cast<NPSetWindowCallbackStruct*>(aWindow->ws_info);
638 window.visualID = ws_info->visual ? ws_info->visual->visualid : None;
639 window.colormap = ws_info->colormap;
640 #endif
642 if (!CallNPP_SetWindow(window))
643 return NPERR_GENERIC_ERROR;
645 return NPERR_NO_ERROR;
648 NPError
649 PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
650 void* _retval)
652 switch (aVariable) {
654 #ifdef MOZ_X11
655 case NPPVpluginNeedsXEmbed: {
656 bool needsXEmbed;
657 NPError rv;
659 if (!CallNPP_GetValue_NPPVpluginNeedsXEmbed(&needsXEmbed, &rv)) {
660 return NPERR_GENERIC_ERROR;
663 if (NPERR_NO_ERROR != rv) {
664 return rv;
667 (*(NPBool*)_retval) = needsXEmbed;
668 return NPERR_NO_ERROR;
670 #endif
672 case NPPVpluginScriptableNPObject: {
673 PPluginScriptableObjectParent* actor;
674 NPError rv;
675 if (!CallNPP_GetValue_NPPVpluginScriptableNPObject(&actor, &rv)) {
676 return NPERR_GENERIC_ERROR;
679 if (NPERR_NO_ERROR != rv) {
680 return rv;
683 if (!actor) {
684 NS_ERROR("NPPVpluginScriptableNPObject succeeded but null.");
685 return NPERR_GENERIC_ERROR;
688 const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
689 if (!npn) {
690 NS_WARNING("No netscape functions?!");
691 return NPERR_GENERIC_ERROR;
694 NPObject* object =
695 static_cast<PluginScriptableObjectParent*>(actor)->GetObject(true);
696 NS_ASSERTION(object, "This shouldn't ever be null!");
698 (*(NPObject**)_retval) = npn->retainobject(object);
699 return NPERR_NO_ERROR;
702 default:
703 PR_LOG(gPluginLog, PR_LOG_WARNING,
704 ("In PluginInstanceParent::NPP_GetValue: Unhandled NPPVariable %i (%s)",
705 (int) aVariable, NPPVariableToString(aVariable)));
706 return NPERR_GENERIC_ERROR;
710 NPError
711 PluginInstanceParent::NPP_SetValue(NPNVariable variable, void* value)
713 switch (variable) {
714 case NPNVprivateModeBool:
715 NPError result;
716 if (!CallNPP_SetValue_NPNVprivateModeBool(*static_cast<NPBool*>(value),
717 &result))
718 return NPERR_GENERIC_ERROR;
720 return result;
722 default:
723 NS_ERROR("Unhandled NPNVariable in NPP_SetValue");
724 PR_LOG(gPluginLog, PR_LOG_WARNING,
725 ("In PluginInstanceParent::NPP_SetValue: Unhandled NPNVariable %i (%s)",
726 (int) variable, NPNVariableToString(variable)));
727 return NPERR_GENERIC_ERROR;
731 int16_t
732 PluginInstanceParent::NPP_HandleEvent(void* event)
734 PLUGIN_LOG_DEBUG_FUNCTION;
736 #if defined(XP_MACOSX)
737 NPCocoaEvent* npevent = reinterpret_cast<NPCocoaEvent*>(event);
738 #else
739 NPEvent* npevent = reinterpret_cast<NPEvent*>(event);
740 #endif
741 NPRemoteEvent npremoteevent;
742 npremoteevent.event = *npevent;
743 int16_t handled = 0;
745 #if defined(OS_WIN)
746 if (mWindowType == NPWindowTypeDrawable) {
747 if (DoublePassRenderingEvent() == npevent->event) {
748 CallPaint(npremoteevent, &handled);
749 return handled;
752 switch (npevent->event) {
753 case WM_PAINT:
755 RECT rect;
756 SharedSurfaceBeforePaint(rect, npremoteevent);
757 CallPaint(npremoteevent, &handled);
758 SharedSurfaceAfterPaint(npevent);
759 return handled;
761 break;
763 case WM_KILLFOCUS:
765 // When the user selects fullscreen mode in Flash video players,
766 // WM_KILLFOCUS will be delayed by deferred event processing:
767 // WM_LBUTTONUP results in a call to CreateWindow within Flash,
768 // which fires WM_KILLFOCUS. Delayed delivery causes Flash to
769 // misinterpret the event, dropping back out of fullscreen. Trap
770 // this event and drop it.
771 PRUnichar szClass[26];
772 HWND hwnd = GetForegroundWindow();
773 if (hwnd && hwnd != mPluginHWND &&
774 GetClassNameW(hwnd, szClass,
775 sizeof(szClass)/sizeof(PRUnichar)) &&
776 !wcscmp(szClass, kFlashFullscreenClass)) {
777 return 0;
780 break;
782 case WM_WINDOWPOSCHANGED:
784 // We send this in nsObjectFrame just before painting
785 SendWindowPosChanged(npremoteevent);
786 // nsObjectFrame doesn't care whether we handle this
787 // or not, just returning 1 for good hygiene
788 return 1;
790 break;
793 #endif
795 #if defined(MOZ_X11)
796 switch (npevent->type) {
797 case GraphicsExpose:
798 PLUGIN_LOG_DEBUG((" schlepping drawable 0x%lx across the pipe\n",
799 npevent->xgraphicsexpose.drawable));
800 // Make sure the X server has created the Drawable and completes any
801 // drawing before the plugin draws on top.
803 // XSync() waits for the X server to complete. Really this parent
804 // process does not need to wait; the child is the process that needs
805 // to wait. A possibly-slightly-better alternative would be to send
806 // an X event to the child that the child would wait for.
807 XSync(DefaultXDisplay(), False);
809 return CallPaint(npremoteevent, &handled) ? handled : 0;
811 case ButtonPress:
812 // Release any active pointer grab so that the plugin X client can
813 // grab the pointer if it wishes.
814 Display *dpy = DefaultXDisplay();
815 # ifdef MOZ_WIDGET_GTK2
816 // GDK attempts to (asynchronously) track whether there is an active
817 // grab so ungrab through GDK.
818 gdk_pointer_ungrab(npevent->xbutton.time);
819 # else
820 XUngrabPointer(dpy, npevent->xbutton.time);
821 # endif
822 // Wait for the ungrab to complete.
823 XSync(dpy, False);
824 break;
826 #endif
828 #ifdef XP_MACOSX
829 if (npevent->type == NPCocoaEventDrawRect) {
830 if (mDrawingModel == NPDrawingModelCoreAnimation ||
831 mDrawingModel == NPDrawingModelInvalidatingCoreAnimation) {
832 if (!mIOSurface) {
833 NS_ERROR("No IOSurface allocated.");
834 return false;
836 if (!CallNPP_HandleEvent_IOSurface(npremoteevent,
837 mIOSurface->GetIOSurfaceID(),
838 &handled))
839 return false; // no good way to handle errors here...
841 CGContextRef cgContext = npevent->data.draw.context;
842 if (!mShColorSpace) {
843 mShColorSpace = CreateSystemColorSpace();
845 if (!mShColorSpace) {
846 PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
847 return false;
849 nsCARenderer::DrawSurfaceToCGContext(cgContext, mIOSurface,
850 mShColorSpace,
851 npevent->data.draw.x,
852 npevent->data.draw.y,
853 npevent->data.draw.width,
854 npevent->data.draw.height);
855 return false;
856 } else {
857 if (mShWidth == 0 && mShHeight == 0) {
858 PLUGIN_LOG_DEBUG(("NPCocoaEventDrawRect on window of size 0."));
859 return false;
861 if (!mShSurface.IsReadable()) {
862 PLUGIN_LOG_DEBUG(("Shmem is not readable."));
863 return false;
866 if (!CallNPP_HandleEvent_Shmem(npremoteevent, mShSurface,
867 &handled, &mShSurface))
868 return false; // no good way to handle errors here...
870 if (!mShSurface.IsReadable()) {
871 PLUGIN_LOG_DEBUG(("Shmem not returned. Either the plugin crashed "
872 "or we have a bug."));
873 return false;
876 char* shContextByte = mShSurface.get<char>();
878 if (!mShColorSpace) {
879 mShColorSpace = CreateSystemColorSpace();
881 if (!mShColorSpace) {
882 PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
883 return false;
885 CGContextRef shContext = ::CGBitmapContextCreate(shContextByte,
886 mShWidth, mShHeight, 8,
887 mShWidth*4, mShColorSpace,
888 kCGImageAlphaPremultipliedFirst |
889 kCGBitmapByteOrder32Host);
890 if (!shContext) {
891 PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext."));
892 return false;
895 CGImageRef shImage = ::CGBitmapContextCreateImage(shContext);
896 if (shImage) {
897 CGContextRef cgContext = npevent->data.draw.context;
899 ::CGContextDrawImage(cgContext,
900 CGRectMake(0,0,mShWidth,mShHeight),
901 shImage);
902 ::CGImageRelease(shImage);
903 } else {
904 ::CGContextRelease(shContext);
905 return false;
907 ::CGContextRelease(shContext);
908 return true;
911 #endif
913 if (!CallNPP_HandleEvent(npremoteevent, &handled))
914 return 0; // no good way to handle errors here...
916 return handled;
919 NPError
920 PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
921 NPBool seekable, uint16_t* stype)
923 PLUGIN_LOG_DEBUG(("%s (type=%s, stream=%p, seekable=%i)",
924 FULLFUNCTION, (char*) type, (void*) stream, (int) seekable));
926 BrowserStreamParent* bs = new BrowserStreamParent(this, stream);
928 NPError err;
929 if (!CallPBrowserStreamConstructor(bs,
930 NullableString(stream->url),
931 stream->end,
932 stream->lastmodified,
933 static_cast<PStreamNotifyParent*>(stream->notifyData),
934 NullableString(stream->headers),
935 NullableString(type), seekable,
936 &err, stype))
937 return NPERR_GENERIC_ERROR;
939 if (NPERR_NO_ERROR != err)
940 unused << PBrowserStreamParent::Send__delete__(bs);
942 return err;
945 NPError
946 PluginInstanceParent::NPP_DestroyStream(NPStream* stream, NPReason reason)
948 PLUGIN_LOG_DEBUG(("%s (stream=%p, reason=%i)",
949 FULLFUNCTION, (void*) stream, (int) reason));
951 AStream* s = static_cast<AStream*>(stream->pdata);
952 if (s->IsBrowserStream()) {
953 BrowserStreamParent* sp =
954 static_cast<BrowserStreamParent*>(s);
955 if (sp->mNPP != this)
956 NS_RUNTIMEABORT("Mismatched plugin data");
958 sp->NPP_DestroyStream(reason);
959 return NPERR_NO_ERROR;
961 else {
962 PluginStreamParent* sp =
963 static_cast<PluginStreamParent*>(s);
964 if (sp->mInstance != this)
965 NS_RUNTIMEABORT("Mismatched plugin data");
967 return PPluginStreamParent::Call__delete__(sp, reason, false) ?
968 NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
972 void
973 PluginInstanceParent::NPP_Print(NPPrint* platformPrint)
975 // TODO: implement me
976 NS_ERROR("Not implemented");
979 PPluginScriptableObjectParent*
980 PluginInstanceParent::AllocPPluginScriptableObject()
982 return new PluginScriptableObjectParent(Proxy);
985 #ifdef DEBUG
986 namespace {
988 struct ActorSearchData
990 PluginScriptableObjectParent* actor;
991 bool found;
994 PLDHashOperator
995 ActorSearch(const void* aKey,
996 PluginScriptableObjectParent* aData,
997 void* aUserData)
999 ActorSearchData* asd = reinterpret_cast<ActorSearchData*>(aUserData);
1000 if (asd->actor == aData) {
1001 asd->found = true;
1002 return PL_DHASH_STOP;
1004 return PL_DHASH_NEXT;
1007 } // anonymous namespace
1008 #endif // DEBUG
1010 bool
1011 PluginInstanceParent::DeallocPPluginScriptableObject(
1012 PPluginScriptableObjectParent* aObject)
1014 PluginScriptableObjectParent* actor =
1015 static_cast<PluginScriptableObjectParent*>(aObject);
1017 NPObject* object = actor->GetObject(false);
1018 if (object) {
1019 NS_ASSERTION(mScriptableObjects.Get(object, nsnull),
1020 "NPObject not in the hash!");
1021 mScriptableObjects.Remove(object);
1023 #ifdef DEBUG
1024 else {
1025 ActorSearchData asd = { actor, false };
1026 mScriptableObjects.EnumerateRead(ActorSearch, &asd);
1027 NS_ASSERTION(!asd.found, "Actor in the hash with a null NPObject!");
1029 #endif
1031 delete actor;
1032 return true;
1035 bool
1036 PluginInstanceParent::RecvPPluginScriptableObjectConstructor(
1037 PPluginScriptableObjectParent* aActor)
1039 // This is only called in response to the child process requesting the
1040 // creation of an actor. This actor will represent an NPObject that is
1041 // created by the plugin and returned to the browser.
1042 PluginScriptableObjectParent* actor =
1043 static_cast<PluginScriptableObjectParent*>(aActor);
1044 NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
1046 actor->InitializeProxy();
1047 NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
1049 return true;
1052 void
1053 PluginInstanceParent::NPP_URLNotify(const char* url, NPReason reason,
1054 void* notifyData)
1056 PLUGIN_LOG_DEBUG(("%s (%s, %i, %p)",
1057 FULLFUNCTION, url, (int) reason, notifyData));
1059 PStreamNotifyParent* streamNotify =
1060 static_cast<PStreamNotifyParent*>(notifyData);
1061 unused << PStreamNotifyParent::Send__delete__(streamNotify, reason);
1064 bool
1065 PluginInstanceParent::RegisterNPObjectForActor(
1066 NPObject* aObject,
1067 PluginScriptableObjectParent* aActor)
1069 NS_ASSERTION(aObject && aActor, "Null pointers!");
1070 NS_ASSERTION(mScriptableObjects.IsInitialized(), "Hash not initialized!");
1071 NS_ASSERTION(!mScriptableObjects.Get(aObject, nsnull), "Duplicate entry!");
1072 return !!mScriptableObjects.Put(aObject, aActor);
1075 void
1076 PluginInstanceParent::UnregisterNPObject(NPObject* aObject)
1078 NS_ASSERTION(aObject, "Null pointer!");
1079 NS_ASSERTION(mScriptableObjects.IsInitialized(), "Hash not initialized!");
1080 NS_ASSERTION(mScriptableObjects.Get(aObject, nsnull), "Unknown entry!");
1081 mScriptableObjects.Remove(aObject);
1084 PluginScriptableObjectParent*
1085 PluginInstanceParent::GetActorForNPObject(NPObject* aObject)
1087 NS_ASSERTION(aObject, "Null pointer!");
1089 if (aObject->_class == PluginScriptableObjectParent::GetClass()) {
1090 // One of ours!
1091 ParentNPObject* object = static_cast<ParentNPObject*>(aObject);
1092 NS_ASSERTION(object->parent, "Null actor!");
1093 return object->parent;
1096 PluginScriptableObjectParent* actor;
1097 if (mScriptableObjects.Get(aObject, &actor)) {
1098 return actor;
1101 actor = new PluginScriptableObjectParent(LocalObject);
1102 if (!actor) {
1103 NS_ERROR("Out of memory!");
1104 return nsnull;
1107 if (!SendPPluginScriptableObjectConstructor(actor)) {
1108 NS_WARNING("Failed to send constructor message!");
1109 return nsnull;
1112 actor->InitializeLocal(aObject);
1113 return actor;
1116 bool
1117 PluginInstanceParent::AnswerNPN_PushPopupsEnabledState(const bool& aState)
1119 mNPNIface->pushpopupsenabledstate(mNPP, aState ? 1 : 0);
1120 return true;
1123 bool
1124 PluginInstanceParent::AnswerNPN_PopPopupsEnabledState()
1126 mNPNIface->poppopupsenabledstate(mNPP);
1127 return true;
1130 bool
1131 PluginInstanceParent::AnswerNPN_GetValueForURL(const NPNURLVariable& variable,
1132 const nsCString& url,
1133 nsCString* value,
1134 NPError* result)
1136 char* v;
1137 uint32_t len;
1139 *result = mNPNIface->getvalueforurl(mNPP, (NPNURLVariable) variable,
1140 url.get(), &v, &len);
1141 if (NPERR_NO_ERROR == *result)
1142 value->Adopt(v, len);
1144 return true;
1147 bool
1148 PluginInstanceParent::AnswerNPN_SetValueForURL(const NPNURLVariable& variable,
1149 const nsCString& url,
1150 const nsCString& value,
1151 NPError* result)
1153 *result = mNPNIface->setvalueforurl(mNPP, (NPNURLVariable) variable,
1154 url.get(), value.get(),
1155 value.Length());
1156 return true;
1159 bool
1160 PluginInstanceParent::AnswerNPN_GetAuthenticationInfo(const nsCString& protocol,
1161 const nsCString& host,
1162 const int32_t& port,
1163 const nsCString& scheme,
1164 const nsCString& realm,
1165 nsCString* username,
1166 nsCString* password,
1167 NPError* result)
1169 char* u;
1170 uint32_t ulen;
1171 char* p;
1172 uint32_t plen;
1174 *result = mNPNIface->getauthenticationinfo(mNPP, protocol.get(),
1175 host.get(), port,
1176 scheme.get(), realm.get(),
1177 &u, &ulen, &p, &plen);
1178 if (NPERR_NO_ERROR == *result) {
1179 username->Adopt(u, ulen);
1180 password->Adopt(p, plen);
1182 return true;
1185 bool
1186 PluginInstanceParent::AnswerNPN_ConvertPoint(const double& sourceX,
1187 const bool& ignoreDestX,
1188 const double& sourceY,
1189 const bool& ignoreDestY,
1190 const NPCoordinateSpace& sourceSpace,
1191 const NPCoordinateSpace& destSpace,
1192 double *destX,
1193 double *destY,
1194 bool *result)
1196 *result = mNPNIface->convertpoint(mNPP, sourceX, sourceY, sourceSpace,
1197 ignoreDestX ? nsnull : destX,
1198 ignoreDestY ? nsnull : destY,
1199 destSpace);
1201 return true;
1204 #if defined(OS_WIN)
1207 plugin focus changes between processes
1209 focus from dom -> child:
1210 Focus manager calls on widget to set the focus on the window.
1211 We pick up the resulting wm_setfocus event here, and forward
1212 that over ipc to the child which calls set focus on itself.
1214 focus from child -> focus manager:
1215 Child picks up the local wm_setfocus and sends it via ipc over
1216 here. We then post a custom event to widget/src/windows/nswindow
1217 which fires off a gui event letting the browser know.
1220 static const PRUnichar kPluginInstanceParentProperty[] =
1221 L"PluginInstanceParentProperty";
1223 // static
1224 LRESULT CALLBACK
1225 PluginInstanceParent::PluginWindowHookProc(HWND hWnd,
1226 UINT message,
1227 WPARAM wParam,
1228 LPARAM lParam)
1230 PluginInstanceParent* self = reinterpret_cast<PluginInstanceParent*>(
1231 ::GetPropW(hWnd, kPluginInstanceParentProperty));
1232 if (!self) {
1233 NS_NOTREACHED("PluginInstanceParent::PluginWindowHookProc null this ptr!");
1234 return DefWindowProc(hWnd, message, wParam, lParam);
1237 NS_ASSERTION(self->mPluginHWND == hWnd, "Wrong window!");
1239 switch (message) {
1240 case WM_SETFOCUS:
1241 // Let the child plugin window know it should take focus.
1242 self->CallSetPluginFocus();
1243 break;
1245 case WM_CLOSE:
1246 self->UnsubclassPluginWindow();
1247 break;
1250 return ::CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
1251 lParam);
1254 void
1255 PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
1257 NS_ASSERTION(!(mPluginHWND && aWnd != mPluginHWND),
1258 "PluginInstanceParent::SubclassPluginWindow hwnd is not our window!");
1260 if (!mPluginHWND) {
1261 mPluginHWND = aWnd;
1262 mPluginWndProc =
1263 (WNDPROC)::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
1264 reinterpret_cast<LONG_PTR>(PluginWindowHookProc));
1265 bool bRes = ::SetPropW(mPluginHWND, kPluginInstanceParentProperty, this);
1266 NS_ASSERTION(mPluginWndProc,
1267 "PluginInstanceParent::SubclassPluginWindow failed to set subclass!");
1268 NS_ASSERTION(bRes,
1269 "PluginInstanceParent::SubclassPluginWindow failed to set prop!");
1273 void
1274 PluginInstanceParent::UnsubclassPluginWindow()
1276 if (mPluginHWND && mPluginWndProc) {
1277 ::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
1278 reinterpret_cast<LONG_PTR>(mPluginWndProc));
1280 ::RemovePropW(mPluginHWND, kPluginInstanceParentProperty);
1282 mPluginWndProc = NULL;
1283 mPluginHWND = NULL;
1287 /* windowless drawing helpers */
1290 * Origin info:
1292 * windowless, offscreen:
1294 * WM_WINDOWPOSCHANGED: origin is relative to container
1295 * setwindow: origin is 0,0
1296 * WM_PAINT: origin is 0,0
1298 * windowless, native:
1300 * WM_WINDOWPOSCHANGED: origin is relative to container
1301 * setwindow: origin is relative to container
1302 * WM_PAINT: origin is relative to container
1304 * PluginInstanceParent:
1306 * painting: mPluginPort (nsIntRect, saved in SetWindow)
1309 void
1310 PluginInstanceParent::SharedSurfaceRelease()
1312 mSharedSurfaceDib.Close();
1315 bool
1316 PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow,
1317 NPRemoteWindow& aRemoteWindow)
1319 aRemoteWindow.window = nsnull;
1320 aRemoteWindow.x = aWindow->x;
1321 aRemoteWindow.y = aWindow->y;
1322 aRemoteWindow.width = aWindow->width;
1323 aRemoteWindow.height = aWindow->height;
1324 aRemoteWindow.type = aWindow->type;
1326 nsIntRect newPort(aWindow->x, aWindow->y, aWindow->width, aWindow->height);
1328 // save the the rect location within the browser window.
1329 mPluginPort = newPort;
1331 // move the port to our shared surface origin
1332 newPort.MoveTo(0,0);
1334 // check to see if we have the room in shared surface
1335 if (mSharedSurfaceDib.IsValid() && mSharedSize.Contains(newPort)) {
1336 // ok to paint
1337 aRemoteWindow.surfaceHandle = 0;
1338 return true;
1341 // allocate a new shared surface
1342 SharedSurfaceRelease();
1343 if (NS_FAILED(mSharedSurfaceDib.Create(reinterpret_cast<HDC>(aWindow->window),
1344 newPort.width, newPort.height, false)))
1345 return false;
1347 // save the new shared surface size we just allocated
1348 mSharedSize = newPort;
1350 base::SharedMemoryHandle handle;
1351 if (NS_FAILED(mSharedSurfaceDib.ShareToProcess(mParent->ChildProcessHandle(), &handle)))
1352 return false;
1354 aRemoteWindow.surfaceHandle = handle;
1356 return true;
1359 void
1360 PluginInstanceParent::SharedSurfaceBeforePaint(RECT& rect,
1361 NPRemoteEvent& npremoteevent)
1363 RECT* dr = (RECT*)npremoteevent.event.lParam;
1364 HDC parentHdc = (HDC)npremoteevent.event.wParam;
1366 nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
1367 dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y); // should always be smaller than dirtyRect
1369 ::BitBlt(mSharedSurfaceDib.GetHDC(),
1370 dirtyRect.x,
1371 dirtyRect.y,
1372 dirtyRect.width,
1373 dirtyRect.height,
1374 parentHdc,
1375 dr->left,
1376 dr->top,
1377 SRCCOPY);
1379 // setup the translated dirty rect we'll send to the child
1380 rect.left = dirtyRect.x;
1381 rect.top = dirtyRect.y;
1382 rect.right = dirtyRect.x + dirtyRect.width;
1383 rect.bottom = dirtyRect.y + dirtyRect.height;
1385 npremoteevent.event.wParam = WPARAM(0);
1386 npremoteevent.event.lParam = LPARAM(&rect);
1389 void
1390 PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent)
1392 RECT* dr = (RECT*)npevent->lParam;
1393 HDC parentHdc = (HDC)npevent->wParam;
1395 nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
1396 dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y);
1398 // src copy the shared dib into the parent surface we are handed.
1399 ::BitBlt(parentHdc,
1400 dr->left,
1401 dr->top,
1402 dirtyRect.width,
1403 dirtyRect.height,
1404 mSharedSurfaceDib.GetHDC(),
1405 dirtyRect.x,
1406 dirtyRect.y,
1407 SRCCOPY);
1410 #endif // defined(OS_WIN)
1412 bool
1413 PluginInstanceParent::AnswerPluginFocusChange(const bool& gotFocus)
1415 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
1417 // Currently only in use on windows - an rpc event we receive from the
1418 // child when it's plugin window (or one of it's children) receives keyboard
1419 // focus. We forward the event down to widget so the dom/focus manager can
1420 // be updated.
1421 #if defined(OS_WIN)
1422 ::SendMessage(mPluginHWND, gOOPPPluginFocusEvent, gotFocus ? 1 : 0, 0);
1423 return true;
1424 #else
1425 NS_NOTREACHED("PluginInstanceParent::AnswerPluginFocusChange not implemented!");
1426 return false;
1427 #endif
1430 #ifdef OS_MACOSX
1431 void
1432 PluginInstanceParent::Invalidate()
1434 NPRect windowRect = {0, 0, mShHeight, mShWidth};
1435 RecvNPN_InvalidateRect(windowRect);
1437 #endif