1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:set ts=2 sts=2 sw=2 et cin:
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 #ifdef MOZ_X11
8 #include <cairo-xlib.h>
9 #include "gfxXlibSurface.h"
10 /* X headers suck */
11 enum { XKeyPress = KeyPress };
12 #include "mozilla/X11Util.h"
13 using mozilla::DefaultXDisplay;
14 #endif
15
16 #include "nsPluginInstanceOwner.h"
17
18 #include "gfxUtils.h"
19 #include "nsIRunnable.h"
20 #include "nsContentUtils.h"
21 #include "nsRect.h"
22 #include "nsSize.h"
23 #include "nsDisplayList.h"
24 #include "ImageLayers.h"
25 #include "GLImages.h"
26 #include "nsPluginFrame.h"
27 #include "nsIPluginDocument.h"
28 #include "nsIStringStream.h"
29 #include "nsNetUtil.h"
30 #include "mozilla/Preferences.h"
31 #include "nsILinkHandler.h"
32 #include "nsIDocShellTreeItem.h"
33 #include "nsIWebBrowserChrome.h"
34 #include "nsLayoutUtils.h"
35 #include "nsIPluginWidget.h"
36 #include "nsViewManager.h"
37 #include "nsIDocShellTreeOwner.h"
38 #include "nsIDOMHTMLObjectElement.h"
39 #include "nsIAppShell.h"
40 #include "nsIDOMHTMLAppletElement.h"
41 #include "nsIObjectLoadingContent.h"
42 #include "nsObjectLoadingContent.h"
43 #include "nsAttrName.h"
44 #include "nsIFocusManager.h"
45 #include "nsFocusManager.h"
46 #include "nsIDOMDragEvent.h"
47 #include "nsIScriptSecurityManager.h"
48 #include "nsIScrollableFrame.h"
49 #include "nsIDocShell.h"
50 #include "ImageContainer.h"
51 #include "nsIDOMHTMLCollection.h"
52 #include "GLContext.h"
53 #include "EGLUtils.h"
54 #include "nsIContentInlines.h"
55 #include "mozilla/MiscEvents.h"
56 #include "mozilla/MouseEvents.h"
57 #include "mozilla/TextEvents.h"
58 #include "mozilla/dom/Event.h"
59 #include "mozilla/dom/HTMLObjectElementBinding.h"
60 #include "mozilla/dom/TabChild.h"
61 #include "nsFrameSelection.h"
62 #include "PuppetWidget.h"
63 #include "nsPIWindowRoot.h"
64 #include "mozilla/IMEStateManager.h"
65 #include "mozilla/TextComposition.h"
66 #include "mozilla/AutoRestore.h"
67
68 #include "nsContentCID.h"
69 #include "nsWidgetsCID.h"
70 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
71 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
72
73 #ifdef XP_WIN
74 #include <wtypes.h>
75 #include <winuser.h>
76 #include "mozilla/widget/WinMessages.h"
77 #endif // #ifdef XP_WIN
78
79 #ifdef XP_MACOSX
80 #include "ComplexTextInputPanel.h"
81 #include "nsIDOMXULDocument.h"
82 #include "nsIDOMXULCommandDispatcher.h"
83 #endif
84
85 #ifdef MOZ_WIDGET_GTK
86 #include <gdk/gdk.h>
87 #include <gtk/gtk.h>
88 #endif
89
90 #ifdef MOZ_WIDGET_ANDROID
91 #include "ANPBase.h"
92 #include "AndroidBridge.h"
93 #include "ClientLayerManager.h"
94 #include "nsWindow.h"
95
96 static nsPluginInstanceOwner* sFullScreenInstance = nullptr;
97
98 using namespace mozilla::dom;
99
100 #include <android/log.h>
101 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
102 #endif
103
104 using namespace mozilla;
105 using namespace mozilla::dom;
106 using namespace mozilla::layers;
107
AsNsPoint(const nsIntPoint & p)108 static inline nsPoint AsNsPoint(const nsIntPoint &p) {
109 return nsPoint(p.x, p.y);
110 }
111
112 // special class for handeling DOM context menu events because for
113 // some reason it starves other mouse events if implemented on the
114 // same class
115 class nsPluginDOMContextMenuListener : public nsIDOMEventListener
116 {
117 virtual ~nsPluginDOMContextMenuListener();
118
119 public:
120 explicit nsPluginDOMContextMenuListener(nsIContent* aContent);
121
122 NS_DECL_ISUPPORTS
123 NS_DECL_NSIDOMEVENTLISTENER
124
125 void Destroy(nsIContent* aContent);
126
ProcessEvent(const WidgetGUIEvent & anEvent)127 nsEventStatus ProcessEvent(const WidgetGUIEvent& anEvent)
128 {
129 return nsEventStatus_eConsumeNoDefault;
130 }
131 };
132
133 class AsyncPaintWaitEvent : public Runnable
134 {
135 public:
AsyncPaintWaitEvent(nsIContent * aContent,bool aFinished)136 AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) :
137 mContent(aContent), mFinished(aFinished)
138 {
139 }
140
Run()141 NS_IMETHOD Run() override
142 {
143 nsContentUtils::DispatchTrustedEvent(mContent->OwnerDoc(), mContent,
144 mFinished ? NS_LITERAL_STRING("MozPaintWaitFinished") : NS_LITERAL_STRING("MozPaintWait"),
145 true, true);
146 return NS_OK;
147 }
148
149 private:
150 nsCOMPtr<nsIContent> mContent;
151 bool mFinished;
152 };
153
154 void
NotifyPaintWaiter(nsDisplayListBuilder * aBuilder)155 nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
156 {
157 // This is notification for reftests about async plugin paint start
158 if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) {
159 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
160 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(content, false);
161 // Run this event as soon as it's safe to do so, since listeners need to
162 // receive it immediately
163 nsContentUtils::AddScriptRunner(event);
164 mWaitingForPaint = true;
165 }
166 }
167
168 #if MOZ_WIDGET_ANDROID
169 static void
AttachToContainerAsSurfaceTexture(ImageContainer * container,nsNPAPIPluginInstance * instance,const LayoutDeviceRect & rect,RefPtr<Image> * out_image)170 AttachToContainerAsSurfaceTexture(ImageContainer* container,
171 nsNPAPIPluginInstance* instance,
172 const LayoutDeviceRect& rect,
173 RefPtr<Image>* out_image)
174 {
175 MOZ_ASSERT(out_image);
176 MOZ_ASSERT(!*out_image);
177
178 mozilla::gl::AndroidSurfaceTexture* surfTex = instance->AsSurfaceTexture();
179 if (!surfTex) {
180 return;
181 }
182
183 RefPtr<Image> img = new SurfaceTextureImage(
184 surfTex,
185 gfx::IntSize::Truncate(rect.width, rect.height),
186 instance->OriginPos());
187 *out_image = img;
188 }
189 #endif
190
191 bool
NeedsScrollImageLayer()192 nsPluginInstanceOwner::NeedsScrollImageLayer()
193 {
194 #if defined(XP_WIN)
195 // If this is a windowed plugin and we're doing layout in the content
196 // process, force the creation of an image layer for the plugin. We'll
197 // paint to this when scrolling.
198 return XRE_IsContentProcess() &&
199 mPluginWindow &&
200 mPluginWindow->type == NPWindowTypeWindow;
201 #else
202 return false;
203 #endif
204 }
205
206 already_AddRefed<ImageContainer>
GetImageContainer()207 nsPluginInstanceOwner::GetImageContainer()
208 {
209 if (!mInstance)
210 return nullptr;
211
212 RefPtr<ImageContainer> container;
213
214 #if MOZ_WIDGET_ANDROID
215 LayoutDeviceRect r = GetPluginRect();
216
217 // NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
218 // into, set y-flip flags, etc, so we do this at the beginning.
219 float resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
220 ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution)).Size();
221 mInstance->NotifySize(nsIntSize::Truncate(screenSize.width, screenSize.height));
222
223 container = LayerManager::CreateImageContainer();
224
225 if (r.width && r.height) {
226 // Try to get it as an EGLImage first.
227 RefPtr<Image> img;
228 AttachToContainerAsSurfaceTexture(container, mInstance, r, &img);
229
230 if (img) {
231 container->SetCurrentImageInTransaction(img);
232 }
233 }
234 #else
235 if (NeedsScrollImageLayer()) {
236 // windowed plugin under e10s
237 #if defined(XP_WIN)
238 mInstance->GetScrollCaptureContainer(getter_AddRefs(container));
239 #endif
240 } else {
241 // async windowless rendering
242 mInstance->GetImageContainer(getter_AddRefs(container));
243 }
244 #endif
245
246 return container.forget();
247 }
248
249 void
DidComposite()250 nsPluginInstanceOwner::DidComposite()
251 {
252 if (mInstance) {
253 mInstance->DidComposite();
254 }
255 }
256
257 void
SetBackgroundUnknown()258 nsPluginInstanceOwner::SetBackgroundUnknown()
259 {
260 if (mInstance) {
261 mInstance->SetBackgroundUnknown();
262 }
263 }
264
265 already_AddRefed<mozilla::gfx::DrawTarget>
BeginUpdateBackground(const nsIntRect & aRect)266 nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect)
267 {
268 nsIntRect rect = aRect;
269 RefPtr<DrawTarget> dt;
270 if (mInstance &&
271 NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(dt)))) {
272 return dt.forget();
273 }
274 return nullptr;
275 }
276
277 void
EndUpdateBackground(const nsIntRect & aRect)278 nsPluginInstanceOwner::EndUpdateBackground(const nsIntRect& aRect)
279 {
280 nsIntRect rect = aRect;
281 if (mInstance) {
282 mInstance->EndUpdateBackground(&rect);
283 }
284 }
285
286 bool
UseAsyncRendering()287 nsPluginInstanceOwner::UseAsyncRendering()
288 {
289 #ifdef XP_MACOSX
290 if (mUseAsyncRendering) {
291 return true;
292 }
293 #endif
294
295 bool isOOP;
296 bool result = (mInstance &&
297 NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP
298 #ifndef XP_MACOSX
299 && (!mPluginWindow ||
300 mPluginWindow->type == NPWindowTypeDrawable)
301 #endif
302 );
303
304 #ifdef XP_MACOSX
305 if (result) {
306 mUseAsyncRendering = true;
307 }
308 #endif
309
310 return result;
311 }
312
313 nsIntSize
GetCurrentImageSize()314 nsPluginInstanceOwner::GetCurrentImageSize()
315 {
316 nsIntSize size(0,0);
317 if (mInstance) {
318 mInstance->GetImageSize(&size);
319 }
320 return size;
321 }
322
nsPluginInstanceOwner()323 nsPluginInstanceOwner::nsPluginInstanceOwner()
324 : mPluginWindow(nullptr)
325 {
326 // create nsPluginNativeWindow object, it is derived from NPWindow
327 // struct and allows to manipulate native window procedure
328 nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
329 mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
330 if (mPluginHost)
331 mPluginHost->NewPluginNativeWindow(&mPluginWindow);
332
333 mPluginFrame = nullptr;
334 mWidgetCreationComplete = false;
335 #ifdef XP_MACOSX
336 mSentInitialTopLevelWindowEvent = false;
337 mLastWindowIsActive = false;
338 mLastContentFocused = false;
339 mLastScaleFactor = 1.0;
340 mShouldBlurOnActivate = false;
341 #endif
342 mLastCSSZoomFactor = 1.0;
343 mContentFocused = false;
344 mWidgetVisible = true;
345 mPluginWindowVisible = false;
346 mPluginDocumentActiveState = true;
347 mLastMouseDownButtonType = -1;
348
349 #ifdef XP_MACOSX
350 #ifndef NP_NO_CARBON
351 // We don't support Carbon, but it is still the default model for i386 NPAPI.
352 mEventModel = NPEventModelCarbon;
353 #else
354 mEventModel = NPEventModelCocoa;
355 #endif
356 mUseAsyncRendering = false;
357 #endif
358
359 mWaitingForPaint = false;
360
361 #ifdef MOZ_WIDGET_ANDROID
362 mFullScreen = false;
363 mJavaView = nullptr;
364 #endif
365
366 #ifdef XP_WIN
367 mGotCompositionData = false;
368 mSentStartComposition = false;
369 mPluginDidNotHandleIMEComposition = false;
370 #endif
371 }
372
~nsPluginInstanceOwner()373 nsPluginInstanceOwner::~nsPluginInstanceOwner()
374 {
375 if (mWaitingForPaint) {
376 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
377 if (content) {
378 // We don't care when the event is dispatched as long as it's "soon",
379 // since whoever needs it will be waiting for it.
380 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(content, true);
381 NS_DispatchToMainThread(event);
382 }
383 }
384
385 mPluginFrame = nullptr;
386
387 PLUG_DeletePluginNativeWindow(mPluginWindow);
388 mPluginWindow = nullptr;
389
390 #ifdef MOZ_WIDGET_ANDROID
391 RemovePluginView();
392 #endif
393
394 if (mInstance) {
395 mInstance->SetOwner(nullptr);
396 }
397 }
398
NS_IMPL_ISUPPORTS(nsPluginInstanceOwner,nsIPluginInstanceOwner,nsIDOMEventListener,nsIPrivacyTransitionObserver,nsIKeyEventInPluginCallback,nsISupportsWeakReference)399 NS_IMPL_ISUPPORTS(nsPluginInstanceOwner,
400 nsIPluginInstanceOwner,
401 nsIDOMEventListener,
402 nsIPrivacyTransitionObserver,
403 nsIKeyEventInPluginCallback,
404 nsISupportsWeakReference)
405
406 nsresult
407 nsPluginInstanceOwner::SetInstance(nsNPAPIPluginInstance *aInstance)
408 {
409 NS_ASSERTION(!mInstance || !aInstance, "mInstance should only be set or unset!");
410
411 // If we're going to null out mInstance after use, be sure to call
412 // mInstance->SetOwner(nullptr) here, since it now won't be called
413 // from our destructor. This fixes bug 613376.
414 if (mInstance && !aInstance) {
415 mInstance->SetOwner(nullptr);
416
417 #ifdef MOZ_WIDGET_ANDROID
418 RemovePluginView();
419 #endif
420 }
421
422 mInstance = aInstance;
423
424 nsCOMPtr<nsIDocument> doc;
425 GetDocument(getter_AddRefs(doc));
426 if (doc) {
427 if (nsCOMPtr<nsPIDOMWindowOuter> domWindow = doc->GetWindow()) {
428 nsCOMPtr<nsIDocShell> docShell = domWindow->GetDocShell();
429 if (docShell)
430 docShell->AddWeakPrivacyTransitionObserver(this);
431 }
432 }
433
434 return NS_OK;
435 }
436
GetWindow(NPWindow * & aWindow)437 NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(NPWindow *&aWindow)
438 {
439 NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
440 aWindow = mPluginWindow;
441 return NS_OK;
442 }
443
GetMode(int32_t * aMode)444 NS_IMETHODIMP nsPluginInstanceOwner::GetMode(int32_t *aMode)
445 {
446 nsCOMPtr<nsIDocument> doc;
447 nsresult rv = GetDocument(getter_AddRefs(doc));
448 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
449
450 if (pDoc) {
451 *aMode = NP_FULL;
452 } else {
453 *aMode = NP_EMBED;
454 }
455
456 return rv;
457 }
458
GetAttributes(nsTArray<MozPluginParameter> & attributes)459 void nsPluginInstanceOwner::GetAttributes(nsTArray<MozPluginParameter>& attributes)
460 {
461 nsCOMPtr<nsIObjectLoadingContent> content = do_QueryReferent(mContent);
462 nsObjectLoadingContent *loadingContent =
463 static_cast<nsObjectLoadingContent*>(content.get());
464
465 loadingContent->GetPluginAttributes(attributes);
466 }
467
GetDOMElement(nsIDOMElement ** result)468 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
469 {
470 return CallQueryReferent(mContent.get(), result);
471 }
472
GetInstance(nsNPAPIPluginInstance ** aInstance)473 nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
474 {
475 NS_ENSURE_ARG_POINTER(aInstance);
476
477 *aInstance = mInstance;
478 NS_IF_ADDREF(*aInstance);
479 return NS_OK;
480 }
481
GetURL(const char * aURL,const char * aTarget,nsIInputStream * aPostStream,void * aHeadersData,uint32_t aHeadersDataLen,bool aDoCheckLoadURIChecks)482 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
483 const char *aTarget,
484 nsIInputStream *aPostStream,
485 void *aHeadersData,
486 uint32_t aHeadersDataLen,
487 bool aDoCheckLoadURIChecks)
488 {
489 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
490 if (!content) {
491 return NS_ERROR_NULL_POINTER;
492 }
493
494 if (content->IsEditable()) {
495 return NS_OK;
496 }
497
498 nsIDocument *doc = content->GetUncomposedDoc();
499 if (!doc) {
500 return NS_ERROR_FAILURE;
501 }
502
503 nsIPresShell *presShell = doc->GetShell();
504 if (!presShell) {
505 return NS_ERROR_FAILURE;
506 }
507
508 nsPresContext *presContext = presShell->GetPresContext();
509 if (!presContext) {
510 return NS_ERROR_FAILURE;
511 }
512
513 // the container of the pres context will give us the link handler
514 nsCOMPtr<nsISupports> container = presContext->GetContainerWeak();
515 NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
516 nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
517 NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
518
519 nsAutoString unitarget;
520 if ((0 == PL_strcmp(aTarget, "newwindow")) ||
521 (0 == PL_strcmp(aTarget, "_new"))) {
522 unitarget.AssignASCII("_blank");
523 }
524 else if (0 == PL_strcmp(aTarget, "_current")) {
525 unitarget.AssignASCII("_self");
526 }
527 else {
528 unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
529 }
530
531 nsCOMPtr<nsIURI> baseURI = GetBaseURI();
532
533 // Create an absolute URL
534 nsCOMPtr<nsIURI> uri;
535 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
536 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
537
538 if (aDoCheckLoadURIChecks) {
539 nsCOMPtr<nsIScriptSecurityManager> secMan(
540 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
541 NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
542
543 rv = secMan->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri,
544 nsIScriptSecurityManager::STANDARD);
545 NS_ENSURE_SUCCESS(rv, rv);
546 }
547
548 nsCOMPtr<nsIInputStream> headersDataStream;
549 if (aPostStream && aHeadersData) {
550 if (!aHeadersDataLen)
551 return NS_ERROR_UNEXPECTED;
552
553 nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
554 if (!sis)
555 return NS_ERROR_OUT_OF_MEMORY;
556
557 rv = sis->SetData((char *)aHeadersData, aHeadersDataLen);
558 NS_ENSURE_SUCCESS(rv, rv);
559 headersDataStream = do_QueryInterface(sis);
560 }
561
562 int32_t blockPopups =
563 Preferences::GetInt("privacy.popups.disable_from_plugins");
564 nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
565
566 rv = lh->OnLinkClick(content, uri, unitarget.get(), NullString(),
567 aPostStream, headersDataStream, true);
568
569 return rv;
570 }
571
GetDocument(nsIDocument ** aDocument)572 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
573 {
574 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
575 if (!aDocument || !content) {
576 return NS_ERROR_NULL_POINTER;
577 }
578
579 // XXX sXBL/XBL2 issue: current doc or owner doc?
580 // But keep in mind bug 322414 comment 33
581 NS_IF_ADDREF(*aDocument = content->OwnerDoc());
582 return NS_OK;
583 }
584
InvalidateRect(NPRect * invalidRect)585 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
586 {
587 // If our object frame has gone away, we won't be able to determine
588 // up-to-date-ness, so just fire off the event.
589 if (mWaitingForPaint && (!mPluginFrame || IsUpToDate())) {
590 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
591 // We don't care when the event is dispatched as long as it's "soon",
592 // since whoever needs it will be waiting for it.
593 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(content, true);
594 NS_DispatchToMainThread(event);
595 mWaitingForPaint = false;
596 }
597
598 if (!mPluginFrame || !invalidRect || !mWidgetVisible)
599 return NS_ERROR_FAILURE;
600
601 #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
602 // Each time an asynchronously-drawing plugin sends a new surface to display,
603 // the image in the ImageContainer is updated and InvalidateRect is called.
604 // There are different side effects for (sync) Android plugins.
605 RefPtr<ImageContainer> container;
606 mInstance->GetImageContainer(getter_AddRefs(container));
607 #endif
608
609 #ifndef XP_MACOSX
610 // Silverlight calls invalidate for windowed plugins so this needs to work.
611 if (mWidget) {
612 mWidget->Invalidate(
613 LayoutDeviceIntRect(invalidRect->left, invalidRect->top,
614 invalidRect->right - invalidRect->left,
615 invalidRect->bottom - invalidRect->top));
616 // Plugin instances also call invalidate when plugin windows are hidden
617 // during scrolling. In this case fall through so we invalidate the
618 // underlying layer.
619 if (!NeedsScrollImageLayer()) {
620 return NS_OK;
621 }
622 }
623 #endif
624 nsIntRect rect(invalidRect->left,
625 invalidRect->top,
626 invalidRect->right - invalidRect->left,
627 invalidRect->bottom - invalidRect->top);
628 // invalidRect is in "display pixels". In non-HiDPI modes "display pixels"
629 // are device pixels. But in HiDPI modes each display pixel corresponds
630 // to more than one device pixel.
631 double scaleFactor = 1.0;
632 GetContentsScaleFactor(&scaleFactor);
633 rect.ScaleRoundOut(scaleFactor);
634 mPluginFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
635 return NS_OK;
636 }
637
InvalidateRegion(NPRegion invalidRegion)638 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
639 {
640 return NS_ERROR_NOT_IMPLEMENTED;
641 }
642
643 NS_IMETHODIMP
RedrawPlugin()644 nsPluginInstanceOwner::RedrawPlugin()
645 {
646 if (mPluginFrame) {
647 mPluginFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
648 }
649 return NS_OK;
650 }
651
652 #if defined(XP_WIN)
653 nsIWidget*
GetContainingWidgetIfOffset()654 nsPluginInstanceOwner::GetContainingWidgetIfOffset()
655 {
656 MOZ_ASSERT(mPluginFrame, "Caller should have checked for null mPluginFrame.");
657
658 // This property is provided to allow a "windowless" plugin to determine the window it is drawing
659 // in, so it can translate mouse coordinates it receives directly from the operating system
660 // to coordinates relative to itself.
661
662 // The original code returns the document's window, which is OK if the window the "windowless" plugin
663 // is drawing into has the same origin as the document's window, but this is not the case for "windowless" plugins inside of scrolling DIVs etc
664
665 // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
666 // determines the window handle of the mozilla window containing the "windowless" plugin.
667
668 // Given that this HWND may not be that of the document's window, there is a slight risk
669 // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
670 // does not suggest this HWND IS that of the document window, rather that of the window
671 // the plugin is drawn in, this seems like a safe fix.
672
673 // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
674 // to change any behaviour for the much more common windowed plugins,
675 // though why this method would even be being called for a windowed plugin escapes me.
676 if (!XRE_IsContentProcess() &&
677 mPluginWindow && mPluginWindow->type == NPWindowTypeDrawable) {
678 // it turns out that flash also uses this window for determining focus, and is currently
679 // unable to show a caret correctly if we return the enclosing window. Therefore for
680 // now we only return the enclosing window when there is an actual offset which
681 // would otherwise cause coordinates to be offset incorrectly. (i.e.
682 // if the enclosing window if offset from the document window)
683 //
684 // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
685 // does not seem to be possible without a change to the flash plugin
686
687 nsIWidget* win = mPluginFrame->GetNearestWidget();
688 if (win) {
689 nsView *view = nsView::GetViewFor(win);
690 NS_ASSERTION(view, "No view for widget");
691 nsPoint offset = view->GetOffsetTo(nullptr);
692
693 if (offset.x || offset.y) {
694 // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
695 // so that mouse co-ordinates are not messed up.
696 return win;
697 }
698 }
699 }
700
701 return nullptr;
702 }
703
704 static already_AddRefed<nsIWidget>
GetRootWidgetForPluginFrame(const nsPluginFrame * aPluginFrame)705 GetRootWidgetForPluginFrame(const nsPluginFrame* aPluginFrame)
706 {
707 MOZ_ASSERT(aPluginFrame);
708
709 nsViewManager* vm =
710 aPluginFrame->PresContext()->GetPresShell()->GetViewManager();
711 if (!vm) {
712 NS_WARNING("Could not find view manager for plugin frame.");
713 return nullptr;
714 }
715
716 nsCOMPtr<nsIWidget> rootWidget;
717 vm->GetRootWidget(getter_AddRefs(rootWidget));
718 return rootWidget.forget();
719 }
720 #endif
721
GetNetscapeWindow(void * value)722 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
723 {
724 if (!mPluginFrame) {
725 NS_WARNING("plugin owner has no owner in getting doc's window handle");
726 return NS_ERROR_FAILURE;
727 }
728
729 #if defined(XP_WIN)
730 void** pvalue = (void**)value;
731 nsIWidget* offsetContainingWidget = GetContainingWidgetIfOffset();
732 if (offsetContainingWidget) {
733 *pvalue = (void*)offsetContainingWidget->GetNativeData(NS_NATIVE_WINDOW);
734 if (*pvalue) {
735 return NS_OK;
736 }
737 }
738
739 // simply return the topmost document window
740 nsCOMPtr<nsIWidget> widget = GetRootWidgetForPluginFrame(mPluginFrame);
741 if (widget) {
742 *pvalue = widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
743 } else {
744 NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
745 }
746
747 return NS_OK;
748 #elif defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
749 // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
750 nsIWidget* win = mPluginFrame->GetNearestWidget();
751 if (!win)
752 return NS_ERROR_FAILURE;
753 *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
754 return NS_OK;
755 #else
756 return NS_ERROR_NOT_IMPLEMENTED;
757 #endif
758 }
759
760 #if defined(XP_WIN)
761 void
SetWidgetWindowAsParent(HWND aWindowToAdopt)762 nsPluginInstanceOwner::SetWidgetWindowAsParent(HWND aWindowToAdopt)
763 {
764 if (!mWidget) {
765 NS_ERROR("mWidget should exist before this gets called.");
766 return;
767 }
768
769 mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
770 reinterpret_cast<uintptr_t>(aWindowToAdopt));
771 }
772
773 nsresult
SetNetscapeWindowAsParent(HWND aWindowToAdopt)774 nsPluginInstanceOwner::SetNetscapeWindowAsParent(HWND aWindowToAdopt)
775 {
776 if (!mPluginFrame) {
777 NS_WARNING("Plugin owner has no plugin frame.");
778 return NS_ERROR_FAILURE;
779 }
780
781 // If there is a containing window that is offset then ask that to adopt.
782 nsIWidget* offsetWidget = GetContainingWidgetIfOffset();
783 if (offsetWidget) {
784 offsetWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
785 reinterpret_cast<uintptr_t>(aWindowToAdopt));
786 return NS_OK;
787 }
788
789 // Otherwise ask the topmost document window to adopt.
790 nsCOMPtr<nsIWidget> rootWidget = GetRootWidgetForPluginFrame(mPluginFrame);
791 if (!rootWidget) {
792 NS_ASSERTION(rootWidget, "Couldn't get topmost document's widget.");
793 return NS_ERROR_FAILURE;
794 }
795
796 rootWidget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW,
797 reinterpret_cast<uintptr_t>(aWindowToAdopt));
798 return NS_OK;
799 }
800
801 bool
GetCompositionString(uint32_t aType,nsTArray<uint8_t> * aDist,int32_t * aLength)802 nsPluginInstanceOwner::GetCompositionString(uint32_t aType,
803 nsTArray<uint8_t>* aDist,
804 int32_t* aLength)
805 {
806 // Mark pkugin calls ImmGetCompositionStringW correctly
807 mGotCompositionData = true;
808
809 RefPtr<TextComposition> composition = GetTextComposition();
810 if (NS_WARN_IF(!composition)) {
811 return false;
812 }
813
814 switch(aType) {
815 case GCS_COMPSTR: {
816 if (!composition->IsComposing()) {
817 *aLength = 0;
818 return true;
819 }
820
821 uint32_t len = composition->LastData().Length() * sizeof(char16_t);
822 if (len) {
823 aDist->SetLength(len);
824 memcpy(aDist->Elements(), composition->LastData().get(), len);
825 }
826 *aLength = len;
827 return true;
828 }
829
830 case GCS_RESULTSTR: {
831 if (composition->IsComposing()) {
832 *aLength = 0;
833 return true;
834 }
835
836 uint32_t len = composition->LastData().Length() * sizeof(char16_t);
837 if (len) {
838 aDist->SetLength(len);
839 memcpy(aDist->Elements(), composition->LastData().get(), len);
840 }
841 *aLength = len;
842 return true;
843 }
844
845 case GCS_CURSORPOS: {
846 *aLength = 0;
847 TextRangeArray* ranges = composition->GetLastRanges();
848 if (!ranges) {
849 return true;
850 }
851 *aLength = ranges->GetCaretPosition();
852 if (*aLength < 0) {
853 return false;
854 }
855 return true;
856 }
857
858 case GCS_COMPATTR: {
859 TextRangeArray* ranges = composition->GetLastRanges();
860 if (!ranges || ranges->IsEmpty()) {
861 *aLength = 0;
862 return true;
863 }
864
865 aDist->SetLength(composition->LastData().Length());
866 memset(aDist->Elements(), ATTR_INPUT, aDist->Length());
867
868 for (TextRange& range : *ranges) {
869 uint8_t type = ATTR_INPUT;
870 switch(range.mRangeType) {
871 case TextRangeType::eRawClause:
872 type = ATTR_INPUT;
873 break;
874 case TextRangeType::eSelectedRawClause:
875 type = ATTR_TARGET_NOTCONVERTED;
876 break;
877 case TextRangeType::eConvertedClause:
878 type = ATTR_CONVERTED;
879 break;
880 case TextRangeType::eSelectedClause:
881 type = ATTR_TARGET_CONVERTED;
882 break;
883 default:
884 continue;
885 }
886
887 size_t minLen = std::min<size_t>(range.mEndOffset, aDist->Length());
888 for (size_t i = range.mStartOffset; i < minLen; i++) {
889 (*aDist)[i] = type;
890 }
891 }
892 *aLength = aDist->Length();
893 return true;
894 }
895
896 case GCS_COMPCLAUSE: {
897 RefPtr<TextRangeArray> ranges = composition->GetLastRanges();
898 if (!ranges || ranges->IsEmpty()) {
899 aDist->SetLength(sizeof(uint32_t));
900 memset(aDist->Elements(), 0, sizeof(uint32_t));
901 *aLength = aDist->Length();
902 return true;
903 }
904 AutoTArray<uint32_t, 16> clauses;
905 clauses.AppendElement(0);
906 for (TextRange& range : *ranges) {
907 if (!range.IsClause()) {
908 continue;
909 }
910 clauses.AppendElement(range.mEndOffset);
911 }
912
913 aDist->SetLength(clauses.Length() * sizeof(uint32_t));
914 memcpy(aDist->Elements(), clauses.Elements(), aDist->Length());
915 *aLength = aDist->Length();
916 return true;
917 }
918
919 case GCS_RESULTREADSTR: {
920 // When returning error causes unexpected error, so we return 0 instead.
921 *aLength = 0;
922 return true;
923 }
924
925 case GCS_RESULTCLAUSE: {
926 // When returning error causes unexpected error, so we return 0 instead.
927 *aLength = 0;
928 return true;
929 }
930
931 default:
932 NS_WARNING(
933 nsPrintfCString("Unsupported type %x of ImmGetCompositionStringW hook",
934 aType).get());
935 break;
936 }
937
938 return false;
939 }
940
941 bool
SetCandidateWindow(const widget::CandidateWindowPosition & aPosition)942 nsPluginInstanceOwner::SetCandidateWindow(
943 const widget::CandidateWindowPosition& aPosition)
944 {
945 if (NS_WARN_IF(!mPluginFrame)) {
946 return false;
947 }
948
949 nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
950 if (!widget) {
951 widget = GetRootWidgetForPluginFrame(mPluginFrame);
952 if (NS_WARN_IF(!widget)) {
953 return false;
954 }
955 }
956
957 widget->SetCandidateWindowForPlugin(aPosition);
958 return true;
959 }
960
961 bool
RequestCommitOrCancel(bool aCommitted)962 nsPluginInstanceOwner::RequestCommitOrCancel(bool aCommitted)
963 {
964 nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
965 if (!widget) {
966 widget = GetRootWidgetForPluginFrame(mPluginFrame);
967 if (NS_WARN_IF(!widget)) {
968 return false;
969 }
970 }
971
972 if (aCommitted) {
973 widget->NotifyIME(widget::REQUEST_TO_COMMIT_COMPOSITION);
974 } else {
975 widget->NotifyIME(widget::REQUEST_TO_CANCEL_COMPOSITION);
976 }
977 return true;
978 }
979
980 #endif // #ifdef XP_WIN
981
982 void
HandledWindowedPluginKeyEvent(const NativeEventData & aKeyEventData,bool aIsConsumed)983 nsPluginInstanceOwner::HandledWindowedPluginKeyEvent(
984 const NativeEventData& aKeyEventData,
985 bool aIsConsumed)
986 {
987 if (NS_WARN_IF(!mInstance)) {
988 return;
989 }
990 DebugOnly<nsresult> rv =
991 mInstance->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
992 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HandledWindowedPluginKeyEvent fail");
993 }
994
995 void
OnWindowedPluginKeyEvent(const NativeEventData & aKeyEventData)996 nsPluginInstanceOwner::OnWindowedPluginKeyEvent(
997 const NativeEventData& aKeyEventData)
998 {
999 if (NS_WARN_IF(!mPluginFrame)) {
1000 // Notifies the plugin process of the key event being not consumed by us.
1001 HandledWindowedPluginKeyEvent(aKeyEventData, false);
1002 return;
1003 }
1004
1005 nsCOMPtr<nsIWidget> widget = mPluginFrame->PresContext()->GetRootWidget();
1006 if (NS_WARN_IF(!widget)) {
1007 // Notifies the plugin process of the key event being not consumed by us.
1008 HandledWindowedPluginKeyEvent(aKeyEventData, false);
1009 return;
1010 }
1011
1012 nsresult rv = widget->OnWindowedPluginKeyEvent(aKeyEventData, this);
1013 if (NS_WARN_IF(NS_FAILED(rv))) {
1014 // Notifies the plugin process of the key event being not consumed by us.
1015 HandledWindowedPluginKeyEvent(aKeyEventData, false);
1016 return;
1017 }
1018
1019 // If the key event is posted to another process, we need to wait a call
1020 // of HandledWindowedPluginKeyEvent(). So, nothing to do here in this case.
1021 if (rv == NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY) {
1022 return;
1023 }
1024
1025 // Otherwise, the key event is handled synchronously. Let's notify the
1026 // plugin process of the key event's result.
1027 bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
1028 HandledWindowedPluginKeyEvent(aKeyEventData, consumed);
1029 }
1030
SetEventModel(int32_t eventModel)1031 NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
1032 {
1033 #ifdef XP_MACOSX
1034 mEventModel = static_cast<NPEventModel>(eventModel);
1035 return NS_OK;
1036 #else
1037 return NS_ERROR_NOT_IMPLEMENTED;
1038 #endif
1039 }
1040
1041 #ifdef XP_MACOSX
ConvertPointPuppet(PuppetWidget * widget,nsPluginFrame * pluginFrame,double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)1042 NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
1043 nsPluginFrame* pluginFrame,
1044 double sourceX, double sourceY,
1045 NPCoordinateSpace sourceSpace,
1046 double *destX, double *destY,
1047 NPCoordinateSpace destSpace)
1048 {
1049 NS_ENSURE_TRUE(widget && widget->GetOwningTabChild() && pluginFrame, false);
1050 // Caller has to want a result.
1051 NS_ENSURE_TRUE(destX || destY, false);
1052
1053 if (sourceSpace == destSpace) {
1054 if (destX) {
1055 *destX = sourceX;
1056 }
1057 if (destY) {
1058 *destY = sourceY;
1059 }
1060 return true;
1061 }
1062
1063 nsPresContext* presContext = pluginFrame->PresContext();
1064 double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
1065 presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
1066
1067 PuppetWidget *puppetWidget = static_cast<PuppetWidget*>(widget);
1068 PuppetWidget *rootWidget = static_cast<PuppetWidget*>(widget->GetTopLevelWidget());
1069 if (!rootWidget) {
1070 return false;
1071 }
1072 nsPoint chromeSize = AsNsPoint(rootWidget->GetChromeDimensions()) / scaleFactor;
1073 nsIntSize intScreenDims = rootWidget->GetScreenDimensions();
1074 nsSize screenDims = nsSize(intScreenDims.width / scaleFactor,
1075 intScreenDims.height / scaleFactor);
1076 int32_t screenH = screenDims.height;
1077 nsPoint windowPosition = AsNsPoint(rootWidget->GetWindowPosition()) / scaleFactor;
1078
1079 // Window size is tab size + chrome size.
1080 LayoutDeviceIntRect tabContentBounds = puppetWidget->GetBounds();
1081 tabContentBounds.ScaleInverseRoundOut(scaleFactor);
1082 int32_t windowH = tabContentBounds.height + int(chromeSize.y);
1083
1084 nsPoint pluginPosition = AsNsPoint(pluginFrame->GetScreenRect().TopLeft());
1085
1086 // Convert (sourceX, sourceY) to 'real' (not PuppetWidget) screen space.
1087 // In OSX, the Y-axis increases upward, which is the reverse of ours.
1088 // We want OSX coordinates for window and screen so those equations are swapped.
1089 nsPoint sourcePoint(sourceX, sourceY);
1090 nsPoint screenPoint;
1091 switch (sourceSpace) {
1092 case NPCoordinateSpacePlugin:
1093 screenPoint = sourcePoint + pluginPosition +
1094 pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
1095 break;
1096 case NPCoordinateSpaceWindow:
1097 screenPoint = nsPoint(sourcePoint.x, windowH-sourcePoint.y) +
1098 windowPosition;
1099 break;
1100 case NPCoordinateSpaceFlippedWindow:
1101 screenPoint = sourcePoint + windowPosition;
1102 break;
1103 case NPCoordinateSpaceScreen:
1104 screenPoint = nsPoint(sourcePoint.x, screenH-sourcePoint.y);
1105 break;
1106 case NPCoordinateSpaceFlippedScreen:
1107 screenPoint = sourcePoint;
1108 break;
1109 default:
1110 return false;
1111 }
1112
1113 // Convert from screen to dest space.
1114 nsPoint destPoint;
1115 switch (destSpace) {
1116 case NPCoordinateSpacePlugin:
1117 destPoint = screenPoint - pluginPosition -
1118 pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
1119 break;
1120 case NPCoordinateSpaceWindow:
1121 destPoint = screenPoint - windowPosition;
1122 destPoint.y = windowH - destPoint.y;
1123 break;
1124 case NPCoordinateSpaceFlippedWindow:
1125 destPoint = screenPoint - windowPosition;
1126 break;
1127 case NPCoordinateSpaceScreen:
1128 destPoint = nsPoint(screenPoint.x, screenH-screenPoint.y);
1129 break;
1130 case NPCoordinateSpaceFlippedScreen:
1131 destPoint = screenPoint;
1132 break;
1133 default:
1134 return false;
1135 }
1136
1137 if (destX) {
1138 *destX = destPoint.x;
1139 }
1140 if (destY) {
1141 *destY = destPoint.y;
1142 }
1143
1144 return true;
1145 }
1146
ConvertPointNoPuppet(nsIWidget * widget,nsPluginFrame * pluginFrame,double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)1147 NPBool nsPluginInstanceOwner::ConvertPointNoPuppet(nsIWidget *widget,
1148 nsPluginFrame* pluginFrame,
1149 double sourceX, double sourceY,
1150 NPCoordinateSpace sourceSpace,
1151 double *destX, double *destY,
1152 NPCoordinateSpace destSpace)
1153 {
1154 NS_ENSURE_TRUE(widget && pluginFrame, false);
1155 // Caller has to want a result.
1156 NS_ENSURE_TRUE(destX || destY, false);
1157
1158 if (sourceSpace == destSpace) {
1159 if (destX) {
1160 *destX = sourceX;
1161 }
1162 if (destY) {
1163 *destY = sourceY;
1164 }
1165 return true;
1166 }
1167
1168 nsPresContext* presContext = pluginFrame->PresContext();
1169 double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
1170 presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
1171
1172 nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
1173 if (!screenMgr) {
1174 return false;
1175 }
1176 nsCOMPtr<nsIScreen> screen;
1177 screenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW), getter_AddRefs(screen));
1178 if (!screen) {
1179 return false;
1180 }
1181
1182 int32_t screenX, screenY, screenWidth, screenHeight;
1183 screen->GetRect(&screenX, &screenY, &screenWidth, &screenHeight);
1184 screenHeight /= scaleFactor;
1185
1186 LayoutDeviceIntRect windowScreenBounds = widget->GetScreenBounds();
1187 windowScreenBounds.ScaleInverseRoundOut(scaleFactor);
1188 int32_t windowX = windowScreenBounds.x;
1189 int32_t windowY = windowScreenBounds.y;
1190 int32_t windowHeight = windowScreenBounds.height;
1191
1192 nsIntRect pluginScreenRect = pluginFrame->GetScreenRect();
1193
1194 double screenXGecko, screenYGecko;
1195 switch (sourceSpace) {
1196 case NPCoordinateSpacePlugin:
1197 screenXGecko = pluginScreenRect.x + sourceX;
1198 screenYGecko = pluginScreenRect.y + sourceY;
1199 break;
1200 case NPCoordinateSpaceWindow:
1201 screenXGecko = windowX + sourceX;
1202 screenYGecko = windowY + (windowHeight - sourceY);
1203 break;
1204 case NPCoordinateSpaceFlippedWindow:
1205 screenXGecko = windowX + sourceX;
1206 screenYGecko = windowY + sourceY;
1207 break;
1208 case NPCoordinateSpaceScreen:
1209 screenXGecko = sourceX;
1210 screenYGecko = screenHeight - sourceY;
1211 break;
1212 case NPCoordinateSpaceFlippedScreen:
1213 screenXGecko = sourceX;
1214 screenYGecko = sourceY;
1215 break;
1216 default:
1217 return false;
1218 }
1219
1220 double destXCocoa, destYCocoa;
1221 switch (destSpace) {
1222 case NPCoordinateSpacePlugin:
1223 destXCocoa = screenXGecko - pluginScreenRect.x;
1224 destYCocoa = screenYGecko - pluginScreenRect.y;
1225 break;
1226 case NPCoordinateSpaceWindow:
1227 destXCocoa = screenXGecko - windowX;
1228 destYCocoa = windowHeight - (screenYGecko - windowY);
1229 break;
1230 case NPCoordinateSpaceFlippedWindow:
1231 destXCocoa = screenXGecko - windowX;
1232 destYCocoa = screenYGecko - windowY;
1233 break;
1234 case NPCoordinateSpaceScreen:
1235 destXCocoa = screenXGecko;
1236 destYCocoa = screenHeight - screenYGecko;
1237 break;
1238 case NPCoordinateSpaceFlippedScreen:
1239 destXCocoa = screenXGecko;
1240 destYCocoa = screenYGecko;
1241 break;
1242 default:
1243 return false;
1244 }
1245
1246 if (destX) {
1247 *destX = destXCocoa;
1248 }
1249 if (destY) {
1250 *destY = destYCocoa;
1251 }
1252
1253 return true;
1254 }
1255 #endif // XP_MACOSX
1256
ConvertPoint(double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)1257 NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
1258 double *destX, double *destY, NPCoordinateSpace destSpace)
1259 {
1260 #ifdef XP_MACOSX
1261 if (!mPluginFrame) {
1262 return false;
1263 }
1264
1265 MOZ_ASSERT(mPluginFrame->GetNearestWidget());
1266
1267 if (nsIWidget::UsePuppetWidgets()) {
1268 return ConvertPointPuppet(static_cast<PuppetWidget*>(mPluginFrame->GetNearestWidget()),
1269 mPluginFrame, sourceX, sourceY, sourceSpace,
1270 destX, destY, destSpace);
1271 }
1272
1273 return ConvertPointNoPuppet(mPluginFrame->GetNearestWidget(),
1274 mPluginFrame, sourceX, sourceY, sourceSpace,
1275 destX, destY, destSpace);
1276 #else
1277 return false;
1278 #endif
1279 }
1280
InitAsyncSurface(NPSize * size,NPImageFormat format,void * initData,NPAsyncSurface * surface)1281 NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
1282 void *initData, NPAsyncSurface *surface)
1283 {
1284 return NPERR_INCOMPATIBLE_VERSION_ERROR;
1285 }
1286
FinalizeAsyncSurface(NPAsyncSurface *)1287 NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
1288 {
1289 return NPERR_INCOMPATIBLE_VERSION_ERROR;
1290 }
1291
SetCurrentAsyncSurface(NPAsyncSurface *,NPRect *)1292 void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
1293 {
1294 }
1295
GetTagType(nsPluginTagType * result)1296 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
1297 {
1298 NS_ENSURE_ARG_POINTER(result);
1299
1300 *result = nsPluginTagType_Unknown;
1301
1302 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
1303 if (content->IsHTMLElement(nsGkAtoms::applet))
1304 *result = nsPluginTagType_Applet;
1305 else if (content->IsHTMLElement(nsGkAtoms::embed))
1306 *result = nsPluginTagType_Embed;
1307 else if (content->IsHTMLElement(nsGkAtoms::object))
1308 *result = nsPluginTagType_Object;
1309
1310 return NS_OK;
1311 }
1312
GetParameters(nsTArray<MozPluginParameter> & parameters)1313 void nsPluginInstanceOwner::GetParameters(nsTArray<MozPluginParameter>& parameters)
1314 {
1315 nsCOMPtr<nsIObjectLoadingContent> content = do_QueryReferent(mContent);
1316 nsObjectLoadingContent *loadingContent =
1317 static_cast<nsObjectLoadingContent*>(content.get());
1318
1319 loadingContent->GetPluginParameters(parameters);
1320 }
1321
1322 #ifdef XP_MACOSX
1323
InitializeNPCocoaEvent(NPCocoaEvent * event)1324 static void InitializeNPCocoaEvent(NPCocoaEvent* event)
1325 {
1326 memset(event, 0, sizeof(NPCocoaEvent));
1327 }
1328
GetDrawingModel()1329 NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
1330 {
1331 #ifndef NP_NO_QUICKDRAW
1332 // We don't support the Quickdraw drawing model any more but it's still
1333 // the default model for i386 per NPAPI.
1334 NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
1335 #else
1336 NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
1337 #endif
1338
1339 if (!mInstance)
1340 return drawingModel;
1341
1342 mInstance->GetDrawingModel((int32_t*)&drawingModel);
1343 return drawingModel;
1344 }
1345
IsRemoteDrawingCoreAnimation()1346 bool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation()
1347 {
1348 if (!mInstance)
1349 return false;
1350
1351 bool coreAnimation;
1352 if (!NS_SUCCEEDED(mInstance->IsRemoteDrawingCoreAnimation(&coreAnimation)))
1353 return false;
1354
1355 return coreAnimation;
1356 }
1357
GetEventModel()1358 NPEventModel nsPluginInstanceOwner::GetEventModel()
1359 {
1360 return mEventModel;
1361 }
1362
1363 #define DEFAULT_REFRESH_RATE 20 // 50 FPS
1364
1365 nsCOMPtr<nsITimer> *nsPluginInstanceOwner::sCATimer = nullptr;
1366 nsTArray<nsPluginInstanceOwner*> *nsPluginInstanceOwner::sCARefreshListeners = nullptr;
1367
CARefresh(nsITimer * aTimer,void * aClosure)1368 void nsPluginInstanceOwner::CARefresh(nsITimer *aTimer, void *aClosure) {
1369 if (!sCARefreshListeners) {
1370 return;
1371 }
1372 for (size_t i = 0; i < sCARefreshListeners->Length(); i++) {
1373 nsPluginInstanceOwner* instanceOwner = (*sCARefreshListeners)[i];
1374 NPWindow *window;
1375 instanceOwner->GetWindow(window);
1376 if (!window) {
1377 continue;
1378 }
1379 NPRect r;
1380 r.left = 0;
1381 r.top = 0;
1382 r.right = window->width;
1383 r.bottom = window->height;
1384 instanceOwner->InvalidateRect(&r);
1385 }
1386 }
1387
AddToCARefreshTimer()1388 void nsPluginInstanceOwner::AddToCARefreshTimer() {
1389 if (!mInstance) {
1390 return;
1391 }
1392
1393 // Flash invokes InvalidateRect for us.
1394 const char* mime = nullptr;
1395 if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime &&
1396 nsPluginHost::GetSpecialType(nsDependentCString(mime)) ==
1397 nsPluginHost::eSpecialType_Flash) {
1398 return;
1399 }
1400
1401 if (!sCARefreshListeners) {
1402 sCARefreshListeners = new nsTArray<nsPluginInstanceOwner*>();
1403 }
1404
1405 if (sCARefreshListeners->Contains(this)) {
1406 return;
1407 }
1408
1409 sCARefreshListeners->AppendElement(this);
1410
1411 if (!sCATimer) {
1412 sCATimer = new nsCOMPtr<nsITimer>();
1413 }
1414
1415 if (sCARefreshListeners->Length() == 1) {
1416 *sCATimer = do_CreateInstance("@mozilla.org/timer;1");
1417 (*sCATimer)->InitWithFuncCallback(CARefresh, nullptr,
1418 DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK);
1419 }
1420 }
1421
RemoveFromCARefreshTimer()1422 void nsPluginInstanceOwner::RemoveFromCARefreshTimer() {
1423 if (!sCARefreshListeners || sCARefreshListeners->Contains(this) == false) {
1424 return;
1425 }
1426
1427 sCARefreshListeners->RemoveElement(this);
1428
1429 if (sCARefreshListeners->Length() == 0) {
1430 if (sCATimer) {
1431 (*sCATimer)->Cancel();
1432 delete sCATimer;
1433 sCATimer = nullptr;
1434 }
1435 delete sCARefreshListeners;
1436 sCARefreshListeners = nullptr;
1437 }
1438 }
1439
SetPluginPort()1440 void nsPluginInstanceOwner::SetPluginPort()
1441 {
1442 void* pluginPort = GetPluginPort();
1443 if (!pluginPort || !mPluginWindow)
1444 return;
1445 mPluginWindow->window = pluginPort;
1446 }
1447 #endif
1448 #if defined(XP_MACOSX) || defined(XP_WIN)
ContentsScaleFactorChanged(double aContentsScaleFactor)1449 nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor)
1450 {
1451 if (!mInstance) {
1452 return NS_ERROR_NULL_POINTER;
1453 }
1454 return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor);
1455 }
1456 #endif
1457
1458
1459 // static
1460 uint32_t
GetEventloopNestingLevel()1461 nsPluginInstanceOwner::GetEventloopNestingLevel()
1462 {
1463 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
1464 uint32_t currentLevel = 0;
1465 if (appShell) {
1466 appShell->GetEventloopNestingLevel(¤tLevel);
1467 #ifdef XP_MACOSX
1468 // Cocoa widget code doesn't process UI events through the normal
1469 // appshell event loop, so it needs an additional count here.
1470 currentLevel++;
1471 #endif
1472 }
1473
1474 // No idea how this happens... but Linux doesn't consistently
1475 // process UI events through the appshell event loop. If we get a 0
1476 // here on any platform we increment the level just in case so that
1477 // we make sure we always tear the plugin down eventually.
1478 if (!currentLevel) {
1479 currentLevel++;
1480 }
1481
1482 return currentLevel;
1483 }
1484
1485 #ifdef MOZ_WIDGET_ANDROID
1486
1487 // Modified version of nsFrame::GetOffsetToCrossDoc that stops when it
1488 // hits an element with a displayport (or runs out of frames). This is
1489 // not really the right thing to do, but it's better than what was here before.
1490 static nsPoint
GetOffsetRootContent(nsIFrame * aFrame)1491 GetOffsetRootContent(nsIFrame* aFrame)
1492 {
1493 // offset will hold the final offset
1494 // docOffset holds the currently accumulated offset at the current APD, it
1495 // will be converted and added to offset when the current APD changes.
1496 nsPoint offset(0, 0), docOffset(0, 0);
1497 const nsIFrame* f = aFrame;
1498 int32_t currAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
1499 int32_t apd = currAPD;
1500 while (f) {
1501 if (f->GetContent() && nsLayoutUtils::HasDisplayPort(f->GetContent()))
1502 break;
1503
1504 docOffset += f->GetPosition();
1505 nsIFrame* parent = f->GetParent();
1506 if (parent) {
1507 f = parent;
1508 } else {
1509 nsPoint newOffset(0, 0);
1510 f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
1511 int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
1512 if (!f || newAPD != currAPD) {
1513 // Convert docOffset to the right APD and add it to offset.
1514 offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
1515 docOffset.x = docOffset.y = 0;
1516 }
1517 currAPD = newAPD;
1518 docOffset += newOffset;
1519 }
1520 }
1521
1522 offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
1523
1524 return offset;
1525 }
1526
GetPluginRect()1527 LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
1528 {
1529 // Get the offset of the content relative to the page
1530 nsRect bounds = mPluginFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mPluginFrame);
1531 LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mPluginFrame->PresContext()->AppUnitsPerDevPixel());
1532 return LayoutDeviceRect(rect);
1533 }
1534
AddPluginView(const LayoutDeviceRect & aRect)1535 bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */)
1536 {
1537 if (!mJavaView) {
1538 mJavaView = mInstance->GetJavaSurface();
1539
1540 if (!mJavaView)
1541 return false;
1542
1543 mJavaView = (void*)jni::GetGeckoThreadEnv()->NewGlobalRef((jobject)mJavaView);
1544 }
1545
1546 if (mFullScreen) {
1547 java::GeckoAppShell::AddFullScreenPluginView(jni::Object::Ref::From(jobject(mJavaView)));
1548 sFullScreenInstance = this;
1549 }
1550
1551 return true;
1552 }
1553
RemovePluginView()1554 void nsPluginInstanceOwner::RemovePluginView()
1555 {
1556 if (!mInstance || !mJavaView)
1557 return;
1558
1559 if (mFullScreen) {
1560 java::GeckoAppShell::RemoveFullScreenPluginView(jni::Object::Ref::From(jobject(mJavaView)));
1561 }
1562 jni::GetGeckoThreadEnv()->DeleteGlobalRef((jobject)mJavaView);
1563 mJavaView = nullptr;
1564
1565 if (mFullScreen)
1566 sFullScreenInstance = nullptr;
1567 }
1568
1569 void
GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo * > & aVideos)1570 nsPluginInstanceOwner::GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos)
1571 {
1572 if (!mInstance)
1573 return;
1574
1575 mInstance->GetVideos(aVideos);
1576 }
1577
1578 already_AddRefed<ImageContainer>
GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo * aVideoInfo)1579 nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
1580 {
1581 RefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
1582
1583 if (aVideoInfo->mDimensions.width && aVideoInfo->mDimensions.height) {
1584 RefPtr<Image> img = new SurfaceTextureImage(
1585 aVideoInfo->mSurfaceTexture,
1586 gfx::IntSize::Truncate(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height),
1587 gl::OriginPos::BottomLeft);
1588 container->SetCurrentImageInTransaction(img);
1589 }
1590
1591 return container.forget();
1592 }
1593
Invalidate()1594 void nsPluginInstanceOwner::Invalidate() {
1595 NPRect rect;
1596 rect.left = rect.top = 0;
1597 rect.right = mPluginWindow->width;
1598 rect.bottom = mPluginWindow->height;
1599 InvalidateRect(&rect);
1600 }
1601
Recomposite()1602 void nsPluginInstanceOwner::Recomposite() {
1603 nsIWidget* const widget = mPluginFrame->GetNearestWidget();
1604 NS_ENSURE_TRUE_VOID(widget);
1605
1606 LayerManager* const lm = widget->GetLayerManager();
1607 NS_ENSURE_TRUE_VOID(lm);
1608
1609 ClientLayerManager* const clm = lm->AsClientLayerManager();
1610 NS_ENSURE_TRUE_VOID(clm && clm->GetRoot());
1611
1612 clm->SendInvalidRegion(
1613 clm->GetRoot()->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
1614 clm->Composite();
1615 }
1616
RequestFullScreen()1617 void nsPluginInstanceOwner::RequestFullScreen() {
1618 if (mFullScreen)
1619 return;
1620
1621 // Remove whatever view we currently have (if any, fullscreen or otherwise)
1622 RemovePluginView();
1623
1624 mFullScreen = true;
1625 AddPluginView();
1626
1627 mInstance->NotifyFullScreen(mFullScreen);
1628 }
1629
ExitFullScreen()1630 void nsPluginInstanceOwner::ExitFullScreen() {
1631 if (!mFullScreen)
1632 return;
1633
1634 RemovePluginView();
1635
1636 mFullScreen = false;
1637
1638 int32_t model = mInstance->GetANPDrawingModel();
1639
1640 if (model == kSurface_ANPDrawingModel) {
1641 // We need to do this immediately, otherwise Flash
1642 // sometimes causes a deadlock (bug 762407)
1643 AddPluginView(GetPluginRect());
1644 }
1645
1646 mInstance->NotifyFullScreen(mFullScreen);
1647
1648 // This will cause Paint() to be called, which is where
1649 // we normally add/update views and layers
1650 Invalidate();
1651 }
1652
ExitFullScreen(jobject view)1653 void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
1654 JNIEnv* env = jni::GetGeckoThreadEnv();
1655
1656 if (sFullScreenInstance && sFullScreenInstance->mInstance &&
1657 env->IsSameObject(view, (jobject)sFullScreenInstance->mInstance->GetJavaSurface())) {
1658 sFullScreenInstance->ExitFullScreen();
1659 }
1660 }
1661
1662 #endif
1663
1664 void
NotifyHostAsyncInitFailed()1665 nsPluginInstanceOwner::NotifyHostAsyncInitFailed()
1666 {
1667 nsCOMPtr<nsIObjectLoadingContent> content = do_QueryReferent(mContent);
1668 content->StopPluginInstance();
1669 }
1670
1671 void
NotifyHostCreateWidget()1672 nsPluginInstanceOwner::NotifyHostCreateWidget()
1673 {
1674 mPluginHost->CreateWidget(this);
1675 #ifdef XP_MACOSX
1676 FixUpPluginWindow(ePluginPaintEnable);
1677 #else
1678 if (mPluginFrame) {
1679 mPluginFrame->InvalidateFrame();
1680 } else {
1681 CallSetWindow();
1682 }
1683 #endif
1684 }
1685
1686 void
NotifyDestroyPending()1687 nsPluginInstanceOwner::NotifyDestroyPending()
1688 {
1689 if (!mInstance) {
1690 return;
1691 }
1692 bool isOOP = false;
1693 if (NS_FAILED(mInstance->GetIsOOP(&isOOP)) || !isOOP) {
1694 return;
1695 }
1696 NPP npp = nullptr;
1697 if (NS_FAILED(mInstance->GetNPP(&npp)) || !npp) {
1698 return;
1699 }
1700 PluginAsyncSurrogate::NotifyDestroyPending(npp);
1701 }
1702
DispatchFocusToPlugin(nsIDOMEvent * aFocusEvent)1703 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
1704 {
1705 #ifdef MOZ_WIDGET_ANDROID
1706 if (mInstance) {
1707 ANPEvent event;
1708 event.inSize = sizeof(ANPEvent);
1709 event.eventType = kLifecycle_ANPEventType;
1710
1711 nsAutoString eventType;
1712 aFocusEvent->GetType(eventType);
1713 if (eventType.EqualsLiteral("focus")) {
1714 event.data.lifecycle.action = kGainFocus_ANPLifecycleAction;
1715 }
1716 else if (eventType.EqualsLiteral("blur")) {
1717 event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction;
1718 }
1719 else {
1720 NS_ASSERTION(false, "nsPluginInstanceOwner::DispatchFocusToPlugin, wierd eventType");
1721 }
1722 mInstance->HandleEvent(&event, nullptr);
1723 }
1724 #endif
1725
1726 #ifndef XP_MACOSX
1727 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
1728 // continue only for cases without child window
1729 return aFocusEvent->PreventDefault(); // consume event
1730 }
1731 #endif
1732
1733 WidgetEvent* theEvent = aFocusEvent->WidgetEventPtr();
1734 if (theEvent) {
1735 WidgetGUIEvent focusEvent(theEvent->IsTrusted(), theEvent->mMessage,
1736 nullptr);
1737 nsEventStatus rv = ProcessEvent(focusEvent);
1738 if (nsEventStatus_eConsumeNoDefault == rv) {
1739 aFocusEvent->PreventDefault();
1740 aFocusEvent->StopPropagation();
1741 }
1742 }
1743
1744 return NS_OK;
1745 }
1746
ProcessKeyPress(nsIDOMEvent * aKeyEvent)1747 nsresult nsPluginInstanceOwner::ProcessKeyPress(nsIDOMEvent* aKeyEvent)
1748 {
1749 #ifdef XP_MACOSX
1750 return DispatchKeyToPlugin(aKeyEvent);
1751 #else
1752 if (SendNativeEvents())
1753 DispatchKeyToPlugin(aKeyEvent);
1754
1755 if (mInstance) {
1756 // If this event is going to the plugin, we want to kill it.
1757 // Not actually sending keypress to the plugin, since we didn't before.
1758 aKeyEvent->PreventDefault();
1759 aKeyEvent->StopPropagation();
1760 }
1761 return NS_OK;
1762 #endif
1763 }
1764
DispatchKeyToPlugin(nsIDOMEvent * aKeyEvent)1765 nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
1766 {
1767 #if !defined(XP_MACOSX)
1768 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
1769 return aKeyEvent->PreventDefault(); // consume event
1770 // continue only for cases without child window
1771 #endif
1772
1773 if (mInstance) {
1774 WidgetKeyboardEvent* keyEvent =
1775 aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
1776 if (keyEvent && keyEvent->mClass == eKeyboardEventClass) {
1777 nsEventStatus rv = ProcessEvent(*keyEvent);
1778 if (nsEventStatus_eConsumeNoDefault == rv) {
1779 aKeyEvent->PreventDefault();
1780 aKeyEvent->StopPropagation();
1781 }
1782 }
1783 }
1784
1785 return NS_OK;
1786 }
1787
1788 nsresult
ProcessMouseDown(nsIDOMEvent * aMouseEvent)1789 nsPluginInstanceOwner::ProcessMouseDown(nsIDOMEvent* aMouseEvent)
1790 {
1791 #if !defined(XP_MACOSX)
1792 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
1793 return aMouseEvent->PreventDefault(); // consume event
1794 // continue only for cases without child window
1795 #endif
1796
1797 // if the plugin is windowless, we need to set focus ourselves
1798 // otherwise, we might not get key events
1799 if (mPluginFrame && mPluginWindow &&
1800 mPluginWindow->type == NPWindowTypeDrawable) {
1801
1802 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1803 if (fm) {
1804 nsCOMPtr<nsIDOMElement> elem = do_QueryReferent(mContent);
1805 fm->SetFocus(elem, 0);
1806 }
1807 }
1808
1809 WidgetMouseEvent* mouseEvent =
1810 aMouseEvent->WidgetEventPtr()->AsMouseEvent();
1811 if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
1812 mLastMouseDownButtonType = mouseEvent->button;
1813 nsEventStatus rv = ProcessEvent(*mouseEvent);
1814 if (nsEventStatus_eConsumeNoDefault == rv) {
1815 return aMouseEvent->PreventDefault(); // consume event
1816 }
1817 }
1818
1819 return NS_OK;
1820 }
1821
DispatchMouseToPlugin(nsIDOMEvent * aMouseEvent,bool aAllowPropagate)1822 nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
1823 bool aAllowPropagate)
1824 {
1825 #if !defined(XP_MACOSX)
1826 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
1827 return aMouseEvent->PreventDefault(); // consume event
1828 // continue only for cases without child window
1829 #endif
1830 // don't send mouse events if we are hidden
1831 if (!mWidgetVisible)
1832 return NS_OK;
1833
1834 WidgetMouseEvent* mouseEvent =
1835 aMouseEvent->WidgetEventPtr()->AsMouseEvent();
1836 if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
1837 nsEventStatus rv = ProcessEvent(*mouseEvent);
1838 if (nsEventStatus_eConsumeNoDefault == rv) {
1839 aMouseEvent->PreventDefault();
1840 if (!aAllowPropagate) {
1841 aMouseEvent->StopPropagation();
1842 }
1843 }
1844 if (mouseEvent->mMessage == eMouseUp) {
1845 mLastMouseDownButtonType = -1;
1846 }
1847 }
1848 return NS_OK;
1849 }
1850
1851 #ifdef XP_WIN
1852 void
CallDefaultProc(const WidgetGUIEvent * aEvent)1853 nsPluginInstanceOwner::CallDefaultProc(const WidgetGUIEvent* aEvent)
1854 {
1855 nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
1856 if (!widget) {
1857 widget = GetRootWidgetForPluginFrame(mPluginFrame);
1858 if (NS_WARN_IF(!widget)) {
1859 return;
1860 }
1861 }
1862
1863 const NPEvent* npEvent =
1864 static_cast<const NPEvent*>(aEvent->mPluginEvent);
1865 if (NS_WARN_IF(!npEvent)) {
1866 return;
1867 }
1868
1869 WidgetPluginEvent pluginEvent(true, ePluginInputEvent, widget);
1870 pluginEvent.mPluginEvent.Copy(*npEvent);
1871 widget->DefaultProcOfPluginEvent(pluginEvent);
1872 }
1873
1874 already_AddRefed<TextComposition>
GetTextComposition()1875 nsPluginInstanceOwner::GetTextComposition()
1876 {
1877 if (NS_WARN_IF(!mPluginFrame)) {
1878 return nullptr;
1879 }
1880
1881 nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
1882 if (!widget) {
1883 widget = GetRootWidgetForPluginFrame(mPluginFrame);
1884 if (NS_WARN_IF(!widget)) {
1885 return nullptr;
1886 }
1887 }
1888
1889 RefPtr<TextComposition> composition =
1890 IMEStateManager::GetTextCompositionFor(widget);
1891 if (NS_WARN_IF(!composition)) {
1892 return nullptr;
1893 }
1894
1895 return composition.forget();
1896 }
1897
1898 void
HandleNoConsumedCompositionMessage(WidgetCompositionEvent * aCompositionEvent,const NPEvent * aPluginEvent)1899 nsPluginInstanceOwner::HandleNoConsumedCompositionMessage(
1900 WidgetCompositionEvent* aCompositionEvent,
1901 const NPEvent* aPluginEvent)
1902 {
1903 nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
1904 if (!widget) {
1905 widget = GetRootWidgetForPluginFrame(mPluginFrame);
1906 if (NS_WARN_IF(!widget)) {
1907 return;
1908 }
1909 }
1910
1911 NPEvent npevent;
1912 if (aPluginEvent->lParam & GCS_RESULTSTR) {
1913 // GCS_RESULTSTR's default proc will generate WM_CHAR. So emulate it.
1914 for (size_t i = 0; i < aCompositionEvent->mData.Length(); i++) {
1915 WidgetPluginEvent charEvent(true, ePluginInputEvent, widget);
1916 npevent.event = WM_CHAR;
1917 npevent.wParam = aCompositionEvent->mData[i];
1918 npevent.lParam = 0;
1919 charEvent.mPluginEvent.Copy(npevent);
1920 ProcessEvent(charEvent);
1921 }
1922 return;
1923 }
1924 if (!mSentStartComposition) {
1925 // We post WM_IME_COMPOSITION to default proc, but
1926 // WM_IME_STARTCOMPOSITION isn't post yet. We should post it at first.
1927 WidgetPluginEvent startEvent(true, ePluginInputEvent, widget);
1928 npevent.event = WM_IME_STARTCOMPOSITION;
1929 npevent.wParam = 0;
1930 npevent.lParam = 0;
1931 startEvent.mPluginEvent.Copy(npevent);
1932 CallDefaultProc(&startEvent);
1933 mSentStartComposition = true;
1934 }
1935
1936 CallDefaultProc(aCompositionEvent);
1937 }
1938 #endif
1939
1940 nsresult
DispatchCompositionToPlugin(nsIDOMEvent * aEvent)1941 nsPluginInstanceOwner::DispatchCompositionToPlugin(nsIDOMEvent* aEvent)
1942 {
1943 #ifdef XP_WIN
1944 if (!mPluginWindow) {
1945 // CompositionEvent isn't cancellable. So it is unnecessary to call
1946 // PreventDefaults() to consume event
1947 return NS_OK;
1948 }
1949 WidgetCompositionEvent* compositionEvent =
1950 aEvent->WidgetEventPtr()->AsCompositionEvent();
1951 if (NS_WARN_IF(!compositionEvent)) {
1952 return NS_ERROR_INVALID_ARG;
1953 }
1954
1955 if (compositionEvent->mMessage == eCompositionChange) {
1956 RefPtr<TextComposition> composition = GetTextComposition();
1957 if (NS_WARN_IF(!composition)) {
1958 return NS_ERROR_FAILURE;
1959 }
1960 TextComposition::CompositionChangeEventHandlingMarker
1961 compositionChangeEventHandlingMarker(composition, compositionEvent);
1962 }
1963
1964 const NPEvent* pPluginEvent =
1965 static_cast<const NPEvent*>(compositionEvent->mPluginEvent);
1966 if (pPluginEvent && pPluginEvent->event == WM_IME_COMPOSITION &&
1967 mPluginDidNotHandleIMEComposition) {
1968 // This is a workaround when running windowed and windowless Flash on
1969 // same process.
1970 // Flash with protected mode calls IMM APIs on own render process. This
1971 // is a bug of Flash's protected mode.
1972 // ImmGetCompositionString with GCS_RESULTSTR returns *LAST* committed
1973 // string. So when windowed mode Flash handles IME composition,
1974 // windowless plugin can get windowed mode's commited string by that API.
1975 // So we never post WM_IME_COMPOSITION when plugin doesn't call
1976 // ImmGetCompositionString() during WM_IME_COMPOSITION correctly.
1977 HandleNoConsumedCompositionMessage(compositionEvent, pPluginEvent);
1978 aEvent->StopImmediatePropagation();
1979 return NS_OK;
1980 }
1981
1982 // Protected mode Flash returns noDefault by NPP_HandleEvent, but
1983 // composition information into plugin is invalid because plugin's bug.
1984 // So if plugin doesn't get composition data by WM_IME_COMPOSITION, we
1985 // recongnize it isn't handled
1986 AutoRestore<bool> restore(mGotCompositionData);
1987 mGotCompositionData = false;
1988
1989 nsEventStatus status = ProcessEvent(*compositionEvent);
1990 aEvent->StopImmediatePropagation();
1991
1992 // Composition event isn't handled by plugin, so we have to call default proc.
1993
1994 if (NS_WARN_IF(!pPluginEvent)) {
1995 return NS_OK;
1996 }
1997
1998 if (pPluginEvent->event == WM_IME_STARTCOMPOSITION) {
1999 // Flash's protected mode lies that composition event is handled, but it
2000 // cannot do it well. So even if handled, we should post this message when
2001 // no IMM API calls during WM_IME_COMPOSITION.
2002 if (nsEventStatus_eConsumeNoDefault != status) {
2003 CallDefaultProc(compositionEvent);
2004 mSentStartComposition = true;
2005 } else {
2006 mSentStartComposition = false;
2007 }
2008 mPluginDidNotHandleIMEComposition = false;
2009 return NS_OK;
2010 }
2011
2012 if (pPluginEvent->event == WM_IME_ENDCOMPOSITION) {
2013 // Always post WM_END_COMPOSITION to default proc. Because Flash may lie
2014 // that it doesn't handle composition well, but event is handled.
2015 // Even if posting this message, default proc do nothing if unnecessary.
2016 CallDefaultProc(compositionEvent);
2017 return NS_OK;
2018 }
2019
2020 if (pPluginEvent->event == WM_IME_COMPOSITION && !mGotCompositionData) {
2021 // If plugin doesn't handle WM_IME_COMPOSITION correctly, we don't send
2022 // composition event until end composition.
2023 mPluginDidNotHandleIMEComposition = true;
2024
2025 HandleNoConsumedCompositionMessage(compositionEvent, pPluginEvent);
2026 }
2027 #endif // #ifdef XP_WIN
2028 return NS_OK;
2029 }
2030
2031 nsresult
HandleEvent(nsIDOMEvent * aEvent)2032 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
2033 {
2034 NS_ASSERTION(mInstance, "Should have a valid plugin instance or not receive events.");
2035
2036 nsAutoString eventType;
2037 aEvent->GetType(eventType);
2038
2039 #ifdef XP_MACOSX
2040 if (eventType.EqualsLiteral("activate") ||
2041 eventType.EqualsLiteral("deactivate")) {
2042 WindowFocusMayHaveChanged();
2043 return NS_OK;
2044 }
2045 if (eventType.EqualsLiteral("MozPerformDelayedBlur")) {
2046 if (mShouldBlurOnActivate) {
2047 WidgetGUIEvent blurEvent(true, eBlur, nullptr);
2048 ProcessEvent(blurEvent);
2049 mShouldBlurOnActivate = false;
2050 }
2051 return NS_OK;
2052 }
2053 #endif
2054
2055 if (eventType.EqualsLiteral("focus")) {
2056 mContentFocused = true;
2057 return DispatchFocusToPlugin(aEvent);
2058 }
2059 if (eventType.EqualsLiteral("blur")) {
2060 mContentFocused = false;
2061 return DispatchFocusToPlugin(aEvent);
2062 }
2063 if (eventType.EqualsLiteral("mousedown")) {
2064 return ProcessMouseDown(aEvent);
2065 }
2066 if (eventType.EqualsLiteral("mouseup")) {
2067 return DispatchMouseToPlugin(aEvent);
2068 }
2069 if (eventType.EqualsLiteral("mousemove")) {
2070 return DispatchMouseToPlugin(aEvent, true);
2071 }
2072 if (eventType.EqualsLiteral("click") ||
2073 eventType.EqualsLiteral("dblclick") ||
2074 eventType.EqualsLiteral("mouseover") ||
2075 eventType.EqualsLiteral("mouseout")) {
2076 return DispatchMouseToPlugin(aEvent);
2077 }
2078 if (eventType.EqualsLiteral("keydown") ||
2079 eventType.EqualsLiteral("keyup")) {
2080 return DispatchKeyToPlugin(aEvent);
2081 }
2082 if (eventType.EqualsLiteral("keypress")) {
2083 return ProcessKeyPress(aEvent);
2084 }
2085 if (eventType.EqualsLiteral("compositionstart") ||
2086 eventType.EqualsLiteral("compositionend") ||
2087 eventType.EqualsLiteral("text")) {
2088 return DispatchCompositionToPlugin(aEvent);
2089 }
2090
2091 nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
2092 if (dragEvent && mInstance) {
2093 WidgetEvent* ievent = aEvent->WidgetEventPtr();
2094 if (ievent && ievent->IsTrusted() &&
2095 ievent->mMessage != eDragEnter && ievent->mMessage != eDragOver) {
2096 aEvent->PreventDefault();
2097 }
2098
2099 // Let the plugin handle drag events.
2100 aEvent->StopPropagation();
2101 }
2102 return NS_OK;
2103 }
2104
2105 #ifdef MOZ_X11
XInputEventState(const WidgetInputEvent & anEvent)2106 static unsigned int XInputEventState(const WidgetInputEvent& anEvent)
2107 {
2108 unsigned int state = 0;
2109 if (anEvent.IsShift()) state |= ShiftMask;
2110 if (anEvent.IsControl()) state |= ControlMask;
2111 if (anEvent.IsAlt()) state |= Mod1Mask;
2112 if (anEvent.IsMeta()) state |= Mod4Mask;
2113 return state;
2114 }
2115 #endif
2116
2117 #ifdef XP_MACOSX
2118
2119 // Returns whether or not content is the content that is or would be
2120 // focused if the top-level chrome window was active.
2121 static bool
ContentIsFocusedWithinWindow(nsIContent * aContent)2122 ContentIsFocusedWithinWindow(nsIContent* aContent)
2123 {
2124 nsPIDOMWindowOuter* outerWindow = aContent->OwnerDoc()->GetWindow();
2125 if (!outerWindow) {
2126 return false;
2127 }
2128
2129 nsPIDOMWindowOuter* rootWindow = outerWindow->GetPrivateRoot();
2130 if (!rootWindow) {
2131 return false;
2132 }
2133
2134 nsFocusManager* fm = nsFocusManager::GetFocusManager();
2135 if (!fm) {
2136 return false;
2137 }
2138
2139 nsCOMPtr<nsPIDOMWindowOuter> focusedFrame;
2140 nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedDescendant(rootWindow, true, getter_AddRefs(focusedFrame));
2141 return (focusedContent.get() == aContent);
2142 }
2143
2144 static NPCocoaEventType
CocoaEventTypeForEvent(const WidgetGUIEvent & anEvent,nsIFrame * aObjectFrame)2145 CocoaEventTypeForEvent(const WidgetGUIEvent& anEvent, nsIFrame* aObjectFrame)
2146 {
2147 const NPCocoaEvent* event = static_cast<const NPCocoaEvent*>(anEvent.mPluginEvent);
2148 if (event) {
2149 return event->type;
2150 }
2151
2152 switch (anEvent.mMessage) {
2153 case eMouseOver:
2154 return NPCocoaEventMouseEntered;
2155 case eMouseOut:
2156 return NPCocoaEventMouseExited;
2157 case eMouseMove: {
2158 // We don't know via information on events from the widget code whether or not
2159 // we're dragging. The widget code just generates mouse move events from native
2160 // drag events. If anybody is capturing, this is a drag event.
2161 if (nsIPresShell::GetCapturingContent()) {
2162 return NPCocoaEventMouseDragged;
2163 }
2164
2165 return NPCocoaEventMouseMoved;
2166 }
2167 case eMouseDown:
2168 return NPCocoaEventMouseDown;
2169 case eMouseUp:
2170 return NPCocoaEventMouseUp;
2171 case eKeyDown:
2172 return NPCocoaEventKeyDown;
2173 case eKeyUp:
2174 return NPCocoaEventKeyUp;
2175 case eFocus:
2176 case eBlur:
2177 return NPCocoaEventFocusChanged;
2178 case eLegacyMouseLineOrPageScroll:
2179 return NPCocoaEventScrollWheel;
2180 default:
2181 return (NPCocoaEventType)0;
2182 }
2183 }
2184
2185 static NPCocoaEvent
TranslateToNPCocoaEvent(WidgetGUIEvent * anEvent,nsIFrame * aObjectFrame)2186 TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame)
2187 {
2188 NPCocoaEvent cocoaEvent;
2189 InitializeNPCocoaEvent(&cocoaEvent);
2190 cocoaEvent.type = CocoaEventTypeForEvent(*anEvent, aObjectFrame);
2191
2192 if (anEvent->mMessage == eMouseMove ||
2193 anEvent->mMessage == eMouseDown ||
2194 anEvent->mMessage == eMouseUp ||
2195 anEvent->mMessage == eLegacyMouseLineOrPageScroll ||
2196 anEvent->mMessage == eMouseOver ||
2197 anEvent->mMessage == eMouseOut)
2198 {
2199 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) -
2200 aObjectFrame->GetContentRectRelativeToSelf().TopLeft();
2201 nsPresContext* presContext = aObjectFrame->PresContext();
2202 // Plugin event coordinates need to be translated from device pixels
2203 // into "display pixels" in HiDPI modes.
2204 double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
2205 aObjectFrame->PresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
2206 size_t intScaleFactor = ceil(scaleFactor);
2207 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
2208 presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
2209 cocoaEvent.data.mouse.pluginX = double(ptPx.x);
2210 cocoaEvent.data.mouse.pluginY = double(ptPx.y);
2211 }
2212
2213 switch (anEvent->mMessage) {
2214 case eMouseDown:
2215 case eMouseUp: {
2216 WidgetMouseEvent* mouseEvent = anEvent->AsMouseEvent();
2217 if (mouseEvent) {
2218 switch (mouseEvent->button) {
2219 case WidgetMouseEvent::eLeftButton:
2220 cocoaEvent.data.mouse.buttonNumber = 0;
2221 break;
2222 case WidgetMouseEvent::eRightButton:
2223 cocoaEvent.data.mouse.buttonNumber = 1;
2224 break;
2225 case WidgetMouseEvent::eMiddleButton:
2226 cocoaEvent.data.mouse.buttonNumber = 2;
2227 break;
2228 default:
2229 NS_WARNING("Mouse button we don't know about?");
2230 }
2231 cocoaEvent.data.mouse.clickCount = mouseEvent->mClickCount;
2232 } else {
2233 NS_WARNING("eMouseUp/DOWN is not a WidgetMouseEvent?");
2234 }
2235 break;
2236 }
2237 case eLegacyMouseLineOrPageScroll: {
2238 WidgetWheelEvent* wheelEvent = anEvent->AsWheelEvent();
2239 if (wheelEvent) {
2240 cocoaEvent.data.mouse.deltaX = wheelEvent->mLineOrPageDeltaX;
2241 cocoaEvent.data.mouse.deltaY = wheelEvent->mLineOrPageDeltaY;
2242 } else {
2243 NS_WARNING("eLegacyMouseLineOrPageScroll is not a WidgetWheelEvent? "
2244 "(could be, haven't checked)");
2245 }
2246 break;
2247 }
2248 case eKeyDown:
2249 case eKeyUp:
2250 {
2251 WidgetKeyboardEvent* keyEvent = anEvent->AsKeyboardEvent();
2252
2253 // That keyEvent->mPluginTextEventString is non-empty is a signal that we should
2254 // create a text event for the plugin, instead of a key event.
2255 if (anEvent->mMessage == eKeyDown &&
2256 !keyEvent->mPluginTextEventString.IsEmpty()) {
2257 cocoaEvent.type = NPCocoaEventTextInput;
2258 const char16_t* pluginTextEventString = keyEvent->mPluginTextEventString.get();
2259 cocoaEvent.data.text.text = (NPNSString*)
2260 ::CFStringCreateWithCharacters(NULL,
2261 reinterpret_cast<const UniChar*>(pluginTextEventString),
2262 keyEvent->mPluginTextEventString.Length());
2263 } else {
2264 cocoaEvent.data.key.keyCode = keyEvent->mNativeKeyCode;
2265 cocoaEvent.data.key.isARepeat = keyEvent->mIsRepeat;
2266 cocoaEvent.data.key.modifierFlags = keyEvent->mNativeModifierFlags;
2267 const char16_t* nativeChars = keyEvent->mNativeCharacters.get();
2268 cocoaEvent.data.key.characters = (NPNSString*)
2269 ::CFStringCreateWithCharacters(NULL,
2270 reinterpret_cast<const UniChar*>(nativeChars),
2271 keyEvent->mNativeCharacters.Length());
2272 const char16_t* nativeCharsIgnoringModifiers = keyEvent->mNativeCharactersIgnoringModifiers.get();
2273 cocoaEvent.data.key.charactersIgnoringModifiers = (NPNSString*)
2274 ::CFStringCreateWithCharacters(NULL,
2275 reinterpret_cast<const UniChar*>(nativeCharsIgnoringModifiers),
2276 keyEvent->mNativeCharactersIgnoringModifiers.Length());
2277 }
2278 break;
2279 }
2280 case eFocus:
2281 case eBlur:
2282 cocoaEvent.data.focus.hasFocus = (anEvent->mMessage == eFocus);
2283 break;
2284 default:
2285 break;
2286 }
2287 return cocoaEvent;
2288 }
2289
PerformDelayedBlurs()2290 void nsPluginInstanceOwner::PerformDelayedBlurs()
2291 {
2292 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2293 nsCOMPtr<EventTarget> windowRoot = content->OwnerDoc()->GetWindow()->GetTopWindowRoot();
2294 nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(),
2295 windowRoot,
2296 NS_LITERAL_STRING("MozPerformDelayedBlur"),
2297 false, false, nullptr);
2298 }
2299
2300 #endif
2301
ProcessEvent(const WidgetGUIEvent & anEvent)2302 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
2303 {
2304 nsEventStatus rv = nsEventStatus_eIgnore;
2305
2306 if (!mInstance || !mPluginFrame) {
2307 return nsEventStatus_eIgnore;
2308 }
2309
2310 #ifdef XP_MACOSX
2311 NPEventModel eventModel = GetEventModel();
2312 if (eventModel != NPEventModelCocoa) {
2313 return nsEventStatus_eIgnore;
2314 }
2315
2316 // In the Cocoa event model, focus is per-window. Don't tell a plugin it lost
2317 // focus unless it lost focus within the window. For example, ignore a blur
2318 // event if it's coming due to the plugin's window deactivating.
2319 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2320 if (anEvent.mMessage == eBlur && ContentIsFocusedWithinWindow(content)) {
2321 mShouldBlurOnActivate = true;
2322 return nsEventStatus_eIgnore;
2323 }
2324
2325 // Also, don't tell the plugin it gained focus again after we've already given
2326 // it focus. This might happen if it has focus, its window is blurred, then the
2327 // window is made active again. The plugin never lost in-window focus, so it
2328 // shouldn't get a focus event again.
2329 if (anEvent.mMessage == eFocus && mLastContentFocused == true) {
2330 mShouldBlurOnActivate = false;
2331 return nsEventStatus_eIgnore;
2332 }
2333
2334 // Now, if we're going to send a focus event, update mLastContentFocused and
2335 // tell any plugins in our window that we have taken focus, so they should
2336 // perform any delayed blurs.
2337 if (anEvent.mMessage == eFocus || anEvent.mMessage == eBlur) {
2338 mLastContentFocused = (anEvent.mMessage == eFocus);
2339 mShouldBlurOnActivate = false;
2340 PerformDelayedBlurs();
2341 }
2342
2343 NPCocoaEvent cocoaEvent = TranslateToNPCocoaEvent(const_cast<WidgetGUIEvent*>(&anEvent), mPluginFrame);
2344 if (cocoaEvent.type == (NPCocoaEventType)0) {
2345 return nsEventStatus_eIgnore;
2346 }
2347
2348 if (cocoaEvent.type == NPCocoaEventTextInput) {
2349 mInstance->HandleEvent(&cocoaEvent, nullptr);
2350 return nsEventStatus_eConsumeNoDefault;
2351 }
2352
2353 int16_t response = kNPEventNotHandled;
2354 mInstance->HandleEvent(&cocoaEvent,
2355 &response,
2356 NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2357 if ((response == kNPEventStartIME) && (cocoaEvent.type == NPCocoaEventKeyDown)) {
2358 nsIWidget* widget = mPluginFrame->GetNearestWidget();
2359 if (widget) {
2360 const WidgetKeyboardEvent* keyEvent = anEvent.AsKeyboardEvent();
2361 double screenX, screenY;
2362 ConvertPoint(0.0, mPluginFrame->GetScreenRect().height,
2363 NPCoordinateSpacePlugin, &screenX, &screenY,
2364 NPCoordinateSpaceScreen);
2365 nsAutoString outText;
2366 if (NS_SUCCEEDED(widget->StartPluginIME(*keyEvent, screenX, screenY, outText)) &&
2367 !outText.IsEmpty()) {
2368 CFStringRef cfString =
2369 ::CFStringCreateWithCharacters(kCFAllocatorDefault,
2370 reinterpret_cast<const UniChar*>(outText.get()),
2371 outText.Length());
2372 NPCocoaEvent textEvent;
2373 InitializeNPCocoaEvent(&textEvent);
2374 textEvent.type = NPCocoaEventTextInput;
2375 textEvent.data.text.text = (NPNSString*)cfString;
2376 mInstance->HandleEvent(&textEvent, nullptr);
2377 }
2378 }
2379 }
2380
2381 bool handled = (response == kNPEventHandled || response == kNPEventStartIME);
2382 bool leftMouseButtonDown = (anEvent.mMessage == eMouseDown) &&
2383 (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton);
2384 if (handled && !(leftMouseButtonDown && !mContentFocused)) {
2385 rv = nsEventStatus_eConsumeNoDefault;
2386 }
2387 #endif
2388
2389 #ifdef XP_WIN
2390 // this code supports windowless plugins
2391 const NPEvent *pPluginEvent = static_cast<const NPEvent*>(anEvent.mPluginEvent);
2392 // we can get synthetic events from the EventStateManager... these
2393 // have no pluginEvent
2394 NPEvent pluginEvent;
2395 if (anEvent.mClass == eMouseEventClass ||
2396 anEvent.mClass == eWheelEventClass) {
2397 if (!pPluginEvent) {
2398 // XXX Should extend this list to synthesize events for more event
2399 // types
2400 pluginEvent.event = 0;
2401 bool initWParamWithCurrentState = true;
2402 switch (anEvent.mMessage) {
2403 case eMouseMove: {
2404 pluginEvent.event = WM_MOUSEMOVE;
2405 break;
2406 }
2407 case eMouseDown: {
2408 static const int downMsgs[] =
2409 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
2410 static const int dblClickMsgs[] =
2411 { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
2412 const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
2413 if (mouseEvent->mClickCount == 2) {
2414 pluginEvent.event = dblClickMsgs[mouseEvent->button];
2415 } else {
2416 pluginEvent.event = downMsgs[mouseEvent->button];
2417 }
2418 break;
2419 }
2420 case eMouseUp: {
2421 static const int upMsgs[] =
2422 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
2423 const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
2424 pluginEvent.event = upMsgs[mouseEvent->button];
2425 break;
2426 }
2427 // For plugins which don't support high-resolution scroll, we should
2428 // generate legacy resolution wheel messages. I.e., the delta value
2429 // should be WHEEL_DELTA * n.
2430 case eWheel: {
2431 const WidgetWheelEvent* wheelEvent = anEvent.AsWheelEvent();
2432 int32_t delta = 0;
2433 if (wheelEvent->mLineOrPageDeltaY) {
2434 switch (wheelEvent->mDeltaMode) {
2435 case nsIDOMWheelEvent::DOM_DELTA_PAGE:
2436 pluginEvent.event = WM_MOUSEWHEEL;
2437 delta = -WHEEL_DELTA * wheelEvent->mLineOrPageDeltaY;
2438 break;
2439 case nsIDOMWheelEvent::DOM_DELTA_LINE: {
2440 UINT linesPerWheelDelta = 0;
2441 if (NS_WARN_IF(!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
2442 &linesPerWheelDelta, 0))) {
2443 // Use system default scroll amount, 3, when
2444 // SPI_GETWHEELSCROLLLINES isn't available.
2445 linesPerWheelDelta = 3;
2446 }
2447 if (!linesPerWheelDelta) {
2448 break;
2449 }
2450 pluginEvent.event = WM_MOUSEWHEEL;
2451 delta = -WHEEL_DELTA / linesPerWheelDelta;
2452 delta *= wheelEvent->mLineOrPageDeltaY;
2453 break;
2454 }
2455 case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
2456 default:
2457 // We don't support WM_GESTURE with this path.
2458 MOZ_ASSERT(!pluginEvent.event);
2459 break;
2460 }
2461 } else if (wheelEvent->mLineOrPageDeltaX) {
2462 switch (wheelEvent->mDeltaMode) {
2463 case nsIDOMWheelEvent::DOM_DELTA_PAGE:
2464 pluginEvent.event = WM_MOUSEHWHEEL;
2465 delta = -WHEEL_DELTA * wheelEvent->mLineOrPageDeltaX;
2466 break;
2467 case nsIDOMWheelEvent::DOM_DELTA_LINE: {
2468 pluginEvent.event = WM_MOUSEHWHEEL;
2469 UINT charsPerWheelDelta = 0;
2470 // FYI: SPI_GETWHEELSCROLLCHARS is available on Vista or later.
2471 if (::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
2472 &charsPerWheelDelta, 0)) {
2473 // Use system default scroll amount, 3, when
2474 // SPI_GETWHEELSCROLLCHARS isn't available.
2475 charsPerWheelDelta = 3;
2476 }
2477 if (!charsPerWheelDelta) {
2478 break;
2479 }
2480 delta = WHEEL_DELTA / charsPerWheelDelta;
2481 delta *= wheelEvent->mLineOrPageDeltaX;
2482 break;
2483 }
2484 case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
2485 default:
2486 // We don't support WM_GESTURE with this path.
2487 MOZ_ASSERT(!pluginEvent.event);
2488 break;
2489 }
2490 }
2491
2492 if (!pluginEvent.event) {
2493 break;
2494 }
2495
2496 initWParamWithCurrentState = false;
2497 int32_t modifiers =
2498 (wheelEvent->IsControl() ? MK_CONTROL : 0) |
2499 (wheelEvent->IsShift() ? MK_SHIFT : 0) |
2500 (wheelEvent->IsLeftButtonPressed() ? MK_LBUTTON : 0) |
2501 (wheelEvent->IsMiddleButtonPressed() ? MK_MBUTTON : 0) |
2502 (wheelEvent->IsRightButtonPressed() ? MK_RBUTTON : 0) |
2503 (wheelEvent->Is4thButtonPressed() ? MK_XBUTTON1 : 0) |
2504 (wheelEvent->Is5thButtonPressed() ? MK_XBUTTON2 : 0);
2505 pluginEvent.wParam = MAKEWPARAM(modifiers, delta);
2506 pPluginEvent = &pluginEvent;
2507 break;
2508 }
2509 // don't synthesize anything for eMouseDoubleClick, since that
2510 // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
2511 // messages are sent on mouse-down
2512 default:
2513 break;
2514 }
2515 if (pluginEvent.event && initWParamWithCurrentState) {
2516 pPluginEvent = &pluginEvent;
2517 pluginEvent.wParam =
2518 (::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) |
2519 (::GetKeyState(VK_SHIFT) ? MK_SHIFT : 0) |
2520 (::GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) |
2521 (::GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) |
2522 (::GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0) |
2523 (::GetKeyState(VK_XBUTTON1) ? MK_XBUTTON1 : 0) |
2524 (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0);
2525 }
2526 }
2527 if (pPluginEvent) {
2528 // Make event coordinates relative to our enclosing widget,
2529 // not the widget they were received on.
2530 // See use of NPEvent in widget/windows/nsWindow.cpp
2531 // for why this assert should be safe
2532 NS_ASSERTION(anEvent.mMessage == eMouseDown ||
2533 anEvent.mMessage == eMouseUp ||
2534 anEvent.mMessage == eMouseDoubleClick ||
2535 anEvent.mMessage == eMouseOver ||
2536 anEvent.mMessage == eMouseOut ||
2537 anEvent.mMessage == eMouseMove ||
2538 anEvent.mMessage == eWheel,
2539 "Incorrect event type for coordinate translation");
2540 nsPoint pt =
2541 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
2542 mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
2543 nsPresContext* presContext = mPluginFrame->PresContext();
2544 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
2545 presContext->AppUnitsToDevPixels(pt.y));
2546 nsIntPoint widgetPtPx = ptPx + mPluginFrame->GetWindowOriginInPixels(true);
2547 const_cast<NPEvent*>(pPluginEvent)->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
2548 }
2549 }
2550 else if (!pPluginEvent) {
2551 switch (anEvent.mMessage) {
2552 case eFocus:
2553 pluginEvent.event = WM_SETFOCUS;
2554 pluginEvent.wParam = 0;
2555 pluginEvent.lParam = 0;
2556 pPluginEvent = &pluginEvent;
2557 break;
2558 case eBlur:
2559 pluginEvent.event = WM_KILLFOCUS;
2560 pluginEvent.wParam = 0;
2561 pluginEvent.lParam = 0;
2562 pPluginEvent = &pluginEvent;
2563 break;
2564 default:
2565 break;
2566 }
2567 }
2568
2569 if (pPluginEvent && !pPluginEvent->event) {
2570 // Don't send null events to plugins.
2571 NS_WARNING("nsPluginFrame ProcessEvent: trying to send null event to plugin.");
2572 return rv;
2573 }
2574
2575 if (pPluginEvent) {
2576 int16_t response = kNPEventNotHandled;
2577 mInstance->HandleEvent(const_cast<NPEvent*>(pPluginEvent),
2578 &response,
2579 NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2580 if (response == kNPEventHandled)
2581 rv = nsEventStatus_eConsumeNoDefault;
2582 }
2583 #endif
2584
2585 #ifdef MOZ_X11
2586 // this code supports windowless plugins
2587 nsIWidget* widget = anEvent.mWidget;
2588 XEvent pluginEvent = XEvent();
2589 pluginEvent.type = 0;
2590
2591 switch(anEvent.mClass) {
2592 case eMouseEventClass:
2593 {
2594 switch (anEvent.mMessage) {
2595 case eMouseClick:
2596 case eMouseDoubleClick:
2597 // Button up/down events sent instead.
2598 return rv;
2599 default:
2600 break;
2601 }
2602
2603 // Get reference point relative to plugin origin.
2604 const nsPresContext* presContext = mPluginFrame->PresContext();
2605 nsPoint appPoint =
2606 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
2607 mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
2608 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
2609 presContext->AppUnitsToDevPixels(appPoint.y));
2610 const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
2611 // Get reference point relative to screen:
2612 LayoutDeviceIntPoint rootPoint(-1, -1);
2613 if (widget) {
2614 rootPoint = anEvent.mRefPoint + widget->WidgetToScreenOffset();
2615 }
2616 #ifdef MOZ_WIDGET_GTK
2617 Window root = GDK_ROOT_WINDOW();
2618 #else
2619 Window root = X11None; // Could XQueryTree, but this is not important.
2620 #endif
2621
2622 switch (anEvent.mMessage) {
2623 case eMouseOver:
2624 case eMouseOut:
2625 {
2626 XCrossingEvent& event = pluginEvent.xcrossing;
2627 event.type = anEvent.mMessage == eMouseOver ?
2628 EnterNotify : LeaveNotify;
2629 event.root = root;
2630 event.time = anEvent.mTime;
2631 event.x = pluginPoint.x;
2632 event.y = pluginPoint.y;
2633 event.x_root = rootPoint.x;
2634 event.y_root = rootPoint.y;
2635 event.state = XInputEventState(mouseEvent);
2636 // information lost
2637 event.subwindow = X11None;
2638 event.mode = -1;
2639 event.detail = NotifyDetailNone;
2640 event.same_screen = True;
2641 event.focus = mContentFocused;
2642 }
2643 break;
2644 case eMouseMove:
2645 {
2646 XMotionEvent& event = pluginEvent.xmotion;
2647 event.type = MotionNotify;
2648 event.root = root;
2649 event.time = anEvent.mTime;
2650 event.x = pluginPoint.x;
2651 event.y = pluginPoint.y;
2652 event.x_root = rootPoint.x;
2653 event.y_root = rootPoint.y;
2654 event.state = XInputEventState(mouseEvent);
2655 // information lost
2656 event.subwindow = X11None;
2657 event.is_hint = NotifyNormal;
2658 event.same_screen = True;
2659 }
2660 break;
2661 case eMouseDown:
2662 case eMouseUp:
2663 {
2664 XButtonEvent& event = pluginEvent.xbutton;
2665 event.type = anEvent.mMessage == eMouseDown ?
2666 ButtonPress : ButtonRelease;
2667 event.root = root;
2668 event.time = anEvent.mTime;
2669 event.x = pluginPoint.x;
2670 event.y = pluginPoint.y;
2671 event.x_root = rootPoint.x;
2672 event.y_root = rootPoint.y;
2673 event.state = XInputEventState(mouseEvent);
2674 switch (mouseEvent.button)
2675 {
2676 case WidgetMouseEvent::eMiddleButton:
2677 event.button = 2;
2678 break;
2679 case WidgetMouseEvent::eRightButton:
2680 event.button = 3;
2681 break;
2682 default: // WidgetMouseEvent::eLeftButton;
2683 event.button = 1;
2684 break;
2685 }
2686 // information lost:
2687 event.subwindow = X11None;
2688 event.same_screen = True;
2689 }
2690 break;
2691 default:
2692 break;
2693 }
2694 }
2695 break;
2696
2697 //XXX case eMouseScrollEventClass: not received.
2698
2699 case eKeyboardEventClass:
2700 if (anEvent.mPluginEvent)
2701 {
2702 XKeyEvent &event = pluginEvent.xkey;
2703 #ifdef MOZ_WIDGET_GTK
2704 event.root = GDK_ROOT_WINDOW();
2705 event.time = anEvent.mTime;
2706 const GdkEventKey* gdkEvent =
2707 static_cast<const GdkEventKey*>(anEvent.mPluginEvent);
2708 event.keycode = gdkEvent->hardware_keycode;
2709 event.state = gdkEvent->state;
2710 switch (anEvent.mMessage)
2711 {
2712 case eKeyDown:
2713 // Handle eKeyDown for modifier key presses
2714 // For non-modifiers we get eKeyPress
2715 if (gdkEvent->is_modifier)
2716 event.type = XKeyPress;
2717 break;
2718 case eKeyPress:
2719 event.type = XKeyPress;
2720 break;
2721 case eKeyUp:
2722 event.type = KeyRelease;
2723 break;
2724 default:
2725 break;
2726 }
2727 #endif
2728
2729 // Information that could be obtained from pluginEvent but we may not
2730 // want to promise to provide:
2731 event.subwindow = X11None;
2732 event.x = 0;
2733 event.y = 0;
2734 event.x_root = -1;
2735 event.y_root = -1;
2736 event.same_screen = False;
2737 }
2738 else
2739 {
2740 // If we need to send synthesized key events, then
2741 // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
2742 // gdk_keymap_get_entries_for_keyval will be useful, but the
2743 // mappings will not be unique.
2744 NS_WARNING("Synthesized key event not sent to plugin");
2745 }
2746 break;
2747
2748 default:
2749 switch (anEvent.mMessage) {
2750 case eFocus:
2751 case eBlur:
2752 {
2753 XFocusChangeEvent &event = pluginEvent.xfocus;
2754 event.type = anEvent.mMessage == eFocus ? FocusIn : FocusOut;
2755 // information lost:
2756 event.mode = -1;
2757 event.detail = NotifyDetailNone;
2758 }
2759 break;
2760 default:
2761 break;
2762 }
2763 }
2764
2765 if (!pluginEvent.type) {
2766 return rv;
2767 }
2768
2769 // Fill in (useless) generic event information.
2770 XAnyEvent& event = pluginEvent.xany;
2771 event.display = widget ?
2772 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nullptr;
2773 event.window = X11None; // not a real window
2774 // information lost:
2775 event.serial = 0;
2776 event.send_event = False;
2777
2778 int16_t response = kNPEventNotHandled;
2779 mInstance->HandleEvent(&pluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2780 if (response == kNPEventHandled)
2781 rv = nsEventStatus_eConsumeNoDefault;
2782 #endif
2783
2784 #ifdef MOZ_WIDGET_ANDROID
2785 // this code supports windowless plugins
2786 {
2787 // The plugin needs focus to receive keyboard and touch events
2788 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2789 if (fm) {
2790 nsCOMPtr<nsIDOMElement> elem = do_QueryReferent(mContent);
2791 fm->SetFocus(elem, 0);
2792 }
2793 }
2794 switch(anEvent.mClass) {
2795 case eMouseEventClass:
2796 {
2797 switch (anEvent.mMessage) {
2798 case eMouseClick:
2799 case eMouseDoubleClick:
2800 // Button up/down events sent instead.
2801 return rv;
2802 default:
2803 break;
2804 }
2805
2806 // Get reference point relative to plugin origin.
2807 const nsPresContext* presContext = mPluginFrame->PresContext();
2808 nsPoint appPoint =
2809 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
2810 mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
2811 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
2812 presContext->AppUnitsToDevPixels(appPoint.y));
2813
2814 switch (anEvent.mMessage) {
2815 case eMouseMove:
2816 {
2817 // are these going to be touch events?
2818 // pluginPoint.x;
2819 // pluginPoint.y;
2820 }
2821 break;
2822 case eMouseDown:
2823 {
2824 ANPEvent event;
2825 event.inSize = sizeof(ANPEvent);
2826 event.eventType = kMouse_ANPEventType;
2827 event.data.mouse.action = kDown_ANPMouseAction;
2828 event.data.mouse.x = pluginPoint.x;
2829 event.data.mouse.y = pluginPoint.y;
2830 mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2831 }
2832 break;
2833 case eMouseUp:
2834 {
2835 ANPEvent event;
2836 event.inSize = sizeof(ANPEvent);
2837 event.eventType = kMouse_ANPEventType;
2838 event.data.mouse.action = kUp_ANPMouseAction;
2839 event.data.mouse.x = pluginPoint.x;
2840 event.data.mouse.y = pluginPoint.y;
2841 mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2842 }
2843 break;
2844 default:
2845 break;
2846 }
2847 }
2848 break;
2849
2850 case eKeyboardEventClass:
2851 {
2852 const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent();
2853 LOG("Firing eKeyboardEventClass %d %d\n",
2854 keyEvent.mKeyCode, keyEvent.mCharCode);
2855 // pluginEvent is initialized by nsWindow::InitKeyEvent().
2856 const ANPEvent* pluginEvent = static_cast<const ANPEvent*>(keyEvent.mPluginEvent);
2857 if (pluginEvent) {
2858 MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent));
2859 MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType);
2860 mInstance->HandleEvent(const_cast<ANPEvent*>(pluginEvent),
2861 nullptr,
2862 NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2863 }
2864 }
2865 break;
2866
2867 default:
2868 break;
2869 }
2870 rv = nsEventStatus_eConsumeNoDefault;
2871 #endif
2872
2873 return rv;
2874 }
2875
2876 nsresult
Destroy()2877 nsPluginInstanceOwner::Destroy()
2878 {
2879 SetFrame(nullptr);
2880
2881 #ifdef XP_MACOSX
2882 RemoveFromCARefreshTimer();
2883 #endif
2884
2885 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2886
2887 // unregister context menu listener
2888 if (mCXMenuListener) {
2889 mCXMenuListener->Destroy(content);
2890 mCXMenuListener = nullptr;
2891 }
2892
2893 content->RemoveEventListener(NS_LITERAL_STRING("focus"), this, false);
2894 content->RemoveEventListener(NS_LITERAL_STRING("blur"), this, false);
2895 content->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false);
2896 content->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false);
2897 content->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false);
2898 content->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
2899 content->RemoveEventListener(NS_LITERAL_STRING("dblclick"), this, false);
2900 content->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, false);
2901 content->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false);
2902 content->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
2903 content->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
2904 content->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
2905 content->RemoveEventListener(NS_LITERAL_STRING("drop"), this, true);
2906 content->RemoveEventListener(NS_LITERAL_STRING("drag"), this, true);
2907 content->RemoveEventListener(NS_LITERAL_STRING("dragenter"), this, true);
2908 content->RemoveEventListener(NS_LITERAL_STRING("dragover"), this, true);
2909 content->RemoveEventListener(NS_LITERAL_STRING("dragleave"), this, true);
2910 content->RemoveEventListener(NS_LITERAL_STRING("dragexit"), this, true);
2911 content->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, true);
2912 content->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true);
2913 content->RemoveSystemEventListener(NS_LITERAL_STRING("compositionstart"),
2914 this, true);
2915 content->RemoveSystemEventListener(NS_LITERAL_STRING("compositionend"),
2916 this, true);
2917 content->RemoveSystemEventListener(NS_LITERAL_STRING("text"), this, true);
2918
2919 #if MOZ_WIDGET_ANDROID
2920 RemovePluginView();
2921 #endif
2922
2923 if (mWidget) {
2924 if (mPluginWindow) {
2925 mPluginWindow->SetPluginWidget(nullptr);
2926 }
2927
2928 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2929 if (pluginWidget) {
2930 pluginWidget->SetPluginInstanceOwner(nullptr);
2931 }
2932 mWidget->Destroy();
2933 }
2934
2935 return NS_OK;
2936 }
2937
2938 // Paints are handled differently, so we just simulate an update event.
2939
2940 #ifdef XP_MACOSX
Paint(const gfxRect & aDirtyRect,CGContextRef cgContext)2941 void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
2942 {
2943 if (!mInstance || !mPluginFrame)
2944 return;
2945
2946 gfxRect dirtyRectCopy = aDirtyRect;
2947 double scaleFactor = 1.0;
2948 GetContentsScaleFactor(&scaleFactor);
2949 if (scaleFactor != 1.0) {
2950 ::CGContextScaleCTM(cgContext, scaleFactor, scaleFactor);
2951 // Convert aDirtyRect from device pixels to "display pixels"
2952 // for HiDPI modes
2953 dirtyRectCopy.ScaleRoundOut(1.0 / scaleFactor);
2954 }
2955
2956 DoCocoaEventDrawRect(dirtyRectCopy, cgContext);
2957 }
2958
DoCocoaEventDrawRect(const gfxRect & aDrawRect,CGContextRef cgContext)2959 void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext)
2960 {
2961 if (!mInstance || !mPluginFrame)
2962 return;
2963
2964 // The context given here is only valid during the HandleEvent call.
2965 NPCocoaEvent updateEvent;
2966 InitializeNPCocoaEvent(&updateEvent);
2967 updateEvent.type = NPCocoaEventDrawRect;
2968 updateEvent.data.draw.context = cgContext;
2969 updateEvent.data.draw.x = aDrawRect.X();
2970 updateEvent.data.draw.y = aDrawRect.Y();
2971 updateEvent.data.draw.width = aDrawRect.Width();
2972 updateEvent.data.draw.height = aDrawRect.Height();
2973
2974 mInstance->HandleEvent(&updateEvent, nullptr);
2975 }
2976 #endif
2977
2978 #ifdef XP_WIN
Paint(const RECT & aDirty,HDC aDC)2979 void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
2980 {
2981 if (!mInstance || !mPluginFrame)
2982 return;
2983
2984 NPEvent pluginEvent;
2985 pluginEvent.event = WM_PAINT;
2986 pluginEvent.wParam = WPARAM(aDC);
2987 pluginEvent.lParam = LPARAM(&aDirty);
2988 mInstance->HandleEvent(&pluginEvent, nullptr);
2989 }
2990 #endif
2991
2992 #ifdef MOZ_WIDGET_ANDROID
2993
Paint(gfxContext * aContext,const gfxRect & aFrameRect,const gfxRect & aDirtyRect)2994 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
2995 const gfxRect& aFrameRect,
2996 const gfxRect& aDirtyRect)
2997 {
2998 if (!mInstance || !mPluginFrame || !mPluginDocumentActiveState || mFullScreen)
2999 return;
3000
3001 int32_t model = mInstance->GetANPDrawingModel();
3002
3003 if (model == kSurface_ANPDrawingModel) {
3004 if (!AddPluginView(GetPluginRect())) {
3005 Invalidate();
3006 }
3007 return;
3008 }
3009
3010 if (model != kBitmap_ANPDrawingModel)
3011 return;
3012
3013 #ifdef ANP_BITMAP_DRAWING_MODEL
3014 static RefPtr<gfxImageSurface> pluginSurface;
3015
3016 if (pluginSurface == nullptr ||
3017 aFrameRect.width != pluginSurface->Width() ||
3018 aFrameRect.height != pluginSurface->Height()) {
3019
3020 pluginSurface = new gfxImageSurface(gfx::IntSize(aFrameRect.width, aFrameRect.height),
3021 SurfaceFormat::A8R8G8B8_UINT32);
3022 if (!pluginSurface)
3023 return;
3024 }
3025
3026 // Clears buffer. I think this is needed.
3027 gfxUtils::ClearThebesSurface(pluginSurface);
3028
3029 ANPEvent event;
3030 event.inSize = sizeof(ANPEvent);
3031 event.eventType = 4;
3032 event.data.draw.model = 1;
3033
3034 event.data.draw.clip.top = 0;
3035 event.data.draw.clip.left = 0;
3036 event.data.draw.clip.bottom = aFrameRect.width;
3037 event.data.draw.clip.right = aFrameRect.height;
3038
3039 event.data.draw.data.bitmap.format = kRGBA_8888_ANPBitmapFormat;
3040 event.data.draw.data.bitmap.width = aFrameRect.width;
3041 event.data.draw.data.bitmap.height = aFrameRect.height;
3042 event.data.draw.data.bitmap.baseAddr = pluginSurface->Data();
3043 event.data.draw.data.bitmap.rowBytes = aFrameRect.width * 4;
3044
3045 if (!mInstance)
3046 return;
3047
3048 mInstance->HandleEvent(&event, nullptr);
3049
3050 aContext->SetOp(gfx::CompositionOp::OP_SOURCE);
3051 aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
3052 aContext->Clip(aFrameRect);
3053 aContext->Paint();
3054 #endif
3055 }
3056 #endif
3057
3058 #if defined(MOZ_X11)
Paint(gfxContext * aContext,const gfxRect & aFrameRect,const gfxRect & aDirtyRect)3059 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
3060 const gfxRect& aFrameRect,
3061 const gfxRect& aDirtyRect)
3062 {
3063 if (!mInstance || !mPluginFrame)
3064 return;
3065
3066 // to provide crisper and faster drawing.
3067 gfxRect pluginRect = aFrameRect;
3068 if (aContext->UserToDevicePixelSnapped(pluginRect)) {
3069 pluginRect = aContext->DeviceToUser(pluginRect);
3070 }
3071
3072 // Round out the dirty rect to plugin pixels to ensure the plugin draws
3073 // enough pixels for interpolation to device pixels.
3074 gfxRect dirtyRect = aDirtyRect - pluginRect.TopLeft();
3075 dirtyRect.RoundOut();
3076
3077 // Plugins can only draw an integer number of pixels.
3078 //
3079 // With translation-only transformation matrices, pluginRect is already
3080 // pixel-aligned.
3081 //
3082 // With more complex transformations, modifying the scales in the
3083 // transformation matrix could retain subpixel accuracy and let the plugin
3084 // draw a suitable number of pixels for interpolation to device pixels in
3085 // Renderer::Draw, but such cases are not common enough to warrant the
3086 // effort now.
3087 nsIntSize pluginSize(NS_lround(pluginRect.width),
3088 NS_lround(pluginRect.height));
3089
3090 // Determine what the plugin needs to draw.
3091 nsIntRect pluginDirtyRect(int32_t(dirtyRect.x),
3092 int32_t(dirtyRect.y),
3093 int32_t(dirtyRect.width),
3094 int32_t(dirtyRect.height));
3095 if (!pluginDirtyRect.
3096 IntersectRect(nsIntRect(0, 0, pluginSize.width, pluginSize.height),
3097 pluginDirtyRect))
3098 return;
3099
3100 NPWindow* window;
3101 GetWindow(window);
3102
3103 uint32_t rendererFlags = 0;
3104 if (!mFlash10Quirks) {
3105 rendererFlags |=
3106 Renderer::DRAW_SUPPORTS_CLIP_RECT |
3107 Renderer::DRAW_SUPPORTS_ALTERNATE_VISUAL;
3108 }
3109
3110 bool transparent;
3111 mInstance->IsTransparent(&transparent);
3112 if (!transparent)
3113 rendererFlags |= Renderer::DRAW_IS_OPAQUE;
3114
3115 // Renderer::Draw() draws a rectangle with top-left at the aContext origin.
3116 gfxContextAutoSaveRestore autoSR(aContext);
3117 aContext->SetMatrix(
3118 aContext->CurrentMatrix().Translate(pluginRect.TopLeft()));
3119
3120 Renderer renderer(window, this, pluginSize, pluginDirtyRect);
3121
3122 Display* dpy = mozilla::DefaultXDisplay();
3123 Screen* screen = DefaultScreenOfDisplay(dpy);
3124 Visual* visual = DefaultVisualOfScreen(screen);
3125
3126 renderer.Draw(aContext, nsIntSize(window->width, window->height),
3127 rendererFlags, screen, visual);
3128 }
3129 nsresult
DrawWithXlib(cairo_surface_t * xsurface,nsIntPoint offset,nsIntRect * clipRects,uint32_t numClipRects)3130 nsPluginInstanceOwner::Renderer::DrawWithXlib(cairo_surface_t* xsurface,
3131 nsIntPoint offset,
3132 nsIntRect *clipRects,
3133 uint32_t numClipRects)
3134 {
3135 Screen *screen = cairo_xlib_surface_get_screen(xsurface);
3136 Colormap colormap;
3137 Visual* visual;
3138 if (!gfxXlibSurface::GetColormapAndVisual(xsurface, &colormap, &visual)) {
3139 NS_ERROR("Failed to get visual and colormap");
3140 return NS_ERROR_UNEXPECTED;
3141 }
3142
3143 nsNPAPIPluginInstance *instance = mInstanceOwner->mInstance;
3144 if (!instance)
3145 return NS_ERROR_FAILURE;
3146
3147 // See if the plugin must be notified of new window parameters.
3148 bool doupdatewindow = false;
3149
3150 if (mWindow->x != offset.x || mWindow->y != offset.y) {
3151 mWindow->x = offset.x;
3152 mWindow->y = offset.y;
3153 doupdatewindow = true;
3154 }
3155
3156 if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) {
3157 mWindow->width = mPluginSize.width;
3158 mWindow->height = mPluginSize.height;
3159 doupdatewindow = true;
3160 }
3161
3162 // The clip rect is relative to drawable top-left.
3163 NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!");
3164 nsIntRect clipRect;
3165 if (numClipRects) {
3166 clipRect.x = clipRects[0].x;
3167 clipRect.y = clipRects[0].y;
3168 clipRect.width = clipRects[0].width;
3169 clipRect.height = clipRects[0].height;
3170 // NPRect members are unsigned, but clip rectangles should be contained by
3171 // the surface.
3172 NS_ASSERTION(clipRect.x >= 0 && clipRect.y >= 0,
3173 "Clip rectangle offsets are negative!");
3174 }
3175 else {
3176 clipRect.x = offset.x;
3177 clipRect.y = offset.y;
3178 clipRect.width = mWindow->width;
3179 clipRect.height = mWindow->height;
3180 // Don't ask the plugin to draw outside the drawable.
3181 // This also ensures that the unsigned clip rectangle offsets won't be -ve.
3182 clipRect.IntersectRect(clipRect,
3183 nsIntRect(0, 0,
3184 cairo_xlib_surface_get_width(xsurface),
3185 cairo_xlib_surface_get_height(xsurface)));
3186 }
3187
3188 NPRect newClipRect;
3189 newClipRect.left = clipRect.x;
3190 newClipRect.top = clipRect.y;
3191 newClipRect.right = clipRect.XMost();
3192 newClipRect.bottom = clipRect.YMost();
3193 if (mWindow->clipRect.left != newClipRect.left ||
3194 mWindow->clipRect.top != newClipRect.top ||
3195 mWindow->clipRect.right != newClipRect.right ||
3196 mWindow->clipRect.bottom != newClipRect.bottom) {
3197 mWindow->clipRect = newClipRect;
3198 doupdatewindow = true;
3199 }
3200
3201 NPSetWindowCallbackStruct* ws_info =
3202 static_cast<NPSetWindowCallbackStruct*>(mWindow->ws_info);
3203 #ifdef MOZ_X11
3204 if (ws_info->visual != visual || ws_info->colormap != colormap) {
3205 ws_info->visual = visual;
3206 ws_info->colormap = colormap;
3207 ws_info->depth = gfxXlibSurface::DepthOfVisual(screen, visual);
3208 doupdatewindow = true;
3209 }
3210 #endif
3211
3212 {
3213 if (doupdatewindow)
3214 instance->SetWindow(mWindow);
3215 }
3216
3217 // Translate the dirty rect to drawable coordinates.
3218 nsIntRect dirtyRect = mDirtyRect + offset;
3219 if (mInstanceOwner->mFlash10Quirks) {
3220 // Work around a bug in Flash up to 10.1 d51 at least, where expose event
3221 // top left coordinates within the plugin-rect and not at the drawable
3222 // origin are misinterpreted. (We can move the top left coordinate
3223 // provided it is within the clipRect.)
3224 dirtyRect.SetRect(offset.x, offset.y,
3225 mDirtyRect.XMost(), mDirtyRect.YMost());
3226 }
3227 // Intersect the dirty rect with the clip rect to ensure that it lies within
3228 // the drawable.
3229 if (!dirtyRect.IntersectRect(dirtyRect, clipRect))
3230 return NS_OK;
3231
3232 {
3233 XEvent pluginEvent = XEvent();
3234 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
3235 // set the drawing info
3236 exposeEvent.type = GraphicsExpose;
3237 exposeEvent.display = DisplayOfScreen(screen);
3238 exposeEvent.drawable = cairo_xlib_surface_get_drawable(xsurface);
3239 exposeEvent.x = dirtyRect.x;
3240 exposeEvent.y = dirtyRect.y;
3241 exposeEvent.width = dirtyRect.width;
3242 exposeEvent.height = dirtyRect.height;
3243 exposeEvent.count = 0;
3244 // information not set:
3245 exposeEvent.serial = 0;
3246 exposeEvent.send_event = False;
3247 exposeEvent.major_code = 0;
3248 exposeEvent.minor_code = 0;
3249
3250 instance->HandleEvent(&pluginEvent, nullptr);
3251 }
3252 return NS_OK;
3253 }
3254 #endif
3255
Init(nsIContent * aContent)3256 nsresult nsPluginInstanceOwner::Init(nsIContent* aContent)
3257 {
3258 mLastEventloopNestingLevel = GetEventloopNestingLevel();
3259
3260 mContent = do_GetWeakReference(aContent);
3261
3262 // Get a frame, don't reflow. If a reflow was necessary it should have been
3263 // done at a higher level than this (content).
3264 nsIFrame* frame = aContent->GetPrimaryFrame();
3265 nsIObjectFrame* iObjFrame = do_QueryFrame(frame);
3266 nsPluginFrame* objFrame = static_cast<nsPluginFrame*>(iObjFrame);
3267 if (objFrame) {
3268 SetFrame(objFrame);
3269 // Some plugins require a specific sequence of shutdown and startup when
3270 // a page is reloaded. Shutdown happens usually when the last instance
3271 // is destroyed. Here we make sure the plugin instance in the old
3272 // document is destroyed before we try to create the new one.
3273 objFrame->PresContext()->EnsureVisible();
3274 } else {
3275 NS_NOTREACHED("Should not be initializing plugin without a frame");
3276 return NS_ERROR_FAILURE;
3277 }
3278
3279 // register context menu listener
3280 mCXMenuListener = new nsPluginDOMContextMenuListener(aContent);
3281
3282 aContent->AddEventListener(NS_LITERAL_STRING("focus"), this, false,
3283 false);
3284 aContent->AddEventListener(NS_LITERAL_STRING("blur"), this, false,
3285 false);
3286 aContent->AddEventListener(NS_LITERAL_STRING("mouseup"), this, false,
3287 false);
3288 aContent->AddEventListener(NS_LITERAL_STRING("mousedown"), this, false,
3289 false);
3290 aContent->AddEventListener(NS_LITERAL_STRING("mousemove"), this, false,
3291 false);
3292 aContent->AddEventListener(NS_LITERAL_STRING("click"), this, false,
3293 false);
3294 aContent->AddEventListener(NS_LITERAL_STRING("dblclick"), this, false,
3295 false);
3296 aContent->AddEventListener(NS_LITERAL_STRING("mouseover"), this, false,
3297 false);
3298 aContent->AddEventListener(NS_LITERAL_STRING("mouseout"), this, false,
3299 false);
3300 aContent->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
3301 aContent->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
3302 aContent->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
3303 aContent->AddEventListener(NS_LITERAL_STRING("drop"), this, true);
3304 aContent->AddEventListener(NS_LITERAL_STRING("drag"), this, true);
3305 aContent->AddEventListener(NS_LITERAL_STRING("dragenter"), this, true);
3306 aContent->AddEventListener(NS_LITERAL_STRING("dragover"), this, true);
3307 aContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, true);
3308 aContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, true);
3309 aContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, true);
3310 aContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, true);
3311 aContent->AddSystemEventListener(NS_LITERAL_STRING("compositionstart"),
3312 this, true);
3313 aContent->AddSystemEventListener(NS_LITERAL_STRING("compositionend"), this,
3314 true);
3315 aContent->AddSystemEventListener(NS_LITERAL_STRING("text"), this, true);
3316
3317 return NS_OK;
3318 }
3319
GetPluginPort()3320 void* nsPluginInstanceOwner::GetPluginPort()
3321 {
3322 void* result = nullptr;
3323 if (mWidget) {
3324 #ifdef XP_WIN
3325 if (!mPluginWindow || mPluginWindow->type == NPWindowTypeWindow)
3326 #endif
3327 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT); // HWND/gdk window
3328 }
3329
3330 return result;
3331 }
3332
ReleasePluginPort(void * pluginPort)3333 void nsPluginInstanceOwner::ReleasePluginPort(void * pluginPort)
3334 {
3335 }
3336
CreateWidget(void)3337 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
3338 {
3339 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
3340
3341 nsresult rv = NS_ERROR_FAILURE;
3342
3343 // Can't call this twice!
3344 if (mWidget) {
3345 NS_WARNING("Trying to create a plugin widget twice!");
3346 return NS_ERROR_FAILURE;
3347 }
3348
3349 bool windowless = false;
3350 mInstance->IsWindowless(&windowless);
3351 if (!windowless) {
3352 // Try to get a parent widget, on some platforms widget creation will fail without
3353 // a parent.
3354 nsCOMPtr<nsIWidget> parentWidget;
3355 nsIDocument *doc = nullptr;
3356 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3357 if (content) {
3358 doc = content->OwnerDoc();
3359 parentWidget = nsContentUtils::WidgetForDocument(doc);
3360 #ifndef XP_MACOSX
3361 // If we're running in the content process, we need a remote widget created in chrome.
3362 if (XRE_IsContentProcess()) {
3363 if (nsCOMPtr<nsPIDOMWindowOuter> window = doc->GetWindow()) {
3364 if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetTop()) {
3365 dom::TabChild* tc = dom::TabChild::GetFrom(topWindow);
3366 if (tc) {
3367 // This returns a PluginWidgetProxy which remotes a number of calls.
3368 rv = tc->CreatePluginWidget(parentWidget.get(), getter_AddRefs(mWidget));
3369 if (NS_FAILED(rv)) {
3370 return rv;
3371 }
3372 }
3373 }
3374 }
3375 }
3376 #endif // XP_MACOSX
3377 }
3378
3379 #ifndef XP_MACOSX
3380 // A failure here is terminal since we can't fall back on the non-e10s code
3381 // path below.
3382 if (!mWidget && XRE_IsContentProcess()) {
3383 return NS_ERROR_UNEXPECTED;
3384 }
3385 #endif // XP_MACOSX
3386
3387 if (!mWidget) {
3388 // native (single process)
3389 mWidget = do_CreateInstance(kWidgetCID, &rv);
3390 nsWidgetInitData initData;
3391 initData.mWindowType = eWindowType_plugin;
3392 initData.mUnicode = false;
3393 initData.clipChildren = true;
3394 initData.clipSiblings = true;
3395 rv = mWidget->Create(parentWidget.get(), nullptr,
3396 LayoutDeviceIntRect(0, 0, 0, 0), &initData);
3397 if (NS_FAILED(rv)) {
3398 mWidget->Destroy();
3399 mWidget = nullptr;
3400 return rv;
3401 }
3402 }
3403
3404 mWidget->EnableDragDrop(true);
3405 mWidget->Show(false);
3406 mWidget->Enable(false);
3407 }
3408
3409 if (mPluginFrame) {
3410 // nullptr widget is fine, will result in windowless setup.
3411 mPluginFrame->PrepForDrawing(mWidget);
3412 }
3413
3414 if (windowless) {
3415 mPluginWindow->type = NPWindowTypeDrawable;
3416
3417 // this needs to be a HDC according to the spec, but I do
3418 // not see the right way to release it so let's postpone
3419 // passing HDC till paint event when it is really
3420 // needed. Change spec?
3421 mPluginWindow->window = nullptr;
3422 #ifdef MOZ_X11
3423 // Fill in the display field.
3424 NPSetWindowCallbackStruct* ws_info =
3425 static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
3426 ws_info->display = DefaultXDisplay();
3427
3428 nsAutoCString description;
3429 GetPluginDescription(description);
3430 NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
3431 mFlash10Quirks = StringBeginsWith(description, flash10Head);
3432 #endif
3433 } else if (mWidget) {
3434 // mPluginWindow->type is used in |GetPluginPort| so it must
3435 // be initialized first
3436 mPluginWindow->type = NPWindowTypeWindow;
3437 mPluginWindow->window = GetPluginPort();
3438 // tell the plugin window about the widget
3439 mPluginWindow->SetPluginWidget(mWidget);
3440
3441 // tell the widget about the current plugin instance owner.
3442 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3443 if (pluginWidget) {
3444 pluginWidget->SetPluginInstanceOwner(this);
3445 }
3446 }
3447
3448 #ifdef XP_MACOSX
3449 if (GetDrawingModel() == NPDrawingModelCoreAnimation) {
3450 AddToCARefreshTimer();
3451 }
3452 #endif
3453
3454 mWidgetCreationComplete = true;
3455
3456 return NS_OK;
3457 }
3458
3459 // Mac specific code to fix up the port location and clipping region
3460 #ifdef XP_MACOSX
3461
FixUpPluginWindow(int32_t inPaintState)3462 void nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
3463 {
3464 if (!mPluginWindow || !mInstance || !mPluginFrame) {
3465 return;
3466 }
3467
3468 SetPluginPort();
3469
3470 LayoutDeviceIntSize widgetClip = mPluginFrame->GetWidgetlessClipRect().Size();
3471
3472 mPluginWindow->x = 0;
3473 mPluginWindow->y = 0;
3474
3475 NPRect oldClipRect = mPluginWindow->clipRect;
3476
3477 // fix up the clipping region
3478 mPluginWindow->clipRect.top = 0;
3479 mPluginWindow->clipRect.left = 0;
3480
3481 if (inPaintState == ePluginPaintDisable) {
3482 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
3483 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
3484 }
3485 else if (inPaintState == ePluginPaintEnable)
3486 {
3487 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
3488 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width;
3489 }
3490
3491 // if the clip rect changed, call SetWindow()
3492 // (RealPlayer needs this to draw correctly)
3493 if (mPluginWindow->clipRect.left != oldClipRect.left ||
3494 mPluginWindow->clipRect.top != oldClipRect.top ||
3495 mPluginWindow->clipRect.right != oldClipRect.right ||
3496 mPluginWindow->clipRect.bottom != oldClipRect.bottom)
3497 {
3498 if (UseAsyncRendering()) {
3499 mInstance->AsyncSetWindow(mPluginWindow);
3500 }
3501 else {
3502 mPluginWindow->CallSetWindow(mInstance);
3503 }
3504 }
3505
3506 // After the first NPP_SetWindow call we need to send an initial
3507 // top-level window focus event.
3508 if (!mSentInitialTopLevelWindowEvent) {
3509 // Set this before calling ProcessEvent to avoid endless recursion.
3510 mSentInitialTopLevelWindowEvent = true;
3511
3512 bool isActive = WindowIsActive();
3513 SendWindowFocusChanged(isActive);
3514 mLastWindowIsActive = isActive;
3515 }
3516 }
3517
3518 void
WindowFocusMayHaveChanged()3519 nsPluginInstanceOwner::WindowFocusMayHaveChanged()
3520 {
3521 if (!mSentInitialTopLevelWindowEvent) {
3522 return;
3523 }
3524
3525 bool isActive = WindowIsActive();
3526 if (isActive != mLastWindowIsActive) {
3527 SendWindowFocusChanged(isActive);
3528 mLastWindowIsActive = isActive;
3529 }
3530 }
3531
3532 bool
WindowIsActive()3533 nsPluginInstanceOwner::WindowIsActive()
3534 {
3535 if (!mPluginFrame) {
3536 return false;
3537 }
3538
3539 EventStates docState = mPluginFrame->GetContent()->OwnerDoc()->GetDocumentState();
3540 return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
3541 }
3542
3543 void
SendWindowFocusChanged(bool aIsActive)3544 nsPluginInstanceOwner::SendWindowFocusChanged(bool aIsActive)
3545 {
3546 if (!mInstance) {
3547 return;
3548 }
3549
3550 NPCocoaEvent cocoaEvent;
3551 InitializeNPCocoaEvent(&cocoaEvent);
3552 cocoaEvent.type = NPCocoaEventWindowFocusChanged;
3553 cocoaEvent.data.focus.hasFocus = aIsActive;
3554 mInstance->HandleEvent(&cocoaEvent,
3555 nullptr,
3556 NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
3557 }
3558
3559 void
HidePluginWindow()3560 nsPluginInstanceOwner::HidePluginWindow()
3561 {
3562 if (!mPluginWindow || !mInstance) {
3563 return;
3564 }
3565
3566 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
3567 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
3568 mWidgetVisible = false;
3569 if (UseAsyncRendering()) {
3570 mInstance->AsyncSetWindow(mPluginWindow);
3571 } else {
3572 mInstance->SetWindow(mPluginWindow);
3573 }
3574 }
3575
3576 #else // XP_MACOSX
3577
UpdateWindowPositionAndClipRect(bool aSetWindow)3578 void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
3579 {
3580 if (!mPluginWindow)
3581 return;
3582
3583 // For windowless plugins a non-empty clip rectangle will be
3584 // passed to the plugin during paint, an additional update
3585 // of the the clip rectangle here is not required
3586 if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering())
3587 return;
3588
3589 const NPWindow oldWindow = *mPluginWindow;
3590
3591 bool windowless = (mPluginWindow->type == NPWindowTypeDrawable);
3592 nsIntPoint origin = mPluginFrame->GetWindowOriginInPixels(windowless);
3593
3594 mPluginWindow->x = origin.x;
3595 mPluginWindow->y = origin.y;
3596
3597 mPluginWindow->clipRect.left = 0;
3598 mPluginWindow->clipRect.top = 0;
3599
3600 if (mPluginWindowVisible && mPluginDocumentActiveState) {
3601 mPluginWindow->clipRect.right = mPluginWindow->width;
3602 mPluginWindow->clipRect.bottom = mPluginWindow->height;
3603 } else {
3604 mPluginWindow->clipRect.right = 0;
3605 mPluginWindow->clipRect.bottom = 0;
3606 }
3607
3608 if (!aSetWindow)
3609 return;
3610
3611 if (mPluginWindow->x != oldWindow.x ||
3612 mPluginWindow->y != oldWindow.y ||
3613 mPluginWindow->clipRect.left != oldWindow.clipRect.left ||
3614 mPluginWindow->clipRect.top != oldWindow.clipRect.top ||
3615 mPluginWindow->clipRect.right != oldWindow.clipRect.right ||
3616 mPluginWindow->clipRect.bottom != oldWindow.clipRect.bottom) {
3617 CallSetWindow();
3618 }
3619 }
3620
3621 void
UpdateWindowVisibility(bool aVisible)3622 nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible)
3623 {
3624 mPluginWindowVisible = aVisible;
3625 UpdateWindowPositionAndClipRect(true);
3626 }
3627 #endif // XP_MACOSX
3628
3629 void
ResolutionMayHaveChanged()3630 nsPluginInstanceOwner::ResolutionMayHaveChanged()
3631 {
3632 #if defined(XP_MACOSX) || defined(XP_WIN)
3633 double scaleFactor = 1.0;
3634 GetContentsScaleFactor(&scaleFactor);
3635 if (scaleFactor != mLastScaleFactor) {
3636 ContentsScaleFactorChanged(scaleFactor);
3637 mLastScaleFactor = scaleFactor;
3638 }
3639 #endif
3640 float zoomFactor = 1.0;
3641 GetCSSZoomFactor(&zoomFactor);
3642 if (zoomFactor != mLastCSSZoomFactor) {
3643 if (mInstance) {
3644 mInstance->CSSZoomFactorChanged(zoomFactor);
3645 }
3646 mLastCSSZoomFactor = zoomFactor;
3647 }
3648
3649 }
3650
3651 void
UpdateDocumentActiveState(bool aIsActive)3652 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
3653 {
3654 PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
3655
3656 mPluginDocumentActiveState = aIsActive;
3657 #ifndef XP_MACOSX
3658 UpdateWindowPositionAndClipRect(true);
3659
3660 #ifdef MOZ_WIDGET_ANDROID
3661 if (mInstance) {
3662 if (!mPluginDocumentActiveState) {
3663 RemovePluginView();
3664 }
3665
3666 mInstance->NotifyOnScreen(mPluginDocumentActiveState);
3667
3668 // This is, perhaps, incorrect. It is supposed to be sent
3669 // when "the webview has paused or resumed". The side effect
3670 // is that Flash video players pause or resume (if they were
3671 // playing before) based on the value here. I personally think
3672 // we want that on Android when switching to another tab, so
3673 // that's why we call it here.
3674 mInstance->NotifyForeground(mPluginDocumentActiveState);
3675 }
3676 #endif // #ifdef MOZ_WIDGET_ANDROID
3677
3678 // We don't have a connection to PluginWidgetParent in the chrome
3679 // process when dealing with tab visibility changes, so this needs
3680 // to be forwarded over after the active state is updated. If we
3681 // don't hide plugin widgets in hidden tabs, the native child window
3682 // in chrome will remain visible after a tab switch.
3683 if (mWidget && XRE_IsContentProcess()) {
3684 mWidget->Show(aIsActive);
3685 mWidget->Enable(aIsActive);
3686 }
3687 #endif // #ifndef XP_MACOSX
3688 }
3689
3690 NS_IMETHODIMP
CallSetWindow()3691 nsPluginInstanceOwner::CallSetWindow()
3692 {
3693 if (!mWidgetCreationComplete) {
3694 // No widget yet, we can't run this code
3695 return NS_OK;
3696 }
3697 if (mPluginFrame) {
3698 mPluginFrame->CallSetWindow(false);
3699 } else if (mInstance) {
3700 if (UseAsyncRendering()) {
3701 mInstance->AsyncSetWindow(mPluginWindow);
3702 } else {
3703 mInstance->SetWindow(mPluginWindow);
3704 }
3705 }
3706
3707 return NS_OK;
3708 }
3709
3710 NS_IMETHODIMP
GetContentsScaleFactor(double * result)3711 nsPluginInstanceOwner::GetContentsScaleFactor(double *result)
3712 {
3713 NS_ENSURE_ARG_POINTER(result);
3714 double scaleFactor = 1.0;
3715 // On Mac, device pixels need to be translated to (and from) "display pixels"
3716 // for plugins. On other platforms, plugin coordinates are always in device
3717 // pixels.
3718 #if defined(XP_MACOSX) || defined(XP_WIN)
3719 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3720 nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
3721 if (presShell) {
3722 scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
3723 presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
3724 }
3725 #endif
3726 *result = scaleFactor;
3727 return NS_OK;
3728 }
3729
3730 void
GetCSSZoomFactor(float * result)3731 nsPluginInstanceOwner::GetCSSZoomFactor(float *result)
3732 {
3733 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3734 nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
3735 if (presShell) {
3736 *result = presShell->GetPresContext()->DeviceContext()->GetFullZoom();
3737 } else {
3738 *result = 1.0;
3739 }
3740 }
3741
SetFrame(nsPluginFrame * aFrame)3742 void nsPluginInstanceOwner::SetFrame(nsPluginFrame *aFrame)
3743 {
3744 // Don't do anything if the frame situation hasn't changed.
3745 if (mPluginFrame == aFrame) {
3746 return;
3747 }
3748
3749 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3750
3751 // If we already have a frame that is changing or going away...
3752 if (mPluginFrame) {
3753 if (content && content->OwnerDoc() && content->OwnerDoc()->GetWindow()) {
3754 nsCOMPtr<EventTarget> windowRoot = content->OwnerDoc()->GetWindow()->GetTopWindowRoot();
3755 if (windowRoot) {
3756 windowRoot->RemoveEventListener(NS_LITERAL_STRING("activate"),
3757 this, false);
3758 windowRoot->RemoveEventListener(NS_LITERAL_STRING("deactivate"),
3759 this, false);
3760 windowRoot->RemoveEventListener(NS_LITERAL_STRING("MozPerformDelayedBlur"),
3761 this, false);
3762 }
3763 }
3764
3765 // Make sure the old frame isn't holding a reference to us.
3766 mPluginFrame->SetInstanceOwner(nullptr);
3767 }
3768
3769 // Swap in the new frame (or no frame)
3770 mPluginFrame = aFrame;
3771
3772 // Set up a new frame
3773 if (mPluginFrame) {
3774 mPluginFrame->SetInstanceOwner(this);
3775 // Can only call PrepForDrawing on an object frame once. Don't do it here unless
3776 // widget creation is complete. Doesn't matter if we actually have a widget.
3777 if (mWidgetCreationComplete) {
3778 mPluginFrame->PrepForDrawing(mWidget);
3779 }
3780 mPluginFrame->FixupWindow(mPluginFrame->GetContentRectRelativeToSelf().Size());
3781 mPluginFrame->InvalidateFrame();
3782
3783 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3784 const nsIContent* content = aFrame->GetContent();
3785 if (fm && content) {
3786 mContentFocused = (content == fm->GetFocusedContent());
3787 }
3788
3789 // Register for widget-focus events on the window root.
3790 if (content && content->OwnerDoc() && content->OwnerDoc()->GetWindow()) {
3791 nsCOMPtr<EventTarget> windowRoot = content->OwnerDoc()->GetWindow()->GetTopWindowRoot();
3792 if (windowRoot) {
3793 windowRoot->AddEventListener(NS_LITERAL_STRING("activate"),
3794 this, false, false);
3795 windowRoot->AddEventListener(NS_LITERAL_STRING("deactivate"),
3796 this, false, false);
3797 windowRoot->AddEventListener(NS_LITERAL_STRING("MozPerformDelayedBlur"),
3798 this, false, false);
3799 }
3800 }
3801 }
3802 }
3803
GetFrame()3804 nsPluginFrame* nsPluginInstanceOwner::GetFrame()
3805 {
3806 return mPluginFrame;
3807 }
3808
PrivateModeChanged(bool aEnabled)3809 NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled)
3810 {
3811 return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK;
3812 }
3813
GetBaseURI() const3814 already_AddRefed<nsIURI> nsPluginInstanceOwner::GetBaseURI() const
3815 {
3816 nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3817 if (!content) {
3818 return nullptr;
3819 }
3820 return content->GetBaseURI();
3821 }
3822
3823 // static
3824 void
GeneratePluginEvent(const WidgetCompositionEvent * aSrcCompositionEvent,WidgetCompositionEvent * aDistCompositionEvent)3825 nsPluginInstanceOwner::GeneratePluginEvent(
3826 const WidgetCompositionEvent* aSrcCompositionEvent,
3827 WidgetCompositionEvent* aDistCompositionEvent)
3828 {
3829 #ifdef XP_WIN
3830 NPEvent newEvent;
3831 switch (aDistCompositionEvent->mMessage) {
3832 case eCompositionChange: {
3833 newEvent.event = WM_IME_COMPOSITION;
3834 newEvent.wParam = 0;
3835 if (aSrcCompositionEvent &&
3836 (aSrcCompositionEvent->mMessage == eCompositionCommit ||
3837 aSrcCompositionEvent->mMessage == eCompositionCommitAsIs)) {
3838 newEvent.lParam = GCS_RESULTSTR;
3839 } else {
3840 newEvent.lParam = GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE;
3841 }
3842 TextRangeArray* ranges = aDistCompositionEvent->mRanges;
3843 if (ranges && ranges->HasCaret()) {
3844 newEvent.lParam |= GCS_CURSORPOS;
3845 }
3846 break;
3847 }
3848
3849 case eCompositionStart:
3850 newEvent.event = WM_IME_STARTCOMPOSITION;
3851 newEvent.wParam = 0;
3852 newEvent.lParam = 0;
3853 break;
3854
3855 case eCompositionEnd:
3856 newEvent.event = WM_IME_ENDCOMPOSITION;
3857 newEvent.wParam = 0;
3858 newEvent.lParam = 0;
3859 break;
3860
3861 default:
3862 return;
3863 }
3864 aDistCompositionEvent->mPluginEvent.Copy(newEvent);
3865 #endif
3866 }
3867
3868 // nsPluginDOMContextMenuListener class implementation
3869
nsPluginDOMContextMenuListener(nsIContent * aContent)3870 nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener(nsIContent* aContent)
3871 {
3872 aContent->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
3873 }
3874
~nsPluginDOMContextMenuListener()3875 nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
3876 {
3877 }
3878
NS_IMPL_ISUPPORTS(nsPluginDOMContextMenuListener,nsIDOMEventListener)3879 NS_IMPL_ISUPPORTS(nsPluginDOMContextMenuListener,
3880 nsIDOMEventListener)
3881
3882 NS_IMETHODIMP
3883 nsPluginDOMContextMenuListener::HandleEvent(nsIDOMEvent* aEvent)
3884 {
3885 aEvent->PreventDefault(); // consume event
3886
3887 return NS_OK;
3888 }
3889
Destroy(nsIContent * aContent)3890 void nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
3891 {
3892 // Unregister context menu listener
3893 aContent->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
3894 }
3895