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