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