Coverage Report

Created: 2018-09-25 14:53

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