michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: sw=4 ts=4 et : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "PluginBackgroundDestroyer.h" michael@0: #include "PluginInstanceChild.h" michael@0: #include "PluginModuleChild.h" michael@0: #include "BrowserStreamChild.h" michael@0: #include "PluginStreamChild.h" michael@0: #include "StreamNotifyChild.h" michael@0: #include "PluginProcessChild.h" michael@0: #include "gfxASurface.h" michael@0: #include "gfxContext.h" michael@0: #include "nsNPAPIPluginInstance.h" michael@0: #ifdef MOZ_X11 michael@0: #include "gfxXlibSurface.h" michael@0: #endif michael@0: #ifdef XP_WIN michael@0: #include "mozilla/gfx/SharedDIBSurface.h" michael@0: #include "nsCrashOnException.h" michael@0: extern const wchar_t* kFlashFullscreenClass; michael@0: using mozilla::gfx::SharedDIBSurface; michael@0: #endif michael@0: #include "gfxSharedImageSurface.h" michael@0: #include "gfxUtils.h" michael@0: #include "gfxAlphaRecovery.h" michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/ipc/MessageChannel.h" michael@0: #include "mozilla/AutoRestore.h" michael@0: #include "ImageContainer.h" michael@0: michael@0: using namespace mozilla; michael@0: using mozilla::ipc::ProcessChild; michael@0: using namespace mozilla::plugins; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::gfx; michael@0: using namespace std; michael@0: michael@0: #ifdef MOZ_WIDGET_GTK michael@0: michael@0: #include michael@0: #if (MOZ_WIDGET_GTK == 3) michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: #include "gtk2xtbin.h" michael@0: #endif michael@0: michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: #undef KeyPress michael@0: #undef KeyRelease michael@0: #elif defined(OS_WIN) michael@0: #ifndef WM_MOUSEHWHEEL michael@0: #define WM_MOUSEHWHEEL 0x020E michael@0: #endif michael@0: michael@0: #include "nsWindowsDllInterceptor.h" michael@0: michael@0: typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu, michael@0: UINT uFlags, michael@0: int x, michael@0: int y, michael@0: int nReserved, michael@0: HWND hWnd, michael@0: CONST RECT *prcRect); michael@0: static WindowsDllInterceptor sUser32Intercept; michael@0: static HWND sWinlessPopupSurrogateHWND = nullptr; michael@0: static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr; michael@0: michael@0: using mozilla::gfx::SharedDIB; michael@0: michael@0: #include michael@0: #include michael@0: michael@0: // Flash WM_USER message delay time for PostDelayedTask. Borrowed michael@0: // from Chromium's web plugin delegate src. See 'flash msg throttling michael@0: // helpers' section for details. michael@0: const int kFlashWMUSERMessageThrottleDelayMs = 5; michael@0: michael@0: static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassProperty"); michael@0: michael@0: #elif defined(XP_MACOSX) michael@0: #include michael@0: #include "nsCocoaFeatures.h" michael@0: #include "PluginUtilsOSX.h" michael@0: #endif // defined(XP_MACOSX) michael@0: michael@0: template<> michael@0: struct RunnableMethodTraits michael@0: { michael@0: static void RetainCallee(PluginInstanceChild* obj) { } michael@0: static void ReleaseCallee(PluginInstanceChild* obj) { } michael@0: }; michael@0: michael@0: PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface) michael@0: : mPluginIface(aPluginIface) michael@0: #if defined(XP_MACOSX) michael@0: , mContentsScaleFactor(1.0) michael@0: #endif michael@0: , mDrawingModel(kDefaultDrawingModel) michael@0: , mCurrentAsyncSurface(0) michael@0: , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex") michael@0: , mAsyncInvalidateTask(0) michael@0: , mCachedWindowActor(nullptr) michael@0: , mCachedElementActor(nullptr) michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: , mXEmbed(false) michael@0: #endif // MOZ_WIDGET_GTK michael@0: #if defined(OS_WIN) michael@0: , mPluginWindowHWND(0) michael@0: , mPluginWndProc(0) michael@0: , mPluginParentHWND(0) michael@0: , mCachedWinlessPluginHWND(0) michael@0: , mWinlessPopupSurrogateHWND(0) michael@0: , mWinlessThrottleOldWndProc(0) michael@0: , mWinlessHiddenMsgHWND(0) michael@0: #endif // OS_WIN michael@0: , mAsyncCallMutex("PluginInstanceChild::mAsyncCallMutex") michael@0: #if defined(MOZ_WIDGET_COCOA) michael@0: #if defined(__i386__) michael@0: , mEventModel(NPEventModelCarbon) michael@0: #endif michael@0: , mShColorSpace(nullptr) michael@0: , mShContext(nullptr) michael@0: , mCGLayer(nullptr) michael@0: , mCurrentEvent(nullptr) michael@0: #endif michael@0: , mLayersRendering(false) michael@0: #ifdef XP_WIN michael@0: , mCurrentSurfaceActor(nullptr) michael@0: , mBackSurfaceActor(nullptr) michael@0: #endif michael@0: , mAccumulatedInvalidRect(0,0,0,0) michael@0: , mIsTransparent(false) michael@0: , mSurfaceType(gfxSurfaceType::Max) michael@0: , mCurrentInvalidateTask(nullptr) michael@0: , mCurrentAsyncSetWindowTask(nullptr) michael@0: , mPendingPluginCall(false) michael@0: , mDoAlphaExtraction(false) michael@0: , mHasPainted(false) michael@0: , mSurfaceDifferenceRect(0,0,0,0) michael@0: { michael@0: memset(&mWindow, 0, sizeof(mWindow)); michael@0: mWindow.type = NPWindowTypeWindow; michael@0: mData.ndata = (void*) this; michael@0: mData.pdata = nullptr; michael@0: #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: mWindow.ws_info = &mWsInfo; michael@0: memset(&mWsInfo, 0, sizeof(mWsInfo)); michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: mWsInfo.display = nullptr; michael@0: mXtClient.top_widget = nullptr; michael@0: #else michael@0: mWsInfo.display = DefaultXDisplay(); michael@0: #endif michael@0: #endif // MOZ_X11 && XP_UNIX && !XP_MACOSX michael@0: #if defined(OS_WIN) michael@0: memset(&mAlphaExtract, 0, sizeof(mAlphaExtract)); michael@0: #endif // OS_WIN michael@0: #if defined(OS_WIN) michael@0: InitPopupMenuHook(); michael@0: #endif // OS_WIN michael@0: } michael@0: michael@0: PluginInstanceChild::~PluginInstanceChild() michael@0: { michael@0: #if defined(OS_WIN) michael@0: NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?"); michael@0: #endif michael@0: #if defined(MOZ_WIDGET_COCOA) michael@0: if (mShColorSpace) { michael@0: ::CGColorSpaceRelease(mShColorSpace); michael@0: } michael@0: if (mShContext) { michael@0: ::CGContextRelease(mShContext); michael@0: } michael@0: if (mCGLayer) { michael@0: PluginUtilsOSX::ReleaseCGLayer(mCGLayer); michael@0: } michael@0: if (mDrawingModel == NPDrawingModelCoreAnimation) { michael@0: UnscheduleTimer(mCARefreshTimer); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: int michael@0: PluginInstanceChild::GetQuirks() michael@0: { michael@0: return PluginModuleChild::current()->GetQuirks(); michael@0: } michael@0: michael@0: NPError michael@0: PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue, michael@0: NPObject** aObject) michael@0: { michael@0: PluginScriptableObjectChild* actor = nullptr; michael@0: NPError result = NPERR_NO_ERROR; michael@0: michael@0: switch (aValue) { michael@0: case NPNVWindowNPObject: michael@0: if (!(actor = mCachedWindowActor)) { michael@0: PPluginScriptableObjectChild* actorProtocol; michael@0: CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result); michael@0: if (result == NPERR_NO_ERROR) { michael@0: actor = mCachedWindowActor = michael@0: static_cast(actorProtocol); michael@0: NS_ASSERTION(actor, "Null actor!"); michael@0: PluginModuleChild::sBrowserFuncs.retainobject( michael@0: actor->GetObject(false)); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case NPNVPluginElementNPObject: michael@0: if (!(actor = mCachedElementActor)) { michael@0: PPluginScriptableObjectChild* actorProtocol; michael@0: CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol, michael@0: &result); michael@0: if (result == NPERR_NO_ERROR) { michael@0: actor = mCachedElementActor = michael@0: static_cast(actorProtocol); michael@0: NS_ASSERTION(actor, "Null actor!"); michael@0: PluginModuleChild::sBrowserFuncs.retainobject( michael@0: actor->GetObject(false)); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: NS_NOTREACHED("Don't know what to do with this value type!"); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: NPError currentResult; michael@0: PPluginScriptableObjectChild* currentActor = nullptr; michael@0: michael@0: switch (aValue) { michael@0: case NPNVWindowNPObject: michael@0: CallNPN_GetValue_NPNVWindowNPObject(¤tActor, michael@0: ¤tResult); michael@0: break; michael@0: case NPNVPluginElementNPObject: michael@0: CallNPN_GetValue_NPNVPluginElementNPObject(¤tActor, michael@0: ¤tResult); michael@0: break; michael@0: default: michael@0: MOZ_ASSERT(false); michael@0: } michael@0: michael@0: // Make sure that the current actor returned by the parent matches our michael@0: // cached actor! michael@0: NS_ASSERTION(!currentActor || michael@0: static_cast(currentActor) == michael@0: actor, "Cached actor is out of date!"); michael@0: } michael@0: #endif michael@0: michael@0: if (result != NPERR_NO_ERROR) { michael@0: return result; michael@0: } michael@0: michael@0: NPObject* object = actor->GetObject(false); michael@0: NS_ASSERTION(object, "Null object?!"); michael@0: michael@0: *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object); michael@0: return NPERR_NO_ERROR; michael@0: michael@0: } michael@0: michael@0: NPError michael@0: PluginInstanceChild::NPN_GetValue(NPNVariable aVar, michael@0: void* aValue) michael@0: { michael@0: PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar)); michael@0: AssertPluginThread(); michael@0: michael@0: switch(aVar) { michael@0: michael@0: #if defined(MOZ_X11) michael@0: case NPNVToolkit: michael@0: *((NPNToolkitType*)aValue) = NPNVGtk2; michael@0: return NPERR_NO_ERROR; michael@0: michael@0: case NPNVxDisplay: michael@0: if (!mWsInfo.display) { michael@0: // We are called before Initialize() so we have to call it now. michael@0: Initialize(); michael@0: NS_ASSERTION(mWsInfo.display, "We should have a valid display!"); michael@0: } michael@0: *(void **)aValue = mWsInfo.display; michael@0: return NPERR_NO_ERROR; michael@0: michael@0: #elif defined(OS_WIN) michael@0: case NPNVToolkit: michael@0: return NPERR_GENERIC_ERROR; michael@0: #endif michael@0: case NPNVprivateModeBool: { michael@0: bool v = false; michael@0: NPError result; michael@0: if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: *static_cast(aValue) = v; michael@0: return result; michael@0: } michael@0: michael@0: case NPNVdocumentOrigin: { michael@0: nsCString v; michael@0: NPError result; michael@0: if (!CallNPN_GetValue_NPNVdocumentOrigin(&v, &result)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: if (result == NPERR_NO_ERROR) { michael@0: *static_cast(aValue) = ToNewCString(v); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: case NPNVWindowNPObject: // Intentional fall-through michael@0: case NPNVPluginElementNPObject: { michael@0: NPObject* object; michael@0: NPError result = InternalGetNPObjectForValue(aVar, &object); michael@0: if (result == NPERR_NO_ERROR) { michael@0: *((NPObject**)aValue) = object; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: case NPNVnetscapeWindow: { michael@0: #ifdef XP_WIN michael@0: if (mWindow.type == NPWindowTypeDrawable) { michael@0: if (mCachedWinlessPluginHWND) { michael@0: *static_cast(aValue) = mCachedWinlessPluginHWND; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: NPError result; michael@0: if (!CallNPN_GetValue_NPNVnetscapeWindow(&mCachedWinlessPluginHWND, &result)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: *static_cast(aValue) = mCachedWinlessPluginHWND; michael@0: return result; michael@0: } michael@0: else { michael@0: *static_cast(aValue) = mPluginWindowHWND; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #elif defined(MOZ_X11) michael@0: NPError result; michael@0: CallNPN_GetValue_NPNVnetscapeWindow(static_cast(aValue), &result); michael@0: return result; michael@0: #else michael@0: return NPERR_GENERIC_ERROR; michael@0: #endif michael@0: } michael@0: michael@0: case NPNVsupportsAsyncBitmapSurfaceBool: { michael@0: #ifdef XP_WIN michael@0: *((NPBool*)aValue) = PluginModuleChild::current()->AsyncDrawingAllowed(); michael@0: #else michael@0: // We do not support non-windows yet. michael@0: *((NPBool*)aValue) = false; michael@0: #endif michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: case NPNVsupportsAsyncWindowsDXGISurfaceBool: { michael@0: bool val; michael@0: CallNPN_GetValue_DrawingModelSupport(NPNVsupportsAsyncWindowsDXGISurfaceBool, &val); michael@0: *((NPBool*)aValue) = val; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: case NPNVsupportsCoreGraphicsBool: { michael@0: *((NPBool*)aValue) = true; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsCoreAnimationBool: { michael@0: *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins(); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsInvalidatingCoreAnimationBool: { michael@0: *((NPBool*)aValue) = nsCocoaFeatures::SupportCoreAnimationPlugins(); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsCompositingCoreAnimationPluginsBool: { michael@0: *((NPBool*)aValue) = true; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: case NPNVsupportsCocoaBool: { michael@0: *((NPBool*)aValue) = true; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: #ifndef NP_NO_CARBON michael@0: case NPNVsupportsCarbonBool: { michael@0: *((NPBool*)aValue) = false; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: michael@0: case NPNVsupportsUpdatedCocoaTextInputBool: { michael@0: *static_cast(aValue) = true; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: #ifndef NP_NO_QUICKDRAW michael@0: case NPNVsupportsQuickDrawBool: { michael@0: *((NPBool*)aValue) = false; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif /* NP_NO_QUICKDRAW */ michael@0: michael@0: case NPNVcontentsScaleFactor: { michael@0: *static_cast(aValue) = mContentsScaleFactor; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif /* XP_MACOSX */ michael@0: michael@0: #ifdef DEBUG michael@0: case NPNVjavascriptEnabledBool: michael@0: case NPNVasdEnabledBool: michael@0: case NPNVisOfflineBool: michael@0: case NPNVSupportsXEmbedBool: michael@0: case NPNVSupportsWindowless: michael@0: NS_NOTREACHED("NPNVariable should be handled in PluginModuleChild."); michael@0: #endif michael@0: michael@0: default: michael@0: PR_LOG(GetPluginLog(), PR_LOG_WARNING, michael@0: ("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)", michael@0: (int) aVar, NPNVariableToString(aVar))); michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: #define DEFAULT_REFRESH_MS 20 // CoreAnimation: 50 FPS michael@0: michael@0: void michael@0: CAUpdate(NPP npp, uint32_t timerID) { michael@0: static_cast(npp->ndata)->Invalidate(); michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::Invalidate() michael@0: { michael@0: NPRect windowRect = {0, 0, uint16_t(mWindow.height), michael@0: uint16_t(mWindow.width)}; michael@0: michael@0: InvalidateRect(&windowRect); michael@0: } michael@0: #endif michael@0: michael@0: NPError michael@0: PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue) michael@0: { michael@0: PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s (aVar=%i, aValue=%p)", michael@0: FULLFUNCTION, (int) aVar, aValue)); michael@0: michael@0: AssertPluginThread(); michael@0: michael@0: switch (aVar) { michael@0: case NPPVpluginWindowBool: { michael@0: NPError rv; michael@0: bool windowed = (NPBool) (intptr_t) aValue; michael@0: michael@0: if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: NPWindowType newWindowType = windowed ? NPWindowTypeWindow : NPWindowTypeDrawable; michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: if (mWindow.type != newWindowType && mWsInfo.display) { michael@0: // plugin type has been changed but we already have a valid display michael@0: // so update it for the recent plugin mode michael@0: if (mXEmbed || !windowed) { michael@0: // Use default GTK display for XEmbed and windowless plugins michael@0: mWsInfo.display = DefaultXDisplay(); michael@0: } michael@0: else { michael@0: mWsInfo.display = xt_client_get_display(); michael@0: } michael@0: } michael@0: #endif michael@0: mWindow.type = newWindowType; michael@0: return rv; michael@0: } michael@0: michael@0: case NPPVpluginTransparentBool: { michael@0: NPError rv; michael@0: mIsTransparent = (!!aValue); michael@0: michael@0: if (!CallNPN_SetValue_NPPVpluginTransparent(mIsTransparent, &rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: case NPPVpluginUsesDOMForCursorBool: { michael@0: NPError rv = NPERR_GENERIC_ERROR; michael@0: if (!CallNPN_SetValue_NPPVpluginUsesDOMForCursor((NPBool)(intptr_t)aValue, &rv)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: case NPPVpluginDrawingModel: { michael@0: NPError rv; michael@0: int drawingModel = (int16_t) (intptr_t) aValue; michael@0: michael@0: if (!PluginModuleChild::current()->AsyncDrawingAllowed() && michael@0: IsDrawingModelAsync(drawingModel)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: CrossProcessMutexHandle handle; michael@0: OptionalShmem optionalShmem; michael@0: if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &optionalShmem, &handle, &rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: if (IsDrawingModelAsync(drawingModel)) { michael@0: if (optionalShmem.type() != OptionalShmem::TShmem) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: mRemoteImageDataShmem = optionalShmem.get_Shmem(); michael@0: mRemoteImageData = mRemoteImageDataShmem.get(); michael@0: mRemoteImageDataMutex = new CrossProcessMutex(handle); michael@0: } michael@0: mDrawingModel = drawingModel; michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (drawingModel == NPDrawingModelCoreAnimation) { michael@0: mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate); michael@0: } michael@0: #endif michael@0: michael@0: PLUGIN_LOG_DEBUG((" Plugin requested drawing model id #%i\n", michael@0: mDrawingModel)); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: case NPPVpluginEventModel: { michael@0: NPError rv; michael@0: int eventModel = (int16_t) (intptr_t) aValue; michael@0: michael@0: if (!CallNPN_SetValue_NPPVpluginEventModel(eventModel, &rv)) michael@0: return NPERR_GENERIC_ERROR; michael@0: #if defined(__i386__) michael@0: mEventModel = static_cast(eventModel); michael@0: #endif michael@0: michael@0: PLUGIN_LOG_DEBUG((" Plugin requested event model id # %i\n", michael@0: eventModel)); michael@0: michael@0: return rv; michael@0: } michael@0: #endif michael@0: michael@0: default: michael@0: PR_LOG(GetPluginLog(), PR_LOG_WARNING, michael@0: ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)", michael@0: (int) aVar, NPPVariableToString(aVar))); michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams( michael@0: bool* wantsAllStreams, NPError* rv) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: uint32_t value = 0; michael@0: if (!mPluginIface->getvalue) { michael@0: *rv = NPERR_GENERIC_ERROR; michael@0: } michael@0: else { michael@0: *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginWantsAllNetworkStreams, michael@0: &value); michael@0: } michael@0: *wantsAllStreams = value; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed( michael@0: bool* needs, NPError* rv) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: #ifdef MOZ_X11 michael@0: // The documentation on the types for many variables in NP(N|P)_GetValue michael@0: // is vague. Often boolean values are NPBool (1 byte), but michael@0: // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins michael@0: // treats NPPVpluginNeedsXEmbed as PRBool (int), and michael@0: // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|. michael@0: // thus we can't use NPBool for needsXEmbed, or the three bytes above michael@0: // it on the stack would get clobbered. so protect with the larger bool. michael@0: int needsXEmbed = 0; michael@0: if (!mPluginIface->getvalue) { michael@0: *rv = NPERR_GENERIC_ERROR; michael@0: } michael@0: else { michael@0: *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginNeedsXEmbed, michael@0: &needsXEmbed); michael@0: } michael@0: *needs = needsXEmbed; michael@0: return true; michael@0: michael@0: #else michael@0: michael@0: NS_RUNTIMEABORT("shouldn't be called on non-X11 platforms"); michael@0: return false; // not reached michael@0: michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject( michael@0: PPluginScriptableObjectChild** aValue, michael@0: NPError* aResult) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: NPObject* object = nullptr; michael@0: NPError result = NPERR_GENERIC_ERROR; michael@0: if (mPluginIface->getvalue) { michael@0: result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject, michael@0: &object); michael@0: } michael@0: if (result == NPERR_NO_ERROR && object) { michael@0: PluginScriptableObjectChild* actor = GetActorForNPObject(object); michael@0: michael@0: // If we get an actor then it has retained. Otherwise we don't need it michael@0: // any longer. michael@0: PluginModuleChild::sBrowserFuncs.releaseobject(object); michael@0: if (actor) { michael@0: *aValue = actor; michael@0: *aResult = NPERR_NO_ERROR; michael@0: return true; michael@0: } michael@0: michael@0: NS_ERROR("Failed to get actor!"); michael@0: result = NPERR_GENERIC_ERROR; michael@0: } michael@0: else { michael@0: result = NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: *aValue = nullptr; michael@0: *aResult = result; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId( michael@0: nsCString* aPlugId, michael@0: NPError* aResult) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: #if MOZ_ACCESSIBILITY_ATK michael@0: michael@0: char* plugId = nullptr; michael@0: NPError result = NPERR_GENERIC_ERROR; michael@0: if (mPluginIface->getvalue) { michael@0: result = mPluginIface->getvalue(GetNPP(), michael@0: NPPVpluginNativeAccessibleAtkPlugId, michael@0: &plugId); michael@0: } michael@0: michael@0: *aPlugId = nsCString(plugId); michael@0: *aResult = result; michael@0: return true; michael@0: michael@0: #else michael@0: michael@0: NS_RUNTIMEABORT("shouldn't be called on non-ATK platforms"); michael@0: return false; michael@0: michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value, michael@0: NPError* result) michael@0: { michael@0: if (!mPluginIface->setvalue) { michael@0: *result = NPERR_GENERIC_ERROR; michael@0: return true; michael@0: } michael@0: michael@0: NPBool v = value; michael@0: *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event, michael@0: int16_t* handled) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: #if defined(MOZ_X11) && defined(DEBUG) michael@0: if (GraphicsExpose == event.event.type) michael@0: PLUGIN_LOG_DEBUG((" received drawable 0x%lx\n", michael@0: event.event.xgraphicsexpose.drawable)); michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Mac OS X does not define an NPEvent structure. It defines more specific types. michael@0: NPCocoaEvent evcopy = event.event; michael@0: // event.contentsScaleFactor <= 0 is a signal we shouldn't use it, michael@0: // for example when AnswerNPP_HandleEvent() is called from elsewhere michael@0: // in the child process (not via rpc code from the parent process). michael@0: if (event.contentsScaleFactor > 0) { michael@0: mContentsScaleFactor = event.contentsScaleFactor; michael@0: } michael@0: michael@0: // Make sure we reset mCurrentEvent in case of an exception michael@0: AutoRestore savePreviousEvent(mCurrentEvent); michael@0: michael@0: // Track the current event for NPN_PopUpContextMenu. michael@0: mCurrentEvent = &event.event; michael@0: #else michael@0: // Make a copy since we may modify values. michael@0: NPEvent evcopy = event.event; michael@0: #endif michael@0: michael@0: #ifdef OS_WIN michael@0: // FIXME/bug 567645: temporarily drop the "dummy event" on the floor michael@0: if (WM_NULL == evcopy.event) michael@0: return true; michael@0: michael@0: // Painting for win32. SharedSurfacePaint handles everything. michael@0: if (mWindow.type == NPWindowTypeDrawable) { michael@0: if (evcopy.event == WM_PAINT) { michael@0: *handled = SharedSurfacePaint(evcopy); michael@0: return true; michael@0: } michael@0: else if (DoublePassRenderingEvent() == evcopy.event) { michael@0: // We'll render to mSharedSurfaceDib first, then render to a cached bitmap michael@0: // we store locally. The two passes are for alpha extraction, so the second michael@0: // pass must be to a flat white surface in order for things to work. michael@0: mAlphaExtract.doublePass = RENDER_BACK_ONE; michael@0: *handled = true; michael@0: return true; michael@0: } michael@0: } michael@0: *handled = WinlessHandleEvent(evcopy); michael@0: return true; michael@0: #endif michael@0: michael@0: // XXX A previous call to mPluginIface->event might block, e.g. right click michael@0: // for context menu. Still, we might get here again, calling into the plugin michael@0: // a second time while it's in the previous call. michael@0: if (!mPluginIface->event) michael@0: *handled = false; michael@0: else michael@0: *handled = mPluginIface->event(&mData, reinterpret_cast(&evcopy)); michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Release any reference counted objects created in the child process. michael@0: if (evcopy.type == NPCocoaEventKeyDown || michael@0: evcopy.type == NPCocoaEventKeyUp) { michael@0: ::CFRelease((CFStringRef)evcopy.data.key.characters); michael@0: ::CFRelease((CFStringRef)evcopy.data.key.charactersIgnoringModifiers); michael@0: } michael@0: else if (evcopy.type == NPCocoaEventTextInput) { michael@0: ::CFRelease((CFStringRef)evcopy.data.text.text); michael@0: } michael@0: #endif michael@0: michael@0: #ifdef MOZ_X11 michael@0: if (GraphicsExpose == event.event.type) { michael@0: // Make sure the X server completes the drawing before the parent michael@0: // draws on top and destroys the Drawable. michael@0: // michael@0: // XSync() waits for the X server to complete. Really this child michael@0: // process does not need to wait; the parent is the process that needs michael@0: // to wait. A possibly-slightly-better alternative would be to send michael@0: // an X event to the parent that the parent would wait for. michael@0: XSync(mWsInfo.display, False); michael@0: } michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event, michael@0: Shmem& mem, michael@0: int16_t* handled, michael@0: Shmem* rtnmem) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: PaintTracker pt; michael@0: michael@0: NPCocoaEvent evcopy = event.event; michael@0: mContentsScaleFactor = event.contentsScaleFactor; michael@0: michael@0: if (evcopy.type == NPCocoaEventDrawRect) { michael@0: int scaleFactor = ceil(mContentsScaleFactor); michael@0: if (!mShColorSpace) { michael@0: mShColorSpace = CreateSystemColorSpace(); michael@0: if (!mShColorSpace) { michael@0: PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace.")); michael@0: *handled = false; michael@0: *rtnmem = mem; michael@0: return true; michael@0: } michael@0: } michael@0: if (!mShContext) { michael@0: void* cgContextByte = mem.get(); michael@0: mShContext = ::CGBitmapContextCreate(cgContextByte, michael@0: mWindow.width * scaleFactor, michael@0: mWindow.height * scaleFactor, 8, michael@0: mWindow.width * 4 * scaleFactor, mShColorSpace, michael@0: kCGImageAlphaPremultipliedFirst | michael@0: kCGBitmapByteOrder32Host); michael@0: michael@0: if (!mShContext) { michael@0: PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext.")); michael@0: *handled = false; michael@0: *rtnmem = mem; michael@0: return true; michael@0: } michael@0: } michael@0: CGRect clearRect = ::CGRectMake(0, 0, mWindow.width, mWindow.height); michael@0: ::CGContextClearRect(mShContext, clearRect); michael@0: evcopy.data.draw.context = mShContext; michael@0: } else { michael@0: PLUGIN_LOG_DEBUG(("Invalid event type for AnswerNNP_HandleEvent_Shmem.")); michael@0: *handled = false; michael@0: *rtnmem = mem; michael@0: return true; michael@0: } michael@0: michael@0: if (!mPluginIface->event) { michael@0: *handled = false; michael@0: } else { michael@0: ::CGContextSaveGState(evcopy.data.draw.context); michael@0: *handled = mPluginIface->event(&mData, reinterpret_cast(&evcopy)); michael@0: ::CGContextRestoreGState(evcopy.data.draw.context); michael@0: } michael@0: michael@0: *rtnmem = mem; michael@0: return true; michael@0: } michael@0: michael@0: #else michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event, michael@0: Shmem& mem, michael@0: int16_t* handled, michael@0: Shmem* rtnmem) michael@0: { michael@0: NS_RUNTIMEABORT("not reached."); michael@0: *rtnmem = mem; michael@0: return true; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: michael@0: void CallCGDraw(CGContextRef ref, void* aPluginInstance, nsIntRect aUpdateRect) { michael@0: PluginInstanceChild* pluginInstance = (PluginInstanceChild*)aPluginInstance; michael@0: michael@0: pluginInstance->CGDraw(ref, aUpdateRect); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::CGDraw(CGContextRef ref, nsIntRect aUpdateRect) { michael@0: michael@0: NPCocoaEvent drawEvent; michael@0: drawEvent.type = NPCocoaEventDrawRect; michael@0: drawEvent.version = 0; michael@0: drawEvent.data.draw.x = aUpdateRect.x; michael@0: drawEvent.data.draw.y = aUpdateRect.y; michael@0: drawEvent.data.draw.width = aUpdateRect.width; michael@0: drawEvent.data.draw.height = aUpdateRect.height; michael@0: drawEvent.data.draw.context = ref; michael@0: michael@0: NPRemoteEvent remoteDrawEvent = {drawEvent}; michael@0: // Signal to AnswerNPP_HandleEvent() not to use this value michael@0: remoteDrawEvent.contentsScaleFactor = -1.0; michael@0: michael@0: int16_t handled; michael@0: AnswerNPP_HandleEvent(remoteDrawEvent, &handled); michael@0: return handled == true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, michael@0: const uint32_t &surfaceid, michael@0: int16_t* handled) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: PaintTracker pt; michael@0: michael@0: NPCocoaEvent evcopy = event.event; michael@0: mContentsScaleFactor = event.contentsScaleFactor; michael@0: RefPtr surf = MacIOSurface::LookupSurface(surfaceid, michael@0: mContentsScaleFactor); michael@0: if (!surf) { michael@0: NS_ERROR("Invalid IOSurface."); michael@0: *handled = false; michael@0: return false; michael@0: } michael@0: michael@0: if (!mCARenderer) { michael@0: mCARenderer = new nsCARenderer(); michael@0: } michael@0: michael@0: if (evcopy.type == NPCocoaEventDrawRect) { michael@0: mCARenderer->AttachIOSurface(surf); michael@0: if (!mCARenderer->isInit()) { michael@0: void *caLayer = nullptr; michael@0: NPError result = mPluginIface->getvalue(GetNPP(), michael@0: NPPVpluginCoreAnimationLayer, michael@0: &caLayer); michael@0: michael@0: if (result != NPERR_NO_ERROR || !caLayer) { michael@0: PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not " michael@0: "provide CALayer.")); michael@0: *handled = false; michael@0: return false; michael@0: } michael@0: michael@0: mCARenderer->SetupRenderer(caLayer, mWindow.width, mWindow.height, michael@0: mContentsScaleFactor, michael@0: GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ? michael@0: ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER); michael@0: michael@0: // Flash needs to have the window set again after this step michael@0: if (mPluginIface->setwindow) michael@0: (void) mPluginIface->setwindow(&mData, &mWindow); michael@0: } michael@0: } else { michael@0: PLUGIN_LOG_DEBUG(("Invalid event type for " michael@0: "AnswerNNP_HandleEvent_IOSurface.")); michael@0: *handled = false; michael@0: return false; michael@0: } michael@0: michael@0: mCARenderer->Render(mWindow.width, mWindow.height, michael@0: mContentsScaleFactor, nullptr); michael@0: michael@0: return true; michael@0: michael@0: } michael@0: michael@0: #else michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, michael@0: const uint32_t &surfaceid, michael@0: int16_t* handled) michael@0: { michael@0: NS_RUNTIMEABORT("NPP_HandleEvent_IOSurface is a OSX-only message"); michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event) michael@0: { michael@0: NS_ASSERTION(!mLayersRendering && !mPendingPluginCall, michael@0: "Shouldn't be receiving WindowPosChanged with layer rendering"); michael@0: michael@0: #ifdef OS_WIN michael@0: int16_t dontcare; michael@0: return AnswerNPP_HandleEvent(event, &dontcare); michael@0: #else michael@0: NS_RUNTIMEABORT("WindowPosChanged is a windows-only message"); michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvContentsScaleFactorChanged(const double& aContentsScaleFactor) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: mContentsScaleFactor = aContentsScaleFactor; michael@0: if (mShContext) { michael@0: // Release the shared context so that it is reallocated michael@0: // with the new size. michael@0: ::CGContextRelease(mShContext); michael@0: mShContext = nullptr; michael@0: } michael@0: return true; michael@0: #else michael@0: NS_RUNTIMEABORT("ContentsScaleFactorChanged is an OSX-only message"); michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: // Create a new window from NPWindow michael@0: bool PluginInstanceChild::CreateWindow(const NPRemoteWindow& aWindow) michael@0: { michael@0: PLUGIN_LOG_DEBUG(("%s (aWindow=)", michael@0: FULLFUNCTION, michael@0: aWindow.window, michael@0: aWindow.x, aWindow.y, michael@0: aWindow.width, aWindow.height)); michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: if (mXEmbed) { michael@0: mWindow.window = reinterpret_cast(aWindow.window); michael@0: } michael@0: else { michael@0: Window browserSocket = (Window)(aWindow.window); michael@0: xt_client_init(&mXtClient, mWsInfo.visual, mWsInfo.colormap, mWsInfo.depth); michael@0: xt_client_create(&mXtClient, browserSocket, mWindow.width, mWindow.height); michael@0: mWindow.window = (void *)XtWindow(mXtClient.child_widget); michael@0: } michael@0: #else michael@0: mWindow.window = reinterpret_cast(aWindow.window); michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // Destroy window michael@0: void PluginInstanceChild::DeleteWindow() michael@0: { michael@0: PLUGIN_LOG_DEBUG(("%s (aWindow=)", michael@0: FULLFUNCTION, michael@0: mWindow.window, michael@0: mWindow.x, mWindow.y, michael@0: mWindow.width, mWindow.height)); michael@0: michael@0: if (!mWindow.window) michael@0: return; michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: if (mXtClient.top_widget) { michael@0: xt_client_unrealize(&mXtClient); michael@0: xt_client_destroy(&mXtClient); michael@0: mXtClient.top_widget = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: // We don't have to keep the plug-in window ID any longer. michael@0: mWindow.window = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow) michael@0: { michael@0: PLUGIN_LOG_DEBUG(("%s (aWindow=)", michael@0: FULLFUNCTION, michael@0: aWindow.window, michael@0: aWindow.x, aWindow.y, michael@0: aWindow.width, aWindow.height)); michael@0: NS_ASSERTION(!mLayersRendering && !mPendingPluginCall, michael@0: "Shouldn't be receiving NPP_SetWindow with layer rendering"); michael@0: AssertPluginThread(); michael@0: michael@0: #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: NS_ASSERTION(mWsInfo.display, "We should have a valid display!"); michael@0: michael@0: // The minimum info is sent over IPC to allow this michael@0: // code to determine the rest. michael@0: michael@0: mWindow.x = aWindow.x; michael@0: mWindow.y = aWindow.y; michael@0: mWindow.width = aWindow.width; michael@0: mWindow.height = aWindow.height; michael@0: mWindow.clipRect = aWindow.clipRect; michael@0: mWindow.type = aWindow.type; michael@0: michael@0: mWsInfo.colormap = aWindow.colormap; michael@0: int depth; michael@0: FindVisualAndDepth(mWsInfo.display, aWindow.visualID, michael@0: &mWsInfo.visual, &depth); michael@0: mWsInfo.depth = depth; michael@0: michael@0: if (!mWindow.window && mWindow.type == NPWindowTypeWindow) { michael@0: CreateWindow(aWindow); michael@0: } michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: if (mXEmbed && gtk_check_version(2,18,7) != nullptr) { // older michael@0: if (aWindow.type == NPWindowTypeWindow) { michael@0: GdkWindow* socket_window = gdk_window_lookup(static_cast(aWindow.window)); michael@0: if (socket_window) { michael@0: // A GdkWindow for the socket already exists. Need to michael@0: // workaround https://bugzilla.gnome.org/show_bug.cgi?id=607061 michael@0: // See wrap_gtk_plug_embedded in PluginModuleChild.cpp. michael@0: g_object_set_data(G_OBJECT(socket_window), michael@0: "moz-existed-before-set-window", michael@0: GUINT_TO_POINTER(1)); michael@0: } michael@0: } michael@0: michael@0: if (aWindow.visualID != None michael@0: && gtk_check_version(2, 12, 10) != nullptr) { // older michael@0: // Workaround for a bug in Gtk+ (prior to 2.12.10) where deleting michael@0: // a foreign GdkColormap will also free the XColormap. michael@0: // http://git.gnome.org/browse/gtk+/log/gdk/x11/gdkcolor-x11.c?id=GTK_2_12_10 michael@0: GdkVisual *gdkvisual = gdkx_visual_get(aWindow.visualID); michael@0: GdkColormap *gdkcolor = michael@0: gdk_x11_colormap_foreign_new(gdkvisual, aWindow.colormap); michael@0: michael@0: if (g_object_get_data(G_OBJECT(gdkcolor), "moz-have-extra-ref")) { michael@0: // We already have a ref to keep the object alive. michael@0: g_object_unref(gdkcolor); michael@0: } else { michael@0: // leak and mark as already leaked michael@0: g_object_set_data(G_OBJECT(gdkcolor), michael@0: "moz-have-extra-ref", GUINT_TO_POINTER(1)); michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: PLUGIN_LOG_DEBUG( michael@0: ("[InstanceChild][%p] Answer_SetWindow w=, clip=", michael@0: this, mWindow.x, mWindow.y, mWindow.width, mWindow.height, michael@0: mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom)); michael@0: michael@0: if (mPluginIface->setwindow) michael@0: (void) mPluginIface->setwindow(&mData, &mWindow); michael@0: michael@0: #elif defined(OS_WIN) michael@0: switch (aWindow.type) { michael@0: case NPWindowTypeWindow: michael@0: { michael@0: if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) && michael@0: aWindow.width == 0 && michael@0: aWindow.height == 0) { michael@0: // Skip SetWindow call for hidden QuickTime plugins michael@0: return true; michael@0: } michael@0: michael@0: if (!CreatePluginWindow()) michael@0: return false; michael@0: michael@0: ReparentPluginWindow(reinterpret_cast(aWindow.window)); michael@0: SizePluginWindow(aWindow.width, aWindow.height); michael@0: michael@0: mWindow.window = (void*)mPluginWindowHWND; michael@0: mWindow.x = aWindow.x; michael@0: mWindow.y = aWindow.y; michael@0: mWindow.width = aWindow.width; michael@0: mWindow.height = aWindow.height; michael@0: mWindow.type = aWindow.type; michael@0: michael@0: if (mPluginIface->setwindow) { michael@0: SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1); michael@0: (void) mPluginIface->setwindow(&mData, &mWindow); michael@0: WNDPROC wndProc = reinterpret_cast( michael@0: GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC)); michael@0: if (wndProc != PluginWindowProc) { michael@0: mPluginWndProc = reinterpret_cast( michael@0: SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC, michael@0: reinterpret_cast(PluginWindowProc))); michael@0: NS_ASSERTION(mPluginWndProc != PluginWindowProc, "WTF?"); michael@0: } michael@0: RemoveProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty); michael@0: HookSetWindowLongPtr(); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case NPWindowTypeDrawable: michael@0: mWindow.type = aWindow.type; michael@0: if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) michael@0: CreateWinlessPopupSurrogate(); michael@0: if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) michael@0: SetupFlashMsgThrottle(); michael@0: return SharedSurfaceSetWindow(aWindow); michael@0: break; michael@0: michael@0: default: michael@0: NS_NOTREACHED("Bad plugin window type."); michael@0: return false; michael@0: break; michael@0: } michael@0: michael@0: #elif defined(XP_MACOSX) michael@0: michael@0: mWindow.x = aWindow.x; michael@0: mWindow.y = aWindow.y; michael@0: mWindow.width = aWindow.width; michael@0: mWindow.height = aWindow.height; michael@0: mWindow.clipRect = aWindow.clipRect; michael@0: mWindow.type = aWindow.type; michael@0: mContentsScaleFactor = aWindow.contentsScaleFactor; michael@0: michael@0: if (mShContext) { michael@0: // Release the shared context so that it is reallocated michael@0: // with the new size. michael@0: ::CGContextRelease(mShContext); michael@0: mShContext = nullptr; michael@0: } michael@0: michael@0: if (mPluginIface->setwindow) michael@0: (void) mPluginIface->setwindow(&mData, &mWindow); michael@0: michael@0: #elif defined(ANDROID) michael@0: // TODO: Need Android impl michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: // TODO: Need QT-nonX impl michael@0: #else michael@0: # error Implement me for your OS michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::Initialize() michael@0: { michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: NPError rv; michael@0: michael@0: if (mWsInfo.display) { michael@0: // Already initialized michael@0: return false; michael@0: } michael@0: michael@0: // Request for windowless plugins is set in newp(), before this call. michael@0: if (mWindow.type == NPWindowTypeWindow) { michael@0: AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(&mXEmbed, &rv); michael@0: michael@0: // Set up Xt loop for windowed plugins without XEmbed support michael@0: if (!mXEmbed) { michael@0: xt_client_xloop_create(); michael@0: } michael@0: } michael@0: michael@0: // Use default GTK display for XEmbed and windowless plugins michael@0: if (mXEmbed || mWindow.type != NPWindowTypeWindow) { michael@0: mWsInfo.display = DefaultXDisplay(); michael@0: } michael@0: else { michael@0: mWsInfo.display = xt_client_get_display(); michael@0: } michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: #if defined(OS_WIN) michael@0: michael@0: static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow"); michael@0: static const TCHAR kPluginInstanceChildProperty[] = TEXT("PluginInstanceChildProperty"); michael@0: static const TCHAR kFlashThrottleProperty[] = TEXT("MozillaFlashThrottleProperty"); michael@0: michael@0: // static michael@0: bool michael@0: PluginInstanceChild::RegisterWindowClass() michael@0: { michael@0: static bool alreadyRegistered = false; michael@0: if (alreadyRegistered) michael@0: return true; michael@0: michael@0: alreadyRegistered = true; michael@0: michael@0: WNDCLASSEX wcex; michael@0: wcex.cbSize = sizeof(WNDCLASSEX); michael@0: wcex.style = CS_DBLCLKS; michael@0: wcex.lpfnWndProc = DummyWindowProc; michael@0: wcex.cbClsExtra = 0; michael@0: wcex.cbWndExtra = 0; michael@0: wcex.hInstance = GetModuleHandle(nullptr); michael@0: wcex.hIcon = 0; michael@0: wcex.hCursor = 0; michael@0: wcex.hbrBackground = reinterpret_cast(COLOR_WINDOW + 1); michael@0: wcex.lpszMenuName = 0; michael@0: wcex.lpszClassName = kWindowClassName; michael@0: wcex.hIconSm = 0; michael@0: michael@0: return RegisterClassEx(&wcex) ? true : false; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::CreatePluginWindow() michael@0: { michael@0: // already initialized michael@0: if (mPluginWindowHWND) michael@0: return true; michael@0: michael@0: if (!RegisterWindowClass()) michael@0: return false; michael@0: michael@0: mPluginWindowHWND = michael@0: CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING | michael@0: WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this! michael@0: WS_EX_RIGHTSCROLLBAR, michael@0: kWindowClassName, 0, michael@0: WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, michael@0: 0, 0, nullptr, 0, GetModuleHandle(nullptr), 0); michael@0: if (!mPluginWindowHWND) michael@0: return false; michael@0: if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this)) michael@0: return false; michael@0: michael@0: // Apparently some plugins require an ASCII WndProc. michael@0: SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC, michael@0: reinterpret_cast(DefWindowProcA)); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::DestroyPluginWindow() michael@0: { michael@0: if (mPluginWindowHWND) { michael@0: // Unsubclass the window. michael@0: WNDPROC wndProc = reinterpret_cast( michael@0: GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC)); michael@0: // Removed prior to SetWindowLongPtr, see HookSetWindowLongPtr. michael@0: RemoveProp(mPluginWindowHWND, kPluginInstanceChildProperty); michael@0: if (wndProc == PluginWindowProc) { michael@0: NS_ASSERTION(mPluginWndProc, "Should have old proc here!"); michael@0: SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC, michael@0: reinterpret_cast(mPluginWndProc)); michael@0: mPluginWndProc = 0; michael@0: } michael@0: DestroyWindow(mPluginWindowHWND); michael@0: mPluginWindowHWND = 0; michael@0: } michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::ReparentPluginWindow(HWND hWndParent) michael@0: { michael@0: if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) { michael@0: // Fix the child window's style to be a child window. michael@0: LONG_PTR style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE); michael@0: style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; michael@0: style &= ~WS_POPUP; michael@0: SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style); michael@0: michael@0: // Do the reparenting. michael@0: SetParent(mPluginWindowHWND, hWndParent); michael@0: michael@0: // Make sure we're visible. michael@0: ShowWindow(mPluginWindowHWND, SW_SHOWNA); michael@0: } michael@0: mPluginParentHWND = hWndParent; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::SizePluginWindow(int width, michael@0: int height) michael@0: { michael@0: if (mPluginWindowHWND) { michael@0: mPluginSize.x = width; michael@0: mPluginSize.y = height; michael@0: SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height, michael@0: SWP_NOZORDER | SWP_NOREPOSITION); michael@0: } michael@0: } michael@0: michael@0: // See chromium's webplugin_delegate_impl.cc for explanation of this function. michael@0: // static michael@0: LRESULT CALLBACK michael@0: PluginInstanceChild::DummyWindowProc(HWND hWnd, michael@0: UINT message, michael@0: WPARAM wParam, michael@0: LPARAM lParam) michael@0: { michael@0: return CallWindowProc(DefWindowProc, hWnd, message, wParam, lParam); michael@0: } michael@0: michael@0: // static michael@0: LRESULT CALLBACK michael@0: PluginInstanceChild::PluginWindowProc(HWND hWnd, michael@0: UINT message, michael@0: WPARAM wParam, michael@0: LPARAM lParam) michael@0: { michael@0: return mozilla::CallWindowProcCrashProtected(PluginWindowProcInternal, hWnd, message, wParam, lParam); michael@0: } michael@0: michael@0: // static michael@0: LRESULT CALLBACK michael@0: PluginInstanceChild::PluginWindowProcInternal(HWND hWnd, michael@0: UINT message, michael@0: WPARAM wParam, michael@0: LPARAM lParam) michael@0: { michael@0: NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(), michael@0: "Failed to prevent a nonqueued message from running!"); michael@0: PluginInstanceChild* self = reinterpret_cast( michael@0: GetProp(hWnd, kPluginInstanceChildProperty)); michael@0: if (!self) { michael@0: NS_NOTREACHED("Badness!"); michael@0: return 0; michael@0: } michael@0: michael@0: NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!"); michael@0: NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Self-referential windowproc. Infinite recursion will happen soon."); michael@0: michael@0: // Adobe's shockwave positions the plugin window relative to the browser michael@0: // frame when it initializes. With oopp disabled, this wouldn't have an michael@0: // effect. With oopp, GeckoPluginWindow is a child of the parent plugin michael@0: // window, so the move offsets the child within the parent. Generally michael@0: // we don't want plugins moving or sizing our window, so we prevent these michael@0: // changes here. michael@0: if (message == WM_WINDOWPOSCHANGING) { michael@0: WINDOWPOS* pos = reinterpret_cast(lParam); michael@0: if (pos && (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE))) { michael@0: pos->x = pos->y = 0; michael@0: pos->cx = self->mPluginSize.x; michael@0: pos->cy = self->mPluginSize.y; michael@0: LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam, michael@0: lParam); michael@0: pos->x = pos->y = 0; michael@0: pos->cx = self->mPluginSize.x; michael@0: pos->cy = self->mPluginSize.y; michael@0: return res; michael@0: } michael@0: } michael@0: michael@0: // The plugin received keyboard focus, let the parent know so the dom is up to date. michael@0: if (message == WM_MOUSEACTIVATE) michael@0: self->CallPluginFocusChange(true); michael@0: michael@0: // Prevent lockups due to plugins making rpc calls when the parent michael@0: // is making a synchronous SendMessage call to the child window. Add michael@0: // more messages as needed. michael@0: if ((InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { michael@0: switch(message) { michael@0: case WM_KILLFOCUS: michael@0: ReplyMessage(0); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (message == WM_KILLFOCUS) michael@0: self->CallPluginFocusChange(false); michael@0: michael@0: if (message == WM_USER+1 && michael@0: (self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) { michael@0: self->FlashThrottleMessage(hWnd, message, wParam, lParam, true); michael@0: return 0; michael@0: } michael@0: michael@0: NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, michael@0: "Self-referential windowproc happened inside our hook proc. " michael@0: "Infinite recursion will happen soon."); michael@0: michael@0: LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam, michael@0: lParam); michael@0: michael@0: // Make sure capture is released by the child on mouse events. Fixes a michael@0: // problem with flash full screen mode mouse input. Appears to be michael@0: // caused by a bug in flash, since we are not setting the capture michael@0: // on the window. michael@0: if (message == WM_LBUTTONDOWN && michael@0: self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) { michael@0: wchar_t szClass[26]; michael@0: HWND hwnd = GetForegroundWindow(); michael@0: if (hwnd && GetClassNameW(hwnd, szClass, michael@0: sizeof(szClass)/sizeof(char16_t)) && michael@0: !wcscmp(szClass, kFlashFullscreenClass)) { michael@0: ReleaseCapture(); michael@0: SetFocus(hwnd); michael@0: } michael@0: } michael@0: michael@0: if (message == WM_CLOSE) michael@0: self->DestroyPluginWindow(); michael@0: michael@0: if (message == WM_NCDESTROY) michael@0: RemoveProp(hWnd, kPluginInstanceChildProperty); michael@0: michael@0: return res; michael@0: } michael@0: michael@0: /* set window long ptr hook for flash */ michael@0: michael@0: /* michael@0: * Flash will reset the subclass of our widget at various times. michael@0: * (Notably when entering and exiting full screen mode.) This michael@0: * occurs independent of the main plugin window event procedure. michael@0: * We trap these subclass calls to prevent our subclass hook from michael@0: * getting dropped. michael@0: * Note, ascii versions can be nixed once flash versions < 10.1 michael@0: * are considered obsolete. michael@0: */ michael@0: michael@0: #ifdef _WIN64 michael@0: typedef LONG_PTR michael@0: (WINAPI *User32SetWindowLongPtrA)(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR dwNewLong); michael@0: typedef LONG_PTR michael@0: (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR dwNewLong); michael@0: static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; michael@0: static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; michael@0: #else michael@0: typedef LONG michael@0: (WINAPI *User32SetWindowLongA)(HWND hWnd, michael@0: int nIndex, michael@0: LONG dwNewLong); michael@0: typedef LONG michael@0: (WINAPI *User32SetWindowLongW)(HWND hWnd, michael@0: int nIndex, michael@0: LONG dwNewLong); michael@0: static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; michael@0: static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; michael@0: #endif michael@0: michael@0: extern LRESULT CALLBACK michael@0: NeuteredWindowProc(HWND hwnd, michael@0: UINT uMsg, michael@0: WPARAM wParam, michael@0: LPARAM lParam); michael@0: michael@0: const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc"; michael@0: michael@0: // static michael@0: bool michael@0: PluginInstanceChild::SetWindowLongHookCheck(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR newLong) michael@0: { michael@0: // Let this go through if it's not a subclass michael@0: if (nIndex != GWLP_WNDPROC || michael@0: // if it's not a subclassed plugin window michael@0: !GetProp(hWnd, kPluginInstanceChildProperty) || michael@0: // if we're not disabled michael@0: GetProp(hWnd, kPluginIgnoreSubclassProperty) || michael@0: // if the subclass is set to a known procedure michael@0: newLong == reinterpret_cast(PluginWindowProc) || michael@0: newLong == reinterpret_cast(NeuteredWindowProc) || michael@0: newLong == reinterpret_cast(DefWindowProcA) || michael@0: newLong == reinterpret_cast(DefWindowProcW) || michael@0: // if the subclass is a WindowsMessageLoop subclass restore michael@0: GetProp(hWnd, kOldWndProcProp)) michael@0: return true; michael@0: // prevent the subclass michael@0: return false; michael@0: } michael@0: michael@0: #ifdef _WIN64 michael@0: LONG_PTR WINAPI michael@0: PluginInstanceChild::SetWindowLongPtrAHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR newLong) michael@0: #else michael@0: LONG WINAPI michael@0: PluginInstanceChild::SetWindowLongAHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG newLong) michael@0: #endif michael@0: { michael@0: if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) michael@0: return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // Set flash's new subclass to get the result. michael@0: LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // We already checked this in SetWindowLongHookCheck michael@0: PluginInstanceChild* self = reinterpret_cast( michael@0: GetProp(hWnd, kPluginInstanceChildProperty)); michael@0: michael@0: // Hook our subclass back up, just like we do on setwindow. michael@0: WNDPROC currentProc = michael@0: reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_WNDPROC)); michael@0: if (currentProc != PluginWindowProc) { michael@0: self->mPluginWndProc = michael@0: reinterpret_cast(sUser32SetWindowLongWHookStub(hWnd, nIndex, michael@0: reinterpret_cast(PluginWindowProc))); michael@0: NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!"); michael@0: } michael@0: return proc; michael@0: } michael@0: michael@0: #ifdef _WIN64 michael@0: LONG_PTR WINAPI michael@0: PluginInstanceChild::SetWindowLongPtrWHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR newLong) michael@0: #else michael@0: LONG WINAPI michael@0: PluginInstanceChild::SetWindowLongWHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG newLong) michael@0: #endif michael@0: { michael@0: if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) michael@0: return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // Set flash's new subclass to get the result. michael@0: LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // We already checked this in SetWindowLongHookCheck michael@0: PluginInstanceChild* self = reinterpret_cast( michael@0: GetProp(hWnd, kPluginInstanceChildProperty)); michael@0: michael@0: // Hook our subclass back up, just like we do on setwindow. michael@0: WNDPROC currentProc = michael@0: reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_WNDPROC)); michael@0: if (currentProc != PluginWindowProc) { michael@0: self->mPluginWndProc = michael@0: reinterpret_cast(sUser32SetWindowLongWHookStub(hWnd, nIndex, michael@0: reinterpret_cast(PluginWindowProc))); michael@0: NS_ASSERTION(self->mPluginWndProc != PluginWindowProc, "Infinite recursion coming up!"); michael@0: } michael@0: return proc; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::HookSetWindowLongPtr() michael@0: { michael@0: if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_SETLONGPTR)) michael@0: return; michael@0: michael@0: sUser32Intercept.Init("user32.dll"); michael@0: #ifdef _WIN64 michael@0: if (!sUser32SetWindowLongAHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongPtrA", reinterpret_cast(SetWindowLongPtrAHook), michael@0: (void**) &sUser32SetWindowLongAHookStub); michael@0: if (!sUser32SetWindowLongWHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongPtrW", reinterpret_cast(SetWindowLongPtrWHook), michael@0: (void**) &sUser32SetWindowLongWHookStub); michael@0: #else michael@0: if (!sUser32SetWindowLongAHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongA", reinterpret_cast(SetWindowLongAHook), michael@0: (void**) &sUser32SetWindowLongAHookStub); michael@0: if (!sUser32SetWindowLongWHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongW", reinterpret_cast(SetWindowLongWHook), michael@0: (void**) &sUser32SetWindowLongWHookStub); michael@0: #endif michael@0: } michael@0: michael@0: /* windowless track popup menu helpers */ michael@0: michael@0: BOOL michael@0: WINAPI michael@0: PluginInstanceChild::TrackPopupHookProc(HMENU hMenu, michael@0: UINT uFlags, michael@0: int x, michael@0: int y, michael@0: int nReserved, michael@0: HWND hWnd, michael@0: CONST RECT *prcRect) michael@0: { michael@0: if (!sUser32TrackPopupMenuStub) { michael@0: NS_ERROR("TrackPopupMenu stub isn't set! Badness!"); michael@0: return 0; michael@0: } michael@0: michael@0: // Only change the parent when we know this is a context on the plugin michael@0: // surface within the browser. Prevents resetting the parent on child ui michael@0: // displayed by plugins that have working parent-child relationships. michael@0: wchar_t szClass[21]; michael@0: bool haveClass = GetClassNameW(hWnd, szClass, ArrayLength(szClass)); michael@0: if (!haveClass || michael@0: (wcscmp(szClass, L"MozillaWindowClass") && michael@0: wcscmp(szClass, L"SWFlash_Placeholder"))) { michael@0: // Unrecognized parent michael@0: return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved, michael@0: hWnd, prcRect); michael@0: } michael@0: michael@0: // Called on an unexpected event, warn. michael@0: if (!sWinlessPopupSurrogateHWND) { michael@0: NS_WARNING( michael@0: "Untraced TrackPopupHookProc call! Menu might not work right!"); michael@0: return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved, michael@0: hWnd, prcRect); michael@0: } michael@0: michael@0: HWND surrogateHwnd = sWinlessPopupSurrogateHWND; michael@0: sWinlessPopupSurrogateHWND = nullptr; michael@0: michael@0: // Popups that don't use TPM_RETURNCMD expect a final command message michael@0: // when an item is selected and the context closes. Since we replace michael@0: // the parent, we need to forward this back to the real parent so it michael@0: // can act on the menu item selected. michael@0: bool isRetCmdCall = (uFlags & TPM_RETURNCMD); michael@0: michael@0: DWORD res = sUser32TrackPopupMenuStub(hMenu, uFlags|TPM_RETURNCMD, x, y, michael@0: nReserved, surrogateHwnd, prcRect); michael@0: michael@0: if (!isRetCmdCall && res) { michael@0: SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(res, 0), 0); michael@0: } michael@0: michael@0: return res; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::InitPopupMenuHook() michael@0: { michael@0: if (!(GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) || michael@0: sUser32TrackPopupMenuStub) michael@0: return; michael@0: michael@0: // Note, once WindowsDllInterceptor is initialized for a module, michael@0: // it remains initialized for that particular module for it's michael@0: // lifetime. Additional instances are needed if other modules need michael@0: // to be hooked. michael@0: if (!sUser32TrackPopupMenuStub) { michael@0: sUser32Intercept.Init("user32.dll"); michael@0: sUser32Intercept.AddHook("TrackPopupMenu", reinterpret_cast(TrackPopupHookProc), michael@0: (void**) &sUser32TrackPopupMenuStub); michael@0: } michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::CreateWinlessPopupSurrogate() michael@0: { michael@0: // already initialized michael@0: if (mWinlessPopupSurrogateHWND) michael@0: return; michael@0: michael@0: HWND hwnd = nullptr; michael@0: NPError result; michael@0: if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) { michael@0: NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed."); michael@0: return; michael@0: } michael@0: michael@0: mWinlessPopupSurrogateHWND = michael@0: CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_CHILD, michael@0: 0, 0, 0, 0, hwnd, 0, GetModuleHandle(nullptr), 0); michael@0: if (!mWinlessPopupSurrogateHWND) { michael@0: NS_ERROR("CreateWindowEx failed for winless placeholder!"); michael@0: return; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::DestroyWinlessPopupSurrogate() michael@0: { michael@0: if (mWinlessPopupSurrogateHWND) michael@0: DestroyWindow(mWinlessPopupSurrogateHWND); michael@0: mWinlessPopupSurrogateHWND = nullptr; michael@0: } michael@0: michael@0: int16_t michael@0: PluginInstanceChild::WinlessHandleEvent(NPEvent& event) michael@0: { michael@0: if (!mPluginIface->event) michael@0: return false; michael@0: michael@0: // Events that might generate nested event dispatch loops need michael@0: // special handling during delivery. michael@0: int16_t handled; michael@0: michael@0: HWND focusHwnd = nullptr; michael@0: michael@0: // TrackPopupMenu will fail if the parent window is not associated with michael@0: // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate michael@0: // parent created in the child process. michael@0: if ((GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default? michael@0: (event.event == WM_RBUTTONDOWN || // flash michael@0: event.event == WM_RBUTTONUP)) { // silverlight michael@0: sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND; michael@0: michael@0: // A little trick scrounged from chromium's code - set the focus michael@0: // to our surrogate parent so keyboard nav events go to the menu. michael@0: focusHwnd = SetFocus(mWinlessPopupSurrogateHWND); michael@0: } michael@0: michael@0: MessageLoop* loop = MessageLoop::current(); michael@0: AutoRestore modalLoop(loop->os_modal_loop()); michael@0: michael@0: handled = mPluginIface->event(&mData, reinterpret_cast(&event)); michael@0: michael@0: sWinlessPopupSurrogateHWND = nullptr; michael@0: michael@0: if (IsWindow(focusHwnd)) { michael@0: SetFocus(focusHwnd); michael@0: } michael@0: michael@0: return handled; michael@0: } michael@0: michael@0: /* windowless drawing helpers */ michael@0: michael@0: bool michael@0: PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow) michael@0: { michael@0: // If the surfaceHandle is empty, parent is telling us we can reuse our cached michael@0: // memory surface and hdc. Otherwise, we need to reset, usually due to a michael@0: // expanding plugin port size. michael@0: if (!aWindow.surfaceHandle) { michael@0: if (!mSharedSurfaceDib.IsValid()) { michael@0: return false; michael@0: } michael@0: } michael@0: else { michael@0: // Attach to the new shared surface parent handed us. michael@0: if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle, michael@0: aWindow.width, aWindow.height, false))) michael@0: return false; michael@0: // Free any alpha extraction resources if needed. This will be reset michael@0: // the next time it's used. michael@0: AlphaExtractCacheRelease(); michael@0: } michael@0: michael@0: // NPRemoteWindow's origin is the origin of our shared dib. michael@0: mWindow.x = aWindow.x; michael@0: mWindow.y = aWindow.y; michael@0: mWindow.width = aWindow.width; michael@0: mWindow.height = aWindow.height; michael@0: mWindow.type = aWindow.type; michael@0: michael@0: mWindow.window = reinterpret_cast(mSharedSurfaceDib.GetHDC()); michael@0: ::SetViewportOrgEx(mSharedSurfaceDib.GetHDC(), michael@0: -aWindow.x, -aWindow.y, nullptr); michael@0: michael@0: if (mPluginIface->setwindow) michael@0: mPluginIface->setwindow(&mData, &mWindow); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::SharedSurfaceRelease() michael@0: { michael@0: mSharedSurfaceDib.Close(); michael@0: AlphaExtractCacheRelease(); michael@0: } michael@0: michael@0: /* double pass cache buffer - (rarely) used in cases where alpha extraction michael@0: * occurs for windowless plugins. */ michael@0: michael@0: bool michael@0: PluginInstanceChild::AlphaExtractCacheSetup() michael@0: { michael@0: AlphaExtractCacheRelease(); michael@0: michael@0: mAlphaExtract.hdc = ::CreateCompatibleDC(nullptr); michael@0: michael@0: if (!mAlphaExtract.hdc) michael@0: return false; michael@0: michael@0: BITMAPINFOHEADER bmih; michael@0: memset((void*)&bmih, 0, sizeof(BITMAPINFOHEADER)); michael@0: bmih.biSize = sizeof(BITMAPINFOHEADER); michael@0: bmih.biWidth = mWindow.width; michael@0: bmih.biHeight = mWindow.height; michael@0: bmih.biPlanes = 1; michael@0: bmih.biBitCount = 32; michael@0: bmih.biCompression = BI_RGB; michael@0: michael@0: void* ppvBits = nullptr; michael@0: mAlphaExtract.bmp = ::CreateDIBSection(mAlphaExtract.hdc, michael@0: (BITMAPINFO*)&bmih, michael@0: DIB_RGB_COLORS, michael@0: (void**)&ppvBits, michael@0: nullptr, michael@0: (unsigned long)sizeof(BITMAPINFOHEADER)); michael@0: if (!mAlphaExtract.bmp) michael@0: return false; michael@0: michael@0: DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp)); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::AlphaExtractCacheRelease() michael@0: { michael@0: if (mAlphaExtract.bmp) michael@0: ::DeleteObject(mAlphaExtract.bmp); michael@0: michael@0: if (mAlphaExtract.hdc) michael@0: ::DeleteObject(mAlphaExtract.hdc); michael@0: michael@0: mAlphaExtract.bmp = nullptr; michael@0: mAlphaExtract.hdc = nullptr; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::UpdatePaintClipRect(RECT* aRect) michael@0: { michael@0: if (aRect) { michael@0: // Update the clip rect on our internal hdc michael@0: HRGN clip = ::CreateRectRgnIndirect(aRect); michael@0: ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip); michael@0: ::DeleteObject(clip); michael@0: } michael@0: } michael@0: michael@0: int16_t michael@0: PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy) michael@0: { michael@0: if (!mPluginIface->event) michael@0: return false; michael@0: michael@0: RECT* pRect = reinterpret_cast(evcopy.lParam); michael@0: michael@0: switch(mAlphaExtract.doublePass) { michael@0: case RENDER_NATIVE: michael@0: // pass the internal hdc to the plugin michael@0: UpdatePaintClipRect(pRect); michael@0: evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC()); michael@0: return mPluginIface->event(&mData, reinterpret_cast(&evcopy)); michael@0: break; michael@0: case RENDER_BACK_ONE: michael@0: // Handle a double pass render used in alpha extraction for transparent michael@0: // plugins. (See nsObjectFrame and gfxWindowsNativeDrawing for details.) michael@0: // We render twice, once to the shared dib, and once to a cache which michael@0: // we copy back on a second paint. These paints can't be spread across michael@0: // multiple rpc messages as delays cause animation frame changes. michael@0: if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) { michael@0: mAlphaExtract.doublePass = RENDER_NATIVE; michael@0: return false; michael@0: } michael@0: michael@0: // See gfxWindowsNativeDrawing, color order doesn't have to match. michael@0: UpdatePaintClipRect(pRect); michael@0: ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(WHITE_BRUSH)); michael@0: evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC()); michael@0: if (!mPluginIface->event(&mData, reinterpret_cast(&evcopy))) { michael@0: mAlphaExtract.doublePass = RENDER_NATIVE; michael@0: return false; michael@0: } michael@0: michael@0: // Copy to cache. We render to shared dib so we don't have to call michael@0: // setwindow between calls (flash issue). michael@0: ::BitBlt(mAlphaExtract.hdc, michael@0: pRect->left, michael@0: pRect->top, michael@0: pRect->right - pRect->left, michael@0: pRect->bottom - pRect->top, michael@0: mSharedSurfaceDib.GetHDC(), michael@0: pRect->left, michael@0: pRect->top, michael@0: SRCCOPY); michael@0: michael@0: ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); michael@0: if (!mPluginIface->event(&mData, reinterpret_cast(&evcopy))) { michael@0: mAlphaExtract.doublePass = RENDER_NATIVE; michael@0: return false; michael@0: } michael@0: mAlphaExtract.doublePass = RENDER_BACK_TWO; michael@0: return true; michael@0: break; michael@0: case RENDER_BACK_TWO: michael@0: // copy our cached surface back michael@0: UpdatePaintClipRect(pRect); michael@0: ::BitBlt(mSharedSurfaceDib.GetHDC(), michael@0: pRect->left, michael@0: pRect->top, michael@0: pRect->right - pRect->left, michael@0: pRect->bottom - pRect->top, michael@0: mAlphaExtract.hdc, michael@0: pRect->left, michael@0: pRect->top, michael@0: SRCCOPY); michael@0: mAlphaExtract.doublePass = RENDER_NATIVE; michael@0: return true; michael@0: break; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /* flash msg throttling helpers */ michael@0: michael@0: // Flash has the unfortunate habit of flooding dispatch loops with custom michael@0: // windowing events they use for timing. We throttle these by dropping the michael@0: // delivery priority below any other event, including pending ipc io michael@0: // notifications. We do this for both windowed and windowless controls. michael@0: // Note flash's windowless msg window can last longer than our instance, michael@0: // so we try to unhook when the window is destroyed and in NPP_Destroy. michael@0: michael@0: void michael@0: PluginInstanceChild::UnhookWinlessFlashThrottle() michael@0: { michael@0: // We may have already unhooked michael@0: if (!mWinlessThrottleOldWndProc) michael@0: return; michael@0: michael@0: WNDPROC tmpProc = mWinlessThrottleOldWndProc; michael@0: mWinlessThrottleOldWndProc = nullptr; michael@0: michael@0: NS_ASSERTION(mWinlessHiddenMsgHWND, michael@0: "Missing mWinlessHiddenMsgHWND w/subclass set??"); michael@0: michael@0: // reset the subclass michael@0: SetWindowLongPtr(mWinlessHiddenMsgHWND, GWLP_WNDPROC, michael@0: reinterpret_cast(tmpProc)); michael@0: michael@0: // Remove our instance prop michael@0: RemoveProp(mWinlessHiddenMsgHWND, kFlashThrottleProperty); michael@0: mWinlessHiddenMsgHWND = nullptr; michael@0: } michael@0: michael@0: // static michael@0: LRESULT CALLBACK michael@0: PluginInstanceChild::WinlessHiddenFlashWndProc(HWND hWnd, michael@0: UINT message, michael@0: WPARAM wParam, michael@0: LPARAM lParam) michael@0: { michael@0: PluginInstanceChild* self = reinterpret_cast( michael@0: GetProp(hWnd, kFlashThrottleProperty)); michael@0: if (!self) { michael@0: NS_NOTREACHED("Badness!"); michael@0: return 0; michael@0: } michael@0: michael@0: NS_ASSERTION(self->mWinlessThrottleOldWndProc, michael@0: "Missing subclass procedure!!"); michael@0: michael@0: // Throttle michael@0: if (message == WM_USER+1) { michael@0: self->FlashThrottleMessage(hWnd, message, wParam, lParam, false); michael@0: return 0; michael@0: } michael@0: michael@0: // Unhook michael@0: if (message == WM_CLOSE || message == WM_NCDESTROY) { michael@0: WNDPROC tmpProc = self->mWinlessThrottleOldWndProc; michael@0: self->UnhookWinlessFlashThrottle(); michael@0: LRESULT res = CallWindowProc(tmpProc, hWnd, message, wParam, lParam); michael@0: return res; michael@0: } michael@0: michael@0: return CallWindowProc(self->mWinlessThrottleOldWndProc, michael@0: hWnd, message, wParam, lParam); michael@0: } michael@0: michael@0: // Enumerate all thread windows looking for flash's hidden message window. michael@0: // Once we find it, sub class it so we can throttle user msgs. michael@0: // static michael@0: BOOL CALLBACK michael@0: PluginInstanceChild::EnumThreadWindowsCallback(HWND hWnd, michael@0: LPARAM aParam) michael@0: { michael@0: PluginInstanceChild* self = reinterpret_cast(aParam); michael@0: if (!self) { michael@0: NS_NOTREACHED("Enum befuddled!"); michael@0: return FALSE; michael@0: } michael@0: michael@0: wchar_t className[64]; michael@0: if (!GetClassNameW(hWnd, className, sizeof(className)/sizeof(char16_t))) michael@0: return TRUE; michael@0: michael@0: if (!wcscmp(className, L"SWFlash_PlaceholderX")) { michael@0: WNDPROC oldWndProc = michael@0: reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_WNDPROC)); michael@0: // Only set this if we haven't already. michael@0: if (oldWndProc != WinlessHiddenFlashWndProc) { michael@0: if (self->mWinlessThrottleOldWndProc) { michael@0: NS_WARNING("mWinlessThrottleWndProc already set???"); michael@0: return FALSE; michael@0: } michael@0: // Subsclass and store self as a property michael@0: self->mWinlessHiddenMsgHWND = hWnd; michael@0: self->mWinlessThrottleOldWndProc = michael@0: reinterpret_cast(SetWindowLongPtr(hWnd, GWLP_WNDPROC, michael@0: reinterpret_cast(WinlessHiddenFlashWndProc))); michael@0: SetProp(hWnd, kFlashThrottleProperty, self); michael@0: NS_ASSERTION(self->mWinlessThrottleOldWndProc, michael@0: "SetWindowLongPtr failed?!"); michael@0: } michael@0: // Return no matter what once we find the right window. michael@0: return FALSE; michael@0: } michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: michael@0: void michael@0: PluginInstanceChild::SetupFlashMsgThrottle() michael@0: { michael@0: if (mWindow.type == NPWindowTypeDrawable) { michael@0: // Search for the flash hidden message window and subclass it. Only michael@0: // search for flash windows belonging to our ui thread! michael@0: if (mWinlessThrottleOldWndProc) michael@0: return; michael@0: EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsCallback, michael@0: reinterpret_cast(this)); michael@0: } michael@0: else { michael@0: // Already setup through quirks and the subclass. michael@0: return; michael@0: } michael@0: } michael@0: michael@0: WNDPROC michael@0: PluginInstanceChild::FlashThrottleAsyncMsg::GetProc() michael@0: { michael@0: if (mInstance) { michael@0: return mWindowed ? mInstance->mPluginWndProc : michael@0: mInstance->mWinlessThrottleOldWndProc; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::FlashThrottleAsyncMsg::Run() michael@0: { michael@0: RemoveFromAsyncList(); michael@0: michael@0: // GetProc() checks mInstance, and pulls the procedure from michael@0: // PluginInstanceChild. We don't transport sub-class procedure michael@0: // ptrs around in FlashThrottleAsyncMsg msgs. michael@0: if (!GetProc()) michael@0: return; michael@0: michael@0: // deliver the event to flash michael@0: CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam()); michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::FlashThrottleMessage(HWND aWnd, michael@0: UINT aMsg, michael@0: WPARAM aWParam, michael@0: LPARAM aLParam, michael@0: bool isWindowed) michael@0: { michael@0: // We reuse ChildAsyncCall so we get the cancelation work michael@0: // that's done in Destroy. michael@0: FlashThrottleAsyncMsg* task = new FlashThrottleAsyncMsg(this, michael@0: aWnd, aMsg, aWParam, aLParam, isWindowed); michael@0: if (!task) michael@0: return; michael@0: michael@0: { michael@0: MutexAutoLock lock(mAsyncCallMutex); michael@0: mPendingAsyncCalls.AppendElement(task); michael@0: } michael@0: MessageLoop::current()->PostDelayedTask(FROM_HERE, michael@0: task, kFlashWMUSERMessageThrottleDelayMs); michael@0: } michael@0: michael@0: #endif // OS_WIN michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerSetPluginFocus() michael@0: { michael@0: PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s", FULLFUNCTION)); michael@0: michael@0: #if defined(OS_WIN) michael@0: // Parent is letting us know the dom set focus to the plugin. Note, michael@0: // focus can change during transit in certain edge cases, for example michael@0: // when a button click brings up a full screen window. Since we send michael@0: // this in response to a WM_SETFOCUS event on our parent, the parent michael@0: // should have focus when we receive this. If not, ignore the call. michael@0: if (::GetFocus() == mPluginWindowHWND || michael@0: ((GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT) && michael@0: (::GetFocus() != mPluginParentHWND))) michael@0: return true; michael@0: ::SetFocus(mPluginWindowHWND); michael@0: return true; michael@0: #else michael@0: NS_NOTREACHED("PluginInstanceChild::AnswerSetPluginFocus not implemented!"); michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerUpdateWindow() michael@0: { michael@0: PR_LOG(GetPluginLog(), PR_LOG_DEBUG, ("%s", FULLFUNCTION)); michael@0: michael@0: #if defined(OS_WIN) michael@0: if (mPluginWindowHWND) { michael@0: RECT rect; michael@0: if (GetUpdateRect(GetParent(mPluginWindowHWND), &rect, FALSE)) { michael@0: ::InvalidateRect(mPluginWindowHWND, &rect, FALSE); michael@0: } michael@0: UpdateWindow(mPluginWindowHWND); michael@0: } michael@0: return true; michael@0: #else michael@0: NS_NOTREACHED("PluginInstanceChild::AnswerUpdateWindow not implemented!"); michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvNPP_DidComposite() michael@0: { michael@0: if (mPluginIface->didComposite) { michael@0: mPluginIface->didComposite(GetNPP()); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: PPluginScriptableObjectChild* michael@0: PluginInstanceChild::AllocPPluginScriptableObjectChild() michael@0: { michael@0: AssertPluginThread(); michael@0: return new PluginScriptableObjectChild(Proxy); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::DeallocPPluginScriptableObjectChild( michael@0: PPluginScriptableObjectChild* aObject) michael@0: { michael@0: AssertPluginThread(); michael@0: delete aObject; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvPPluginScriptableObjectConstructor( michael@0: PPluginScriptableObjectChild* aActor) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: // This is only called in response to the parent process requesting the michael@0: // creation of an actor. This actor will represent an NPObject that is michael@0: // created by the browser and returned to the plugin. michael@0: PluginScriptableObjectChild* actor = michael@0: static_cast(aActor); michael@0: NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!"); michael@0: michael@0: actor->InitializeProxy(); michael@0: NS_ASSERTION(actor->GetObject(false), "Actor should have an object!"); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerPBrowserStreamConstructor( michael@0: PBrowserStreamChild* aActor, michael@0: const nsCString& url, michael@0: const uint32_t& length, michael@0: const uint32_t& lastmodified, michael@0: PStreamNotifyChild* notifyData, michael@0: const nsCString& headers, michael@0: const nsCString& mimeType, michael@0: const bool& seekable, michael@0: NPError* rv, michael@0: uint16_t* stype) michael@0: { michael@0: AssertPluginThread(); michael@0: *rv = static_cast(aActor) michael@0: ->StreamConstructed(mimeType, seekable, stype); michael@0: return true; michael@0: } michael@0: michael@0: PBrowserStreamChild* michael@0: PluginInstanceChild::AllocPBrowserStreamChild(const nsCString& url, michael@0: const uint32_t& length, michael@0: const uint32_t& lastmodified, michael@0: PStreamNotifyChild* notifyData, michael@0: const nsCString& headers, michael@0: const nsCString& mimeType, michael@0: const bool& seekable, michael@0: NPError* rv, michael@0: uint16_t *stype) michael@0: { michael@0: AssertPluginThread(); michael@0: return new BrowserStreamChild(this, url, length, lastmodified, michael@0: static_cast(notifyData), michael@0: headers, mimeType, seekable, rv, stype); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::DeallocPBrowserStreamChild(PBrowserStreamChild* stream) michael@0: { michael@0: AssertPluginThread(); michael@0: delete stream; michael@0: return true; michael@0: } michael@0: michael@0: PPluginStreamChild* michael@0: PluginInstanceChild::AllocPPluginStreamChild(const nsCString& mimeType, michael@0: const nsCString& target, michael@0: NPError* result) michael@0: { michael@0: NS_RUNTIMEABORT("not callable"); michael@0: return nullptr; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::DeallocPPluginStreamChild(PPluginStreamChild* stream) michael@0: { michael@0: AssertPluginThread(); michael@0: delete stream; michael@0: return true; michael@0: } michael@0: michael@0: PStreamNotifyChild* michael@0: PluginInstanceChild::AllocPStreamNotifyChild(const nsCString& url, michael@0: const nsCString& target, michael@0: const bool& post, michael@0: const nsCString& buffer, michael@0: const bool& file, michael@0: NPError* result) michael@0: { michael@0: AssertPluginThread(); michael@0: NS_RUNTIMEABORT("not reached"); michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: StreamNotifyChild::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (AncestorDeletion == why && mBrowserStream) { michael@0: NS_ERROR("Pending NPP_URLNotify not called when closing an instance."); michael@0: michael@0: // reclaim responsibility for deleting ourself michael@0: mBrowserStream->mStreamNotify = nullptr; michael@0: mBrowserStream = nullptr; michael@0: } michael@0: } michael@0: michael@0: michael@0: void michael@0: StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs) michael@0: { michael@0: NS_ASSERTION(bs, "Shouldn't be null"); michael@0: NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?"); michael@0: michael@0: mBrowserStream = bs; michael@0: } michael@0: michael@0: bool michael@0: StreamNotifyChild::Recv__delete__(const NPReason& reason) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: if (mBrowserStream) michael@0: mBrowserStream->NotifyPending(); michael@0: else michael@0: NPP_URLNotify(reason); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: StreamNotifyChild::RecvRedirectNotify(const nsCString& url, const int32_t& status) michael@0: { michael@0: // NPP_URLRedirectNotify requires a non-null closure. Since core logic michael@0: // assumes that all out-of-process notify streams have non-null closure michael@0: // data it will assume that the plugin was notified at this point and michael@0: // expect a response otherwise the redirect will hang indefinitely. michael@0: if (!mClosure) { michael@0: SendRedirectNotifyResponse(false); michael@0: } michael@0: michael@0: PluginInstanceChild* instance = static_cast(Manager()); michael@0: if (instance->mPluginIface->urlredirectnotify) michael@0: instance->mPluginIface->urlredirectnotify(instance->GetNPP(), url.get(), status, mClosure); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: StreamNotifyChild::NPP_URLNotify(NPReason reason) michael@0: { michael@0: PluginInstanceChild* instance = static_cast(Manager()); michael@0: michael@0: if (mClosure) michael@0: instance->mPluginIface->urlnotify(instance->GetNPP(), mURL.get(), michael@0: reason, mClosure); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::DeallocPStreamNotifyChild(PStreamNotifyChild* notifyData) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: if (!static_cast(notifyData)->mBrowserStream) michael@0: delete notifyData; michael@0: return true; michael@0: } michael@0: michael@0: PluginScriptableObjectChild* michael@0: PluginInstanceChild::GetActorForNPObject(NPObject* aObject) michael@0: { michael@0: AssertPluginThread(); michael@0: NS_ASSERTION(aObject, "Null pointer!"); michael@0: michael@0: if (aObject->_class == PluginScriptableObjectChild::GetClass()) { michael@0: // One of ours! It's a browser-provided object. michael@0: ChildNPObject* object = static_cast(aObject); michael@0: NS_ASSERTION(object->parent, "Null actor!"); michael@0: return object->parent; michael@0: } michael@0: michael@0: PluginScriptableObjectChild* actor = michael@0: PluginModuleChild::current()->GetActorForNPObject(aObject); michael@0: if (actor) { michael@0: // Plugin-provided object that we've previously wrapped. michael@0: return actor; michael@0: } michael@0: michael@0: actor = new PluginScriptableObjectChild(LocalObject); michael@0: if (!SendPPluginScriptableObjectConstructor(actor)) { michael@0: NS_ERROR("Failed to send constructor message!"); michael@0: return nullptr; michael@0: } michael@0: michael@0: actor->InitializeLocal(aObject); michael@0: return actor; michael@0: } michael@0: michael@0: NPError michael@0: PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow, michael@0: NPStream** aStream) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: PluginStreamChild* ps = new PluginStreamChild(); michael@0: michael@0: NPError result; michael@0: CallPPluginStreamConstructor(ps, nsDependentCString(aMIMEType), michael@0: NullableString(aWindow), &result); michael@0: if (NPERR_NO_ERROR != result) { michael@0: *aStream = nullptr; michael@0: PPluginStreamChild::Call__delete__(ps, NPERR_GENERIC_ERROR, true); michael@0: return result; michael@0: } michael@0: michael@0: *aStream = &ps->mStream; michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow) michael@0: { michael@0: if (!notifyData) { michael@0: return; michael@0: } michael@0: michael@0: InfallibleTArray notifyStreams; michael@0: ManagedPStreamNotifyChild(notifyStreams); michael@0: uint32_t notifyStreamCount = notifyStreams.Length(); michael@0: for (uint32_t i = 0; i < notifyStreamCount; i++) { michael@0: StreamNotifyChild* sn = static_cast(notifyStreams[i]); michael@0: if (sn->mClosure == notifyData) { michael@0: sn->SendRedirectNotifyResponse(static_cast(allow)); michael@0: return; michael@0: } michael@0: } michael@0: NS_ASSERTION(false, "Couldn't find stream for redirect response!"); michael@0: } michael@0: michael@0: NPError michael@0: PluginInstanceChild::DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface) michael@0: { michael@0: AsyncBitmapData* data; michael@0: michael@0: if (!mAsyncBitmaps.Get(aSurface, &data)) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: DeallocShmem(data->mShmem); michael@0: aSurface->bitmap.data = nullptr; michael@0: michael@0: mAsyncBitmaps.Remove(aSurface); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::IsAsyncDrawing() michael@0: { michael@0: return IsDrawingModelAsync(mDrawingModel); michael@0: } michael@0: michael@0: NPError michael@0: PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format, michael@0: void *initData, NPAsyncSurface *surface) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: surface->bitmap.data = nullptr; michael@0: michael@0: if (!IsAsyncDrawing()) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: switch (mDrawingModel) { michael@0: case NPDrawingModelAsyncBitmapSurface: { michael@0: if (mAsyncBitmaps.Get(surface, nullptr)) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: if (size->width < 0 || size->height < 0) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: michael@0: bool result; michael@0: NPRemoteAsyncSurface remote; michael@0: michael@0: if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) { michael@0: return NPERR_OUT_OF_MEMORY_ERROR; michael@0: } michael@0: michael@0: NS_ABORT_IF_FALSE(remote.data().get_Shmem().IsWritable(), michael@0: "Failed to create writable shared memory."); michael@0: michael@0: AsyncBitmapData *data = new AsyncBitmapData; michael@0: mAsyncBitmaps.Put(surface, data); michael@0: michael@0: data->mRemotePtr = (void*)remote.hostPtr(); michael@0: data->mShmem = remote.data().get_Shmem(); michael@0: michael@0: surface->bitmap.data = data->mShmem.get(); michael@0: surface->bitmap.stride = remote.stride(); michael@0: surface->format = remote.format(); michael@0: surface->size.width = remote.size().width; michael@0: surface->size.height = remote.size().height; michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #ifdef XP_WIN michael@0: case NPDrawingModelAsyncWindowsDXGISurface: { michael@0: if (size->width < 0 || size->height < 0) { michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: bool result; michael@0: NPRemoteAsyncSurface remote; michael@0: michael@0: if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) { michael@0: return NPERR_OUT_OF_MEMORY_ERROR; michael@0: } michael@0: michael@0: surface->format = remote.format(); michael@0: surface->size.width = remote.size().width; michael@0: surface->size.height = remote.size().height; michael@0: surface->sharedHandle = remote.data().get_DXGISharedSurfaceHandle(); michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NPError michael@0: PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: if (!IsAsyncDrawing()) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: switch (mDrawingModel) { michael@0: case NPDrawingModelAsyncBitmapSurface: { michael@0: AsyncBitmapData *bitmapData; michael@0: michael@0: if (!mAsyncBitmaps.Get(surface, &bitmapData)) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex); michael@0: RemoteImageData *data = mRemoteImageData; michael@0: if (data->mBitmap.mData == bitmapData->mRemotePtr) { michael@0: data->mBitmap.mData = nullptr; michael@0: data->mSize = IntSize(0, 0); michael@0: data->mWasUpdated = true; michael@0: } michael@0: } michael@0: michael@0: return DeallocateAsyncBitmapSurface(surface); michael@0: } michael@0: #ifdef XP_WIN michael@0: case NPDrawingModelAsyncWindowsDXGISurface: { michael@0: michael@0: { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex); michael@0: RemoteImageData *data = mRemoteImageData; michael@0: if (data->mTextureHandle == surface->sharedHandle) { michael@0: data->mTextureHandle = nullptr; michael@0: data->mSize = IntSize(0, 0); michael@0: data->mWasUpdated = true; michael@0: } michael@0: } michael@0: michael@0: SendReleaseDXGISharedSurface(surface->sharedHandle); michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) michael@0: { michael@0: if (!IsAsyncDrawing()) { michael@0: return; michael@0: } michael@0: michael@0: RemoteImageData *data = mRemoteImageData; michael@0: michael@0: if (!surface) { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex); michael@0: data->mBitmap.mData = nullptr; michael@0: data->mSize = IntSize(0, 0); michael@0: data->mWasUpdated = true; michael@0: } else { michael@0: switch (mDrawingModel) { michael@0: case NPDrawingModelAsyncBitmapSurface: michael@0: { michael@0: AsyncBitmapData *bitmapData; michael@0: michael@0: if (!mAsyncBitmaps.Get(surface, &bitmapData)) { michael@0: return; michael@0: } michael@0: michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex); michael@0: data->mBitmap.mData = (unsigned char*)bitmapData->mRemotePtr; michael@0: data->mSize = IntSize(surface->size.width, surface->size.height); michael@0: data->mFormat = surface->format == NPImageFormatBGRX32 ? michael@0: RemoteImageData::BGRX32 : RemoteImageData::BGRA32; michael@0: data->mBitmap.mStride = surface->bitmap.stride; michael@0: data->mWasUpdated = true; michael@0: break; michael@0: } michael@0: #ifdef XP_WIN michael@0: case NPDrawingModelAsyncWindowsDXGISurface: michael@0: { michael@0: CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex); michael@0: data->mType = RemoteImageData::DXGI_TEXTURE_HANDLE; michael@0: data->mSize = IntSize(surface->size.width, surface->size.height); michael@0: data->mFormat = surface->format == NPImageFormatBGRX32 ? michael@0: RemoteImageData::BGRX32 : RemoteImageData::BGRA32; michael@0: data->mTextureHandle = surface->sharedHandle; michael@0: michael@0: data->mWasUpdated = true; michael@0: break; michael@0: } michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: { michael@0: MutexAutoLock autoLock(mAsyncInvalidateMutex); michael@0: if (!mAsyncInvalidateTask) { michael@0: mAsyncInvalidateTask = michael@0: NewRunnableMethod michael@0: (this, &PluginInstanceChild::DoAsyncRedraw); michael@0: ProcessChild::message_loop()->PostTask(FROM_HERE, mAsyncInvalidateTask); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::DoAsyncRedraw() michael@0: { michael@0: { michael@0: MutexAutoLock autoLock(mAsyncInvalidateMutex); michael@0: mAsyncInvalidateTask = nullptr; michael@0: } michael@0: michael@0: SendRedrawPlugin(); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType, michael@0: const NPRemoteWindow& aWindow) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: NS_ASSERTION(!aWindow.window, "Remote window should be null."); michael@0: michael@0: if (mCurrentAsyncSetWindowTask) { michael@0: mCurrentAsyncSetWindowTask->Cancel(); michael@0: mCurrentAsyncSetWindowTask = nullptr; michael@0: } michael@0: michael@0: // We shouldn't process this now because it may be received within a nested michael@0: // RPC call, and both Flash and Java don't expect to receive setwindow calls michael@0: // at arbitrary times. michael@0: mCurrentAsyncSetWindowTask = michael@0: NewRunnableMethod michael@0: (this, &PluginInstanceChild::DoAsyncSetWindow, michael@0: aSurfaceType, aWindow, true); michael@0: MessageLoop::current()->PostTask(FROM_HERE, mCurrentAsyncSetWindowTask); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType, michael@0: const NPRemoteWindow& aWindow, michael@0: bool aIsAsync) michael@0: { michael@0: PLUGIN_LOG_DEBUG( michael@0: ("[InstanceChild][%p] AsyncSetWindow to ", michael@0: this, aWindow.x, aWindow.y, aWindow.width, aWindow.height)); michael@0: michael@0: AssertPluginThread(); michael@0: NS_ASSERTION(!aWindow.window, "Remote window should be null."); michael@0: NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!"); michael@0: michael@0: if (aIsAsync) { michael@0: if (!mCurrentAsyncSetWindowTask) { michael@0: return; michael@0: } michael@0: mCurrentAsyncSetWindowTask = nullptr; michael@0: } michael@0: michael@0: mWindow.window = nullptr; michael@0: if (mWindow.width != aWindow.width || mWindow.height != aWindow.height || michael@0: mWindow.clipRect.top != aWindow.clipRect.top || michael@0: mWindow.clipRect.left != aWindow.clipRect.left || michael@0: mWindow.clipRect.bottom != aWindow.clipRect.bottom || michael@0: mWindow.clipRect.right != aWindow.clipRect.right) michael@0: mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height); michael@0: michael@0: mWindow.x = aWindow.x; michael@0: mWindow.y = aWindow.y; michael@0: mWindow.width = aWindow.width; michael@0: mWindow.height = aWindow.height; michael@0: mWindow.clipRect = aWindow.clipRect; michael@0: mWindow.type = aWindow.type; michael@0: #ifdef XP_MACOSX michael@0: mContentsScaleFactor = aWindow.contentsScaleFactor; michael@0: #endif michael@0: michael@0: if (GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT) michael@0: mIsTransparent = true; michael@0: michael@0: mLayersRendering = true; michael@0: mSurfaceType = aSurfaceType; michael@0: UpdateWindowAttributes(true); michael@0: michael@0: #ifdef XP_WIN michael@0: if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) michael@0: CreateWinlessPopupSurrogate(); michael@0: if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) michael@0: SetupFlashMsgThrottle(); michael@0: #endif michael@0: michael@0: if (!mAccumulatedInvalidRect.IsEmpty()) { michael@0: AsyncShowPluginFrame(); michael@0: } michael@0: } michael@0: michael@0: static inline gfxRect michael@0: GfxFromNsRect(const nsIntRect& aRect) michael@0: { michael@0: return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::CreateOptSurface(void) michael@0: { michael@0: NS_ABORT_IF_FALSE(mSurfaceType != gfxSurfaceType::Max, michael@0: "Need a valid surface type here"); michael@0: NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync."); michael@0: michael@0: nsRefPtr retsurf; michael@0: // Use an opaque surface unless we're transparent and *don't* have michael@0: // a background to source from. michael@0: gfxImageFormat format = michael@0: (mIsTransparent && !mBackground) ? gfxImageFormat::ARGB32 : michael@0: gfxImageFormat::RGB24; michael@0: michael@0: #ifdef MOZ_X11 michael@0: Display* dpy = mWsInfo.display; michael@0: Screen* screen = DefaultScreenOfDisplay(dpy); michael@0: if (format == gfxImageFormat::RGB24 && michael@0: DefaultDepth(dpy, DefaultScreen(dpy)) == 16) { michael@0: format = gfxImageFormat::RGB16_565; michael@0: } michael@0: michael@0: if (mSurfaceType == gfxSurfaceType::Xlib) { michael@0: if (!mIsTransparent || mBackground) { michael@0: Visual* defaultVisual = DefaultVisualOfScreen(screen); michael@0: mCurrentSurface = michael@0: gfxXlibSurface::Create(screen, defaultVisual, michael@0: gfxIntSize(mWindow.width, michael@0: mWindow.height)); michael@0: return mCurrentSurface != nullptr; michael@0: } michael@0: michael@0: XRenderPictFormat* xfmt = XRenderFindStandardFormat(dpy, PictStandardARGB32); michael@0: if (!xfmt) { michael@0: NS_ERROR("Need X falback surface, but FindRenderFormat failed"); michael@0: return false; michael@0: } michael@0: mCurrentSurface = michael@0: gfxXlibSurface::Create(screen, xfmt, michael@0: gfxIntSize(mWindow.width, michael@0: mWindow.height)); michael@0: return mCurrentSurface != nullptr; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: if (mSurfaceType == gfxSurfaceType::Win32 || michael@0: mSurfaceType == gfxSurfaceType::D2D) { michael@0: bool willHaveTransparentPixels = mIsTransparent && !mBackground; michael@0: michael@0: SharedDIBSurface* s = new SharedDIBSurface(); michael@0: if (!s->Create(reinterpret_cast(mWindow.window), michael@0: mWindow.width, mWindow.height, michael@0: willHaveTransparentPixels)) michael@0: return false; michael@0: michael@0: mCurrentSurface = s; michael@0: return true; michael@0: } michael@0: michael@0: NS_RUNTIMEABORT("Shared-memory drawing not expected on Windows."); michael@0: #endif michael@0: michael@0: // Make common shmem implementation working for any platform michael@0: mCurrentSurface = michael@0: gfxSharedImageSurface::CreateUnsafe(this, gfxIntSize(mWindow.width, mWindow.height), format); michael@0: return !!mCurrentSurface; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::MaybeCreatePlatformHelperSurface(void) michael@0: { michael@0: if (!mCurrentSurface) { michael@0: NS_ERROR("Cannot create helper surface without mCurrentSurface"); michael@0: return false; michael@0: } michael@0: michael@0: #ifdef MOZ_X11 michael@0: bool supportNonDefaultVisual = false; michael@0: Screen* screen = DefaultScreenOfDisplay(mWsInfo.display); michael@0: Visual* defaultVisual = DefaultVisualOfScreen(screen); michael@0: Visual* visual = nullptr; michael@0: Colormap colormap = 0; michael@0: mDoAlphaExtraction = false; michael@0: bool createHelperSurface = false; michael@0: michael@0: if (mCurrentSurface->GetType() == gfxSurfaceType::Xlib) { michael@0: static_cast(mCurrentSurface.get())-> michael@0: GetColormapAndVisual(&colormap, &visual); michael@0: // Create helper surface if layer surface visual not same as default michael@0: // and we don't support non-default visual rendering michael@0: if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) { michael@0: createHelperSurface = true; michael@0: visual = defaultVisual; michael@0: mDoAlphaExtraction = mIsTransparent; michael@0: } michael@0: } else if (mCurrentSurface->GetType() == gfxSurfaceType::Image) { michael@0: // For image layer surface we should always create helper surface michael@0: createHelperSurface = true; michael@0: // Check if we can create helper surface with non-default visual michael@0: visual = gfxXlibSurface::FindVisual(screen, michael@0: static_cast(mCurrentSurface.get())->Format()); michael@0: if (!visual || (defaultVisual != visual && !supportNonDefaultVisual)) { michael@0: visual = defaultVisual; michael@0: mDoAlphaExtraction = mIsTransparent; michael@0: } michael@0: } michael@0: michael@0: if (createHelperSurface) { michael@0: if (!visual) { michael@0: NS_ERROR("Need X falback surface, but visual failed"); michael@0: return false; michael@0: } michael@0: mHelperSurface = michael@0: gfxXlibSurface::Create(screen, visual, michael@0: mCurrentSurface->GetSize()); michael@0: if (!mHelperSurface) { michael@0: NS_WARNING("Fail to create create helper surface"); michael@0: return false; michael@0: } michael@0: } michael@0: #elif defined(XP_WIN) michael@0: mDoAlphaExtraction = mIsTransparent && !mBackground; michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::EnsureCurrentBuffer(void) michael@0: { michael@0: #ifndef XP_MACOSX michael@0: nsIntRect toInvalidate(0, 0, 0, 0); michael@0: gfxIntSize winSize = gfxIntSize(mWindow.width, mWindow.height); michael@0: michael@0: if (mBackground && mBackground->GetSize() != winSize) { michael@0: // It would be nice to keep the old background here, but doing michael@0: // so can lead to cases in which we permanently keep the old michael@0: // background size. michael@0: mBackground = nullptr; michael@0: toInvalidate.UnionRect(toInvalidate, michael@0: nsIntRect(0, 0, winSize.width, winSize.height)); michael@0: } michael@0: michael@0: if (mCurrentSurface) { michael@0: gfxIntSize surfSize = mCurrentSurface->GetSize(); michael@0: if (winSize != surfSize || michael@0: (mBackground && !CanPaintOnBackground()) || michael@0: (mBackground && michael@0: gfxContentType::COLOR != mCurrentSurface->GetContentType()) || michael@0: (!mBackground && mIsTransparent && michael@0: gfxContentType::COLOR == mCurrentSurface->GetContentType())) { michael@0: // Don't try to use an old, invalid DC. michael@0: mWindow.window = nullptr; michael@0: ClearCurrentSurface(); michael@0: toInvalidate.UnionRect(toInvalidate, michael@0: nsIntRect(0, 0, winSize.width, winSize.height)); michael@0: } michael@0: } michael@0: michael@0: mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate); michael@0: michael@0: if (mCurrentSurface) { michael@0: return true; michael@0: } michael@0: michael@0: if (!CreateOptSurface()) { michael@0: NS_ERROR("Cannot create optimized surface"); michael@0: return false; michael@0: } michael@0: michael@0: if (!MaybeCreatePlatformHelperSurface()) { michael@0: NS_ERROR("Cannot create helper surface"); michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: #else // XP_MACOSX michael@0: michael@0: if (!mDoubleBufferCARenderer.HasCALayer()) { michael@0: void *caLayer = nullptr; michael@0: if (mDrawingModel == NPDrawingModelCoreGraphics) { michael@0: if (!mCGLayer) { michael@0: bool avoidCGCrashes = !nsCocoaFeatures::OnMountainLionOrLater() && michael@0: (GetQuirks() & PluginModuleChild::QUIRK_FLASH_AVOID_CGMODE_CRASHES); michael@0: caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this, michael@0: avoidCGCrashes, michael@0: mContentsScaleFactor); michael@0: michael@0: if (!caLayer) { michael@0: PLUGIN_LOG_DEBUG(("GetCGLayer failed.")); michael@0: return false; michael@0: } michael@0: } michael@0: mCGLayer = caLayer; michael@0: } else { michael@0: NPError result = mPluginIface->getvalue(GetNPP(), michael@0: NPPVpluginCoreAnimationLayer, michael@0: &caLayer); michael@0: if (result != NPERR_NO_ERROR || !caLayer) { michael@0: PLUGIN_LOG_DEBUG(("Plugin requested CoreAnimation but did not " michael@0: "provide CALayer.")); michael@0: return false; michael@0: } michael@0: } michael@0: mDoubleBufferCARenderer.SetCALayer(caLayer); michael@0: } michael@0: michael@0: if (mDoubleBufferCARenderer.HasFrontSurface() && michael@0: (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != mWindow.width || michael@0: mDoubleBufferCARenderer.GetFrontSurfaceHeight() != mWindow.height || michael@0: mDoubleBufferCARenderer.GetContentsScaleFactor() != mContentsScaleFactor)) { michael@0: mDoubleBufferCARenderer.ClearFrontSurface(); michael@0: } michael@0: michael@0: if (!mDoubleBufferCARenderer.HasFrontSurface()) { michael@0: bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface( michael@0: mWindow.width, mWindow.height, mContentsScaleFactor, michael@0: GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ? michael@0: ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER); michael@0: if (!allocSurface) { michael@0: PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface")); michael@0: return false; michael@0: } michael@0: michael@0: if (mPluginIface->setwindow) michael@0: (void) mPluginIface->setwindow(&mData, &mWindow); michael@0: michael@0: nsIntRect toInvalidate(0, 0, mWindow.width, mWindow.height); michael@0: mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, toInvalidate); michael@0: } michael@0: michael@0: return true; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow) michael@0: { michael@0: nsRefPtr curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface; michael@0: bool needWindowUpdate = aForceSetWindow; michael@0: #ifdef MOZ_X11 michael@0: Visual* visual = nullptr; michael@0: Colormap colormap = 0; michael@0: if (curSurface && curSurface->GetType() == gfxSurfaceType::Xlib) { michael@0: static_cast(curSurface.get())-> michael@0: GetColormapAndVisual(&colormap, &visual); michael@0: if (visual != mWsInfo.visual || colormap != mWsInfo.colormap) { michael@0: mWsInfo.visual = visual; michael@0: mWsInfo.colormap = colormap; michael@0: needWindowUpdate = true; michael@0: } michael@0: } michael@0: #endif // MOZ_X11 michael@0: #ifdef XP_WIN michael@0: HDC dc = nullptr; michael@0: michael@0: if (curSurface) { michael@0: if (!SharedDIBSurface::IsSharedDIBSurface(curSurface)) michael@0: NS_RUNTIMEABORT("Expected SharedDIBSurface!"); michael@0: michael@0: SharedDIBSurface* dibsurf = static_cast(curSurface.get()); michael@0: dc = dibsurf->GetHDC(); michael@0: } michael@0: if (mWindow.window != dc) { michael@0: mWindow.window = dc; michael@0: needWindowUpdate = true; michael@0: } michael@0: #endif // XP_WIN michael@0: michael@0: if (!needWindowUpdate) { michael@0: return; michael@0: } michael@0: michael@0: #ifndef XP_MACOSX michael@0: // Adjusting the window isn't needed for OSX michael@0: #ifndef XP_WIN michael@0: // On Windows, we translate the device context, in order for the window michael@0: // origin to be correct. michael@0: mWindow.x = mWindow.y = 0; michael@0: #endif michael@0: michael@0: if (IsVisible()) { michael@0: // The clip rect is relative to drawable top-left. michael@0: nsIntRect clipRect; michael@0: michael@0: // Don't ask the plugin to draw outside the drawable. The clip rect michael@0: // is in plugin coordinates, not window coordinates. michael@0: // This also ensures that the unsigned clip rectangle offsets won't be -ve. michael@0: clipRect.SetRect(0, 0, mWindow.width, mWindow.height); michael@0: michael@0: mWindow.clipRect.left = 0; michael@0: mWindow.clipRect.top = 0; michael@0: mWindow.clipRect.right = clipRect.XMost(); michael@0: mWindow.clipRect.bottom = clipRect.YMost(); michael@0: } michael@0: #endif // XP_MACOSX michael@0: michael@0: #ifdef XP_WIN michael@0: // Windowless plugins on Windows need a WM_WINDOWPOSCHANGED event to update michael@0: // their location... or at least Flash does: Silverlight uses the michael@0: // window.x/y passed to NPP_SetWindow michael@0: michael@0: if (mPluginIface->event) { michael@0: WINDOWPOS winpos = { michael@0: 0, 0, michael@0: mWindow.x, mWindow.y, michael@0: mWindow.width, mWindow.height, michael@0: 0 michael@0: }; michael@0: NPEvent pluginEvent = { michael@0: WM_WINDOWPOSCHANGED, 0, michael@0: (LPARAM) &winpos michael@0: }; michael@0: mPluginIface->event(&mData, &pluginEvent); michael@0: } michael@0: #endif michael@0: michael@0: PLUGIN_LOG_DEBUG( michael@0: ("[InstanceChild][%p] UpdateWindow w=, clip=", michael@0: this, mWindow.x, mWindow.y, mWindow.width, mWindow.height, michael@0: mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom)); michael@0: michael@0: if (mPluginIface->setwindow) { michael@0: mPluginIface->setwindow(&mData, &mWindow); michael@0: } michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect, michael@0: gfxASurface* aSurface) michael@0: { michael@0: UpdateWindowAttributes(); michael@0: michael@0: #ifdef MOZ_X11 michael@0: { michael@0: NS_ASSERTION(aSurface->GetType() == gfxSurfaceType::Xlib, michael@0: "Non supported platform surface type"); michael@0: michael@0: NPEvent pluginEvent; michael@0: XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose; michael@0: exposeEvent.type = GraphicsExpose; michael@0: exposeEvent.display = mWsInfo.display; michael@0: exposeEvent.drawable = static_cast(aSurface)->XDrawable(); michael@0: exposeEvent.x = aRect.x; michael@0: exposeEvent.y = aRect.y; michael@0: exposeEvent.width = aRect.width; michael@0: exposeEvent.height = aRect.height; michael@0: exposeEvent.count = 0; michael@0: // information not set: michael@0: exposeEvent.serial = 0; michael@0: exposeEvent.send_event = False; michael@0: exposeEvent.major_code = 0; michael@0: exposeEvent.minor_code = 0; michael@0: mPluginIface->event(&mData, reinterpret_cast(&exposeEvent)); michael@0: } michael@0: #elif defined(XP_WIN) michael@0: NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(aSurface), michael@0: "Expected (SharedDIB) image surface."); michael@0: michael@0: // This rect is in the window coordinate space. aRect is in the plugin michael@0: // coordinate space. michael@0: RECT rect = { michael@0: mWindow.x + aRect.x, michael@0: mWindow.y + aRect.y, michael@0: mWindow.x + aRect.XMost(), michael@0: mWindow.y + aRect.YMost() michael@0: }; michael@0: NPEvent paintEvent = { michael@0: WM_PAINT, michael@0: uintptr_t(mWindow.window), michael@0: uintptr_t(&rect) michael@0: }; michael@0: michael@0: ::SetViewportOrgEx((HDC) mWindow.window, -mWindow.x, -mWindow.y, nullptr); michael@0: ::SelectClipRgn((HDC) mWindow.window, nullptr); michael@0: ::IntersectClipRect((HDC) mWindow.window, rect.left, rect.top, rect.right, rect.bottom); michael@0: mPluginIface->event(&mData, reinterpret_cast(&paintEvent)); michael@0: #else michael@0: NS_RUNTIMEABORT("Surface type not implemented."); michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect, michael@0: gfxASurface* aSurface, michael@0: const gfxRGBA& aColor) michael@0: { michael@0: // Render using temporary X surface, with copy to image surface michael@0: nsIntRect plPaintRect(aRect); michael@0: nsRefPtr renderSurface = aSurface; michael@0: #ifdef MOZ_X11 michael@0: if (mIsTransparent && (GetQuirks() & PluginModuleChild::QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) { michael@0: // Work around a bug in Flash up to 10.1 d51 at least, where expose event michael@0: // top left coordinates within the plugin-rect and not at the drawable michael@0: // origin are misinterpreted. (We can move the top left coordinate michael@0: // provided it is within the clipRect.), see bug 574583 michael@0: plPaintRect.SetRect(0, 0, aRect.XMost(), aRect.YMost()); michael@0: } michael@0: if (mHelperSurface) { michael@0: // On X11 we can paint to non Xlib surface only with HelperSurface michael@0: renderSurface = mHelperSurface; michael@0: } michael@0: #endif michael@0: michael@0: if (mIsTransparent && !CanPaintOnBackground()) { michael@0: // Clear surface content for transparent rendering michael@0: nsRefPtr ctx = new gfxContext(renderSurface); michael@0: ctx->SetDeviceColor(aColor); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->Rectangle(GfxFromNsRect(plPaintRect)); michael@0: ctx->Fill(); michael@0: } michael@0: michael@0: PaintRectToPlatformSurface(plPaintRect, renderSurface); michael@0: michael@0: if (renderSurface != aSurface) { michael@0: // Copy helper surface content to target michael@0: nsRefPtr ctx = new gfxContext(aSurface); michael@0: ctx->SetSource(renderSurface); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->Rectangle(GfxFromNsRect(aRect)); michael@0: ctx->Fill(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::PaintRectWithAlphaExtraction(const nsIntRect& aRect, michael@0: gfxASurface* aSurface) michael@0: { michael@0: NS_ABORT_IF_FALSE(aSurface->GetContentType() == gfxContentType::COLOR_ALPHA, michael@0: "Refusing to pointlessly recover alpha"); michael@0: michael@0: nsIntRect rect(aRect); michael@0: // If |aSurface| can be used to paint and can have alpha values michael@0: // recovered directly to it, do that to save a tmp surface and michael@0: // copy. michael@0: bool useSurfaceSubimageForBlack = false; michael@0: if (gfxSurfaceType::Image == aSurface->GetType()) { michael@0: gfxImageSurface* surfaceAsImage = michael@0: static_cast(aSurface); michael@0: useSurfaceSubimageForBlack = michael@0: (surfaceAsImage->Format() == gfxImageFormat::ARGB32); michael@0: // If we're going to use a subimage, nudge the rect so that we michael@0: // can use optimal alpha recovery. If we're not using a michael@0: // subimage, the temporaries should automatically get michael@0: // fast-path alpha recovery so we don't need to do anything. michael@0: if (useSurfaceSubimageForBlack) { michael@0: rect = michael@0: gfxAlphaRecovery::AlignRectForSubimageRecovery(aRect, michael@0: surfaceAsImage); michael@0: } michael@0: } michael@0: michael@0: nsRefPtr whiteImage; michael@0: nsRefPtr blackImage; michael@0: gfxRect targetRect(rect.x, rect.y, rect.width, rect.height); michael@0: gfxIntSize targetSize(rect.width, rect.height); michael@0: gfxPoint deviceOffset = -targetRect.TopLeft(); michael@0: michael@0: // We always use a temporary "white image" michael@0: whiteImage = new gfxImageSurface(targetSize, gfxImageFormat::RGB24); michael@0: if (whiteImage->CairoStatus()) { michael@0: return; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: // On windows, we need an HDC and so can't paint directly to michael@0: // vanilla image surfaces. Bifurcate this painting code so that michael@0: // we don't accidentally attempt that. michael@0: if (!SharedDIBSurface::IsSharedDIBSurface(aSurface)) michael@0: NS_RUNTIMEABORT("Expected SharedDIBSurface!"); michael@0: michael@0: // Paint the plugin directly onto the target, with a white michael@0: // background and copy the result michael@0: PaintRectToSurface(rect, aSurface, gfxRGBA(1.0, 1.0, 1.0)); michael@0: { michael@0: gfxRect copyRect(gfxPoint(0, 0), targetRect.Size()); michael@0: nsRefPtr ctx = new gfxContext(whiteImage); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->SetSource(aSurface, deviceOffset); michael@0: ctx->Rectangle(copyRect); michael@0: ctx->Fill(); michael@0: } michael@0: michael@0: // Paint the plugin directly onto the target, with a black michael@0: // background michael@0: PaintRectToSurface(rect, aSurface, gfxRGBA(0.0, 0.0, 0.0)); michael@0: michael@0: // Don't copy the result, just extract a subimage so that we can michael@0: // recover alpha directly into the target michael@0: gfxImageSurface *image = static_cast(aSurface); michael@0: blackImage = image->GetSubimage(targetRect); michael@0: michael@0: #else michael@0: // Paint onto white background michael@0: whiteImage->SetDeviceOffset(deviceOffset); michael@0: PaintRectToSurface(rect, whiteImage, gfxRGBA(1.0, 1.0, 1.0)); michael@0: michael@0: if (useSurfaceSubimageForBlack) { michael@0: gfxImageSurface *surface = static_cast(aSurface); michael@0: blackImage = surface->GetSubimage(targetRect); michael@0: } else { michael@0: blackImage = new gfxImageSurface(targetSize, michael@0: gfxImageFormat::ARGB32); michael@0: } michael@0: michael@0: // Paint onto black background michael@0: blackImage->SetDeviceOffset(deviceOffset); michael@0: PaintRectToSurface(rect, blackImage, gfxRGBA(0.0, 0.0, 0.0)); michael@0: #endif michael@0: michael@0: NS_ABORT_IF_FALSE(whiteImage && blackImage, "Didn't paint enough!"); michael@0: michael@0: // Extract alpha from black and white image and store to black michael@0: // image michael@0: if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) { michael@0: return; michael@0: } michael@0: michael@0: // If we had to use a temporary black surface, copy the pixels michael@0: // with alpha back to the target michael@0: if (!useSurfaceSubimageForBlack) { michael@0: nsRefPtr ctx = new gfxContext(aSurface); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->SetSource(blackImage); michael@0: ctx->Rectangle(targetRect); michael@0: ctx->Fill(); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::CanPaintOnBackground() michael@0: { michael@0: return (mBackground && michael@0: mCurrentSurface && michael@0: mCurrentSurface->GetSize() == mBackground->GetSize()); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::ShowPluginFrame() michael@0: { michael@0: // mLayersRendering can be false if we somehow get here without michael@0: // receiving AsyncSetWindow() first. mPendingPluginCall is our michael@0: // re-entrancy guard; we can't paint while nested inside another michael@0: // paint. michael@0: if (!mLayersRendering || mPendingPluginCall) { michael@0: return false; michael@0: } michael@0: michael@0: AutoRestore pending(mPendingPluginCall); michael@0: mPendingPluginCall = true; michael@0: michael@0: bool temporarilyMakeVisible = !IsVisible() && !mHasPainted; michael@0: if (temporarilyMakeVisible && mWindow.width && mWindow.height) { michael@0: mWindow.clipRect.right = mWindow.width; michael@0: mWindow.clipRect.bottom = mWindow.height; michael@0: } else if (!IsVisible()) { michael@0: // If we're not visible, don't bother painting a <0,0,0,0> michael@0: // rect. If we're eventually made visible, the visibility michael@0: // change will invalidate our window. michael@0: ClearCurrentSurface(); michael@0: return true; michael@0: } michael@0: michael@0: if (!EnsureCurrentBuffer()) { michael@0: return false; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: // We can't use the thebes code with CoreAnimation so we will michael@0: // take a different code path. michael@0: if (mDrawingModel == NPDrawingModelCoreAnimation || michael@0: mDrawingModel == NPDrawingModelInvalidatingCoreAnimation || michael@0: mDrawingModel == NPDrawingModelCoreGraphics) { michael@0: michael@0: if (!IsVisible()) { michael@0: return true; michael@0: } michael@0: michael@0: if (!mDoubleBufferCARenderer.HasFrontSurface()) { michael@0: NS_ERROR("CARenderer not initialized for rendering"); michael@0: return false; michael@0: } michael@0: michael@0: // Clear accRect here to be able to pass michael@0: // test_invalidate_during_plugin_paint test michael@0: nsIntRect rect = mAccumulatedInvalidRect; michael@0: mAccumulatedInvalidRect.SetEmpty(); michael@0: michael@0: // Fix up old invalidations that might have been made when our michael@0: // surface was a different size michael@0: rect.IntersectRect(rect, michael@0: nsIntRect(0, 0, michael@0: mDoubleBufferCARenderer.GetFrontSurfaceWidth(), michael@0: mDoubleBufferCARenderer.GetFrontSurfaceHeight())); michael@0: michael@0: if (mDrawingModel == NPDrawingModelCoreGraphics) { michael@0: mozilla::plugins::PluginUtilsOSX::Repaint(mCGLayer, rect); michael@0: } michael@0: michael@0: mDoubleBufferCARenderer.Render(); michael@0: michael@0: NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x, michael@0: (uint16_t)rect.YMost(), (uint16_t)rect.XMost() }; michael@0: SurfaceDescriptor currSurf; michael@0: currSurf = IOSurfaceDescriptor(mDoubleBufferCARenderer.GetFrontSurfaceID(), michael@0: mDoubleBufferCARenderer.GetContentsScaleFactor()); michael@0: michael@0: mHasPainted = true; michael@0: michael@0: SurfaceDescriptor returnSurf; michael@0: michael@0: if (!SendShow(r, currSurf, &returnSurf)) { michael@0: return false; michael@0: } michael@0: michael@0: SwapSurfaces(); michael@0: return true; michael@0: } else { michael@0: NS_ERROR("Unsupported drawing model for async layer rendering"); michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: NS_ASSERTION(mWindow.width == uint32_t(mWindow.clipRect.right - mWindow.clipRect.left) && michael@0: mWindow.height == uint32_t(mWindow.clipRect.bottom - mWindow.clipRect.top), michael@0: "Clip rect should be same size as window when using layers"); michael@0: michael@0: // Clear accRect here to be able to pass michael@0: // test_invalidate_during_plugin_paint test michael@0: nsIntRect rect = mAccumulatedInvalidRect; michael@0: mAccumulatedInvalidRect.SetEmpty(); michael@0: michael@0: // Fix up old invalidations that might have been made when our michael@0: // surface was a different size michael@0: gfxIntSize surfaceSize = mCurrentSurface->GetSize(); michael@0: rect.IntersectRect(rect, michael@0: nsIntRect(0, 0, surfaceSize.width, surfaceSize.height)); michael@0: michael@0: if (!ReadbackDifferenceRect(rect)) { michael@0: // We couldn't read back the pixels that differ between the michael@0: // current surface and last, so we have to invalidate the michael@0: // entire window. michael@0: rect.SetRect(0, 0, mWindow.width, mWindow.height); michael@0: } michael@0: michael@0: bool haveTransparentPixels = michael@0: gfxContentType::COLOR_ALPHA == mCurrentSurface->GetContentType(); michael@0: PLUGIN_LOG_DEBUG( michael@0: ("[InstanceChild][%p] Painting%s on surface ", michael@0: this, haveTransparentPixels ? " with alpha" : "", michael@0: rect.x, rect.y, rect.width, rect.height, michael@0: mCurrentSurface->GetSize().width, mCurrentSurface->GetSize().height)); michael@0: michael@0: if (CanPaintOnBackground()) { michael@0: PLUGIN_LOG_DEBUG((" (on background)")); michael@0: // Source the background pixels ... michael@0: { michael@0: nsRefPtr ctx = michael@0: new gfxContext(mHelperSurface ? mHelperSurface : mCurrentSurface); michael@0: ctx->SetSource(mBackground); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height)); michael@0: ctx->Fill(); michael@0: } michael@0: // ... and hand off to the plugin michael@0: // BEWARE: mBackground may die during this call michael@0: PaintRectToSurface(rect, mCurrentSurface, gfxRGBA(0.0, 0.0, 0.0, 0.0)); michael@0: } else if (!temporarilyMakeVisible && mDoAlphaExtraction) { michael@0: // We don't want to pay the expense of alpha extraction for michael@0: // phony paints. michael@0: PLUGIN_LOG_DEBUG((" (with alpha recovery)")); michael@0: PaintRectWithAlphaExtraction(rect, mCurrentSurface); michael@0: } else { michael@0: PLUGIN_LOG_DEBUG((" (onto opaque surface)")); michael@0: michael@0: // If we're on a platform that needs helper surfaces for michael@0: // plugins, and we're forcing a throwaway paint of a michael@0: // wmode=transparent plugin, then make sure to use the helper michael@0: // surface here. michael@0: nsRefPtr target = michael@0: (temporarilyMakeVisible && mHelperSurface) ? michael@0: mHelperSurface : mCurrentSurface; michael@0: michael@0: PaintRectToSurface(rect, target, gfxRGBA(0.0, 0.0, 0.0, 0.0)); michael@0: } michael@0: mHasPainted = true; michael@0: michael@0: if (temporarilyMakeVisible) { michael@0: mWindow.clipRect.right = mWindow.clipRect.bottom = 0; michael@0: michael@0: PLUGIN_LOG_DEBUG( michael@0: ("[InstanceChild][%p] Undoing temporary clipping w=, clip=", michael@0: this, mWindow.x, mWindow.y, mWindow.width, mWindow.height, michael@0: mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom)); michael@0: michael@0: if (mPluginIface->setwindow) { michael@0: mPluginIface->setwindow(&mData, &mWindow); michael@0: } michael@0: michael@0: // Skip forwarding the results of the phony paint to the michael@0: // browser. We may have painted a transparent plugin using michael@0: // the opaque-plugin path, which can result in wrong pixels. michael@0: // We also don't want to pay the expense of forwarding the michael@0: // surface for plugins that might really be invisible. michael@0: mAccumulatedInvalidRect.SetRect(0, 0, mWindow.width, mWindow.height); michael@0: return true; michael@0: } michael@0: michael@0: NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x, michael@0: (uint16_t)rect.YMost(), (uint16_t)rect.XMost() }; michael@0: SurfaceDescriptor currSurf; michael@0: #ifdef MOZ_X11 michael@0: if (mCurrentSurface->GetType() == gfxSurfaceType::Xlib) { michael@0: gfxXlibSurface *xsurf = static_cast(mCurrentSurface.get()); michael@0: currSurf = SurfaceDescriptorX11(xsurf); michael@0: // Need to sync all pending x-paint requests michael@0: // before giving drawable to another process michael@0: XSync(mWsInfo.display, False); michael@0: } else michael@0: #endif michael@0: #ifdef XP_WIN michael@0: if (SharedDIBSurface::IsSharedDIBSurface(mCurrentSurface)) { michael@0: SharedDIBSurface* s = static_cast(mCurrentSurface.get()); michael@0: if (!mCurrentSurfaceActor) { michael@0: base::SharedMemoryHandle handle = nullptr; michael@0: s->ShareToProcess(PluginModuleChild::current()->OtherProcess(), &handle); michael@0: michael@0: mCurrentSurfaceActor = michael@0: SendPPluginSurfaceConstructor(handle, michael@0: mCurrentSurface->GetSize(), michael@0: haveTransparentPixels); michael@0: } michael@0: currSurf = mCurrentSurfaceActor; michael@0: s->Flush(); michael@0: } else michael@0: #endif michael@0: if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) { michael@0: currSurf = static_cast(mCurrentSurface.get())->GetShmem(); michael@0: } else { michael@0: NS_RUNTIMEABORT("Surface type is not remotable"); michael@0: return false; michael@0: } michael@0: michael@0: // Unused, except to possibly return a shmem to us michael@0: SurfaceDescriptor returnSurf; michael@0: michael@0: if (!SendShow(r, currSurf, &returnSurf)) { michael@0: return false; michael@0: } michael@0: michael@0: SwapSurfaces(); michael@0: mSurfaceDifferenceRect = rect; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect) michael@0: { michael@0: if (!mBackSurface) michael@0: return false; michael@0: michael@0: // We can read safely from XSurface,SharedDIBSurface and Unsafe SharedMemory, michael@0: // because PluginHost is not able to modify that surface michael@0: #if defined(MOZ_X11) michael@0: if (mBackSurface->GetType() != gfxSurfaceType::Xlib && michael@0: !gfxSharedImageSurface::IsSharedImage(mBackSurface)) michael@0: return false; michael@0: #elif defined(XP_WIN) michael@0: if (!SharedDIBSurface::IsSharedDIBSurface(mBackSurface)) michael@0: return false; michael@0: #else michael@0: return false; michael@0: #endif michael@0: michael@0: if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType()) michael@0: return false; michael@0: michael@0: if (mSurfaceDifferenceRect.IsEmpty()) michael@0: return true; michael@0: michael@0: PLUGIN_LOG_DEBUG( michael@0: ("[InstanceChild][%p] Reading back part of ", michael@0: this, mSurfaceDifferenceRect.x, mSurfaceDifferenceRect.y, michael@0: mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height)); michael@0: michael@0: // Read back previous content michael@0: nsRefPtr ctx = new gfxContext(mCurrentSurface); michael@0: ctx->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: ctx->SetSource(mBackSurface); michael@0: // Subtract from mSurfaceDifferenceRect area which is overlapping with rect michael@0: nsIntRegion result; michael@0: result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect)); michael@0: nsIntRegionRectIterator iter(result); michael@0: const nsIntRect* r; michael@0: while ((r = iter.Next()) != nullptr) { michael@0: ctx->Rectangle(GfxFromNsRect(*r)); michael@0: } michael@0: ctx->Fill(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::InvalidateRectDelayed(void) michael@0: { michael@0: if (!mCurrentInvalidateTask) { michael@0: return; michael@0: } michael@0: michael@0: mCurrentInvalidateTask = nullptr; michael@0: if (mAccumulatedInvalidRect.IsEmpty()) { michael@0: return; michael@0: } michael@0: michael@0: if (!ShowPluginFrame()) { michael@0: AsyncShowPluginFrame(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::AsyncShowPluginFrame(void) michael@0: { michael@0: if (mCurrentInvalidateTask) { michael@0: return; michael@0: } michael@0: michael@0: mCurrentInvalidateTask = michael@0: NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed); michael@0: MessageLoop::current()->PostTask(FROM_HERE, mCurrentInvalidateTask); michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect) michael@0: { michael@0: NS_ASSERTION(aInvalidRect, "Null pointer!"); michael@0: michael@0: #ifdef OS_WIN michael@0: // Invalidate and draw locally for windowed plugins. michael@0: if (mWindow.type == NPWindowTypeWindow) { michael@0: NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!"); michael@0: RECT rect = { aInvalidRect->left, aInvalidRect->top, michael@0: aInvalidRect->right, aInvalidRect->bottom }; michael@0: ::InvalidateRect(mPluginWindowHWND, &rect, FALSE); michael@0: return; michael@0: } michael@0: #endif michael@0: michael@0: if (mLayersRendering) { michael@0: nsIntRect r(aInvalidRect->left, aInvalidRect->top, michael@0: aInvalidRect->right - aInvalidRect->left, michael@0: aInvalidRect->bottom - aInvalidRect->top); michael@0: michael@0: mAccumulatedInvalidRect.UnionRect(r, mAccumulatedInvalidRect); michael@0: // If we are able to paint and invalidate sent, then reset michael@0: // accumulated rectangle michael@0: AsyncShowPluginFrame(); michael@0: return; michael@0: } michael@0: michael@0: // If we were going to use layers rendering but it's not set up michael@0: // yet, and the plugin happens to call this first, we'll forward michael@0: // the invalidation to the browser. It's unclear whether michael@0: // non-layers plugins need this rect forwarded when their window michael@0: // width or height is 0, which it would be for layers plugins michael@0: // before their first SetWindow(). michael@0: SendNPN_InvalidateRect(*aInvalidRect); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground, michael@0: const nsIntRect& aRect) michael@0: { michael@0: NS_ABORT_IF_FALSE(mIsTransparent, "Only transparent plugins use backgrounds"); michael@0: michael@0: if (!mBackground) { michael@0: // XXX refactor me michael@0: switch (aBackground.type()) { michael@0: #ifdef MOZ_X11 michael@0: case SurfaceDescriptor::TSurfaceDescriptorX11: { michael@0: mBackground = aBackground.get_SurfaceDescriptorX11().OpenForeign(); michael@0: break; michael@0: } michael@0: #endif michael@0: case SurfaceDescriptor::TShmem: { michael@0: mBackground = gfxSharedImageSurface::Open(aBackground.get_Shmem()); michael@0: break; michael@0: } michael@0: default: michael@0: NS_RUNTIMEABORT("Unexpected background surface descriptor"); michael@0: } michael@0: michael@0: if (!mBackground) { michael@0: return false; michael@0: } michael@0: michael@0: gfxIntSize bgSize = mBackground->GetSize(); michael@0: mAccumulatedInvalidRect.UnionRect(mAccumulatedInvalidRect, michael@0: nsIntRect(0, 0, bgSize.width, bgSize.height)); michael@0: AsyncShowPluginFrame(); michael@0: return true; michael@0: } michael@0: michael@0: // XXX refactor me michael@0: mAccumulatedInvalidRect.UnionRect(aRect, mAccumulatedInvalidRect); michael@0: michael@0: // This must be asynchronous, because we may be nested within RPC messages michael@0: // which do not expect to receiving paint events. michael@0: AsyncShowPluginFrame(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: PPluginBackgroundDestroyerChild* michael@0: PluginInstanceChild::AllocPPluginBackgroundDestroyerChild() michael@0: { michael@0: return new PluginBackgroundDestroyerChild(); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::RecvPPluginBackgroundDestroyerConstructor( michael@0: PPluginBackgroundDestroyerChild* aActor) michael@0: { michael@0: // Our background changed, so we have to invalidate the area michael@0: // painted with the old background. If the background was michael@0: // destroyed because we have a new background, then we expect to michael@0: // be notified of that "soon", before processing the asynchronous michael@0: // invalidation here. If we're *not* getting a new background, michael@0: // our current front surface is stale and we want to repaint michael@0: // "soon" so that we can hand the browser back a surface with michael@0: // alpha values. (We should be notified of that invalidation soon michael@0: // too, but we don't assume that here.) michael@0: if (mBackground) { michael@0: gfxIntSize bgsize = mBackground->GetSize(); michael@0: mAccumulatedInvalidRect.UnionRect( michael@0: nsIntRect(0, 0, bgsize.width, bgsize.height), mAccumulatedInvalidRect); michael@0: michael@0: // NB: we don't have to XSync here because only ShowPluginFrame() michael@0: // uses mBackground, and it always XSyncs after finishing. michael@0: mBackground = nullptr; michael@0: AsyncShowPluginFrame(); michael@0: } michael@0: michael@0: return PPluginBackgroundDestroyerChild::Send__delete__(aActor); michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::DeallocPPluginBackgroundDestroyerChild( michael@0: PPluginBackgroundDestroyerChild* aActor) michael@0: { michael@0: delete aActor; michael@0: return true; michael@0: } michael@0: michael@0: uint32_t michael@0: PluginInstanceChild::ScheduleTimer(uint32_t interval, bool repeat, michael@0: TimerFunc func) michael@0: { michael@0: ChildTimer* t = new ChildTimer(this, interval, repeat, func); michael@0: if (0 == t->ID()) { michael@0: delete t; michael@0: return 0; michael@0: } michael@0: michael@0: mTimers.AppendElement(t); michael@0: return t->ID(); michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::UnscheduleTimer(uint32_t id) michael@0: { michael@0: if (0 == id) michael@0: return; michael@0: michael@0: mTimers.RemoveElement(id, ChildTimer::IDComparator()); michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData) michael@0: { michael@0: ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData); michael@0: michael@0: { michael@0: MutexAutoLock lock(mAsyncCallMutex); michael@0: mPendingAsyncCalls.AppendElement(task); michael@0: } michael@0: ProcessChild::message_loop()->PostTask(FROM_HERE, task); michael@0: } michael@0: michael@0: static PLDHashOperator michael@0: InvalidateObject(DeletingObjectEntry* e, void* userArg) michael@0: { michael@0: NPObject* o = e->GetKey(); michael@0: if (!e->mDeleted && o->_class && o->_class->invalidate) michael@0: o->_class->invalidate(o); michael@0: michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: static PLDHashOperator michael@0: DeleteObject(DeletingObjectEntry* e, void* userArg) michael@0: { michael@0: NPObject* o = e->GetKey(); michael@0: if (!e->mDeleted) { michael@0: e->mDeleted = true; michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: { michael@0: int32_t refcnt = o->referenceCount; michael@0: while (refcnt) { michael@0: --refcnt; michael@0: NS_LOG_RELEASE(o, refcnt, "NPObject"); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: PluginModuleChild::DeallocNPObject(o); michael@0: } michael@0: michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::SwapSurfaces() michael@0: { michael@0: nsRefPtr tmpsurf = mCurrentSurface; michael@0: #ifdef XP_WIN michael@0: PPluginSurfaceChild* tmpactor = mCurrentSurfaceActor; michael@0: #endif michael@0: michael@0: mCurrentSurface = mBackSurface; michael@0: #ifdef XP_WIN michael@0: mCurrentSurfaceActor = mBackSurfaceActor; michael@0: #endif michael@0: michael@0: mBackSurface = tmpsurf; michael@0: #ifdef XP_WIN michael@0: mBackSurfaceActor = tmpactor; michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: mDoubleBufferCARenderer.SwapSurfaces(); michael@0: michael@0: // Outdated back surface... not usable anymore due to changed plugin size. michael@0: // Dropping obsolete surface michael@0: if (mDoubleBufferCARenderer.HasFrontSurface() && michael@0: mDoubleBufferCARenderer.HasBackSurface() && michael@0: (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != michael@0: mDoubleBufferCARenderer.GetBackSurfaceWidth() || michael@0: mDoubleBufferCARenderer.GetFrontSurfaceHeight() != michael@0: mDoubleBufferCARenderer.GetBackSurfaceHeight() || michael@0: mDoubleBufferCARenderer.GetFrontSurfaceContentsScaleFactor() != michael@0: mDoubleBufferCARenderer.GetBackSurfaceContentsScaleFactor())) { michael@0: michael@0: mDoubleBufferCARenderer.ClearFrontSurface(); michael@0: } michael@0: #else michael@0: if (mCurrentSurface && mBackSurface && michael@0: (mCurrentSurface->GetSize() != mBackSurface->GetSize() || michael@0: mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) { michael@0: ClearCurrentSurface(); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::ClearCurrentSurface() michael@0: { michael@0: mCurrentSurface = nullptr; michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: if (mDoubleBufferCARenderer.HasFrontSurface()) { michael@0: mDoubleBufferCARenderer.ClearFrontSurface(); michael@0: } michael@0: #endif michael@0: #ifdef XP_WIN michael@0: if (mCurrentSurfaceActor) { michael@0: PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor); michael@0: mCurrentSurfaceActor = nullptr; michael@0: } michael@0: #endif michael@0: mHelperSurface = nullptr; michael@0: } michael@0: michael@0: void michael@0: PluginInstanceChild::ClearAllSurfaces() michael@0: { michael@0: if (mBackSurface) { michael@0: // Get last surface back, and drop it michael@0: SurfaceDescriptor temp = null_t(); michael@0: NPRect r = { 0, 0, 1, 1 }; michael@0: SendShow(r, temp, &temp); michael@0: } michael@0: michael@0: if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) michael@0: DeallocShmem(static_cast(mCurrentSurface.get())->GetShmem()); michael@0: if (gfxSharedImageSurface::IsSharedImage(mBackSurface)) michael@0: DeallocShmem(static_cast(mBackSurface.get())->GetShmem()); michael@0: mCurrentSurface = nullptr; michael@0: mBackSurface = nullptr; michael@0: michael@0: #ifdef XP_WIN michael@0: if (mCurrentSurfaceActor) { michael@0: PPluginSurfaceChild::Send__delete__(mCurrentSurfaceActor); michael@0: mCurrentSurfaceActor = nullptr; michael@0: } michael@0: if (mBackSurfaceActor) { michael@0: PPluginSurfaceChild::Send__delete__(mBackSurfaceActor); michael@0: mBackSurfaceActor = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: if (mDoubleBufferCARenderer.HasBackSurface()) { michael@0: // Get last surface back, and drop it michael@0: SurfaceDescriptor temp = null_t(); michael@0: NPRect r = { 0, 0, 1, 1 }; michael@0: SendShow(r, temp, &temp); michael@0: } michael@0: michael@0: if (mCGLayer) { michael@0: mozilla::plugins::PluginUtilsOSX::ReleaseCGLayer(mCGLayer); michael@0: mCGLayer = nullptr; michael@0: } michael@0: michael@0: mDoubleBufferCARenderer.ClearFrontSurface(); michael@0: mDoubleBufferCARenderer.ClearBackSurface(); michael@0: #endif michael@0: } michael@0: michael@0: PLDHashOperator michael@0: PluginInstanceChild::DeleteSurface(NPAsyncSurface* surf, nsAutoPtr &data, void* userArg) michael@0: { michael@0: PluginInstanceChild *inst = static_cast(userArg); michael@0: michael@0: inst->DeallocShmem(data->mShmem); michael@0: michael@0: return PL_DHASH_REMOVE; michael@0: } michael@0: michael@0: bool michael@0: PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: AssertPluginThread(); michael@0: *aResult = NPERR_NO_ERROR; michael@0: michael@0: #if defined(OS_WIN) michael@0: SetProp(mPluginWindowHWND, kPluginIgnoreSubclassProperty, (HANDLE)1); michael@0: #endif michael@0: michael@0: InfallibleTArray streams; michael@0: ManagedPBrowserStreamChild(streams); michael@0: michael@0: // First make sure none of these streams become deleted michael@0: for (uint32_t i = 0; i < streams.Length(); ) { michael@0: if (static_cast(streams[i])->InstanceDying()) michael@0: ++i; michael@0: else michael@0: streams.RemoveElementAt(i); michael@0: } michael@0: for (uint32_t i = 0; i < streams.Length(); ++i) michael@0: static_cast(streams[i])->FinishDelivery(); michael@0: michael@0: mTimers.Clear(); michael@0: michael@0: // NPP_Destroy() should be a synchronization point for plugin threads michael@0: // calling NPN_AsyncCall: after this function returns, they are no longer michael@0: // allowed to make async calls on this instance. michael@0: PluginModuleChild::current()->NPP_Destroy(this); michael@0: mData.ndata = 0; michael@0: michael@0: if (mCurrentInvalidateTask) { michael@0: mCurrentInvalidateTask->Cancel(); michael@0: mCurrentInvalidateTask = nullptr; michael@0: } michael@0: if (mCurrentAsyncSetWindowTask) { michael@0: mCurrentAsyncSetWindowTask->Cancel(); michael@0: mCurrentAsyncSetWindowTask = nullptr; michael@0: } michael@0: { michael@0: MutexAutoLock autoLock(mAsyncInvalidateMutex); michael@0: if (mAsyncInvalidateTask) { michael@0: mAsyncInvalidateTask->Cancel(); michael@0: mAsyncInvalidateTask = nullptr; michael@0: } michael@0: } michael@0: michael@0: ClearAllSurfaces(); michael@0: michael@0: mDeletingHash = new nsTHashtable; michael@0: PluginModuleChild::current()->FindNPObjectsForInstance(this); michael@0: michael@0: mDeletingHash->EnumerateEntries(InvalidateObject, nullptr); michael@0: mDeletingHash->EnumerateEntries(DeleteObject, nullptr); michael@0: michael@0: // Null out our cached actors as they should have been killed in the michael@0: // PluginInstanceDestroyed call above. michael@0: mCachedWindowActor = nullptr; michael@0: mCachedElementActor = nullptr; michael@0: michael@0: #if defined(OS_WIN) michael@0: SharedSurfaceRelease(); michael@0: DestroyWinlessPopupSurrogate(); michael@0: UnhookWinlessFlashThrottle(); michael@0: DestroyPluginWindow(); michael@0: #endif michael@0: michael@0: // Pending async calls are discarded, not delivered. This matches the michael@0: // in-process behavior. michael@0: for (uint32_t i = 0; i < mPendingAsyncCalls.Length(); ++i) michael@0: mPendingAsyncCalls[i]->Cancel(); michael@0: michael@0: mPendingAsyncCalls.Clear(); michael@0: michael@0: if (mAsyncBitmaps.Count()) { michael@0: NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!"); michael@0: mAsyncBitmaps.Enumerate(DeleteSurface, this); michael@0: } michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: if (mWindow.type == NPWindowTypeWindow && !mXEmbed) { michael@0: xt_client_xloop_destroy(); michael@0: } michael@0: #endif michael@0: #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: DeleteWindow(); michael@0: #endif michael@0: michael@0: return true; michael@0: }