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(&currentLevel);
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