Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/plugins/ipc/PluginInstanceParent.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 "mozilla/DebugOnly.h"
8
#include <stdint.h> // for intptr_t
9
10
#include "mozilla/BasicEvents.h"
11
#include "mozilla/Preferences.h"
12
#include "mozilla/Telemetry.h"
13
#include "mozilla/dom/Element.h"
14
#include "PluginInstanceParent.h"
15
#include "BrowserStreamParent.h"
16
#include "PluginBackgroundDestroyer.h"
17
#include "PluginModuleParent.h"
18
#include "StreamNotifyParent.h"
19
#include "npfunctions.h"
20
#include "nsAutoPtr.h"
21
#include "gfxASurface.h"
22
#include "gfxContext.h"
23
#include "gfxPlatform.h"
24
#include "gfxSharedImageSurface.h"
25
#include "nsNetUtil.h"
26
#include "nsNPAPIPluginInstance.h"
27
#include "nsPluginInstanceOwner.h"
28
#include "nsFocusManager.h"
29
#ifdef MOZ_X11
30
#include "gfxXlibSurface.h"
31
#endif
32
#include "gfxUtils.h"
33
#include "mozilla/gfx/2D.h"
34
#include "Layers.h"
35
#include "ImageContainer.h"
36
#include "GLContext.h"
37
#include "GLContextProvider.h"
38
#include "gfxPrefs.h"
39
#include "LayersLogging.h"
40
#include "mozilla/layers/TextureWrapperImage.h"
41
#include "mozilla/layers/TextureClientRecycleAllocator.h"
42
#include "mozilla/layers/ImageBridgeChild.h"
43
#if defined(XP_WIN)
44
# include "mozilla/layers/D3D11ShareHandleImage.h"
45
# include "mozilla/gfx/DeviceManagerDx.h"
46
# include "mozilla/layers/TextureD3D11.h"
47
#endif
48
49
#ifdef XP_MACOSX
50
#include "MacIOSurfaceImage.h"
51
#endif
52
53
#if defined(OS_WIN)
54
#include <windowsx.h>
55
#include "gfxWindowsPlatform.h"
56
#include "mozilla/plugins/PluginSurfaceParent.h"
57
#include "nsClassHashtable.h"
58
#include "nsHashKeys.h"
59
#include "nsIWidget.h"
60
#include "nsPluginNativeWindow.h"
61
#include "PluginQuirks.h"
62
extern const wchar_t* kFlashFullscreenClass;
63
#elif defined(MOZ_WIDGET_GTK)
64
#include "mozilla/dom/ContentChild.h"
65
#include <gdk/gdk.h>
66
#elif defined(XP_MACOSX)
67
#include <ApplicationServices/ApplicationServices.h>
68
#endif // defined(XP_MACOSX)
69
70
using namespace mozilla::plugins;
71
using namespace mozilla::layers;
72
using namespace mozilla::gl;
73
74
void
75
StreamNotifyParent::ActorDestroy(ActorDestroyReason aWhy)
76
0
{
77
0
  // Implement me! Bug 1005162
78
0
}
79
80
mozilla::ipc::IPCResult
81
StreamNotifyParent::RecvRedirectNotifyResponse(const bool& allow)
82
0
{
83
0
  PluginInstanceParent* instance = static_cast<PluginInstanceParent*>(Manager());
84
0
  instance->mNPNIface->urlredirectresponse(instance->mNPP, this, static_cast<NPBool>(allow));
85
0
  return IPC_OK();
86
0
}
87
88
#if defined(XP_WIN)
89
namespace mozilla {
90
namespace plugins {
91
/**
92
 * e10s specific, used in cross referencing hwnds with plugin instances so we
93
 * can access methods here from PluginWidgetChild.
94
 */
95
static nsClassHashtable<nsVoidPtrHashKey, PluginInstanceParent>* sPluginInstanceList;
96
97
// static
98
PluginInstanceParent*
99
PluginInstanceParent::LookupPluginInstanceByID(uintptr_t aId)
100
{
101
    MOZ_ASSERT(NS_IsMainThread());
102
    if (sPluginInstanceList) {
103
        return sPluginInstanceList->Get((void*)aId);
104
    }
105
    return nullptr;
106
}
107
}
108
}
109
#endif
110
111
PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
112
                                           NPP npp,
113
                                           const nsCString& aMimeType,
114
                                           const NPNetscapeFuncs* npniface)
115
    : mParent(parent)
116
    , mNPP(npp)
117
    , mNPNIface(npniface)
118
    , mWindowType(NPWindowTypeWindow)
119
    , mDrawingModel(kDefaultDrawingModel)
120
    , mLastRecordedDrawingModel(-1)
121
    , mFrameID(0)
122
#if defined(OS_WIN)
123
    , mPluginHWND(nullptr)
124
    , mChildPluginHWND(nullptr)
125
    , mChildPluginsParentHWND(nullptr)
126
    , mPluginWndProc(nullptr)
127
    , mNestedEventState(false)
128
#endif // defined(XP_WIN)
129
#if defined(XP_MACOSX)
130
    , mShWidth(0)
131
    , mShHeight(0)
132
    , mShColorSpace(nullptr)
133
#endif
134
0
{
135
#if defined(OS_WIN)
136
    if (!sPluginInstanceList) {
137
        sPluginInstanceList = new nsClassHashtable<nsVoidPtrHashKey, PluginInstanceParent>();
138
    }
139
#endif
140
}
141
142
PluginInstanceParent::~PluginInstanceParent()
143
0
{
144
0
    if (mNPP)
145
0
        mNPP->pdata = nullptr;
146
0
147
#if defined(OS_WIN)
148
    NS_ASSERTION(!(mPluginHWND || mPluginWndProc),
149
        "Subclass was not reset correctly before the dtor was reached!");
150
#endif
151
#if defined(MOZ_WIDGET_COCOA)
152
    if (mShWidth != 0 && mShHeight != 0) {
153
        DeallocShmem(mShSurface);
154
    }
155
    if (mShColorSpace)
156
        ::CGColorSpaceRelease(mShColorSpace);
157
#endif
158
}
159
160
bool
161
PluginInstanceParent::InitMetadata(const nsACString& aMimeType,
162
                                   const nsACString& aSrcAttribute)
163
0
{
164
0
    if (aSrcAttribute.IsEmpty()) {
165
0
        return false;
166
0
    }
167
0
    // Ensure that the src attribute is absolute
168
0
    RefPtr<nsPluginInstanceOwner> owner = GetOwner();
169
0
    if (!owner) {
170
0
        return false;
171
0
    }
172
0
    nsCOMPtr<nsIURI> baseUri(owner->GetBaseURI());
173
0
    return NS_SUCCEEDED(NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri));
174
0
}
175
176
void
177
PluginInstanceParent::ActorDestroy(ActorDestroyReason why)
178
0
{
179
#if defined(OS_WIN)
180
    if (why == AbnormalShutdown) {
181
        // If the plugin process crashes, this is the only
182
        // chance we get to destroy resources.
183
        UnsubclassPluginWindow();
184
    }
185
#endif
186
0
    if (mFrontSurface) {
187
0
        mFrontSurface = nullptr;
188
0
        if (mImageContainer) {
189
0
            mImageContainer->ClearAllImages();
190
0
        }
191
0
#ifdef MOZ_X11
192
0
        FinishX(DefaultXDisplay());
193
0
#endif
194
0
    }
195
0
    if (IsUsingDirectDrawing() && mImageContainer) {
196
0
        mImageContainer->ClearAllImages();
197
0
    }
198
0
}
199
200
NPError
201
PluginInstanceParent::Destroy()
202
0
{
203
0
    NPError retval;
204
0
    if (!CallNPP_Destroy(&retval)) {
205
0
        retval = NPERR_GENERIC_ERROR;
206
0
    }
207
0
208
#if defined(OS_WIN)
209
    UnsubclassPluginWindow();
210
#endif
211
212
0
    return retval;
213
0
}
214
215
bool
216
PluginInstanceParent::IsUsingDirectDrawing()
217
0
{
218
0
    return IsDrawingModelDirect(mDrawingModel);
219
0
}
220
221
PBrowserStreamParent*
222
PluginInstanceParent::AllocPBrowserStreamParent(const nsCString& url,
223
                                                const uint32_t& length,
224
                                                const uint32_t& lastmodified,
225
                                                PStreamNotifyParent* notifyData,
226
                                                const nsCString& headers)
227
0
{
228
0
    MOZ_CRASH("Not reachable");
229
0
    return nullptr;
230
0
}
231
232
bool
233
PluginInstanceParent::DeallocPBrowserStreamParent(PBrowserStreamParent* stream)
234
0
{
235
0
    delete stream;
236
0
    return true;
237
0
}
238
239
240
mozilla::ipc::IPCResult
241
PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
242
                                                            NPError* result)
243
0
{
244
#ifdef XP_WIN
245
    HWND id;
246
#elif defined(MOZ_X11)
247
    XID id;
248
#elif defined(XP_DARWIN)
249
    intptr_t id;
250
#elif defined(ANDROID)
251
    // TODO: Need Android impl
252
    int id;
253
#else
254
#warning Implement me
255
#endif
256
257
0
    *result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow, &id);
258
0
    *value = id;
259
0
    return IPC_OK();
260
0
}
261
262
bool
263
PluginInstanceParent::InternalGetValueForNPObject(
264
                                         NPNVariable aVariable,
265
                                         PPluginScriptableObjectParent** aValue,
266
                                         NPError* aResult)
267
0
{
268
0
    NPObject* npobject;
269
0
    NPError result = mNPNIface->getvalue(mNPP, aVariable, (void*)&npobject);
270
0
    if (result == NPERR_NO_ERROR) {
271
0
        NS_ASSERTION(npobject, "Shouldn't return null and NPERR_NO_ERROR!");
272
0
273
0
        PluginScriptableObjectParent* actor = GetActorForNPObject(npobject);
274
0
        mNPNIface->releaseobject(npobject);
275
0
        if (actor) {
276
0
            *aValue = actor;
277
0
            *aResult = NPERR_NO_ERROR;
278
0
            return true;
279
0
        }
280
0
281
0
        NS_ERROR("Failed to get actor!");
282
0
        result = NPERR_GENERIC_ERROR;
283
0
    }
284
0
285
0
    *aValue = nullptr;
286
0
    *aResult = result;
287
0
    return true;
288
0
}
289
290
mozilla::ipc::IPCResult
291
PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
292
                                         PPluginScriptableObjectParent** aValue,
293
                                         NPError* aResult)
294
0
{
295
0
    if (!InternalGetValueForNPObject(NPNVWindowNPObject, aValue, aResult)) {
296
0
      return IPC_FAIL_NO_REASON(this);
297
0
    }
298
0
    return IPC_OK();
299
0
}
300
301
mozilla::ipc::IPCResult
302
PluginInstanceParent::AnswerNPN_GetValue_NPNVPluginElementNPObject(
303
                                         PPluginScriptableObjectParent** aValue,
304
                                         NPError* aResult)
305
0
{
306
0
    if (!InternalGetValueForNPObject(NPNVPluginElementNPObject, aValue,
307
0
                                     aResult)) {
308
0
      return IPC_FAIL_NO_REASON(this);
309
0
    }
310
0
    return IPC_OK();
311
0
}
312
313
mozilla::ipc::IPCResult
314
PluginInstanceParent::AnswerNPN_GetValue_NPNVprivateModeBool(bool* value,
315
                                                             NPError* result)
316
0
{
317
0
    NPBool v;
318
0
    *result = mNPNIface->getvalue(mNPP, NPNVprivateModeBool, &v);
319
0
    *value = v;
320
0
    return IPC_OK();
321
0
}
322
323
mozilla::ipc::IPCResult
324
PluginInstanceParent::AnswerNPN_GetValue_DrawingModelSupport(const NPNVariable& model, bool* value)
325
0
{
326
0
    *value = false;
327
0
    return IPC_OK();
328
0
}
329
330
mozilla::ipc::IPCResult
331
PluginInstanceParent::AnswerNPN_GetValue_NPNVdocumentOrigin(nsCString* value,
332
                                                            NPError* result)
333
0
{
334
0
    void *v = nullptr;
335
0
    *result = mNPNIface->getvalue(mNPP, NPNVdocumentOrigin, &v);
336
0
    if (*result == NPERR_NO_ERROR && v) {
337
0
        value->Adopt(static_cast<char*>(v));
338
0
    }
339
0
    return IPC_OK();
340
0
}
341
342
static inline bool
343
AllowDirectBitmapSurfaceDrawing()
344
0
{
345
0
    if (!gfxPrefs::PluginAsyncDrawingEnabled()) {
346
0
        return false;
347
0
    }
348
0
    return gfxPlatform::GetPlatform()->SupportsPluginDirectBitmapDrawing();
349
0
}
350
351
static inline bool
352
AllowDirectDXGISurfaceDrawing()
353
0
{
354
0
    if (!gfxPrefs::PluginAsyncDrawingEnabled()) {
355
0
        return false;
356
0
    }
357
#if defined(XP_WIN)
358
    return gfxWindowsPlatform::GetPlatform()->SupportsPluginDirectDXGIDrawing();
359
#else
360
0
    return false;
361
0
#endif
362
0
}
363
364
mozilla::ipc::IPCResult
365
PluginInstanceParent::AnswerNPN_GetValue_SupportsAsyncBitmapSurface(bool* value)
366
0
{
367
0
    *value = AllowDirectBitmapSurfaceDrawing();
368
0
    return IPC_OK();
369
0
}
370
371
mozilla::ipc::IPCResult
372
PluginInstanceParent::AnswerNPN_GetValue_SupportsAsyncDXGISurface(bool* value)
373
0
{
374
0
    *value = AllowDirectDXGISurfaceDrawing();
375
0
    return IPC_OK();
376
0
}
377
378
mozilla::ipc::IPCResult
379
PluginInstanceParent::AnswerNPN_GetValue_PreferredDXGIAdapter(DxgiAdapterDesc* aOutDesc)
380
0
{
381
0
    PodZero(aOutDesc);
382
#ifdef XP_WIN
383
    if (!AllowDirectDXGISurfaceDrawing()) {
384
        return IPC_FAIL_NO_REASON(this);
385
    }
386
387
    RefPtr<ID3D11Device> device = DeviceManagerDx::Get()->GetContentDevice();
388
    if (!device) {
389
        return IPC_FAIL_NO_REASON(this);
390
    }
391
392
    RefPtr<IDXGIDevice> dxgi;
393
    if (FAILED(device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgi))) || !dxgi) {
394
        return IPC_FAIL_NO_REASON(this);
395
    }
396
    RefPtr<IDXGIAdapter> adapter;
397
    if (FAILED(dxgi->GetAdapter(getter_AddRefs(adapter))) || !adapter) {
398
        return IPC_FAIL_NO_REASON(this);
399
    }
400
401
    DXGI_ADAPTER_DESC desc;
402
    if (FAILED(adapter->GetDesc(&desc))) {
403
        return IPC_FAIL_NO_REASON(this);
404
    }
405
406
    *aOutDesc = DxgiAdapterDesc::From(desc);
407
#endif
408
0
    return IPC_OK();
409
0
}
410
411
mozilla::ipc::IPCResult
412
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
413
    const bool& windowed, NPError* result)
414
0
{
415
0
    // Yes, we are passing a boolean as a void*.  We have to cast to intptr_t
416
0
    // first to avoid gcc warnings about casting to a pointer from a
417
0
    // non-pointer-sized integer.
418
0
    *result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
419
0
                                  (void*)(intptr_t)windowed);
420
0
    return IPC_OK();
421
0
}
422
423
mozilla::ipc::IPCResult
424
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginTransparent(
425
    const bool& transparent, NPError* result)
426
0
{
427
0
    *result = mNPNIface->setvalue(mNPP, NPPVpluginTransparentBool,
428
0
                                  (void*)(intptr_t)transparent);
429
0
    return IPC_OK();
430
0
}
431
432
mozilla::ipc::IPCResult
433
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginUsesDOMForCursor(
434
    const bool& useDOMForCursor, NPError* result)
435
0
{
436
0
    *result = mNPNIface->setvalue(mNPP, NPPVpluginUsesDOMForCursorBool,
437
0
                                  (void*)(intptr_t)useDOMForCursor);
438
0
    return IPC_OK();
439
0
}
440
441
mozilla::ipc::IPCResult
442
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
443
    const int& drawingModel, NPError* result)
444
0
{
445
0
    bool allowed = false;
446
0
447
0
    switch (drawingModel) {
448
#if defined(XP_MACOSX)
449
        case NPDrawingModelCoreAnimation:
450
        case NPDrawingModelInvalidatingCoreAnimation:
451
        case NPDrawingModelOpenGL:
452
        case NPDrawingModelCoreGraphics:
453
            allowed = true;
454
            break;
455
#elif defined(XP_WIN)
456
        case NPDrawingModelSyncWin:
457
            allowed = true;
458
            break;
459
        case NPDrawingModelAsyncWindowsDXGISurface:
460
            allowed = AllowDirectDXGISurfaceDrawing();
461
            break;
462
#elif defined(MOZ_X11)
463
0
        case NPDrawingModelSyncX:
464
0
            allowed = true;
465
0
            break;
466
0
#endif
467
0
        case NPDrawingModelAsyncBitmapSurface:
468
0
            allowed = AllowDirectBitmapSurfaceDrawing();
469
0
            break;
470
0
        default:
471
0
            allowed = false;
472
0
            break;
473
0
    }
474
0
475
0
    if (!allowed) {
476
0
        *result = NPERR_GENERIC_ERROR;
477
0
        return IPC_OK();
478
0
    }
479
0
480
0
    mDrawingModel = drawingModel;
481
0
482
0
    int requestModel = drawingModel;
483
0
484
#ifdef XP_MACOSX
485
    if (drawingModel == NPDrawingModelCoreAnimation ||
486
        drawingModel == NPDrawingModelInvalidatingCoreAnimation) {
487
        // We need to request CoreGraphics otherwise
488
        // the nsPluginFrame will try to draw a CALayer
489
        // that can not be shared across process.
490
        requestModel = NPDrawingModelCoreGraphics;
491
    }
492
#endif
493
494
0
    *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
495
0
                                  (void*)(intptr_t)requestModel);
496
0
497
0
    return IPC_OK();
498
0
}
499
500
mozilla::ipc::IPCResult
501
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
502
    const int& eventModel, NPError* result)
503
0
{
504
#ifdef XP_MACOSX
505
    *result = mNPNIface->setvalue(mNPP, NPPVpluginEventModel,
506
                                  (void*)(intptr_t)eventModel);
507
    return IPC_OK();
508
#else
509
0
    *result = NPERR_GENERIC_ERROR;
510
0
    return IPC_OK();
511
0
#endif
512
0
}
513
514
mozilla::ipc::IPCResult
515
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginIsPlayingAudio(
516
    const bool& isAudioPlaying, NPError* result)
517
0
{
518
0
    *result = mNPNIface->setvalue(mNPP, NPPVpluginIsPlayingAudio,
519
0
                                  (void*)(intptr_t)isAudioPlaying);
520
0
    return IPC_OK();
521
0
}
522
523
mozilla::ipc::IPCResult
524
PluginInstanceParent::AnswerNPN_GetURL(const nsCString& url,
525
                                       const nsCString& target,
526
                                       NPError* result)
527
0
{
528
0
    *result = mNPNIface->geturl(mNPP,
529
0
                                NullableStringGet(url),
530
0
                                NullableStringGet(target));
531
0
    return IPC_OK();
532
0
}
533
534
mozilla::ipc::IPCResult
535
PluginInstanceParent::AnswerNPN_PostURL(const nsCString& url,
536
                                        const nsCString& target,
537
                                        const nsCString& buffer,
538
                                        const bool& file,
539
                                        NPError* result)
540
0
{
541
0
    *result = mNPNIface->posturl(mNPP, url.get(), NullableStringGet(target),
542
0
                                 buffer.Length(), buffer.get(), file);
543
0
    return IPC_OK();
544
0
}
545
546
PStreamNotifyParent*
547
PluginInstanceParent::AllocPStreamNotifyParent(const nsCString& url,
548
                                               const nsCString& target,
549
                                               const bool& post,
550
                                               const nsCString& buffer,
551
                                               const bool& file,
552
                                               NPError* result)
553
0
{
554
0
    return new StreamNotifyParent();
555
0
}
556
557
mozilla::ipc::IPCResult
558
PluginInstanceParent::AnswerPStreamNotifyConstructor(PStreamNotifyParent* actor,
559
                                                     const nsCString& url,
560
                                                     const nsCString& target,
561
                                                     const bool& post,
562
                                                     const nsCString& buffer,
563
                                                     const bool& file,
564
                                                     NPError* result)
565
0
{
566
0
    bool streamDestroyed = false;
567
0
    static_cast<StreamNotifyParent*>(actor)->
568
0
        SetDestructionFlag(&streamDestroyed);
569
0
570
0
    if (!post) {
571
0
        *result = mNPNIface->geturlnotify(mNPP,
572
0
                                          NullableStringGet(url),
573
0
                                          NullableStringGet(target),
574
0
                                          actor);
575
0
    }
576
0
    else {
577
0
        *result = mNPNIface->posturlnotify(mNPP,
578
0
                                           NullableStringGet(url),
579
0
                                           NullableStringGet(target),
580
0
                                           buffer.Length(),
581
0
                                           NullableStringGet(buffer),
582
0
                                           file, actor);
583
0
    }
584
0
585
0
    if (streamDestroyed) {
586
0
        // If the stream was destroyed, we must return an error code in the
587
0
        // constructor.
588
0
        *result = NPERR_GENERIC_ERROR;
589
0
    }
590
0
    else {
591
0
        static_cast<StreamNotifyParent*>(actor)->ClearDestructionFlag();
592
0
        if (*result != NPERR_NO_ERROR) {
593
0
            if (!PStreamNotifyParent::Send__delete__(actor,
594
0
                                                     NPERR_GENERIC_ERROR)) {
595
0
              return IPC_FAIL_NO_REASON(this);
596
0
            }
597
0
            return IPC_OK();
598
0
        }
599
0
    }
600
0
601
0
    return IPC_OK();
602
0
}
603
604
bool
605
PluginInstanceParent::DeallocPStreamNotifyParent(PStreamNotifyParent* notifyData)
606
0
{
607
0
    delete notifyData;
608
0
    return true;
609
0
}
610
611
mozilla::ipc::IPCResult
612
PluginInstanceParent::RecvNPN_InvalidateRect(const NPRect& rect)
613
0
{
614
0
    mNPNIface->invalidaterect(mNPP, const_cast<NPRect*>(&rect));
615
0
    return IPC_OK();
616
0
}
617
618
mozilla::ipc::IPCResult
619
PluginInstanceParent::RecvRevokeCurrentDirectSurface()
620
0
{
621
0
    ImageContainer *container = GetImageContainer();
622
0
    if (!container) {
623
0
        return IPC_OK();
624
0
    }
625
0
626
0
    container->ClearAllImages();
627
0
628
0
    PLUGIN_LOG_DEBUG(("   (RecvRevokeCurrentDirectSurface)"));
629
0
    return IPC_OK();
630
0
}
631
632
mozilla::ipc::IPCResult
633
PluginInstanceParent::RecvInitDXGISurface(const gfx::SurfaceFormat& format,
634
                                           const gfx::IntSize& size,
635
                                           WindowsHandle* outHandle,
636
                                           NPError* outError)
637
0
{
638
0
    *outHandle = 0;
639
0
    *outError = NPERR_GENERIC_ERROR;
640
0
641
#if defined(XP_WIN)
642
    if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
643
        *outError = NPERR_INVALID_PARAM;
644
        return IPC_OK();
645
    }
646
    if (size.width <= 0 || size.height <= 0) {
647
        *outError = NPERR_INVALID_PARAM;
648
        return IPC_OK();
649
    }
650
651
    ImageContainer *container = GetImageContainer();
652
    if (!container) {
653
        return IPC_OK();
654
    }
655
656
    RefPtr<ImageBridgeChild> forwarder = ImageBridgeChild::GetSingleton();
657
    if (!forwarder) {
658
        return IPC_OK();
659
    }
660
661
    RefPtr<ID3D11Device> d3d11 = DeviceManagerDx::Get()->GetContentDevice();
662
    if (!d3d11) {
663
        return IPC_OK();
664
    }
665
666
    // Create the texture we'll give to the plugin process.
667
    HANDLE sharedHandle = 0;
668
    RefPtr<ID3D11Texture2D> back;
669
    {
670
        CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, size.width, size.height, 1, 1);
671
        desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
672
        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
673
        if (FAILED(d3d11->CreateTexture2D(&desc, nullptr, getter_AddRefs(back))) || !back) {
674
            return IPC_OK();
675
        }
676
677
        RefPtr<IDXGIResource> resource;
678
        if (FAILED(back->QueryInterface(IID_IDXGIResource, getter_AddRefs(resource))) || !resource) {
679
            return IPC_OK();
680
        }
681
        if (FAILED(resource->GetSharedHandle(&sharedHandle) || !sharedHandle)) {
682
            return IPC_OK();
683
        }
684
    }
685
686
    RefPtr<D3D11SurfaceHolder> holder = new D3D11SurfaceHolder(back, format, size);
687
    mD3D11Surfaces.Put(reinterpret_cast<void*>(sharedHandle), holder);
688
689
    *outHandle = reinterpret_cast<uintptr_t>(sharedHandle);
690
    *outError = NPERR_NO_ERROR;
691
#endif
692
0
    return IPC_OK();
693
0
}
694
695
mozilla::ipc::IPCResult
696
PluginInstanceParent::RecvFinalizeDXGISurface(const WindowsHandle& handle)
697
0
{
698
#if defined(XP_WIN)
699
    mD3D11Surfaces.Remove(reinterpret_cast<void*>(handle));
700
#endif
701
0
    return IPC_OK();
702
0
}
703
704
mozilla::ipc::IPCResult
705
PluginInstanceParent::RecvShowDirectBitmap(Shmem&& buffer,
706
                                           const SurfaceFormat& format,
707
                                           const uint32_t& stride,
708
                                           const IntSize& size,
709
                                           const IntRect& dirty)
710
0
{
711
0
    // Validate format.
712
0
    if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) {
713
0
        MOZ_ASSERT_UNREACHABLE("bad format type");
714
0
        return IPC_FAIL_NO_REASON(this);
715
0
    }
716
0
    if (size.width <= 0 || size.height <= 0) {
717
0
        MOZ_ASSERT_UNREACHABLE("bad image size");
718
0
        return IPC_FAIL_NO_REASON(this);
719
0
    }
720
0
    if (mDrawingModel != NPDrawingModelAsyncBitmapSurface) {
721
0
        MOZ_ASSERT_UNREACHABLE("plugin did not set a bitmap drawing model");
722
0
        return IPC_FAIL_NO_REASON(this);
723
0
    }
724
0
725
0
    // Validate buffer and size.
726
0
    CheckedInt<uint32_t> nbytes = CheckedInt<uint32_t>(uint32_t(size.height)) * stride;
727
0
    if (!nbytes.isValid() || nbytes.value() != buffer.Size<uint8_t>()) {
728
0
        MOZ_ASSERT_UNREACHABLE("bad shmem size");
729
0
        return IPC_FAIL_NO_REASON(this);
730
0
    }
731
0
732
0
    ImageContainer* container = GetImageContainer();
733
0
    if (!container) {
734
0
        return IPC_FAIL_NO_REASON(this);
735
0
    }
736
0
737
0
    RefPtr<gfx::DataSourceSurface> source =
738
0
        gfx::Factory::CreateWrappingDataSourceSurface(buffer.get<uint8_t>(), stride, size, format);
739
0
    if (!source) {
740
0
        return IPC_FAIL_NO_REASON(this);
741
0
    }
742
0
743
0
    // Allocate a texture for the compositor.
744
0
    RefPtr<TextureClientRecycleAllocator> allocator = mParent->EnsureTextureAllocatorForDirectBitmap();
745
0
    RefPtr<TextureClient> texture = allocator->CreateOrRecycle(
746
0
        format, size, BackendSelector::Content,
747
0
        TextureFlags::NO_FLAGS,
748
0
        TextureAllocationFlags(ALLOC_FOR_OUT_OF_BAND_CONTENT | ALLOC_UPDATE_FROM_SURFACE));
749
0
    if (!texture) {
750
0
        NS_WARNING("Could not allocate a TextureClient for plugin!");
751
0
        return IPC_FAIL_NO_REASON(this);
752
0
    }
753
0
754
0
    // Upload the plugin buffer.
755
0
    {
756
0
        TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
757
0
        if (!autoLock.Succeeded()) {
758
0
            return IPC_FAIL_NO_REASON(this);
759
0
        }
760
0
        texture->UpdateFromSurface(source);
761
0
    }
762
0
763
0
    // Wrap the texture in an image and ship it off.
764
0
    RefPtr<TextureWrapperImage> image =
765
0
        new TextureWrapperImage(texture, gfx::IntRect(gfx::IntPoint(0, 0), size));
766
0
    SetCurrentImage(image);
767
0
768
0
    PLUGIN_LOG_DEBUG(("   (RecvShowDirectBitmap received shmem=%p stride=%d size=%s dirty=%s)",
769
0
        buffer.get<unsigned char>(), stride, Stringify(size).c_str(), Stringify(dirty).c_str()));
770
0
    return IPC_OK();
771
0
}
772
773
void
774
PluginInstanceParent::SetCurrentImage(Image* aImage)
775
0
{
776
0
    MOZ_ASSERT(IsUsingDirectDrawing());
777
0
    ImageContainer::NonOwningImage holder(aImage);
778
0
    holder.mFrameID = ++mFrameID;
779
0
780
0
    AutoTArray<ImageContainer::NonOwningImage,1> imageList;
781
0
    imageList.AppendElement(holder);
782
0
    mImageContainer->SetCurrentImages(imageList);
783
0
784
0
    // Invalidate our area in the page so the image gets flushed.
785
0
    gfx::IntRect rect = aImage->GetPictureRect();
786
0
    NPRect nprect = {uint16_t(rect.x), uint16_t(rect.y), uint16_t(rect.width), uint16_t(rect.height)};
787
0
    RecvNPN_InvalidateRect(nprect);
788
0
789
0
    RecordDrawingModel();
790
0
}
791
792
mozilla::ipc::IPCResult
793
PluginInstanceParent::RecvShowDirectDXGISurface(const WindowsHandle& handle,
794
                                                 const gfx::IntRect& dirty)
795
0
{
796
#if defined(XP_WIN)
797
    RefPtr<D3D11SurfaceHolder> surface;
798
    if (!mD3D11Surfaces.Get(reinterpret_cast<void*>(handle), getter_AddRefs(surface))) {
799
        return IPC_FAIL_NO_REASON(this);
800
    }
801
    if (!surface->IsValid()) {
802
        return IPC_FAIL_NO_REASON(this);
803
    }
804
805
    ImageContainer* container = GetImageContainer();
806
    if (!container) {
807
        return IPC_FAIL_NO_REASON(this);
808
    }
809
810
    RefPtr<TextureClientRecycleAllocator> allocator = mParent->EnsureTextureAllocatorForDXGISurface();
811
    RefPtr<TextureClient> texture = allocator->CreateOrRecycle(
812
        surface->GetFormat(), surface->GetSize(),
813
        BackendSelector::Content,
814
        TextureFlags::NO_FLAGS,
815
        ALLOC_FOR_OUT_OF_BAND_CONTENT);
816
    if (!texture) {
817
        NS_WARNING("Could not allocate a TextureClient for plugin!");
818
        return IPC_FAIL_NO_REASON(this);
819
    }
820
821
    surface->CopyToTextureClient(texture);
822
823
    gfx::IntSize size(surface->GetSize());
824
    gfx::IntRect pictureRect(gfx::IntPoint(0, 0), size);
825
826
    // Wrap the texture in an image and ship it off.
827
    RefPtr<TextureWrapperImage> image = new TextureWrapperImage(texture, pictureRect);
828
    SetCurrentImage(image);
829
830
    PLUGIN_LOG_DEBUG(("   (RecvShowDirect3D10Surface received handle=%p rect=%s)",
831
        reinterpret_cast<void*>(handle), Stringify(dirty).c_str()));
832
    return IPC_OK();
833
#else
834
0
    return IPC_FAIL_NO_REASON(this);
835
0
#endif
836
0
}
837
838
mozilla::ipc::IPCResult
839
PluginInstanceParent::RecvShow(const NPRect& updatedRect,
840
                               const SurfaceDescriptor& newSurface,
841
                               SurfaceDescriptor* prevSurface)
842
0
{
843
0
    PLUGIN_LOG_DEBUG(
844
0
        ("[InstanceParent][%p] RecvShow for <x=%d,y=%d, w=%d,h=%d>",
845
0
         this, updatedRect.left, updatedRect.top,
846
0
         updatedRect.right - updatedRect.left,
847
0
         updatedRect.bottom - updatedRect.top));
848
0
849
0
    MOZ_ASSERT(!IsUsingDirectDrawing());
850
0
851
0
    // XXXjwatt rewrite to use Moz2D
852
0
    RefPtr<gfxASurface> surface;
853
0
    if (newSurface.type() == SurfaceDescriptor::TShmem) {
854
0
        if (!newSurface.get_Shmem().IsReadable()) {
855
0
            NS_WARNING("back surface not readable");
856
0
            return IPC_FAIL_NO_REASON(this);
857
0
        }
858
0
        surface = gfxSharedImageSurface::Open(newSurface.get_Shmem());
859
0
    }
860
#ifdef XP_MACOSX
861
    else if (newSurface.type() == SurfaceDescriptor::TIOSurfaceDescriptor) {
862
        IOSurfaceDescriptor iodesc = newSurface.get_IOSurfaceDescriptor();
863
864
        RefPtr<MacIOSurface> newIOSurface =
865
          MacIOSurface::LookupSurface(iodesc.surfaceId(),
866
                                      iodesc.contentsScaleFactor());
867
868
        if (!newIOSurface) {
869
            NS_WARNING("Got bad IOSurfaceDescriptor in RecvShow");
870
            return IPC_FAIL_NO_REASON(this);
871
        }
872
873
        if (mFrontIOSurface)
874
            *prevSurface = IOSurfaceDescriptor(mFrontIOSurface->GetIOSurfaceID(),
875
                                               mFrontIOSurface->GetContentsScaleFactor());
876
        else
877
            *prevSurface = null_t();
878
879
        mFrontIOSurface = newIOSurface;
880
881
        RecvNPN_InvalidateRect(updatedRect);
882
883
        PLUGIN_LOG_DEBUG(("   (RecvShow invalidated for surface %p)",
884
                          mFrontSurface.get()));
885
886
        return IPC_OK();
887
    }
888
#endif
889
#ifdef MOZ_X11
890
0
    else if (newSurface.type() == SurfaceDescriptor::TSurfaceDescriptorX11) {
891
0
        surface = newSurface.get_SurfaceDescriptorX11().OpenForeign();
892
0
    }
893
0
#endif
894
#ifdef XP_WIN
895
    else if (newSurface.type() == SurfaceDescriptor::TPPluginSurfaceParent) {
896
        PluginSurfaceParent* s =
897
            static_cast<PluginSurfaceParent*>(newSurface.get_PPluginSurfaceParent());
898
        surface = s->Surface();
899
    }
900
#endif
901
902
0
    if (mFrontSurface) {
903
0
        // This is the "old front buffer" we're about to hand back to
904
0
        // the plugin.  We might still have drawing operations
905
0
        // referencing it.
906
0
#ifdef MOZ_X11
907
0
        if (mFrontSurface->GetType() == gfxSurfaceType::Xlib) {
908
0
            // Finish with the surface and XSync here to ensure the server has
909
0
            // finished operations on the surface before the plugin starts
910
0
            // scribbling on it again, or worse, destroys it.
911
0
            mFrontSurface->Finish();
912
0
            FinishX(DefaultXDisplay());
913
0
        } else
914
0
#endif
915
0
        {
916
0
            mFrontSurface->Flush();
917
0
        }
918
0
    }
919
0
920
0
    if (mFrontSurface && gfxSharedImageSurface::IsSharedImage(mFrontSurface))
921
0
        *prevSurface = static_cast<gfxSharedImageSurface*>(mFrontSurface.get())->GetShmem();
922
0
    else
923
0
        *prevSurface = null_t();
924
0
925
0
    if (surface) {
926
0
        // Notify the cairo backend that this surface has changed behind
927
0
        // its back.
928
0
        gfxRect ur(updatedRect.left, updatedRect.top,
929
0
                   updatedRect.right - updatedRect.left,
930
0
                   updatedRect.bottom - updatedRect.top);
931
0
        surface->MarkDirty(ur);
932
0
933
0
        bool isPlugin = true;
934
0
        RefPtr<gfx::SourceSurface> sourceSurface =
935
0
            gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface, isPlugin);
936
0
        RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), sourceSurface);
937
0
938
0
        AutoTArray<ImageContainer::NonOwningImage,1> imageList;
939
0
        imageList.AppendElement(
940
0
            ImageContainer::NonOwningImage(image));
941
0
942
0
        ImageContainer *container = GetImageContainer();
943
0
        container->SetCurrentImages(imageList);
944
0
    }
945
0
    else if (mImageContainer) {
946
0
        mImageContainer->ClearAllImages();
947
0
    }
948
0
949
0
    mFrontSurface = surface;
950
0
    RecvNPN_InvalidateRect(updatedRect);
951
0
952
0
    PLUGIN_LOG_DEBUG(("   (RecvShow invalidated for surface %p)",
953
0
                      mFrontSurface.get()));
954
0
955
0
    RecordDrawingModel();
956
0
    return IPC_OK();
957
0
}
958
959
nsresult
960
PluginInstanceParent::AsyncSetWindow(NPWindow* aWindow)
961
0
{
962
0
    NPRemoteWindow window;
963
0
    mWindowType = aWindow->type;
964
0
    window.window = reinterpret_cast<uint64_t>(aWindow->window);
965
0
    window.x = aWindow->x;
966
0
    window.y = aWindow->y;
967
0
    window.width = aWindow->width;
968
0
    window.height = aWindow->height;
969
0
    window.clipRect = aWindow->clipRect;
970
0
    window.type = aWindow->type;
971
#if defined(XP_MACOSX) || defined(XP_WIN)
972
    double scaleFactor = 1.0;
973
    mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &scaleFactor);
974
    window.contentsScaleFactor = scaleFactor;
975
#endif
976
977
#if defined(OS_WIN)
978
    MaybeCreateChildPopupSurrogate();
979
#endif
980
981
0
    if (!SendAsyncSetWindow(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(),
982
0
                            window))
983
0
        return NS_ERROR_FAILURE;
984
0
985
0
    return NS_OK;
986
0
}
987
988
nsresult
989
PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
990
0
{
991
0
    if (IsUsingDirectDrawing()) {
992
0
        // Use the image container created by the most recent direct surface
993
0
        // call, if any. We don't create one if no surfaces were presented
994
0
        // yet.
995
0
        ImageContainer *container = mImageContainer;
996
0
        NS_IF_ADDREF(container);
997
0
        *aContainer = container;
998
0
        return NS_OK;
999
0
    }
1000
0
1001
#ifdef XP_MACOSX
1002
    MacIOSurface* ioSurface = nullptr;
1003
1004
    if (mFrontIOSurface) {
1005
      ioSurface = mFrontIOSurface;
1006
    } else if (mIOSurface) {
1007
      ioSurface = mIOSurface;
1008
    }
1009
1010
    if (!mFrontSurface && !ioSurface)
1011
#else
1012
0
    if (!mFrontSurface)
1013
0
#endif
1014
0
        return NS_ERROR_NOT_AVAILABLE;
1015
0
1016
0
    ImageContainer *container = GetImageContainer();
1017
0
1018
0
    if (!container) {
1019
0
        return NS_ERROR_FAILURE;
1020
0
    }
1021
0
1022
#ifdef XP_MACOSX
1023
    if (ioSurface) {
1024
        RefPtr<Image> image = new MacIOSurfaceImage(ioSurface);
1025
        container->SetCurrentImageInTransaction(image);
1026
1027
        NS_IF_ADDREF(container);
1028
        *aContainer = container;
1029
        return NS_OK;
1030
    }
1031
#endif
1032
1033
0
    NS_IF_ADDREF(container);
1034
0
    *aContainer = container;
1035
0
    return NS_OK;
1036
0
}
1037
1038
nsresult
1039
PluginInstanceParent::GetImageSize(nsIntSize* aSize)
1040
0
{
1041
0
    if (IsUsingDirectDrawing()) {
1042
0
        if (!mImageContainer) {
1043
0
            return NS_ERROR_NOT_AVAILABLE;
1044
0
        }
1045
0
        *aSize = mImageContainer->GetCurrentSize();
1046
0
        return NS_OK;
1047
0
    }
1048
0
1049
0
    if (mFrontSurface) {
1050
0
        mozilla::gfx::IntSize size = mFrontSurface->GetSize();
1051
0
        *aSize = nsIntSize(size.width, size.height);
1052
0
        return NS_OK;
1053
0
    }
1054
0
1055
#ifdef XP_MACOSX
1056
    if (mFrontIOSurface) {
1057
        *aSize = nsIntSize(mFrontIOSurface->GetWidth(), mFrontIOSurface->GetHeight());
1058
        return NS_OK;
1059
    } else if (mIOSurface) {
1060
        *aSize = nsIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
1061
        return NS_OK;
1062
    }
1063
#endif
1064
1065
0
    return NS_ERROR_NOT_AVAILABLE;
1066
0
}
1067
1068
void
1069
PluginInstanceParent::DidComposite()
1070
0
{
1071
0
    if (!IsUsingDirectDrawing()) {
1072
0
        return;
1073
0
    }
1074
0
    Unused << SendNPP_DidComposite();
1075
0
}
1076
1077
#ifdef XP_MACOSX
1078
nsresult
1079
PluginInstanceParent::IsRemoteDrawingCoreAnimation(bool *aDrawing)
1080
{
1081
    *aDrawing = (NPDrawingModelCoreAnimation == (NPDrawingModel)mDrawingModel ||
1082
                 NPDrawingModelInvalidatingCoreAnimation == (NPDrawingModel)mDrawingModel);
1083
    return NS_OK;
1084
}
1085
#endif
1086
#if defined(XP_MACOSX) || defined(XP_WIN)
1087
nsresult
1088
PluginInstanceParent::ContentsScaleFactorChanged(double aContentsScaleFactor)
1089
{
1090
    bool rv = SendContentsScaleFactorChanged(aContentsScaleFactor);
1091
    return rv ? NS_OK : NS_ERROR_FAILURE;
1092
}
1093
#endif // #ifdef XP_MACOSX
1094
1095
nsresult
1096
PluginInstanceParent::SetBackgroundUnknown()
1097
0
{
1098
0
    PLUGIN_LOG_DEBUG(("[InstanceParent][%p] SetBackgroundUnknown", this));
1099
0
1100
0
    if (mBackground) {
1101
0
        DestroyBackground();
1102
0
        MOZ_ASSERT(!mBackground, "Background not destroyed");
1103
0
    }
1104
0
1105
0
    return NS_OK;
1106
0
}
1107
1108
nsresult
1109
PluginInstanceParent::BeginUpdateBackground(const nsIntRect& aRect,
1110
                                            DrawTarget** aDrawTarget)
1111
0
{
1112
0
    PLUGIN_LOG_DEBUG(
1113
0
        ("[InstanceParent][%p] BeginUpdateBackground for <x=%d,y=%d, w=%d,h=%d>",
1114
0
         this, aRect.x, aRect.y, aRect.width, aRect.height));
1115
0
1116
0
    if (!mBackground) {
1117
0
        // XXX if we failed to create a background surface on one
1118
0
        // update, there's no guarantee that later updates will be for
1119
0
        // the entire background area until successful.  We might want
1120
0
        // to fix that eventually.
1121
0
        MOZ_ASSERT(aRect.TopLeft() == nsIntPoint(0, 0),
1122
0
                   "Expecting rect for whole frame");
1123
0
        if (!CreateBackground(aRect.Size())) {
1124
0
            *aDrawTarget = nullptr;
1125
0
            return NS_OK;
1126
0
        }
1127
0
    }
1128
0
1129
0
    mozilla::gfx::IntSize sz = mBackground->GetSize();
1130
#ifdef DEBUG
1131
    MOZ_ASSERT(nsIntRect(0, 0, sz.width, sz.height).Contains(aRect),
1132
               "Update outside of background area");
1133
#endif
1134
1135
0
    RefPtr<gfx::DrawTarget> dt = gfxPlatform::GetPlatform()->
1136
0
      CreateDrawTargetForSurface(mBackground, gfx::IntSize(sz.width, sz.height));
1137
0
    dt.forget(aDrawTarget);
1138
0
1139
0
    return NS_OK;
1140
0
}
1141
1142
nsresult
1143
PluginInstanceParent::EndUpdateBackground(const nsIntRect& aRect)
1144
0
{
1145
0
    PLUGIN_LOG_DEBUG(
1146
0
        ("[InstanceParent][%p] EndUpdateBackground for <x=%d,y=%d, w=%d,h=%d>",
1147
0
         this, aRect.x, aRect.y, aRect.width, aRect.height));
1148
0
1149
0
#ifdef MOZ_X11
1150
0
    // Have to XSync here to avoid the plugin trying to draw with this
1151
0
    // surface racing with its creation in the X server.  We also want
1152
0
    // to avoid the plugin drawing onto stale pixels, then handing us
1153
0
    // back a front surface from those pixels that we might
1154
0
    // recomposite for "a while" until the next update.  This XSync
1155
0
    // still doesn't guarantee that the plugin draws onto a consistent
1156
0
    // view of its background, but it does mean that the plugin is
1157
0
    // drawing onto pixels no older than those in the latest
1158
0
    // EndUpdateBackground().
1159
0
    XSync(DefaultXDisplay(), False);
1160
0
#endif
1161
0
1162
0
    Unused << SendUpdateBackground(BackgroundDescriptor(), aRect);
1163
0
1164
0
    return NS_OK;
1165
0
}
1166
1167
#if defined(XP_WIN)
1168
nsresult
1169
PluginInstanceParent::SetScrollCaptureId(uint64_t aScrollCaptureId)
1170
{
1171
  if (aScrollCaptureId == ImageContainer::sInvalidAsyncContainerId) {
1172
    return NS_ERROR_FAILURE;
1173
  }
1174
1175
  mImageContainer = new ImageContainer(CompositableHandle(aScrollCaptureId));
1176
  return NS_OK;
1177
}
1178
1179
nsresult
1180
PluginInstanceParent::GetScrollCaptureContainer(ImageContainer** aContainer)
1181
{
1182
  if (!aContainer || !mImageContainer) {
1183
    return NS_ERROR_FAILURE;
1184
  }
1185
1186
  RefPtr<ImageContainer> container = GetImageContainer();
1187
  container.forget(aContainer);
1188
1189
  return NS_OK;
1190
}
1191
#endif // XP_WIN
1192
1193
bool
1194
PluginInstanceParent::CreateBackground(const nsIntSize& aSize)
1195
0
{
1196
0
    MOZ_ASSERT(!mBackground, "Already have a background");
1197
0
1198
0
    // XXX refactor me
1199
0
1200
0
#if defined(MOZ_X11)
1201
0
    Screen* screen = DefaultScreenOfDisplay(DefaultXDisplay());
1202
0
    Visual* visual = DefaultVisualOfScreen(screen);
1203
0
    mBackground = gfxXlibSurface::Create(screen, visual,
1204
0
                                         mozilla::gfx::IntSize(aSize.width, aSize.height));
1205
0
    return !!mBackground;
1206
0
1207
#elif defined(XP_WIN)
1208
    // We have chosen to create an unsafe surface in which the plugin
1209
    // can read from the region while we're writing to it.
1210
    mBackground =
1211
        gfxSharedImageSurface::CreateUnsafe(
1212
            this,
1213
            mozilla::gfx::IntSize(aSize.width, aSize.height),
1214
            mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32);
1215
    return !!mBackground;
1216
#else
1217
    return false;
1218
#endif
1219
}
1220
1221
void
1222
PluginInstanceParent::DestroyBackground()
1223
0
{
1224
0
    if (!mBackground) {
1225
0
        return;
1226
0
    }
1227
0
1228
0
    // Relinquish ownership of |mBackground| to its destroyer
1229
0
    PPluginBackgroundDestroyerParent* pbd =
1230
0
        new PluginBackgroundDestroyerParent(mBackground);
1231
0
    mBackground = nullptr;
1232
0
1233
0
    // If this fails, there's no problem: |bd| will be destroyed along
1234
0
    // with the old background surface.
1235
0
    Unused << SendPPluginBackgroundDestroyerConstructor(pbd);
1236
0
}
1237
1238
mozilla::plugins::SurfaceDescriptor
1239
PluginInstanceParent::BackgroundDescriptor()
1240
0
{
1241
0
    MOZ_ASSERT(mBackground, "Need a background here");
1242
0
1243
0
    // XXX refactor me
1244
0
1245
0
#ifdef MOZ_X11
1246
0
    gfxXlibSurface* xsurf = static_cast<gfxXlibSurface*>(mBackground.get());
1247
0
    return SurfaceDescriptorX11(xsurf);
1248
0
#endif
1249
0
1250
#ifdef XP_WIN
1251
    MOZ_ASSERT(gfxSharedImageSurface::IsSharedImage(mBackground),
1252
               "Expected shared image surface");
1253
    gfxSharedImageSurface* shmem =
1254
        static_cast<gfxSharedImageSurface*>(mBackground.get());
1255
    return shmem->GetShmem();
1256
#endif
1257
1258
0
    // If this is ever used, which it shouldn't be, it will trigger a
1259
0
    // hard assertion in IPDL-generated code.
1260
0
    return mozilla::plugins::SurfaceDescriptor();
1261
0
}
1262
1263
ImageContainer*
1264
PluginInstanceParent::GetImageContainer()
1265
0
{
1266
0
  if (mImageContainer) {
1267
0
    return mImageContainer;
1268
0
  }
1269
0
1270
0
  if (IsUsingDirectDrawing()) {
1271
0
      mImageContainer = LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
1272
0
  } else {
1273
0
      mImageContainer = LayerManager::CreateImageContainer();
1274
0
  }
1275
0
  return mImageContainer;
1276
0
}
1277
1278
PPluginBackgroundDestroyerParent*
1279
PluginInstanceParent::AllocPPluginBackgroundDestroyerParent()
1280
0
{
1281
0
    MOZ_CRASH("'Power-user' ctor is used exclusively");
1282
0
    return nullptr;
1283
0
}
1284
1285
bool
1286
PluginInstanceParent::DeallocPPluginBackgroundDestroyerParent(
1287
    PPluginBackgroundDestroyerParent* aActor)
1288
0
{
1289
0
    delete aActor;
1290
0
    return true;
1291
0
}
1292
1293
NPError
1294
PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
1295
0
{
1296
0
    PLUGIN_LOG_DEBUG(("%s (aWindow=%p)", FULLFUNCTION, (void*) aWindow));
1297
0
1298
0
    NS_ENSURE_TRUE(aWindow, NPERR_GENERIC_ERROR);
1299
0
1300
0
    NPRemoteWindow window;
1301
0
    mWindowType = aWindow->type;
1302
0
1303
#if defined(OS_WIN)
1304
    // On windowless controls, reset the shared memory surface as needed.
1305
    if (mWindowType == NPWindowTypeDrawable) {
1306
        MaybeCreateChildPopupSurrogate();
1307
    } else {
1308
        SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
1309
1310
        window.window = reinterpret_cast<uint64_t>(aWindow->window);
1311
        window.x = aWindow->x;
1312
        window.y = aWindow->y;
1313
        window.width = aWindow->width;
1314
        window.height = aWindow->height;
1315
        window.type = aWindow->type;
1316
1317
        // On Windows we need to create and set the parent before we set the
1318
        // window on the plugin, or keyboard interaction will not work.
1319
        if (!MaybeCreateAndParentChildPluginWindow()) {
1320
            return NPERR_GENERIC_ERROR;
1321
        }
1322
    }
1323
#else
1324
    window.window = reinterpret_cast<uint64_t>(aWindow->window);
1325
0
    window.x = aWindow->x;
1326
0
    window.y = aWindow->y;
1327
0
    window.width = aWindow->width;
1328
0
    window.height = aWindow->height;
1329
0
    window.clipRect = aWindow->clipRect; // MacOS specific
1330
0
    window.type = aWindow->type;
1331
0
#endif
1332
0
1333
#if defined(XP_MACOSX) || defined(XP_WIN)
1334
    double floatScaleFactor = 1.0;
1335
    mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &floatScaleFactor);
1336
    window.contentsScaleFactor = floatScaleFactor;
1337
#endif
1338
#if defined(XP_MACOSX)
1339
    int scaleFactor = ceil(floatScaleFactor);
1340
    if (mShWidth != window.width * scaleFactor || mShHeight != window.height * scaleFactor) {
1341
        if (mDrawingModel == NPDrawingModelCoreAnimation ||
1342
            mDrawingModel == NPDrawingModelInvalidatingCoreAnimation) {
1343
            mIOSurface = MacIOSurface::CreateIOSurface(window.width, window.height,
1344
                                                       floatScaleFactor);
1345
        } else if (uint32_t(mShWidth * mShHeight) !=
1346
                   window.width * scaleFactor * window.height * scaleFactor) {
1347
            if (mShWidth != 0 && mShHeight != 0) {
1348
                DeallocShmem(mShSurface);
1349
                mShWidth = 0;
1350
                mShHeight = 0;
1351
            }
1352
1353
            if (window.width != 0 && window.height != 0) {
1354
                if (!AllocShmem(window.width * scaleFactor * window.height*4 * scaleFactor,
1355
                                SharedMemory::TYPE_BASIC, &mShSurface)) {
1356
                    PLUGIN_LOG_DEBUG(("Shared memory could not be allocated."));
1357
                    return NPERR_GENERIC_ERROR;
1358
                }
1359
            }
1360
        }
1361
        mShWidth = window.width * scaleFactor;
1362
        mShHeight = window.height * scaleFactor;
1363
    }
1364
#endif
1365
1366
0
#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
1367
0
    const NPSetWindowCallbackStruct* ws_info =
1368
0
      static_cast<NPSetWindowCallbackStruct*>(aWindow->ws_info);
1369
0
    window.visualID = ws_info->visual ? ws_info->visual->visualid : 0;
1370
0
    window.colormap = ws_info->colormap;
1371
0
#endif
1372
0
1373
0
    if (!CallNPP_SetWindow(window)) {
1374
0
        return NPERR_GENERIC_ERROR;
1375
0
    }
1376
0
1377
0
    RecordDrawingModel();
1378
0
    return NPERR_NO_ERROR;
1379
0
}
1380
1381
NPError
1382
PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
1383
                                   void* _retval)
1384
0
{
1385
0
    switch (aVariable) {
1386
0
1387
0
    case NPPVpluginWantsAllNetworkStreams: {
1388
0
        bool wantsAllStreams;
1389
0
        NPError rv;
1390
0
1391
0
        if (!CallNPP_GetValue_NPPVpluginWantsAllNetworkStreams(&wantsAllStreams, &rv)) {
1392
0
            return NPERR_GENERIC_ERROR;
1393
0
        }
1394
0
1395
0
        if (NPERR_NO_ERROR != rv) {
1396
0
            return rv;
1397
0
        }
1398
0
1399
0
        (*(NPBool*)_retval) = wantsAllStreams;
1400
0
        return NPERR_NO_ERROR;
1401
0
    }
1402
0
1403
0
    case NPPVpluginScriptableNPObject: {
1404
0
        PPluginScriptableObjectParent* actor;
1405
0
        NPError rv;
1406
0
        if (!CallNPP_GetValue_NPPVpluginScriptableNPObject(&actor, &rv)) {
1407
0
            return NPERR_GENERIC_ERROR;
1408
0
        }
1409
0
1410
0
        if (NPERR_NO_ERROR != rv) {
1411
0
            return rv;
1412
0
        }
1413
0
1414
0
        if (!actor) {
1415
0
            NS_ERROR("NPPVpluginScriptableNPObject succeeded but null.");
1416
0
            return NPERR_GENERIC_ERROR;
1417
0
        }
1418
0
1419
0
        const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
1420
0
        if (!npn) {
1421
0
            NS_WARNING("No netscape functions?!");
1422
0
            return NPERR_GENERIC_ERROR;
1423
0
        }
1424
0
1425
0
        NPObject* object =
1426
0
            static_cast<PluginScriptableObjectParent*>(actor)->GetObject(true);
1427
0
        NS_ASSERTION(object, "This shouldn't ever be null!");
1428
0
1429
0
        (*(NPObject**)_retval) = npn->retainobject(object);
1430
0
        return NPERR_NO_ERROR;
1431
0
    }
1432
0
1433
0
#ifdef MOZ_ACCESSIBILITY_ATK
1434
0
    case NPPVpluginNativeAccessibleAtkPlugId: {
1435
0
        nsCString plugId;
1436
0
        NPError rv;
1437
0
        if (!CallNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId(&plugId, &rv)) {
1438
0
            return NPERR_GENERIC_ERROR;
1439
0
        }
1440
0
1441
0
        if (NPERR_NO_ERROR != rv) {
1442
0
            return rv;
1443
0
        }
1444
0
1445
0
        (*(nsCString*)_retval) = plugId;
1446
0
        return NPERR_NO_ERROR;
1447
0
    }
1448
0
#endif
1449
0
1450
0
    default:
1451
0
        MOZ_LOG(GetPluginLog(), LogLevel::Warning,
1452
0
               ("In PluginInstanceParent::NPP_GetValue: Unhandled NPPVariable %i (%s)",
1453
0
                (int) aVariable, NPPVariableToString(aVariable)));
1454
0
        return NPERR_GENERIC_ERROR;
1455
0
    }
1456
0
}
1457
1458
NPError
1459
PluginInstanceParent::NPP_SetValue(NPNVariable variable, void* value)
1460
0
{
1461
0
    NPError result;
1462
0
    switch (variable) {
1463
0
    case NPNVprivateModeBool:
1464
0
        if (!CallNPP_SetValue_NPNVprivateModeBool(*static_cast<NPBool*>(value),
1465
0
                                                  &result))
1466
0
            return NPERR_GENERIC_ERROR;
1467
0
1468
0
        return result;
1469
0
1470
0
    case NPNVmuteAudioBool:
1471
0
        if (!CallNPP_SetValue_NPNVmuteAudioBool(*static_cast<NPBool*>(value),
1472
0
                                                &result))
1473
0
            return NPERR_GENERIC_ERROR;
1474
0
1475
0
        return result;
1476
0
1477
0
    case NPNVCSSZoomFactor:
1478
0
        if (!CallNPP_SetValue_NPNVCSSZoomFactor(*static_cast<double*>(value),
1479
0
                                                &result))
1480
0
            return NPERR_GENERIC_ERROR;
1481
0
1482
0
        return result;
1483
0
1484
0
    default:
1485
0
        NS_ERROR("Unhandled NPNVariable in NPP_SetValue");
1486
0
        MOZ_LOG(GetPluginLog(), LogLevel::Warning,
1487
0
               ("In PluginInstanceParent::NPP_SetValue: Unhandled NPNVariable %i (%s)",
1488
0
                (int) variable, NPNVariableToString(variable)));
1489
0
        return NPERR_GENERIC_ERROR;
1490
0
    }
1491
0
}
1492
1493
void
1494
PluginInstanceParent::NPP_URLRedirectNotify(const char* url, int32_t status,
1495
                                            void* notifyData)
1496
0
{
1497
0
  if (!notifyData)
1498
0
    return;
1499
0
1500
0
  PStreamNotifyParent* streamNotify = static_cast<PStreamNotifyParent*>(notifyData);
1501
0
  Unused << streamNotify->SendRedirectNotify(NullableString(url), status);
1502
0
}
1503
1504
int16_t
1505
PluginInstanceParent::NPP_HandleEvent(void* event)
1506
0
{
1507
0
    PLUGIN_LOG_DEBUG_FUNCTION;
1508
0
1509
#if defined(XP_MACOSX)
1510
    NPCocoaEvent* npevent = reinterpret_cast<NPCocoaEvent*>(event);
1511
#else
1512
    NPEvent* npevent = reinterpret_cast<NPEvent*>(event);
1513
0
#endif
1514
0
    NPRemoteEvent npremoteevent;
1515
0
    npremoteevent.event = *npevent;
1516
#if defined(XP_MACOSX) || defined(XP_WIN)
1517
    double scaleFactor = 1.0;
1518
    mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &scaleFactor);
1519
    npremoteevent.contentsScaleFactor = scaleFactor;
1520
#endif
1521
    int16_t handled = 0;
1522
0
1523
#if defined(OS_WIN)
1524
    if (mWindowType == NPWindowTypeDrawable) {
1525
        switch (npevent->event) {
1526
            case WM_KILLFOCUS:
1527
            {
1528
              // When the user selects fullscreen mode in Flash video players,
1529
              // WM_KILLFOCUS will be delayed by deferred event processing:
1530
              // WM_LBUTTONUP results in a call to CreateWindow within Flash,
1531
              // which fires WM_KILLFOCUS. Delayed delivery causes Flash to
1532
              // misinterpret the event, dropping back out of fullscreen. Trap
1533
              // this event and drop it.
1534
              wchar_t szClass[26];
1535
              HWND hwnd = GetForegroundWindow();
1536
              if (hwnd && hwnd != mPluginHWND &&
1537
                  GetClassNameW(hwnd, szClass,
1538
                                sizeof(szClass)/sizeof(char16_t)) &&
1539
                  !wcscmp(szClass, kFlashFullscreenClass)) {
1540
                  return 0;
1541
              }
1542
            }
1543
            break;
1544
1545
            case WM_WINDOWPOSCHANGED:
1546
            {
1547
                // We send this in nsPluginFrame just before painting
1548
                return SendWindowPosChanged(npremoteevent);
1549
            }
1550
1551
            case WM_IME_STARTCOMPOSITION:
1552
            case WM_IME_COMPOSITION:
1553
            case WM_IME_ENDCOMPOSITION:
1554
                if (!(mParent->GetQuirks() & QUIRK_WINLESS_HOOK_IME)) {
1555
                  // IME message will be posted on allowed plugins only such as
1556
                  // Flash.  Because if we cannot know that plugin can handle
1557
                  // IME correctly.
1558
                  return 0;
1559
                }
1560
            break;
1561
        }
1562
    }
1563
#endif
1564
1565
0
#if defined(MOZ_X11)
1566
0
    switch (npevent->type) {
1567
0
    case GraphicsExpose:
1568
0
        PLUGIN_LOG_DEBUG(("  schlepping drawable 0x%lx across the pipe\n",
1569
0
                          npevent->xgraphicsexpose.drawable));
1570
0
        // Make sure the X server has created the Drawable and completes any
1571
0
        // drawing before the plugin draws on top.
1572
0
        //
1573
0
        // XSync() waits for the X server to complete.  Really this parent
1574
0
        // process does not need to wait; the child is the process that needs
1575
0
        // to wait.  A possibly-slightly-better alternative would be to send
1576
0
        // an X event to the child that the child would wait for.
1577
0
        FinishX(DefaultXDisplay());
1578
0
1579
0
        return CallPaint(npremoteevent, &handled) ? handled : 0;
1580
0
1581
0
    case ButtonPress:
1582
0
        // Release any active pointer grab so that the plugin X client can
1583
0
        // grab the pointer if it wishes.
1584
0
        Display *dpy = DefaultXDisplay();
1585
0
#  ifdef MOZ_WIDGET_GTK
1586
0
        // GDK attempts to (asynchronously) track whether there is an active
1587
0
        // grab so ungrab through GDK.
1588
0
        //
1589
0
        // This call needs to occur in the same process that receives the event in
1590
0
        // the first place (chrome process)
1591
0
        if (XRE_IsContentProcess()) {
1592
0
          dom::ContentChild* cp = dom::ContentChild::GetSingleton();
1593
0
          cp->SendUngrabPointer(npevent->xbutton.time);
1594
0
        } else {
1595
0
          gdk_pointer_ungrab(npevent->xbutton.time);
1596
0
        }
1597
#  else
1598
        XUngrabPointer(dpy, npevent->xbutton.time);
1599
#  endif
1600
        // Wait for the ungrab to complete.
1601
0
        XSync(dpy, False);
1602
0
        break;
1603
0
    }
1604
0
#endif
1605
0
1606
#ifdef XP_MACOSX
1607
    if (npevent->type == NPCocoaEventDrawRect) {
1608
        if (mDrawingModel == NPDrawingModelCoreAnimation ||
1609
            mDrawingModel == NPDrawingModelInvalidatingCoreAnimation) {
1610
            if (!mIOSurface) {
1611
                NS_ERROR("No IOSurface allocated.");
1612
                return false;
1613
            }
1614
            if (!CallNPP_HandleEvent_IOSurface(npremoteevent,
1615
                                               mIOSurface->GetIOSurfaceID(),
1616
                                               &handled))
1617
                return false; // no good way to handle errors here...
1618
1619
            CGContextRef cgContext = npevent->data.draw.context;
1620
            if (!mShColorSpace) {
1621
                mShColorSpace = CreateSystemColorSpace();
1622
            }
1623
            if (!mShColorSpace) {
1624
                PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
1625
                return false;
1626
            }
1627
            if (cgContext) {
1628
                nsCARenderer::DrawSurfaceToCGContext(cgContext, mIOSurface,
1629
                                                     mShColorSpace,
1630
                                                     npevent->data.draw.x,
1631
                                                     npevent->data.draw.y,
1632
                                                     npevent->data.draw.width,
1633
                                                     npevent->data.draw.height);
1634
            }
1635
            return true;
1636
        } else if (mFrontIOSurface) {
1637
            CGContextRef cgContext = npevent->data.draw.context;
1638
            if (!mShColorSpace) {
1639
                mShColorSpace = CreateSystemColorSpace();
1640
            }
1641
            if (!mShColorSpace) {
1642
                PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
1643
                return false;
1644
            }
1645
            if (cgContext) {
1646
                nsCARenderer::DrawSurfaceToCGContext(cgContext, mFrontIOSurface,
1647
                                                     mShColorSpace,
1648
                                                     npevent->data.draw.x,
1649
                                                     npevent->data.draw.y,
1650
                                                     npevent->data.draw.width,
1651
                                                     npevent->data.draw.height);
1652
            }
1653
            return true;
1654
        } else {
1655
            if (mShWidth == 0 && mShHeight == 0) {
1656
                PLUGIN_LOG_DEBUG(("NPCocoaEventDrawRect on window of size 0."));
1657
                return false;
1658
            }
1659
            if (!mShSurface.IsReadable()) {
1660
                PLUGIN_LOG_DEBUG(("Shmem is not readable."));
1661
                return false;
1662
            }
1663
1664
            if (!CallNPP_HandleEvent_Shmem(npremoteevent, mShSurface,
1665
                                           &handled, &mShSurface))
1666
                return false; // no good way to handle errors here...
1667
1668
            if (!mShSurface.IsReadable()) {
1669
                PLUGIN_LOG_DEBUG(("Shmem not returned. Either the plugin crashed "
1670
                                  "or we have a bug."));
1671
                return false;
1672
            }
1673
1674
            char* shContextByte = mShSurface.get<char>();
1675
1676
            if (!mShColorSpace) {
1677
                mShColorSpace = CreateSystemColorSpace();
1678
            }
1679
            if (!mShColorSpace) {
1680
                PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
1681
                return false;
1682
            }
1683
            CGContextRef shContext = ::CGBitmapContextCreate(shContextByte,
1684
                                    mShWidth, mShHeight, 8,
1685
                                    mShWidth*4, mShColorSpace,
1686
                                    kCGImageAlphaPremultipliedFirst |
1687
                                    kCGBitmapByteOrder32Host);
1688
            if (!shContext) {
1689
                PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext."));
1690
                return false;
1691
            }
1692
1693
            CGImageRef shImage = ::CGBitmapContextCreateImage(shContext);
1694
            if (shImage) {
1695
                CGContextRef cgContext = npevent->data.draw.context;
1696
1697
                ::CGContextDrawImage(cgContext,
1698
                                     CGRectMake(0,0,mShWidth,mShHeight),
1699
                                     shImage);
1700
                ::CGImageRelease(shImage);
1701
            } else {
1702
                ::CGContextRelease(shContext);
1703
                return false;
1704
            }
1705
            ::CGContextRelease(shContext);
1706
            return true;
1707
        }
1708
    }
1709
#endif
1710
1711
0
    if (!CallNPP_HandleEvent(npremoteevent, &handled))
1712
0
        return 0; // no good way to handle errors here...
1713
0
1714
0
    return handled;
1715
0
}
1716
1717
NPError
1718
PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
1719
                                    NPBool seekable, uint16_t* stype)
1720
0
{
1721
0
    PLUGIN_LOG_DEBUG(("%s (type=%s, stream=%p, seekable=%i)",
1722
0
                      FULLFUNCTION, (char*) type, (void*) stream, (int) seekable));
1723
0
1724
0
    BrowserStreamParent* bs = new BrowserStreamParent(this, stream);
1725
0
1726
0
    if (!SendPBrowserStreamConstructor(bs,
1727
0
                                       NullableString(stream->url),
1728
0
                                       stream->end,
1729
0
                                       stream->lastmodified,
1730
0
                                       static_cast<PStreamNotifyParent*>(stream->notifyData),
1731
0
                                       NullableString(stream->headers))) {
1732
0
        return NPERR_GENERIC_ERROR;
1733
0
    }
1734
0
1735
0
    NPError err = NPERR_NO_ERROR;
1736
0
    bs->SetAlive();
1737
0
    if (!CallNPP_NewStream(bs, NullableString(type), seekable, &err, stype)) {
1738
0
        err = NPERR_GENERIC_ERROR;
1739
0
    }
1740
0
    if (NPERR_NO_ERROR != err) {
1741
0
        Unused << PBrowserStreamParent::Send__delete__(bs);
1742
0
    }
1743
0
1744
0
    return err;
1745
0
}
1746
1747
NPError
1748
PluginInstanceParent::NPP_DestroyStream(NPStream* stream, NPReason reason)
1749
0
{
1750
0
    PLUGIN_LOG_DEBUG(("%s (stream=%p, reason=%i)",
1751
0
                      FULLFUNCTION, (void*) stream, (int) reason));
1752
0
1753
0
    AStream* s = static_cast<AStream*>(stream->pdata);
1754
0
    if (!s) {
1755
0
        // The stream has already been deleted by other means.
1756
0
        // With async plugin init this could happen if async NPP_NewStream
1757
0
        // returns an error code.
1758
0
        return NPERR_NO_ERROR;
1759
0
    }
1760
0
    MOZ_ASSERT(s->IsBrowserStream());
1761
0
    BrowserStreamParent* sp =
1762
0
        static_cast<BrowserStreamParent*>(s);
1763
0
    if (sp->mNPP != this)
1764
0
        MOZ_CRASH("Mismatched plugin data");
1765
0
    sp->NPP_DestroyStream(reason);
1766
0
    return NPERR_NO_ERROR;
1767
0
}
1768
1769
void
1770
PluginInstanceParent::NPP_Print(NPPrint* platformPrint)
1771
0
{
1772
0
    // TODO: implement me
1773
0
    NS_ERROR("Not implemented");
1774
0
}
1775
1776
PPluginScriptableObjectParent*
1777
PluginInstanceParent::AllocPPluginScriptableObjectParent()
1778
0
{
1779
0
    return new PluginScriptableObjectParent(Proxy);
1780
0
}
1781
1782
bool
1783
PluginInstanceParent::DeallocPPluginScriptableObjectParent(
1784
                                         PPluginScriptableObjectParent* aObject)
1785
0
{
1786
0
    PluginScriptableObjectParent* actor =
1787
0
        static_cast<PluginScriptableObjectParent*>(aObject);
1788
0
1789
0
    NPObject* object = actor->GetObject(false);
1790
0
    if (object) {
1791
0
        NS_ASSERTION(mScriptableObjects.Get(object, nullptr),
1792
0
                     "NPObject not in the hash!");
1793
0
        mScriptableObjects.Remove(object);
1794
0
    }
1795
#ifdef DEBUG
1796
    else {
1797
        for (auto iter = mScriptableObjects.Iter(); !iter.Done(); iter.Next()) {
1798
            NS_ASSERTION(actor != iter.UserData(),
1799
                         "Actor in the hash with a null NPObject!");
1800
        }
1801
    }
1802
#endif
1803
1804
0
    delete actor;
1805
0
    return true;
1806
0
}
1807
1808
mozilla::ipc::IPCResult
1809
PluginInstanceParent::RecvPPluginScriptableObjectConstructor(
1810
                                          PPluginScriptableObjectParent* aActor)
1811
0
{
1812
0
    // This is only called in response to the child process requesting the
1813
0
    // creation of an actor. This actor will represent an NPObject that is
1814
0
    // created by the plugin and returned to the browser.
1815
0
    PluginScriptableObjectParent* actor =
1816
0
        static_cast<PluginScriptableObjectParent*>(aActor);
1817
0
    NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
1818
0
1819
0
    actor->InitializeProxy();
1820
0
    NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
1821
0
1822
0
    return IPC_OK();
1823
0
}
1824
1825
void
1826
PluginInstanceParent::NPP_URLNotify(const char* url, NPReason reason,
1827
                                    void* notifyData)
1828
0
{
1829
0
    PLUGIN_LOG_DEBUG(("%s (%s, %i, %p)",
1830
0
                      FULLFUNCTION, url, (int) reason, notifyData));
1831
0
1832
0
    PStreamNotifyParent* streamNotify =
1833
0
        static_cast<PStreamNotifyParent*>(notifyData);
1834
0
    Unused << PStreamNotifyParent::Send__delete__(streamNotify, reason);
1835
0
}
1836
1837
bool
1838
PluginInstanceParent::RegisterNPObjectForActor(
1839
                                           NPObject* aObject,
1840
                                           PluginScriptableObjectParent* aActor)
1841
0
{
1842
0
    NS_ASSERTION(aObject && aActor, "Null pointers!");
1843
0
    NS_ASSERTION(!mScriptableObjects.Get(aObject, nullptr), "Duplicate entry!");
1844
0
    mScriptableObjects.Put(aObject, aActor);
1845
0
    return true;
1846
0
}
1847
1848
void
1849
PluginInstanceParent::UnregisterNPObject(NPObject* aObject)
1850
0
{
1851
0
    NS_ASSERTION(aObject, "Null pointer!");
1852
0
    NS_ASSERTION(mScriptableObjects.Get(aObject, nullptr), "Unknown entry!");
1853
0
    mScriptableObjects.Remove(aObject);
1854
0
}
1855
1856
PluginScriptableObjectParent*
1857
PluginInstanceParent::GetActorForNPObject(NPObject* aObject)
1858
0
{
1859
0
    NS_ASSERTION(aObject, "Null pointer!");
1860
0
1861
0
    if (aObject->_class == PluginScriptableObjectParent::GetClass()) {
1862
0
        // One of ours!
1863
0
        ParentNPObject* object = static_cast<ParentNPObject*>(aObject);
1864
0
        NS_ASSERTION(object->parent, "Null actor!");
1865
0
        return object->parent;
1866
0
    }
1867
0
1868
0
    PluginScriptableObjectParent* actor;
1869
0
    if (mScriptableObjects.Get(aObject, &actor)) {
1870
0
        return actor;
1871
0
    }
1872
0
1873
0
    actor = new PluginScriptableObjectParent(LocalObject);
1874
0
    if (!SendPPluginScriptableObjectConstructor(actor)) {
1875
0
        NS_WARNING("Failed to send constructor message!");
1876
0
        return nullptr;
1877
0
    }
1878
0
1879
0
    actor->InitializeLocal(aObject);
1880
0
    return actor;
1881
0
}
1882
1883
PPluginSurfaceParent*
1884
PluginInstanceParent::AllocPPluginSurfaceParent(const WindowsSharedMemoryHandle& handle,
1885
                                                const mozilla::gfx::IntSize& size,
1886
                                                const bool& transparent)
1887
0
{
1888
#ifdef XP_WIN
1889
    return new PluginSurfaceParent(handle, size, transparent);
1890
#else
1891
0
    NS_ERROR("This shouldn't be called!");
1892
0
    return nullptr;
1893
0
#endif
1894
0
}
1895
1896
bool
1897
PluginInstanceParent::DeallocPPluginSurfaceParent(PPluginSurfaceParent* s)
1898
0
{
1899
#ifdef XP_WIN
1900
    delete s;
1901
    return true;
1902
#else
1903
    return false;
1904
0
#endif
1905
0
}
1906
1907
mozilla::ipc::IPCResult
1908
PluginInstanceParent::AnswerNPN_PushPopupsEnabledState(const bool& aState)
1909
0
{
1910
0
    mNPNIface->pushpopupsenabledstate(mNPP, aState ? 1 : 0);
1911
0
    return IPC_OK();
1912
0
}
1913
1914
mozilla::ipc::IPCResult
1915
PluginInstanceParent::AnswerNPN_PopPopupsEnabledState()
1916
0
{
1917
0
    mNPNIface->poppopupsenabledstate(mNPP);
1918
0
    return IPC_OK();
1919
0
}
1920
1921
mozilla::ipc::IPCResult
1922
PluginInstanceParent::AnswerNPN_GetValueForURL(const NPNURLVariable& variable,
1923
                                               const nsCString& url,
1924
                                               nsCString* value,
1925
                                               NPError* result)
1926
0
{
1927
0
    char* v;
1928
0
    uint32_t len;
1929
0
1930
0
    *result = mNPNIface->getvalueforurl(mNPP, (NPNURLVariable) variable,
1931
0
                                        url.get(), &v, &len);
1932
0
    if (NPERR_NO_ERROR == *result)
1933
0
        value->Adopt(v, len);
1934
0
1935
0
    return IPC_OK();
1936
0
}
1937
1938
mozilla::ipc::IPCResult
1939
PluginInstanceParent::AnswerNPN_SetValueForURL(const NPNURLVariable& variable,
1940
                                               const nsCString& url,
1941
                                               const nsCString& value,
1942
                                               NPError* result)
1943
0
{
1944
0
    *result = mNPNIface->setvalueforurl(mNPP, (NPNURLVariable) variable,
1945
0
                                        url.get(), value.get(),
1946
0
                                        value.Length());
1947
0
    return IPC_OK();
1948
0
}
1949
1950
mozilla::ipc::IPCResult
1951
PluginInstanceParent::AnswerNPN_ConvertPoint(const double& sourceX,
1952
                                             const bool&   ignoreDestX,
1953
                                             const double& sourceY,
1954
                                             const bool&   ignoreDestY,
1955
                                             const NPCoordinateSpace& sourceSpace,
1956
                                             const NPCoordinateSpace& destSpace,
1957
                                             double *destX,
1958
                                             double *destY,
1959
                                             bool *result)
1960
0
{
1961
0
    *result = mNPNIface->convertpoint(mNPP, sourceX, sourceY, sourceSpace,
1962
0
                                      ignoreDestX ? nullptr : destX,
1963
0
                                      ignoreDestY ? nullptr : destY,
1964
0
                                      destSpace);
1965
0
1966
0
    return IPC_OK();
1967
0
}
1968
1969
mozilla::ipc::IPCResult
1970
PluginInstanceParent::RecvRedrawPlugin()
1971
0
{
1972
0
    nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
1973
0
    if (!inst) {
1974
0
        return IPC_FAIL_NO_REASON(this);
1975
0
    }
1976
0
1977
0
    inst->RedrawPlugin();
1978
0
    return IPC_OK();
1979
0
}
1980
1981
nsPluginInstanceOwner*
1982
PluginInstanceParent::GetOwner()
1983
0
{
1984
0
    nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
1985
0
    if (!inst) {
1986
0
        return nullptr;
1987
0
    }
1988
0
    return inst->GetOwner();
1989
0
}
1990
1991
mozilla::ipc::IPCResult
1992
PluginInstanceParent::RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow)
1993
0
{
1994
#if defined(XP_WIN)
1995
    nsPluginInstanceOwner* owner = GetOwner();
1996
    if (!owner || NS_FAILED(owner->SetNetscapeWindowAsParent(childWindow))) {
1997
        NS_WARNING("Failed to set Netscape window as parent.");
1998
    }
1999
2000
    return IPC_OK();
2001
#else
2002
0
    MOZ_ASSERT_UNREACHABLE("RecvSetNetscapeWindowAsParent not implemented!");
2003
0
    return IPC_FAIL_NO_REASON(this);
2004
0
#endif
2005
0
}
2006
2007
#if defined(OS_WIN)
2008
2009
/*
2010
  plugin focus changes between processes
2011
2012
  focus from dom -> child:
2013
    Focus manager calls on widget to set the focus on the window.
2014
    We pick up the resulting wm_setfocus event here, and forward
2015
    that over ipc to the child which calls set focus on itself.
2016
2017
  focus from child -> focus manager:
2018
    Child picks up the local wm_setfocus and sends it via ipc over
2019
    here. We then post a custom event to widget/windows/nswindow
2020
    which fires off a gui event letting the browser know.
2021
*/
2022
2023
static const wchar_t kPluginInstanceParentProperty[] =
2024
                         L"PluginInstanceParentProperty";
2025
2026
// static
2027
LRESULT CALLBACK
2028
PluginInstanceParent::PluginWindowHookProc(HWND hWnd,
2029
                                           UINT message,
2030
                                           WPARAM wParam,
2031
                                           LPARAM lParam)
2032
{
2033
    PluginInstanceParent* self = reinterpret_cast<PluginInstanceParent*>(
2034
        ::GetPropW(hWnd, kPluginInstanceParentProperty));
2035
    if (!self) {
2036
        MOZ_ASSERT_UNREACHABLE("PluginInstanceParent::PluginWindowHookProc null this ptr!");
2037
        return DefWindowProc(hWnd, message, wParam, lParam);
2038
    }
2039
2040
    NS_ASSERTION(self->mPluginHWND == hWnd, "Wrong window!");
2041
2042
    switch (message) {
2043
        case WM_SETFOCUS:
2044
        // Let the child plugin window know it should take focus.
2045
        Unused << self->CallSetPluginFocus();
2046
        break;
2047
2048
        case WM_CLOSE:
2049
        self->UnsubclassPluginWindow();
2050
        break;
2051
    }
2052
2053
    if (self->mPluginWndProc == PluginWindowHookProc) {
2054
      MOZ_ASSERT_UNREACHABLE(
2055
        "PluginWindowHookProc invoking mPluginWndProc w/"
2056
        "mPluginWndProc == PluginWindowHookProc????");
2057
        return DefWindowProc(hWnd, message, wParam, lParam);
2058
    }
2059
    return ::CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
2060
                            lParam);
2061
}
2062
2063
void
2064
PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
2065
{
2066
    if ((aWnd && mPluginHWND == aWnd) || (!aWnd && mPluginHWND)) {
2067
        return;
2068
    }
2069
2070
    if (XRE_IsContentProcess()) {
2071
        if (!aWnd) {
2072
            NS_WARNING("PluginInstanceParent::SubclassPluginWindow unexpected null window");
2073
            return;
2074
        }
2075
        mPluginHWND = aWnd; // now a remote window, we can't subclass this
2076
        mPluginWndProc = nullptr;
2077
        // Note sPluginInstanceList wil delete 'this' if we do not remove
2078
        // it on shutdown.
2079
        sPluginInstanceList->Put((void*)mPluginHWND, this);
2080
        return;
2081
    }
2082
2083
    NS_ASSERTION(!(mPluginHWND && aWnd != mPluginHWND),
2084
        "PluginInstanceParent::SubclassPluginWindow hwnd is not our window!");
2085
2086
    mPluginHWND = aWnd;
2087
    mPluginWndProc =
2088
        (WNDPROC)::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
2089
            reinterpret_cast<LONG_PTR>(PluginWindowHookProc));
2090
    DebugOnly<bool> bRes = ::SetPropW(mPluginHWND, kPluginInstanceParentProperty, this);
2091
    NS_ASSERTION(mPluginWndProc,
2092
        "PluginInstanceParent::SubclassPluginWindow failed to set subclass!");
2093
    NS_ASSERTION(bRes,
2094
        "PluginInstanceParent::SubclassPluginWindow failed to set prop!");
2095
}
2096
2097
void
2098
PluginInstanceParent::UnsubclassPluginWindow()
2099
{
2100
    if (XRE_IsContentProcess()) {
2101
        if (mPluginHWND) {
2102
            // Remove 'this' from the plugin list safely
2103
            nsAutoPtr<PluginInstanceParent> tmp;
2104
            MOZ_ASSERT(sPluginInstanceList);
2105
            sPluginInstanceList->Remove((void*)mPluginHWND, &tmp);
2106
            tmp.forget();
2107
            if (!sPluginInstanceList->Count()) {
2108
                delete sPluginInstanceList;
2109
                sPluginInstanceList = nullptr;
2110
            }
2111
        }
2112
        mPluginHWND = nullptr;
2113
        return;
2114
    }
2115
2116
    if (mPluginHWND && mPluginWndProc) {
2117
        ::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
2118
                            reinterpret_cast<LONG_PTR>(mPluginWndProc));
2119
2120
        ::RemovePropW(mPluginHWND, kPluginInstanceParentProperty);
2121
2122
        mPluginWndProc = nullptr;
2123
        mPluginHWND = nullptr;
2124
    }
2125
}
2126
2127
/* windowless drawing helpers */
2128
2129
/*
2130
 * Origin info:
2131
 *
2132
 * windowless, offscreen:
2133
 *
2134
 * WM_WINDOWPOSCHANGED: origin is relative to container
2135
 * setwindow: origin is 0,0
2136
 * WM_PAINT: origin is 0,0
2137
 *
2138
 * windowless, native:
2139
 *
2140
 * WM_WINDOWPOSCHANGED: origin is relative to container
2141
 * setwindow: origin is relative to container
2142
 * WM_PAINT: origin is relative to container
2143
 *
2144
 * PluginInstanceParent:
2145
 *
2146
 * painting: mPluginPort (nsIntRect, saved in SetWindow)
2147
 */
2148
2149
bool
2150
PluginInstanceParent::MaybeCreateAndParentChildPluginWindow()
2151
{
2152
    // On Windows we need to create and set the parent before we set the
2153
    // window on the plugin, or keyboard interaction will not work.
2154
    if (!mChildPluginHWND) {
2155
        if (!CallCreateChildPluginWindow(&mChildPluginHWND) ||
2156
            !mChildPluginHWND) {
2157
            return false;
2158
        }
2159
    }
2160
2161
    // It's not clear if the parent window would ever change, but when this
2162
    // was done in the NPAPI child it used to allow for this.
2163
    if (mPluginHWND == mChildPluginsParentHWND) {
2164
        return true;
2165
    }
2166
2167
    nsPluginInstanceOwner* owner = GetOwner();
2168
    if (!owner) {
2169
        // We can't reparent without an owner, the plugin is probably shutting
2170
        // down, just return true to allow any calls to continue.
2171
        return true;
2172
    }
2173
2174
    // Note that this call will probably cause a sync native message to the
2175
    // process that owns the child window.
2176
    owner->SetWidgetWindowAsParent(mChildPluginHWND);
2177
    mChildPluginsParentHWND = mPluginHWND;
2178
    return true;
2179
}
2180
2181
void
2182
PluginInstanceParent::MaybeCreateChildPopupSurrogate()
2183
{
2184
    // Already created or not required for this plugin.
2185
    if (mChildPluginHWND || mWindowType != NPWindowTypeDrawable ||
2186
        !(mParent->GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK)) {
2187
        return;
2188
    }
2189
2190
    // We need to pass the netscape window down to be cached as part of the call
2191
    // to create the surrogate, because the reparenting of the surrogate in the
2192
    // main process can cause sync Windows messages to the plugin process, which
2193
    // then cause sync messages from the plugin child for the netscape window
2194
    // which causes a deadlock.
2195
    NativeWindowHandle netscapeWindow;
2196
    NPError result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow,
2197
                                         &netscapeWindow);
2198
    if (NPERR_NO_ERROR != result) {
2199
        NS_WARNING("Can't get netscape window to pass to plugin child.");
2200
        return;
2201
    }
2202
2203
    if (!SendCreateChildPopupSurrogate(netscapeWindow)) {
2204
        NS_WARNING("Failed to create popup surrogate in child.");
2205
    }
2206
}
2207
2208
#endif // defined(OS_WIN)
2209
2210
mozilla::ipc::IPCResult
2211
PluginInstanceParent::AnswerPluginFocusChange(const bool& gotFocus)
2212
0
{
2213
0
    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2214
0
2215
0
    // Currently only in use on windows - an event we receive from the child
2216
0
    // when it's plugin window (or one of it's children) receives keyboard
2217
0
    // focus. We detect this and forward a notification here so we can update
2218
0
    // focus.
2219
#if defined(OS_WIN)
2220
    if (gotFocus) {
2221
      nsPluginInstanceOwner* owner = GetOwner();
2222
      if (owner) {
2223
        nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2224
        RefPtr<dom::Element> element;
2225
        owner->GetDOMElement(getter_AddRefs(element));
2226
        if (fm && element) {
2227
          fm->SetFocus(element, 0);
2228
        }
2229
      }
2230
    }
2231
    return IPC_OK();
2232
#else
2233
0
    MOZ_ASSERT_UNREACHABLE("AnswerPluginFocusChange not implemented!");
2234
0
    return IPC_FAIL_NO_REASON(this);
2235
0
#endif
2236
0
}
2237
2238
PluginInstanceParent*
2239
PluginInstanceParent::Cast(NPP aInstance)
2240
0
{
2241
0
    auto ip = static_cast<PluginInstanceParent*>(aInstance->pdata);
2242
0
2243
0
    // If the plugin crashed and the PluginInstanceParent was deleted,
2244
0
    // aInstance->pdata will be nullptr.
2245
0
    if (!ip) {
2246
0
        return nullptr;
2247
0
    }
2248
0
2249
0
    if (aInstance != ip->mNPP) {
2250
0
        MOZ_CRASH("Corrupted plugin data.");
2251
0
    }
2252
0
2253
0
    return ip;
2254
0
}
2255
2256
mozilla::ipc::IPCResult
2257
PluginInstanceParent::RecvGetCompositionString(const uint32_t& aIndex,
2258
                                               nsTArray<uint8_t>* aDist,
2259
                                               int32_t* aLength)
2260
0
{
2261
#if defined(OS_WIN)
2262
    nsPluginInstanceOwner* owner = GetOwner();
2263
    if (!owner) {
2264
        *aLength = IMM_ERROR_GENERAL;
2265
        return IPC_OK();
2266
    }
2267
2268
    if (!owner->GetCompositionString(aIndex, aDist, aLength)) {
2269
        *aLength = IMM_ERROR_NODATA;
2270
    }
2271
#endif
2272
0
    return IPC_OK();
2273
0
}
2274
2275
mozilla::ipc::IPCResult
2276
PluginInstanceParent::RecvSetCandidateWindow(
2277
    const mozilla::widget::CandidateWindowPosition& aPosition)
2278
0
{
2279
#if defined(OS_WIN)
2280
    nsPluginInstanceOwner* owner = GetOwner();
2281
    if (owner) {
2282
        owner->SetCandidateWindow(aPosition);
2283
    }
2284
#endif
2285
0
    return IPC_OK();
2286
0
}
2287
2288
mozilla::ipc::IPCResult
2289
PluginInstanceParent::RecvRequestCommitOrCancel(const bool& aCommitted)
2290
0
{
2291
#if defined(OS_WIN)
2292
    nsPluginInstanceOwner* owner = GetOwner();
2293
    if (owner) {
2294
        owner->RequestCommitOrCancel(aCommitted);
2295
    }
2296
#endif
2297
0
    return IPC_OK();
2298
0
}
2299
2300
mozilla::ipc::IPCResult
2301
PluginInstanceParent::RecvEnableIME(const bool& aEnable)
2302
0
{
2303
#if defined(OS_WIN)
2304
    nsPluginInstanceOwner* owner = GetOwner();
2305
    if (owner) {
2306
        owner->EnableIME(aEnable);
2307
    }
2308
#else
2309
0
    MOZ_CRASH("Not reachable");
2310
0
#endif
2311
0
    return IPC_OK();
2312
0
}
2313
2314
nsresult
2315
PluginInstanceParent::HandledWindowedPluginKeyEvent(
2316
                        const NativeEventData& aKeyEventData,
2317
                        bool aIsConsumed)
2318
0
{
2319
0
    if (NS_WARN_IF(!SendHandledWindowedPluginKeyEvent(aKeyEventData,
2320
0
                                                      aIsConsumed))) {
2321
0
        return NS_ERROR_FAILURE;
2322
0
    }
2323
0
    return NS_OK;
2324
0
}
2325
2326
mozilla::ipc::IPCResult
2327
PluginInstanceParent::RecvOnWindowedPluginKeyEvent(
2328
                        const NativeEventData& aKeyEventData)
2329
0
{
2330
0
    nsPluginInstanceOwner* owner = GetOwner();
2331
0
    if (NS_WARN_IF(!owner)) {
2332
0
        // Notifies the plugin process of the key event being not consumed
2333
0
        // by us.
2334
0
        HandledWindowedPluginKeyEvent(aKeyEventData, false);
2335
0
        return IPC_OK();
2336
0
    }
2337
0
    owner->OnWindowedPluginKeyEvent(aKeyEventData);
2338
0
    return IPC_OK();
2339
0
}
2340
2341
void
2342
PluginInstanceParent::RecordDrawingModel()
2343
0
{
2344
0
    int mode = -1;
2345
0
    switch (mWindowType) {
2346
0
    case NPWindowTypeWindow:
2347
0
        // We use 0=windowed since there is no specific NPDrawingModel value.
2348
0
        mode = 0;
2349
0
        break;
2350
0
    case NPWindowTypeDrawable:
2351
0
        mode = mDrawingModel + 1;
2352
0
        break;
2353
0
    default:
2354
0
        MOZ_ASSERT_UNREACHABLE("bad window type");
2355
0
        return;
2356
0
    }
2357
0
2358
0
    if (mode == mLastRecordedDrawingModel) {
2359
0
        return;
2360
0
    }
2361
0
    MOZ_ASSERT(mode >= 0);
2362
0
2363
0
    Telemetry::Accumulate(Telemetry::PLUGIN_DRAWING_MODEL, mode);
2364
0
    mLastRecordedDrawingModel = mode;
2365
0
}