Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
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
16 #include "nsPluginInstanceOwner.h"
17 #include "nsIRunnable.h"
18 #include "nsContentUtils.h"
19 #include "nsRect.h"
20 #include "nsSize.h"
21 #include "nsDisplayList.h"
22 #include "ImageLayers.h"
23 #include "SharedTextureImage.h"
24 #include "nsObjectFrame.h"
25 #include "nsIPluginDocument.h"
26 #include "nsIStringStream.h"
27 #include "nsNetUtil.h"
28 #include "mozilla/Preferences.h"
29 #include "nsILinkHandler.h"
30 #include "nsIDocShellTreeItem.h"
31 #include "nsIWebBrowserChrome.h"
32 #include "nsLayoutUtils.h"
33 #include "nsIPluginWidget.h"
34 #include "nsViewManager.h"
35 #include "nsIDocShellTreeOwner.h"
36 #include "nsIDOMHTMLObjectElement.h"
37 #include "nsIAppShell.h"
38 #include "nsIDOMHTMLAppletElement.h"
39 #include "nsIObjectLoadingContent.h"
40 #include "nsAttrName.h"
41 #include "nsIFocusManager.h"
42 #include "nsFocusManager.h"
43 #include "nsIDOMDragEvent.h"
44 #include "nsIScrollableFrame.h"
45 #include "nsIDocShell.h"
46 #include "ImageContainer.h"
47 #include "nsIDOMHTMLCollection.h"
48 #include "GLContext.h"
49 #include "GLSharedHandleHelpers.h"
50 #include "nsIContentInlines.h"
51 #include "mozilla/MiscEvents.h"
52 #include "mozilla/MouseEvents.h"
53 #include "mozilla/TextEvents.h"
55 #include "nsContentCID.h"
56 #include "nsWidgetsCID.h"
57 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
58 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
60 #ifdef XP_WIN
61 #include <wtypes.h>
62 #include <winuser.h>
63 #endif
65 #ifdef XP_MACOSX
66 #include <Carbon/Carbon.h>
67 #include "nsPluginUtilsOSX.h"
68 #endif
70 #if (MOZ_WIDGET_GTK == 2)
71 #include <gdk/gdk.h>
72 #include <gdk/gdkx.h>
73 #include <gtk/gtk.h>
74 #endif
76 #ifdef MOZ_WIDGET_ANDROID
77 #include "ANPBase.h"
78 #include "AndroidBridge.h"
79 #include "nsWindow.h"
81 static nsPluginInstanceOwner* sFullScreenInstance = nullptr;
83 using namespace mozilla::dom;
85 #include <android/log.h>
86 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
87 #endif
89 using namespace mozilla;
90 using namespace mozilla::layers;
92 // special class for handeling DOM context menu events because for
93 // some reason it starves other mouse events if implemented on the
94 // same class
95 class nsPluginDOMContextMenuListener : public nsIDOMEventListener
96 {
97 public:
98 nsPluginDOMContextMenuListener(nsIContent* aContent);
99 virtual ~nsPluginDOMContextMenuListener();
101 NS_DECL_ISUPPORTS
102 NS_DECL_NSIDOMEVENTLISTENER
104 void Destroy(nsIContent* aContent);
106 nsEventStatus ProcessEvent(const WidgetGUIEvent& anEvent)
107 {
108 return nsEventStatus_eConsumeNoDefault;
109 }
110 };
112 class AsyncPaintWaitEvent : public nsRunnable
113 {
114 public:
115 AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) :
116 mContent(aContent), mFinished(aFinished)
117 {
118 }
120 NS_IMETHOD Run()
121 {
122 nsContentUtils::DispatchTrustedEvent(mContent->OwnerDoc(), mContent,
123 mFinished ? NS_LITERAL_STRING("MozPaintWaitFinished") : NS_LITERAL_STRING("MozPaintWait"),
124 true, true);
125 return NS_OK;
126 }
128 private:
129 nsCOMPtr<nsIContent> mContent;
130 bool mFinished;
131 };
133 void
134 nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
135 {
136 // This is notification for reftests about async plugin paint start
137 if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) {
138 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, false);
139 // Run this event as soon as it's safe to do so, since listeners need to
140 // receive it immediately
141 mWaitingForPaint = nsContentUtils::AddScriptRunner(event);
142 }
143 }
145 already_AddRefed<ImageContainer>
146 nsPluginInstanceOwner::GetImageContainer()
147 {
148 if (!mInstance)
149 return nullptr;
151 nsRefPtr<ImageContainer> container;
153 #if MOZ_WIDGET_ANDROID
154 // Right now we only draw with Gecko layers on Honeycomb and higher. See Paint()
155 // for what we do on other versions.
156 if (AndroidBridge::Bridge()->GetAPIVersion() < 11)
157 return nullptr;
159 LayoutDeviceRect r = GetPluginRect();
161 // NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
162 // into, set y-flip flags, etc, so we do this at the beginning.
163 gfxSize resolution = mObjectFrame->PresContext()->PresShell()->GetCumulativeResolution();
164 ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution.width, resolution.height)).Size();
165 mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
167 container = LayerManager::CreateImageContainer();
169 nsRefPtr<Image> img = container->CreateImage(ImageFormat::SHARED_TEXTURE);
171 SharedTextureImage::Data data;
172 data.mSize = gfx::IntSize(r.width, r.height);
173 data.mHandle = mInstance->CreateSharedHandle();
174 data.mShareType = mozilla::gl::SharedTextureShareType::SameProcess;
175 data.mInverted = mInstance->Inverted();
177 SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
178 pluginImage->SetData(data);
180 container->SetCurrentImageInTransaction(img);
182 return container.forget();
183 #endif
185 mInstance->GetImageContainer(getter_AddRefs(container));
186 return container.forget();
187 }
189 void
190 nsPluginInstanceOwner::SetBackgroundUnknown()
191 {
192 if (mInstance) {
193 mInstance->SetBackgroundUnknown();
194 }
195 }
197 already_AddRefed<gfxContext>
198 nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect)
199 {
200 nsIntRect rect = aRect;
201 nsRefPtr<gfxContext> ctx;
202 if (mInstance &&
203 NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(ctx)))) {
204 return ctx.forget();
205 }
206 return nullptr;
207 }
209 void
210 nsPluginInstanceOwner::EndUpdateBackground(gfxContext* aContext,
211 const nsIntRect& aRect)
212 {
213 nsIntRect rect = aRect;
214 if (mInstance) {
215 mInstance->EndUpdateBackground(aContext, &rect);
216 }
217 }
219 bool
220 nsPluginInstanceOwner::UseAsyncRendering()
221 {
222 #ifdef XP_MACOSX
223 if (mUseAsyncRendering) {
224 return true;
225 }
226 #endif
228 bool isOOP;
229 bool result = (mInstance &&
230 NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP
231 #ifndef XP_MACOSX
232 && (!mPluginWindow ||
233 mPluginWindow->type == NPWindowTypeDrawable)
234 #endif
235 );
237 #ifdef XP_MACOSX
238 if (result) {
239 mUseAsyncRendering = true;
240 }
241 #endif
243 return result;
244 }
246 nsIntSize
247 nsPluginInstanceOwner::GetCurrentImageSize()
248 {
249 nsIntSize size(0,0);
250 if (mInstance) {
251 mInstance->GetImageSize(&size);
252 }
253 return size;
254 }
256 nsPluginInstanceOwner::nsPluginInstanceOwner()
257 {
258 // create nsPluginNativeWindow object, it is derived from NPWindow
259 // struct and allows to manipulate native window procedure
260 nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
261 mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
262 if (mPluginHost)
263 mPluginHost->NewPluginNativeWindow(&mPluginWindow);
264 else
265 mPluginWindow = nullptr;
267 mObjectFrame = nullptr;
268 mContent = nullptr;
269 mWidgetCreationComplete = false;
270 #ifdef XP_MACOSX
271 memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
272 mInCGPaintLevel = 0;
273 mSentInitialTopLevelWindowEvent = false;
274 mColorProfile = nullptr;
275 mPluginPortChanged = false;
276 #endif
277 mContentFocused = false;
278 mWidgetVisible = true;
279 mPluginWindowVisible = false;
280 mPluginDocumentActiveState = true;
281 mNumCachedAttrs = 0;
282 mNumCachedParams = 0;
283 mCachedAttrParamNames = nullptr;
284 mCachedAttrParamValues = nullptr;
285 mLastMouseDownButtonType = -1;
287 #ifdef XP_MACOSX
288 #ifndef NP_NO_CARBON
289 // We don't support Carbon, but it is still the default model for i386 NPAPI.
290 mEventModel = NPEventModelCarbon;
291 #else
292 mEventModel = NPEventModelCocoa;
293 #endif
294 mUseAsyncRendering = false;
295 #endif
297 mWaitingForPaint = false;
299 #ifdef MOZ_WIDGET_ANDROID
300 mFullScreen = false;
301 mJavaView = nullptr;
302 #endif
303 }
305 nsPluginInstanceOwner::~nsPluginInstanceOwner()
306 {
307 int32_t cnt;
309 if (mWaitingForPaint) {
310 // We don't care when the event is dispatched as long as it's "soon",
311 // since whoever needs it will be waiting for it.
312 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
313 NS_DispatchToMainThread(event);
314 }
316 mObjectFrame = nullptr;
318 for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
319 if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) {
320 NS_Free(mCachedAttrParamNames[cnt]);
321 mCachedAttrParamNames[cnt] = nullptr;
322 }
324 if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) {
325 NS_Free(mCachedAttrParamValues[cnt]);
326 mCachedAttrParamValues[cnt] = nullptr;
327 }
328 }
330 if (mCachedAttrParamNames) {
331 NS_Free(mCachedAttrParamNames);
332 mCachedAttrParamNames = nullptr;
333 }
335 if (mCachedAttrParamValues) {
336 NS_Free(mCachedAttrParamValues);
337 mCachedAttrParamValues = nullptr;
338 }
340 PLUG_DeletePluginNativeWindow(mPluginWindow);
341 mPluginWindow = nullptr;
343 #ifdef MOZ_WIDGET_ANDROID
344 RemovePluginView();
345 #endif
347 if (mInstance) {
348 mInstance->SetOwner(nullptr);
349 }
350 }
352 NS_IMPL_ISUPPORTS(nsPluginInstanceOwner,
353 nsIPluginInstanceOwner,
354 nsIDOMEventListener,
355 nsIPrivacyTransitionObserver,
356 nsISupportsWeakReference)
358 nsresult
359 nsPluginInstanceOwner::SetInstance(nsNPAPIPluginInstance *aInstance)
360 {
361 NS_ASSERTION(!mInstance || !aInstance, "mInstance should only be set or unset!");
363 // If we're going to null out mInstance after use, be sure to call
364 // mInstance->SetOwner(nullptr) here, since it now won't be called
365 // from our destructor. This fixes bug 613376.
366 if (mInstance && !aInstance) {
367 mInstance->SetOwner(nullptr);
369 #ifdef MOZ_WIDGET_ANDROID
370 RemovePluginView();
371 #endif
372 }
374 mInstance = aInstance;
376 nsCOMPtr<nsIDocument> doc;
377 GetDocument(getter_AddRefs(doc));
378 if (doc) {
379 nsCOMPtr<nsPIDOMWindow> domWindow = doc->GetWindow();
380 if (domWindow) {
381 nsCOMPtr<nsIDocShell> docShell = domWindow->GetDocShell();
382 if (docShell)
383 docShell->AddWeakPrivacyTransitionObserver(this);
384 }
385 }
387 return NS_OK;
388 }
390 NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(NPWindow *&aWindow)
391 {
392 NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
393 aWindow = mPluginWindow;
394 return NS_OK;
395 }
397 NS_IMETHODIMP nsPluginInstanceOwner::GetMode(int32_t *aMode)
398 {
399 nsCOMPtr<nsIDocument> doc;
400 nsresult rv = GetDocument(getter_AddRefs(doc));
401 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
403 if (pDoc) {
404 *aMode = NP_FULL;
405 } else {
406 *aMode = NP_EMBED;
407 }
409 return rv;
410 }
412 NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(uint16_t& n,
413 const char*const*& names,
414 const char*const*& values)
415 {
416 nsresult rv = EnsureCachedAttrParamArrays();
417 NS_ENSURE_SUCCESS(rv, rv);
419 n = mNumCachedAttrs;
420 names = (const char **)mCachedAttrParamNames;
421 values = (const char **)mCachedAttrParamValues;
423 return rv;
424 }
426 NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
427 {
428 NS_ENSURE_ARG_POINTER(name);
429 NS_ENSURE_ARG_POINTER(result);
431 nsresult rv = EnsureCachedAttrParamArrays();
432 NS_ENSURE_SUCCESS(rv, rv);
434 *result = nullptr;
436 for (int i = 0; i < mNumCachedAttrs; i++) {
437 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
438 *result = mCachedAttrParamValues[i];
439 return NS_OK;
440 }
441 }
443 return NS_ERROR_FAILURE;
444 }
446 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
447 {
448 return CallQueryInterface(mContent, result);
449 }
451 nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
452 {
453 NS_ENSURE_ARG_POINTER(aInstance);
455 *aInstance = mInstance;
456 NS_IF_ADDREF(*aInstance);
457 return NS_OK;
458 }
460 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
461 const char *aTarget,
462 nsIInputStream *aPostStream,
463 void *aHeadersData,
464 uint32_t aHeadersDataLen)
465 {
466 NS_ENSURE_TRUE(mContent, NS_ERROR_NULL_POINTER);
468 if (mContent->IsEditable()) {
469 return NS_OK;
470 }
472 nsIDocument *doc = mContent->GetCurrentDoc();
473 if (!doc) {
474 return NS_ERROR_FAILURE;
475 }
477 nsIPresShell *presShell = doc->GetShell();
478 if (!presShell) {
479 return NS_ERROR_FAILURE;
480 }
482 nsPresContext *presContext = presShell->GetPresContext();
483 if (!presContext) {
484 return NS_ERROR_FAILURE;
485 }
487 // the container of the pres context will give us the link handler
488 nsCOMPtr<nsISupports> container = presContext->GetContainerWeak();
489 NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
490 nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
491 NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
493 nsAutoString unitarget;
494 unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
496 nsCOMPtr<nsIURI> baseURI = GetBaseURI();
498 // Create an absolute URL
499 nsCOMPtr<nsIURI> uri;
500 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
502 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
504 nsCOMPtr<nsIInputStream> headersDataStream;
505 if (aPostStream && aHeadersData) {
506 if (!aHeadersDataLen)
507 return NS_ERROR_UNEXPECTED;
509 nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
510 if (!sis)
511 return NS_ERROR_OUT_OF_MEMORY;
513 rv = sis->SetData((char *)aHeadersData, aHeadersDataLen);
514 NS_ENSURE_SUCCESS(rv, rv);
515 headersDataStream = do_QueryInterface(sis);
516 }
518 int32_t blockPopups =
519 Preferences::GetInt("privacy.popups.disable_from_plugins");
520 nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
522 rv = lh->OnLinkClick(mContent, uri, unitarget.get(), NullString(),
523 aPostStream, headersDataStream, true);
525 return rv;
526 }
528 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg)
529 {
530 nsresult rv = NS_ERROR_FAILURE;
532 rv = this->ShowStatus(NS_ConvertUTF8toUTF16(aStatusMsg).get());
534 return rv;
535 }
537 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char16_t *aStatusMsg)
538 {
539 nsresult rv = NS_ERROR_FAILURE;
541 if (!mObjectFrame) {
542 return rv;
543 }
544 nsCOMPtr<nsIDocShellTreeItem> docShellItem = mObjectFrame->PresContext()->GetDocShell();
545 if (NS_FAILED(rv) || !docShellItem) {
546 return rv;
547 }
549 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
550 rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
551 if (NS_FAILED(rv) || !treeOwner) {
552 return rv;
553 }
555 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner, &rv));
556 if (NS_FAILED(rv) || !browserChrome) {
557 return rv;
558 }
559 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
560 aStatusMsg);
562 return rv;
563 }
565 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
566 {
567 if (!aDocument)
568 return NS_ERROR_NULL_POINTER;
570 // XXX sXBL/XBL2 issue: current doc or owner doc?
571 // But keep in mind bug 322414 comment 33
572 NS_IF_ADDREF(*aDocument = mContent->OwnerDoc());
573 return NS_OK;
574 }
576 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
577 {
578 // If our object frame has gone away, we won't be able to determine
579 // up-to-date-ness, so just fire off the event.
580 if (mWaitingForPaint && (!mObjectFrame || IsUpToDate())) {
581 // We don't care when the event is dispatched as long as it's "soon",
582 // since whoever needs it will be waiting for it.
583 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
584 NS_DispatchToMainThread(event);
585 mWaitingForPaint = false;
586 }
588 if (!mObjectFrame || !invalidRect || !mWidgetVisible)
589 return NS_ERROR_FAILURE;
591 #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
592 // Each time an asynchronously-drawing plugin sends a new surface to display,
593 // the image in the ImageContainer is updated and InvalidateRect is called.
594 // There are different side effects for (sync) Android plugins.
595 nsRefPtr<ImageContainer> container;
596 mInstance->GetImageContainer(getter_AddRefs(container));
597 #endif
599 #ifndef XP_MACOSX
600 // Windowed plugins should not be calling NPN_InvalidateRect, but
601 // Silverlight does and expects it to "work"
602 if (mWidget) {
603 mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
604 invalidRect->right - invalidRect->left,
605 invalidRect->bottom - invalidRect->top));
606 return NS_OK;
607 }
608 #endif
609 nsIntRect rect(invalidRect->left,
610 invalidRect->top,
611 invalidRect->right - invalidRect->left,
612 invalidRect->bottom - invalidRect->top);
613 // invalidRect is in "display pixels". In non-HiDPI modes "display pixels"
614 // are device pixels. But in HiDPI modes each display pixel corresponds
615 // to more than one device pixel.
616 double scaleFactor = 1.0;
617 GetContentsScaleFactor(&scaleFactor);
618 rect.ScaleRoundOut(scaleFactor);
619 mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
620 return NS_OK;
621 }
623 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
624 {
625 return NS_ERROR_NOT_IMPLEMENTED;
626 }
628 NS_IMETHODIMP
629 nsPluginInstanceOwner::RedrawPlugin()
630 {
631 if (mObjectFrame) {
632 mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
633 }
634 return NS_OK;
635 }
637 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
638 {
639 if (!mObjectFrame) {
640 NS_WARNING("plugin owner has no owner in getting doc's window handle");
641 return NS_ERROR_FAILURE;
642 }
644 #if defined(XP_WIN)
645 void** pvalue = (void**)value;
646 nsViewManager* vm = mObjectFrame->PresContext()->GetPresShell()->GetViewManager();
647 if (!vm)
648 return NS_ERROR_FAILURE;
649 #if defined(XP_WIN)
650 // This property is provided to allow a "windowless" plugin to determine the window it is drawing
651 // in, so it can translate mouse coordinates it receives directly from the operating system
652 // to coordinates relative to itself.
654 // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
655 // 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
657 // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
658 // determines the window handle of the mozilla window containing the "windowless" plugin.
660 // Given that this HWND may not be that of the document's window, there is a slight risk
661 // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
662 // does not suggest this HWND IS that of the document window, rather that of the window
663 // the plugin is drawn in, this seems like a safe fix.
665 // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
666 // to change any behaviour for the much more common windowed plugins,
667 // though why this method would even be being called for a windowed plugin escapes me.
668 if (mPluginWindow && mPluginWindow->type == NPWindowTypeDrawable) {
669 // it turns out that flash also uses this window for determining focus, and is currently
670 // unable to show a caret correctly if we return the enclosing window. Therefore for
671 // now we only return the enclosing window when there is an actual offset which
672 // would otherwise cause coordinates to be offset incorrectly. (i.e.
673 // if the enclosing window if offset from the document window)
674 //
675 // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
676 // does not seem to be possible without a change to the flash plugin
678 nsIWidget* win = mObjectFrame->GetNearestWidget();
679 if (win) {
680 nsView *view = nsView::GetViewFor(win);
681 NS_ASSERTION(view, "No view for widget");
682 nsPoint offset = view->GetOffsetTo(nullptr);
684 if (offset.x || offset.y) {
685 // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
686 // so that mouse co-ordinates are not messed up.
687 *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW);
688 if (*pvalue)
689 return NS_OK;
690 }
691 }
692 }
693 #endif
694 // simply return the topmost document window
695 nsCOMPtr<nsIWidget> widget;
696 vm->GetRootWidget(getter_AddRefs(widget));
697 if (widget) {
698 *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
699 } else {
700 NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
701 }
703 return NS_OK;
704 #elif (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)) && defined(MOZ_X11)
705 // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
706 nsIWidget* win = mObjectFrame->GetNearestWidget();
707 if (!win)
708 return NS_ERROR_FAILURE;
709 *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
710 return NS_OK;
711 #else
712 return NS_ERROR_NOT_IMPLEMENTED;
713 #endif
714 }
716 NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
717 {
718 #ifdef XP_MACOSX
719 mEventModel = static_cast<NPEventModel>(eventModel);
720 return NS_OK;
721 #else
722 return NS_ERROR_NOT_IMPLEMENTED;
723 #endif
724 }
726 NPError nsPluginInstanceOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
727 {
728 if (!menu || !event)
729 return NPERR_GENERIC_ERROR;
731 #ifdef XP_MACOSX
732 if (GetEventModel() != NPEventModelCocoa)
733 return NPERR_INCOMPATIBLE_VERSION_ERROR;
735 return NS_NPAPI_ShowCocoaContextMenu(static_cast<void*>(menu), mWidget,
736 static_cast<NPCocoaEvent*>(event));
737 #else
738 return NPERR_INCOMPATIBLE_VERSION_ERROR;
739 #endif
740 }
742 NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
743 double *destX, double *destY, NPCoordinateSpace destSpace)
744 {
745 #ifdef XP_MACOSX
746 if (!mWidget)
747 return false;
749 return NS_NPAPI_ConvertPointCocoa(mWidget->GetNativeData(NS_NATIVE_WIDGET),
750 sourceX, sourceY, sourceSpace, destX, destY, destSpace);
751 #else
752 // we should implement this for all platforms
753 return false;
754 #endif
755 }
757 NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
758 void *initData, NPAsyncSurface *surface)
759 {
760 return NPERR_INCOMPATIBLE_VERSION_ERROR;
761 }
763 NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
764 {
765 return NPERR_INCOMPATIBLE_VERSION_ERROR;
766 }
768 void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
769 {
770 }
772 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
773 {
774 NS_ENSURE_ARG_POINTER(result);
776 *result = nsPluginTagType_Unknown;
778 nsIAtom *atom = mContent->Tag();
780 if (atom == nsGkAtoms::applet)
781 *result = nsPluginTagType_Applet;
782 else if (atom == nsGkAtoms::embed)
783 *result = nsPluginTagType_Embed;
784 else if (atom == nsGkAtoms::object)
785 *result = nsPluginTagType_Object;
787 return NS_OK;
788 }
790 NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(uint16_t& n, const char*const*& names, const char*const*& values)
791 {
792 nsresult rv = EnsureCachedAttrParamArrays();
793 NS_ENSURE_SUCCESS(rv, rv);
795 n = mNumCachedParams;
796 if (n) {
797 names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
798 values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
799 } else
800 names = values = nullptr;
802 return rv;
803 }
805 NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
806 {
807 NS_ENSURE_ARG_POINTER(name);
808 NS_ENSURE_ARG_POINTER(result);
810 nsresult rv = EnsureCachedAttrParamArrays();
811 NS_ENSURE_SUCCESS(rv, rv);
813 *result = nullptr;
815 for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
816 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
817 *result = mCachedAttrParamValues[i];
818 return NS_OK;
819 }
820 }
822 return NS_ERROR_FAILURE;
823 }
826 // Cache the attributes and/or parameters of our tag into a single set
827 // of arrays to be compatible with Netscape 4.x. The attributes go first,
828 // followed by a PARAM/null and then any PARAM tags. Also, hold the
829 // cached array around for the duration of the life of the instance
830 // because Netscape 4.x did. See bug 111008.
831 nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
832 {
833 if (mCachedAttrParamValues)
834 return NS_OK;
836 NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
837 !mCachedAttrParamNames,
838 "re-cache of attrs/params not implemented! use the DOM "
839 "node directy instead");
841 // Convert to a 16-bit count. Subtract 3 in case we add an extra
842 // "src", "wmode", or "codebase" entry below.
843 uint32_t cattrs = mContent->GetAttrCount();
844 if (cattrs < 0x0000FFFC) {
845 mNumCachedAttrs = static_cast<uint16_t>(cattrs);
846 } else {
847 mNumCachedAttrs = 0xFFFC;
848 }
850 // Check if we are java for special codebase handling
851 const char* mime = nullptr;
852 bool isJava = NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime &&
853 nsPluginHost::IsJavaMIMEType(mime);
855 // now, we need to find all the PARAM tags that are children of us
856 // however, be careful not to include any PARAMs that don't have us
857 // as a direct parent. For nested object (or applet) tags, be sure
858 // to only round up the param tags that coorespond with THIS
859 // instance. And also, weed out any bogus tags that may get in the
860 // way, see bug 39609. Then, with any param tag that meet our
861 // qualification, temporarly cache them in an nsCOMArray until
862 // we can figure out what size to make our fixed char* array.
863 nsCOMArray<nsIDOMElement> ourParams;
865 // Get all dependent PARAM tags, even if they are not direct children.
866 nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mContent);
867 NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
869 // Making DOM method calls can cause our frame to go away.
870 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
872 nsCOMPtr<nsIDOMHTMLCollection> allParams;
873 NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
874 mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
875 getter_AddRefs(allParams));
876 if (allParams) {
877 uint32_t numAllParams;
878 allParams->GetLength(&numAllParams);
879 for (uint32_t i = 0; i < numAllParams; i++) {
880 nsCOMPtr<nsIDOMNode> pnode;
881 allParams->Item(i, getter_AddRefs(pnode));
882 nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
883 if (domelement) {
884 // Ignore params without a name attribute.
885 nsAutoString name;
886 domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
887 if (!name.IsEmpty()) {
888 // Find the first object or applet parent.
889 nsCOMPtr<nsIDOMNode> parent;
890 nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
891 nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
892 pnode->GetParentNode(getter_AddRefs(parent));
893 while (!(domobject || domapplet) && parent) {
894 domobject = do_QueryInterface(parent);
895 domapplet = do_QueryInterface(parent);
896 nsCOMPtr<nsIDOMNode> temp;
897 parent->GetParentNode(getter_AddRefs(temp));
898 parent = temp;
899 }
900 if (domapplet || domobject) {
901 if (domapplet) {
902 parent = do_QueryInterface(domapplet);
903 }
904 else {
905 parent = do_QueryInterface(domobject);
906 }
907 nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
908 if (parent == mydomNode) {
909 ourParams.AppendObject(domelement);
910 }
911 }
912 }
913 }
914 }
915 }
917 // Convert to a 16-bit count.
918 uint32_t cparams = ourParams.Count();
919 if (cparams < 0x0000FFFF) {
920 mNumCachedParams = static_cast<uint16_t>(cparams);
921 } else {
922 mNumCachedParams = 0xFFFF;
923 }
925 uint16_t numRealAttrs = mNumCachedAttrs;
927 // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
928 // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
929 // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
930 // look for "data", lets instead copy the "data" attribute and add another entry
931 // to the bottom of the array if there isn't already a "src" specified.
932 nsAutoString data;
933 if (mContent->Tag() == nsGkAtoms::object &&
934 !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
935 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data) &&
936 !data.IsEmpty()) {
937 mNumCachedAttrs++;
938 }
940 // "plugins.force.wmode" forces us to send a specific "wmode" parameter,
941 // used by flash to select a rendering mode. Common values include
942 // "opaque", "transparent", "windowed", "direct"
943 nsCString wmodeType;
944 nsAdoptingCString wmodePref = Preferences::GetCString("plugins.force.wmode");
945 if (!wmodePref.IsEmpty()) {
946 mNumCachedAttrs++;
947 wmodeType = wmodePref;
948 }
949 #if defined(XP_WIN) || defined(XP_LINUX)
950 // Bug 923745 - Until we support windowed mode plugins in content processes,
951 // force flash to use a windowless rendering mode. This hack should go away
952 // when bug 923746 lands. (OS X plugins always use some native widgets, so
953 // unfortunately this does not help there)
954 else if (XRE_GetProcessType() == GeckoProcessType_Content) {
955 mNumCachedAttrs++;
956 wmodeType.AssignLiteral("transparent");
957 }
958 #endif
960 // (Bug 738396) java has quirks in its codebase parsing, pass the
961 // absolute codebase URI as content sees it.
962 bool addCodebase = false;
963 nsAutoCString codebaseStr;
964 if (isJava) {
965 nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(mContent);
966 NS_ENSURE_TRUE(objlc, NS_ERROR_UNEXPECTED);
967 nsCOMPtr<nsIURI> codebaseURI;
968 nsresult rv = objlc->GetBaseURI(getter_AddRefs(codebaseURI));
969 NS_ENSURE_SUCCESS(rv, rv);
970 codebaseURI->GetSpec(codebaseStr);
971 if (!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::codebase)) {
972 mNumCachedAttrs++;
973 addCodebase = true;
974 }
975 }
977 mCachedAttrParamNames = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
978 NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY);
979 mCachedAttrParamValues = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
980 NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
982 // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the
983 // attribute order. So we want to make sure we give the plugin the
984 // attributes in the order they came in in the source, to be compatible with
985 // other browsers. Now in HTML, the storage order is the reverse of the
986 // source order, while in XML and XHTML it's the same as the source order
987 // (see the AddAttributes functions in the HTML and XML content sinks).
988 int32_t start, end, increment;
989 if (mContent->IsHTML() &&
990 mContent->IsInHTMLDocument()) {
991 // HTML. Walk attributes in reverse order.
992 start = numRealAttrs - 1;
993 end = -1;
994 increment = -1;
995 } else {
996 // XHTML or XML. Walk attributes in forward order.
997 start = 0;
998 end = numRealAttrs;
999 increment = 1;
1000 }
1002 // Set to the next slot to fill in name and value cache arrays.
1003 uint32_t nextAttrParamIndex = 0;
1005 // Whether or not we force the wmode below while traversing
1006 // the name/value pairs.
1007 bool wmodeSet = false;
1009 // Add attribute name/value pairs.
1010 for (int32_t index = start; index != end; index += increment) {
1011 const nsAttrName* attrName = mContent->GetAttrNameAt(index);
1012 nsIAtom* atom = attrName->LocalName();
1013 nsAutoString value;
1014 mContent->GetAttr(attrName->NamespaceID(), atom, value);
1015 nsAutoString name;
1016 atom->ToString(name);
1018 FixUpURLS(name, value);
1020 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
1021 if (!wmodeType.IsEmpty() &&
1022 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "wmode")) {
1023 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
1025 if (!wmodeSet) {
1026 // We allocated space to add a wmode attr, but we don't need it now.
1027 mNumCachedAttrs--;
1028 wmodeSet = true;
1029 }
1030 } else if (isJava && 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "codebase")) {
1031 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr));
1032 } else {
1033 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
1034 }
1035 nextAttrParamIndex++;
1036 }
1038 // Potentially add CODEBASE attribute
1039 if (addCodebase) {
1040 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("codebase"));
1041 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr));
1042 nextAttrParamIndex++;
1043 }
1045 // Potentially add WMODE attribute.
1046 if (!wmodeType.IsEmpty() && !wmodeSet) {
1047 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode"));
1048 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
1049 nextAttrParamIndex++;
1050 }
1052 // Potentially add SRC attribute.
1053 if (!data.IsEmpty()) {
1054 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
1055 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data);
1056 nextAttrParamIndex++;
1057 }
1059 // Add PARAM and null separator.
1060 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
1061 #ifdef MOZ_WIDGET_ANDROID
1062 // Flash expects an empty string on android
1063 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING(""));
1064 #else
1065 mCachedAttrParamValues[nextAttrParamIndex] = nullptr;
1066 #endif
1067 nextAttrParamIndex++;
1069 // Add PARAM name/value pairs.
1071 // We may decrement mNumCachedParams below
1072 uint16_t totalParams = mNumCachedParams;
1073 for (uint16_t i = 0; i < totalParams; i++) {
1074 nsIDOMElement* param = ourParams.ObjectAt(i);
1075 if (!param) {
1076 continue;
1077 }
1079 nsAutoString name;
1080 nsAutoString value;
1081 param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
1082 param->GetAttribute(NS_LITERAL_STRING("value"), value);
1084 FixUpURLS(name, value);
1086 /*
1087 * According to the HTML 4.01 spec, at
1088 * http://www.w3.org/TR/html4/types.html#type-cdata
1089 * ''User agents may ignore leading and trailing
1090 * white space in CDATA attribute values (e.g., "
1091 * myval " may be interpreted as "myval"). Authors
1092 * should not declare attribute values with
1093 * leading or trailing white space.''
1094 * However, do not trim consecutive spaces as in bug 122119
1095 */
1096 name.Trim(" \n\r\t\b", true, true, false);
1097 value.Trim(" \n\r\t\b", true, true, false);
1098 if (isJava && name.EqualsIgnoreCase("codebase")) {
1099 // We inserted normalized codebase above, don't include other versions in
1100 // params
1101 mNumCachedParams--;
1102 continue;
1103 }
1104 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
1105 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
1106 nextAttrParamIndex++;
1107 }
1109 return NS_OK;
1110 }
1112 #ifdef XP_MACOSX
1114 static void InitializeNPCocoaEvent(NPCocoaEvent* event)
1115 {
1116 memset(event, 0, sizeof(NPCocoaEvent));
1117 }
1119 NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
1120 {
1121 #ifndef NP_NO_QUICKDRAW
1122 // We don't support the Quickdraw drawing model any more but it's still
1123 // the default model for i386 per NPAPI.
1124 NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
1125 #else
1126 NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
1127 #endif
1129 if (!mInstance)
1130 return drawingModel;
1132 mInstance->GetDrawingModel((int32_t*)&drawingModel);
1133 return drawingModel;
1134 }
1136 bool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation()
1137 {
1138 if (!mInstance)
1139 return false;
1141 bool coreAnimation;
1142 if (!NS_SUCCEEDED(mInstance->IsRemoteDrawingCoreAnimation(&coreAnimation)))
1143 return false;
1145 return coreAnimation;
1146 }
1148 nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor)
1149 {
1150 if (!mInstance) {
1151 return NS_ERROR_NULL_POINTER;
1152 }
1153 return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor);
1154 }
1156 NPEventModel nsPluginInstanceOwner::GetEventModel()
1157 {
1158 return mEventModel;
1159 }
1161 #define DEFAULT_REFRESH_RATE 20 // 50 FPS
1163 nsCOMPtr<nsITimer> *nsPluginInstanceOwner::sCATimer = nullptr;
1164 nsTArray<nsPluginInstanceOwner*> *nsPluginInstanceOwner::sCARefreshListeners = nullptr;
1166 void nsPluginInstanceOwner::CARefresh(nsITimer *aTimer, void *aClosure) {
1167 if (!sCARefreshListeners) {
1168 return;
1169 }
1170 for (size_t i = 0; i < sCARefreshListeners->Length(); i++) {
1171 nsPluginInstanceOwner* instanceOwner = (*sCARefreshListeners)[i];
1172 NPWindow *window;
1173 instanceOwner->GetWindow(window);
1174 if (!window) {
1175 continue;
1176 }
1177 NPRect r;
1178 r.left = 0;
1179 r.top = 0;
1180 r.right = window->width;
1181 r.bottom = window->height;
1182 instanceOwner->InvalidateRect(&r);
1183 }
1184 }
1186 void nsPluginInstanceOwner::AddToCARefreshTimer() {
1187 if (!mInstance) {
1188 return;
1189 }
1191 // Flash invokes InvalidateRect for us.
1192 const char* mime = nullptr;
1193 if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime) {
1194 if (strcmp(mime, "application/x-shockwave-flash") == 0) {
1195 return;
1196 }
1197 }
1199 if (!sCARefreshListeners) {
1200 sCARefreshListeners = new nsTArray<nsPluginInstanceOwner*>();
1201 if (!sCARefreshListeners) {
1202 return;
1203 }
1204 }
1206 if (sCARefreshListeners->Contains(this)) {
1207 return;
1208 }
1210 sCARefreshListeners->AppendElement(this);
1212 if (!sCATimer) {
1213 sCATimer = new nsCOMPtr<nsITimer>();
1214 if (!sCATimer) {
1215 return;
1216 }
1217 }
1219 if (sCARefreshListeners->Length() == 1) {
1220 *sCATimer = do_CreateInstance("@mozilla.org/timer;1");
1221 (*sCATimer)->InitWithFuncCallback(CARefresh, nullptr,
1222 DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK);
1223 }
1224 }
1226 void nsPluginInstanceOwner::RemoveFromCARefreshTimer() {
1227 if (!sCARefreshListeners || sCARefreshListeners->Contains(this) == false) {
1228 return;
1229 }
1231 sCARefreshListeners->RemoveElement(this);
1233 if (sCARefreshListeners->Length() == 0) {
1234 if (sCATimer) {
1235 (*sCATimer)->Cancel();
1236 delete sCATimer;
1237 sCATimer = nullptr;
1238 }
1239 delete sCARefreshListeners;
1240 sCARefreshListeners = nullptr;
1241 }
1242 }
1244 void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext,
1245 int aWidth, int aHeight)
1246 {
1247 if (aWidth == 0 || aHeight == 0)
1248 return;
1250 if (!mCARenderer) {
1251 mCARenderer = new nsCARenderer();
1252 }
1254 // aWidth and aHeight are in "display pixels". In non-HiDPI modes
1255 // "display pixels" are device pixels. But in HiDPI modes each
1256 // display pixel corresponds to more than one device pixel.
1257 double scaleFactor = 1.0;
1258 GetContentsScaleFactor(&scaleFactor);
1260 if (!mIOSurface ||
1261 (mIOSurface->GetWidth() != (size_t)aWidth ||
1262 mIOSurface->GetHeight() != (size_t)aHeight ||
1263 mIOSurface->GetContentsScaleFactor() != scaleFactor)) {
1264 mIOSurface = nullptr;
1266 // If the renderer is backed by an IOSurface, resize it as required.
1267 mIOSurface = MacIOSurface::CreateIOSurface(aWidth, aHeight, scaleFactor);
1268 if (mIOSurface) {
1269 RefPtr<MacIOSurface> attachSurface = MacIOSurface::LookupSurface(
1270 mIOSurface->GetIOSurfaceID(),
1271 scaleFactor);
1272 if (attachSurface) {
1273 mCARenderer->AttachIOSurface(attachSurface);
1274 } else {
1275 NS_ERROR("IOSurface attachment failed");
1276 mIOSurface = nullptr;
1277 }
1278 }
1279 }
1281 if (!mColorProfile) {
1282 mColorProfile = CreateSystemColorSpace();
1283 }
1285 if (mCARenderer->isInit() == false) {
1286 void *caLayer = nullptr;
1287 nsresult rv = mInstance->GetValueFromPlugin(NPPVpluginCoreAnimationLayer, &caLayer);
1288 if (NS_FAILED(rv) || !caLayer) {
1289 return;
1290 }
1292 // We don't run Flash in-process so we can unconditionally disallow
1293 // the offliner renderer.
1294 mCARenderer->SetupRenderer(caLayer, aWidth, aHeight, scaleFactor,
1295 DISALLOW_OFFLINE_RENDERER);
1297 // Setting up the CALayer requires resetting the painting otherwise we
1298 // get garbage for the first few frames.
1299 FixUpPluginWindow(ePluginPaintDisable);
1300 FixUpPluginWindow(ePluginPaintEnable);
1301 }
1303 CGImageRef caImage = nullptr;
1304 nsresult rt = mCARenderer->Render(aWidth, aHeight, scaleFactor, &caImage);
1305 if (rt == NS_OK && mIOSurface && mColorProfile) {
1306 nsCARenderer::DrawSurfaceToCGContext(aCGContext, mIOSurface, mColorProfile,
1307 0, 0, aWidth, aHeight);
1308 } else if (rt == NS_OK && caImage != nullptr) {
1309 // Significant speed up by resetting the scaling
1310 ::CGContextSetInterpolationQuality(aCGContext, kCGInterpolationNone );
1311 ::CGContextTranslateCTM(aCGContext, 0, (double) aHeight * scaleFactor);
1312 ::CGContextScaleCTM(aCGContext, scaleFactor, -scaleFactor);
1314 ::CGContextDrawImage(aCGContext, CGRectMake(0,0,aWidth,aHeight), caImage);
1315 } else {
1316 NS_NOTREACHED("nsCARenderer::Render failure");
1317 }
1318 }
1320 void* nsPluginInstanceOwner::GetPluginPortCopy()
1321 {
1322 if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
1323 GetDrawingModel() == NPDrawingModelCoreAnimation ||
1324 GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
1325 return &mCGPluginPortCopy;
1326 return nullptr;
1327 }
1329 // Currently (on OS X in Cocoa widgets) any changes made as a result of
1330 // calling GetPluginPortFromWidget() are immediately reflected in the NPWindow
1331 // structure that has been passed to the plugin via SetWindow(). This is
1332 // because calls to nsChildView::GetNativeData(NS_NATIVE_PLUGIN_PORT_CG)
1333 // always return a pointer to the same internal (private) object, but may
1334 // make changes inside that object. All calls to GetPluginPortFromWidget() made while
1335 // the plugin is active (i.e. excluding those made at our initialization)
1336 // need to take this into account. The easiest way to do so is to replace
1337 // them with calls to SetPluginPortAndDetectChange(). This method keeps track
1338 // of when calls to GetPluginPortFromWidget() result in changes, and sets a flag to make
1339 // sure SetWindow() gets called the next time through FixUpPluginWindow(), so
1340 // that the plugin is notified of these changes.
1341 void* nsPluginInstanceOwner::SetPluginPortAndDetectChange()
1342 {
1343 if (!mPluginWindow)
1344 return nullptr;
1345 void* pluginPort = GetPluginPortFromWidget();
1346 if (!pluginPort)
1347 return nullptr;
1348 mPluginWindow->window = pluginPort;
1350 return mPluginWindow->window;
1351 }
1353 void nsPluginInstanceOwner::BeginCGPaint()
1354 {
1355 ++mInCGPaintLevel;
1356 }
1358 void nsPluginInstanceOwner::EndCGPaint()
1359 {
1360 --mInCGPaintLevel;
1361 NS_ASSERTION(mInCGPaintLevel >= 0, "Mismatched call to nsPluginInstanceOwner::EndCGPaint()!");
1362 }
1364 #endif
1366 // static
1367 uint32_t
1368 nsPluginInstanceOwner::GetEventloopNestingLevel()
1369 {
1370 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
1371 uint32_t currentLevel = 0;
1372 if (appShell) {
1373 appShell->GetEventloopNestingLevel(¤tLevel);
1374 #ifdef XP_MACOSX
1375 // Cocoa widget code doesn't process UI events through the normal
1376 // appshell event loop, so it needs an additional count here.
1377 currentLevel++;
1378 #endif
1379 }
1381 // No idea how this happens... but Linux doesn't consistently
1382 // process UI events through the appshell event loop. If we get a 0
1383 // here on any platform we increment the level just in case so that
1384 // we make sure we always tear the plugin down eventually.
1385 if (!currentLevel) {
1386 currentLevel++;
1387 }
1389 return currentLevel;
1390 }
1392 #ifdef MOZ_WIDGET_ANDROID
1394 // Modified version of nsFrame::GetOffsetToCrossDoc that stops when it
1395 // hits an element with a displayport (or runs out of frames). This is
1396 // not really the right thing to do, but it's better than what was here before.
1397 static nsPoint
1398 GetOffsetRootContent(nsIFrame* aFrame)
1399 {
1400 // offset will hold the final offset
1401 // docOffset holds the currently accumulated offset at the current APD, it
1402 // will be converted and added to offset when the current APD changes.
1403 nsPoint offset(0, 0), docOffset(0, 0);
1404 const nsIFrame* f = aFrame;
1405 int32_t currAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
1406 int32_t apd = currAPD;
1407 nsRect displayPort;
1408 while (f) {
1409 if (f->GetContent() && nsLayoutUtils::GetDisplayPort(f->GetContent(), &displayPort))
1410 break;
1412 docOffset += f->GetPosition();
1413 nsIFrame* parent = f->GetParent();
1414 if (parent) {
1415 f = parent;
1416 } else {
1417 nsPoint newOffset(0, 0);
1418 f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
1419 int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
1420 if (!f || newAPD != currAPD) {
1421 // Convert docOffset to the right APD and add it to offset.
1422 offset += docOffset.ConvertAppUnits(currAPD, apd);
1423 docOffset.x = docOffset.y = 0;
1424 }
1425 currAPD = newAPD;
1426 docOffset += newOffset;
1427 }
1428 }
1430 offset += docOffset.ConvertAppUnits(currAPD, apd);
1432 return offset;
1433 }
1435 LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
1436 {
1437 // Get the offset of the content relative to the page
1438 nsRect bounds = mObjectFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mObjectFrame);
1439 LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mObjectFrame->PresContext()->AppUnitsPerDevPixel());
1440 return LayoutDeviceRect(rect);
1441 }
1443 bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */)
1444 {
1445 if (!mJavaView) {
1446 mJavaView = mInstance->GetJavaSurface();
1448 if (!mJavaView)
1449 return false;
1451 mJavaView = (void*)AndroidBridge::GetJNIEnv()->NewGlobalRef((jobject)mJavaView);
1452 }
1454 if (AndroidBridge::Bridge())
1455 AndroidBridge::Bridge()->AddPluginView((jobject)mJavaView, aRect, mFullScreen);
1457 if (mFullScreen)
1458 sFullScreenInstance = this;
1460 return true;
1461 }
1463 void nsPluginInstanceOwner::RemovePluginView()
1464 {
1465 if (!mInstance || !mJavaView)
1466 return;
1468 mozilla::widget::android::GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
1469 AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
1470 mJavaView = nullptr;
1472 if (mFullScreen)
1473 sFullScreenInstance = nullptr;
1474 }
1476 void nsPluginInstanceOwner::GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos)
1477 {
1478 if (!mInstance)
1479 return;
1481 mInstance->GetVideos(aVideos);
1482 }
1484 already_AddRefed<ImageContainer> nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
1485 {
1486 nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
1488 nsRefPtr<Image> img = container->CreateImage(ImageFormat::SHARED_TEXTURE);
1490 SharedTextureImage::Data data;
1492 data.mShareType = gl::SharedTextureShareType::SameProcess;
1493 data.mHandle = gl::CreateSharedHandle(mInstance->GLContext(),
1494 data.mShareType,
1495 aVideoInfo->mSurfaceTexture,
1496 gl::SharedTextureBufferType::SurfaceTexture);
1498 // The logic below for Honeycomb is just a guess, but seems to work. We don't have a separate
1499 // inverted flag for video.
1500 data.mInverted = AndroidBridge::Bridge()->IsHoneycomb() ? true : mInstance->Inverted();
1501 data.mSize = gfx::IntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height);
1503 SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
1504 pluginImage->SetData(data);
1505 container->SetCurrentImageInTransaction(img);
1507 return container.forget();
1508 }
1510 void nsPluginInstanceOwner::Invalidate() {
1511 NPRect rect;
1512 rect.left = rect.top = 0;
1513 rect.right = mPluginWindow->width;
1514 rect.bottom = mPluginWindow->height;
1515 InvalidateRect(&rect);
1516 }
1518 void nsPluginInstanceOwner::RequestFullScreen() {
1519 if (mFullScreen)
1520 return;
1522 // Remove whatever view we currently have (if any, fullscreen or otherwise)
1523 RemovePluginView();
1525 mFullScreen = true;
1526 AddPluginView();
1528 mInstance->NotifyFullScreen(mFullScreen);
1529 }
1531 void nsPluginInstanceOwner::ExitFullScreen() {
1532 if (!mFullScreen)
1533 return;
1535 RemovePluginView();
1537 mFullScreen = false;
1539 int32_t model = mInstance->GetANPDrawingModel();
1541 if (model == kSurface_ANPDrawingModel) {
1542 // We need to do this immediately, otherwise Flash
1543 // sometimes causes a deadlock (bug 762407)
1544 AddPluginView(GetPluginRect());
1545 }
1547 mInstance->NotifyFullScreen(mFullScreen);
1549 // This will cause Paint() to be called, which is where
1550 // we normally add/update views and layers
1551 Invalidate();
1552 }
1554 void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
1555 JNIEnv* env = AndroidBridge::GetJNIEnv();
1557 if (sFullScreenInstance && sFullScreenInstance->mInstance &&
1558 env->IsSameObject(view, (jobject)sFullScreenInstance->mInstance->GetJavaSurface())) {
1559 sFullScreenInstance->ExitFullScreen();
1560 }
1561 }
1563 #endif
1565 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
1566 {
1567 #ifdef MOZ_WIDGET_ANDROID
1568 if (mInstance) {
1569 ANPEvent event;
1570 event.inSize = sizeof(ANPEvent);
1571 event.eventType = kLifecycle_ANPEventType;
1573 nsAutoString eventType;
1574 aFocusEvent->GetType(eventType);
1575 if (eventType.EqualsLiteral("focus")) {
1576 event.data.lifecycle.action = kGainFocus_ANPLifecycleAction;
1577 }
1578 else if (eventType.EqualsLiteral("blur")) {
1579 event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction;
1580 }
1581 else {
1582 NS_ASSERTION(false, "nsPluginInstanceOwner::DispatchFocusToPlugin, wierd eventType");
1583 }
1584 mInstance->HandleEvent(&event, nullptr);
1585 }
1586 #endif
1588 #ifndef XP_MACOSX
1589 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
1590 // continue only for cases without child window
1591 return aFocusEvent->PreventDefault(); // consume event
1592 }
1593 #endif
1595 WidgetEvent* theEvent = aFocusEvent->GetInternalNSEvent();
1596 if (theEvent) {
1597 // we only care about the message in ProcessEvent
1598 WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->message,
1599 nullptr);
1600 nsEventStatus rv = ProcessEvent(focusEvent);
1601 if (nsEventStatus_eConsumeNoDefault == rv) {
1602 aFocusEvent->PreventDefault();
1603 aFocusEvent->StopPropagation();
1604 }
1605 }
1607 return NS_OK;
1608 }
1610 nsresult nsPluginInstanceOwner::ProcessKeyPress(nsIDOMEvent* aKeyEvent)
1611 {
1612 #ifdef XP_MACOSX
1613 return DispatchKeyToPlugin(aKeyEvent);
1614 #else
1615 if (SendNativeEvents())
1616 DispatchKeyToPlugin(aKeyEvent);
1618 if (mInstance) {
1619 // If this event is going to the plugin, we want to kill it.
1620 // Not actually sending keypress to the plugin, since we didn't before.
1621 aKeyEvent->PreventDefault();
1622 aKeyEvent->StopPropagation();
1623 }
1624 return NS_OK;
1625 #endif
1626 }
1628 nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
1629 {
1630 #if !defined(XP_MACOSX)
1631 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
1632 return aKeyEvent->PreventDefault(); // consume event
1633 // continue only for cases without child window
1634 #endif
1636 if (mInstance) {
1637 WidgetKeyboardEvent* keyEvent =
1638 aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
1639 if (keyEvent && keyEvent->eventStructType == NS_KEY_EVENT) {
1640 nsEventStatus rv = ProcessEvent(*keyEvent);
1641 if (nsEventStatus_eConsumeNoDefault == rv) {
1642 aKeyEvent->PreventDefault();
1643 aKeyEvent->StopPropagation();
1644 }
1645 }
1646 }
1648 return NS_OK;
1649 }
1651 nsresult
1652 nsPluginInstanceOwner::ProcessMouseDown(nsIDOMEvent* aMouseEvent)
1653 {
1654 #if !defined(XP_MACOSX)
1655 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
1656 return aMouseEvent->PreventDefault(); // consume event
1657 // continue only for cases without child window
1658 #endif
1660 // if the plugin is windowless, we need to set focus ourselves
1661 // otherwise, we might not get key events
1662 if (mObjectFrame && mPluginWindow &&
1663 mPluginWindow->type == NPWindowTypeDrawable) {
1665 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1666 if (fm) {
1667 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
1668 fm->SetFocus(elem, 0);
1669 }
1670 }
1672 WidgetMouseEvent* mouseEvent =
1673 aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
1674 if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) {
1675 mLastMouseDownButtonType = mouseEvent->button;
1676 nsEventStatus rv = ProcessEvent(*mouseEvent);
1677 if (nsEventStatus_eConsumeNoDefault == rv) {
1678 return aMouseEvent->PreventDefault(); // consume event
1679 }
1680 }
1682 return NS_OK;
1683 }
1685 nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
1686 bool aAllowPropagate)
1687 {
1688 #if !defined(XP_MACOSX)
1689 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
1690 return aMouseEvent->PreventDefault(); // consume event
1691 // continue only for cases without child window
1692 #endif
1693 // don't send mouse events if we are hidden
1694 if (!mWidgetVisible)
1695 return NS_OK;
1697 WidgetMouseEvent* mouseEvent =
1698 aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
1699 if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) {
1700 nsEventStatus rv = ProcessEvent(*mouseEvent);
1701 if (nsEventStatus_eConsumeNoDefault == rv) {
1702 aMouseEvent->PreventDefault();
1703 if (!aAllowPropagate) {
1704 aMouseEvent->StopPropagation();
1705 }
1706 }
1707 if (mouseEvent->message == NS_MOUSE_BUTTON_UP) {
1708 mLastMouseDownButtonType = -1;
1709 }
1710 }
1711 return NS_OK;
1712 }
1714 nsresult
1715 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
1716 {
1717 NS_ASSERTION(mInstance, "Should have a valid plugin instance or not receive events.");
1719 nsAutoString eventType;
1720 aEvent->GetType(eventType);
1721 if (eventType.EqualsLiteral("focus")) {
1722 mContentFocused = true;
1723 return DispatchFocusToPlugin(aEvent);
1724 }
1725 if (eventType.EqualsLiteral("blur")) {
1726 mContentFocused = false;
1727 return DispatchFocusToPlugin(aEvent);
1728 }
1729 if (eventType.EqualsLiteral("mousedown")) {
1730 return ProcessMouseDown(aEvent);
1731 }
1732 if (eventType.EqualsLiteral("mouseup")) {
1733 // Don't send a mouse-up event to the plugin if its button type doesn't
1734 // match that of the preceding mouse-down event (if any). This kind of
1735 // mismatch can happen if the previous mouse-down event was sent to a DOM
1736 // element above the plugin, the mouse is still above the plugin, and the
1737 // mouse-down event caused the element to disappear. See bug 627649 and
1738 // bug 909678.
1739 WidgetMouseEvent* mouseEvent = aEvent->GetInternalNSEvent()->AsMouseEvent();
1740 if (mouseEvent &&
1741 static_cast<int>(mouseEvent->button) != mLastMouseDownButtonType) {
1742 aEvent->PreventDefault();
1743 return NS_OK;
1744 }
1745 return DispatchMouseToPlugin(aEvent);
1746 }
1747 if (eventType.EqualsLiteral("mousemove")) {
1748 return DispatchMouseToPlugin(aEvent, true);
1749 }
1750 if (eventType.EqualsLiteral("click") ||
1751 eventType.EqualsLiteral("dblclick") ||
1752 eventType.EqualsLiteral("mouseover") ||
1753 eventType.EqualsLiteral("mouseout")) {
1754 return DispatchMouseToPlugin(aEvent);
1755 }
1756 if (eventType.EqualsLiteral("keydown") ||
1757 eventType.EqualsLiteral("keyup")) {
1758 return DispatchKeyToPlugin(aEvent);
1759 }
1760 if (eventType.EqualsLiteral("keypress")) {
1761 return ProcessKeyPress(aEvent);
1762 }
1764 nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
1765 if (dragEvent && mInstance) {
1766 WidgetEvent* ievent = aEvent->GetInternalNSEvent();
1767 if ((ievent && ievent->mFlags.mIsTrusted) &&
1768 ievent->message != NS_DRAGDROP_ENTER && ievent->message != NS_DRAGDROP_OVER) {
1769 aEvent->PreventDefault();
1770 }
1772 // Let the plugin handle drag events.
1773 aEvent->StopPropagation();
1774 }
1775 return NS_OK;
1776 }
1778 #ifdef MOZ_X11
1779 static unsigned int XInputEventState(const WidgetInputEvent& anEvent)
1780 {
1781 unsigned int state = 0;
1782 if (anEvent.IsShift()) state |= ShiftMask;
1783 if (anEvent.IsControl()) state |= ControlMask;
1784 if (anEvent.IsAlt()) state |= Mod1Mask;
1785 if (anEvent.IsMeta()) state |= Mod4Mask;
1786 return state;
1787 }
1788 #endif
1790 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
1791 {
1792 nsEventStatus rv = nsEventStatus_eIgnore;
1794 if (!mInstance || !mObjectFrame) // if mInstance is null, we shouldn't be here
1795 return nsEventStatus_eIgnore;
1797 #ifdef XP_MACOSX
1798 if (!mWidget)
1799 return nsEventStatus_eIgnore;
1801 // we never care about synthesized mouse enter
1802 if (anEvent.message == NS_MOUSE_ENTER_SYNTH)
1803 return nsEventStatus_eIgnore;
1805 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
1806 if (!pluginWidget || NS_FAILED(pluginWidget->StartDrawPlugin()))
1807 return nsEventStatus_eIgnore;
1809 NPEventModel eventModel = GetEventModel();
1811 // If we have to synthesize an event we'll use one of these.
1812 NPCocoaEvent synthCocoaEvent;
1813 void* event = anEvent.pluginEvent;
1814 nsPoint pt =
1815 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
1816 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
1817 nsPresContext* presContext = mObjectFrame->PresContext();
1818 // Plugin event coordinates need to be translated from device pixels
1819 // into "display pixels" in HiDPI modes.
1820 double scaleFactor = 1.0;
1821 GetContentsScaleFactor(&scaleFactor);
1822 size_t intScaleFactor = ceil(scaleFactor);
1823 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
1824 presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
1826 if (!event) {
1827 InitializeNPCocoaEvent(&synthCocoaEvent);
1828 switch (anEvent.message) {
1829 case NS_MOUSE_MOVE:
1830 {
1831 // Ignore mouse-moved events that happen as part of a dragging
1832 // operation that started over another frame. See bug 525078.
1833 nsRefPtr<nsFrameSelection> frameselection = mObjectFrame->GetFrameSelection();
1834 if (!frameselection->GetMouseDownState() ||
1835 (nsIPresShell::GetCapturingContent() == mObjectFrame->GetContent())) {
1836 synthCocoaEvent.type = NPCocoaEventMouseMoved;
1837 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
1838 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
1839 event = &synthCocoaEvent;
1840 }
1841 }
1842 break;
1843 case NS_MOUSE_BUTTON_DOWN:
1844 synthCocoaEvent.type = NPCocoaEventMouseDown;
1845 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
1846 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
1847 event = &synthCocoaEvent;
1848 break;
1849 case NS_MOUSE_BUTTON_UP:
1850 // If we're in a dragging operation that started over another frame,
1851 // convert it into a mouse-entered event (in the Cocoa Event Model).
1852 // See bug 525078.
1853 if (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
1854 (nsIPresShell::GetCapturingContent() != mObjectFrame->GetContent())) {
1855 synthCocoaEvent.type = NPCocoaEventMouseEntered;
1856 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
1857 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
1858 event = &synthCocoaEvent;
1859 } else {
1860 synthCocoaEvent.type = NPCocoaEventMouseUp;
1861 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
1862 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
1863 event = &synthCocoaEvent;
1864 }
1865 break;
1866 default:
1867 break;
1868 }
1870 // If we still don't have an event, bail.
1871 if (!event) {
1872 pluginWidget->EndDrawPlugin();
1873 return nsEventStatus_eIgnore;
1874 }
1875 }
1877 int16_t response = kNPEventNotHandled;
1878 void* window = FixUpPluginWindow(ePluginPaintEnable);
1879 if (window || (eventModel == NPEventModelCocoa)) {
1880 mInstance->HandleEvent(event, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
1881 }
1883 if (eventModel == NPEventModelCocoa && response == kNPEventStartIME) {
1884 pluginWidget->StartComplexTextInputForCurrentEvent();
1885 }
1887 if ((response == kNPEventHandled || response == kNPEventStartIME) &&
1888 !(anEvent.message == NS_MOUSE_BUTTON_DOWN &&
1889 anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
1890 !mContentFocused)) {
1891 rv = nsEventStatus_eConsumeNoDefault;
1892 }
1894 pluginWidget->EndDrawPlugin();
1895 #endif
1897 #ifdef XP_WIN
1898 // this code supports windowless plugins
1899 NPEvent *pPluginEvent = (NPEvent*)anEvent.pluginEvent;
1900 // we can get synthetic events from the EventStateManager... these
1901 // have no pluginEvent
1902 NPEvent pluginEvent;
1903 if (anEvent.eventStructType == NS_MOUSE_EVENT) {
1904 if (!pPluginEvent) {
1905 // XXX Should extend this list to synthesize events for more event
1906 // types
1907 pluginEvent.event = 0;
1908 const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
1909 switch (anEvent.message) {
1910 case NS_MOUSE_MOVE:
1911 pluginEvent.event = WM_MOUSEMOVE;
1912 break;
1913 case NS_MOUSE_BUTTON_DOWN: {
1914 static const int downMsgs[] =
1915 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
1916 static const int dblClickMsgs[] =
1917 { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
1918 if (mouseEvent->clickCount == 2) {
1919 pluginEvent.event = dblClickMsgs[mouseEvent->button];
1920 } else {
1921 pluginEvent.event = downMsgs[mouseEvent->button];
1922 }
1923 break;
1924 }
1925 case NS_MOUSE_BUTTON_UP: {
1926 static const int upMsgs[] =
1927 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
1928 pluginEvent.event = upMsgs[mouseEvent->button];
1929 break;
1930 }
1931 // don't synthesize anything for NS_MOUSE_DOUBLECLICK, since that
1932 // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
1933 // messages are sent on mouse-down
1934 default:
1935 break;
1936 }
1937 if (pluginEvent.event) {
1938 pPluginEvent = &pluginEvent;
1939 pluginEvent.wParam =
1940 (::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) |
1941 (::GetKeyState(VK_SHIFT) ? MK_SHIFT : 0) |
1942 (::GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) |
1943 (::GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) |
1944 (::GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0) |
1945 (::GetKeyState(VK_XBUTTON1) ? MK_XBUTTON1 : 0) |
1946 (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0);
1947 }
1948 }
1949 if (pPluginEvent) {
1950 // Make event coordinates relative to our enclosing widget,
1951 // not the widget they were received on.
1952 // See use of NPEvent in widget/windows/nsWindow.cpp
1953 // for why this assert should be safe
1954 NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN ||
1955 anEvent.message == NS_MOUSE_BUTTON_UP ||
1956 anEvent.message == NS_MOUSE_DOUBLECLICK ||
1957 anEvent.message == NS_MOUSE_ENTER_SYNTH ||
1958 anEvent.message == NS_MOUSE_EXIT_SYNTH ||
1959 anEvent.message == NS_MOUSE_MOVE,
1960 "Incorrect event type for coordinate translation");
1961 nsPoint pt =
1962 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
1963 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
1964 nsPresContext* presContext = mObjectFrame->PresContext();
1965 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
1966 presContext->AppUnitsToDevPixels(pt.y));
1967 nsIntPoint widgetPtPx = ptPx + mObjectFrame->GetWindowOriginInPixels(true);
1968 pPluginEvent->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
1969 }
1970 }
1971 else if (!pPluginEvent) {
1972 switch (anEvent.message) {
1973 case NS_FOCUS_CONTENT:
1974 pluginEvent.event = WM_SETFOCUS;
1975 pluginEvent.wParam = 0;
1976 pluginEvent.lParam = 0;
1977 pPluginEvent = &pluginEvent;
1978 break;
1979 case NS_BLUR_CONTENT:
1980 pluginEvent.event = WM_KILLFOCUS;
1981 pluginEvent.wParam = 0;
1982 pluginEvent.lParam = 0;
1983 pPluginEvent = &pluginEvent;
1984 break;
1985 }
1986 }
1988 if (pPluginEvent && !pPluginEvent->event) {
1989 // Don't send null events to plugins.
1990 NS_WARNING("nsObjectFrame ProcessEvent: trying to send null event to plugin.");
1991 return rv;
1992 }
1994 if (pPluginEvent) {
1995 int16_t response = kNPEventNotHandled;
1996 mInstance->HandleEvent(pPluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
1997 if (response == kNPEventHandled)
1998 rv = nsEventStatus_eConsumeNoDefault;
1999 }
2000 #endif
2002 #ifdef MOZ_X11
2003 // this code supports windowless plugins
2004 nsIWidget* widget = anEvent.widget;
2005 XEvent pluginEvent = XEvent();
2006 pluginEvent.type = 0;
2008 switch(anEvent.eventStructType)
2009 {
2010 case NS_MOUSE_EVENT:
2011 {
2012 switch (anEvent.message)
2013 {
2014 case NS_MOUSE_CLICK:
2015 case NS_MOUSE_DOUBLECLICK:
2016 // Button up/down events sent instead.
2017 return rv;
2018 }
2020 // Get reference point relative to plugin origin.
2021 const nsPresContext* presContext = mObjectFrame->PresContext();
2022 nsPoint appPoint =
2023 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
2024 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
2025 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
2026 presContext->AppUnitsToDevPixels(appPoint.y));
2027 const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
2028 // Get reference point relative to screen:
2029 LayoutDeviceIntPoint rootPoint(-1, -1);
2030 if (widget)
2031 rootPoint = anEvent.refPoint +
2032 LayoutDeviceIntPoint::FromUntyped(widget->WidgetToScreenOffset());
2033 #ifdef MOZ_WIDGET_GTK
2034 Window root = GDK_ROOT_WINDOW();
2035 #elif defined(MOZ_WIDGET_QT)
2036 Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay()));
2037 #else
2038 Window root = None; // Could XQueryTree, but this is not important.
2039 #endif
2041 switch (anEvent.message)
2042 {
2043 case NS_MOUSE_ENTER_SYNTH:
2044 case NS_MOUSE_EXIT_SYNTH:
2045 {
2046 XCrossingEvent& event = pluginEvent.xcrossing;
2047 event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ?
2048 EnterNotify : LeaveNotify;
2049 event.root = root;
2050 event.time = anEvent.time;
2051 event.x = pluginPoint.x;
2052 event.y = pluginPoint.y;
2053 event.x_root = rootPoint.x;
2054 event.y_root = rootPoint.y;
2055 event.state = XInputEventState(mouseEvent);
2056 // information lost
2057 event.subwindow = None;
2058 event.mode = -1;
2059 event.detail = NotifyDetailNone;
2060 event.same_screen = True;
2061 event.focus = mContentFocused;
2062 }
2063 break;
2064 case NS_MOUSE_MOVE:
2065 {
2066 XMotionEvent& event = pluginEvent.xmotion;
2067 event.type = MotionNotify;
2068 event.root = root;
2069 event.time = anEvent.time;
2070 event.x = pluginPoint.x;
2071 event.y = pluginPoint.y;
2072 event.x_root = rootPoint.x;
2073 event.y_root = rootPoint.y;
2074 event.state = XInputEventState(mouseEvent);
2075 // information lost
2076 event.subwindow = None;
2077 event.is_hint = NotifyNormal;
2078 event.same_screen = True;
2079 }
2080 break;
2081 case NS_MOUSE_BUTTON_DOWN:
2082 case NS_MOUSE_BUTTON_UP:
2083 {
2084 XButtonEvent& event = pluginEvent.xbutton;
2085 event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ?
2086 ButtonPress : ButtonRelease;
2087 event.root = root;
2088 event.time = anEvent.time;
2089 event.x = pluginPoint.x;
2090 event.y = pluginPoint.y;
2091 event.x_root = rootPoint.x;
2092 event.y_root = rootPoint.y;
2093 event.state = XInputEventState(mouseEvent);
2094 switch (mouseEvent.button)
2095 {
2096 case WidgetMouseEvent::eMiddleButton:
2097 event.button = 2;
2098 break;
2099 case WidgetMouseEvent::eRightButton:
2100 event.button = 3;
2101 break;
2102 default: // WidgetMouseEvent::eLeftButton;
2103 event.button = 1;
2104 break;
2105 }
2106 // information lost:
2107 event.subwindow = None;
2108 event.same_screen = True;
2109 }
2110 break;
2111 }
2112 }
2113 break;
2115 //XXX case NS_MOUSE_SCROLL_EVENT: not received.
2117 case NS_KEY_EVENT:
2118 if (anEvent.pluginEvent)
2119 {
2120 XKeyEvent &event = pluginEvent.xkey;
2121 #ifdef MOZ_WIDGET_GTK
2122 event.root = GDK_ROOT_WINDOW();
2123 event.time = anEvent.time;
2124 const GdkEventKey* gdkEvent =
2125 static_cast<const GdkEventKey*>(anEvent.pluginEvent);
2126 event.keycode = gdkEvent->hardware_keycode;
2127 event.state = gdkEvent->state;
2128 switch (anEvent.message)
2129 {
2130 case NS_KEY_DOWN:
2131 // Handle NS_KEY_DOWN for modifier key presses
2132 // For non-modifiers we get NS_KEY_PRESS
2133 if (gdkEvent->is_modifier)
2134 event.type = XKeyPress;
2135 break;
2136 case NS_KEY_PRESS:
2137 event.type = XKeyPress;
2138 break;
2139 case NS_KEY_UP:
2140 event.type = KeyRelease;
2141 break;
2142 }
2143 #endif
2145 // Information that could be obtained from pluginEvent but we may not
2146 // want to promise to provide:
2147 event.subwindow = None;
2148 event.x = 0;
2149 event.y = 0;
2150 event.x_root = -1;
2151 event.y_root = -1;
2152 event.same_screen = False;
2153 }
2154 else
2155 {
2156 // If we need to send synthesized key events, then
2157 // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
2158 // gdk_keymap_get_entries_for_keyval will be useful, but the
2159 // mappings will not be unique.
2160 NS_WARNING("Synthesized key event not sent to plugin");
2161 }
2162 break;
2164 default:
2165 switch (anEvent.message)
2166 {
2167 case NS_FOCUS_CONTENT:
2168 case NS_BLUR_CONTENT:
2169 {
2170 XFocusChangeEvent &event = pluginEvent.xfocus;
2171 event.type =
2172 anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut;
2173 // information lost:
2174 event.mode = -1;
2175 event.detail = NotifyDetailNone;
2176 }
2177 break;
2178 }
2179 }
2181 if (!pluginEvent.type) {
2182 return rv;
2183 }
2185 // Fill in (useless) generic event information.
2186 XAnyEvent& event = pluginEvent.xany;
2187 event.display = widget ?
2188 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nullptr;
2189 event.window = None; // not a real window
2190 // information lost:
2191 event.serial = 0;
2192 event.send_event = False;
2194 int16_t response = kNPEventNotHandled;
2195 mInstance->HandleEvent(&pluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2196 if (response == kNPEventHandled)
2197 rv = nsEventStatus_eConsumeNoDefault;
2198 #endif
2200 #ifdef MOZ_WIDGET_ANDROID
2201 // this code supports windowless plugins
2202 {
2203 // The plugin needs focus to receive keyboard and touch events
2204 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2205 if (fm) {
2206 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
2207 fm->SetFocus(elem, 0);
2208 }
2209 }
2210 switch(anEvent.eventStructType)
2211 {
2212 case NS_MOUSE_EVENT:
2213 {
2214 switch (anEvent.message)
2215 {
2216 case NS_MOUSE_CLICK:
2217 case NS_MOUSE_DOUBLECLICK:
2218 // Button up/down events sent instead.
2219 return rv;
2220 }
2222 // Get reference point relative to plugin origin.
2223 const nsPresContext* presContext = mObjectFrame->PresContext();
2224 nsPoint appPoint =
2225 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
2226 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
2227 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
2228 presContext->AppUnitsToDevPixels(appPoint.y));
2230 switch (anEvent.message)
2231 {
2232 case NS_MOUSE_MOVE:
2233 {
2234 // are these going to be touch events?
2235 // pluginPoint.x;
2236 // pluginPoint.y;
2237 }
2238 break;
2239 case NS_MOUSE_BUTTON_DOWN:
2240 {
2241 ANPEvent event;
2242 event.inSize = sizeof(ANPEvent);
2243 event.eventType = kMouse_ANPEventType;
2244 event.data.mouse.action = kDown_ANPMouseAction;
2245 event.data.mouse.x = pluginPoint.x;
2246 event.data.mouse.y = pluginPoint.y;
2247 mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2248 }
2249 break;
2250 case NS_MOUSE_BUTTON_UP:
2251 {
2252 ANPEvent event;
2253 event.inSize = sizeof(ANPEvent);
2254 event.eventType = kMouse_ANPEventType;
2255 event.data.mouse.action = kUp_ANPMouseAction;
2256 event.data.mouse.x = pluginPoint.x;
2257 event.data.mouse.y = pluginPoint.y;
2258 mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2259 }
2260 break;
2261 }
2262 }
2263 break;
2265 case NS_KEY_EVENT:
2266 {
2267 const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent();
2268 LOG("Firing NS_KEY_EVENT %d %d\n", keyEvent.keyCode, keyEvent.charCode);
2269 // pluginEvent is initialized by nsWindow::InitKeyEvent().
2270 ANPEvent* pluginEvent = reinterpret_cast<ANPEvent*>(keyEvent.pluginEvent);
2271 if (pluginEvent) {
2272 MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent));
2273 MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType);
2274 mInstance->HandleEvent(pluginEvent, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2275 }
2276 }
2277 break;
2279 default:
2280 break;
2281 }
2282 rv = nsEventStatus_eConsumeNoDefault;
2283 #endif
2285 return rv;
2286 }
2288 nsresult
2289 nsPluginInstanceOwner::Destroy()
2290 {
2291 SetFrame(nullptr);
2293 #ifdef XP_MACOSX
2294 RemoveFromCARefreshTimer();
2295 if (mColorProfile)
2296 ::CGColorSpaceRelease(mColorProfile);
2297 #endif
2299 // unregister context menu listener
2300 if (mCXMenuListener) {
2301 mCXMenuListener->Destroy(mContent);
2302 mCXMenuListener = nullptr;
2303 }
2305 mContent->RemoveEventListener(NS_LITERAL_STRING("focus"), this, false);
2306 mContent->RemoveEventListener(NS_LITERAL_STRING("blur"), this, false);
2307 mContent->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false);
2308 mContent->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false);
2309 mContent->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false);
2310 mContent->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
2311 mContent->RemoveEventListener(NS_LITERAL_STRING("dblclick"), this, false);
2312 mContent->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, false);
2313 mContent->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false);
2314 mContent->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
2315 mContent->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
2316 mContent->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
2317 mContent->RemoveEventListener(NS_LITERAL_STRING("drop"), this, true);
2318 mContent->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), this, true);
2319 mContent->RemoveEventListener(NS_LITERAL_STRING("drag"), this, true);
2320 mContent->RemoveEventListener(NS_LITERAL_STRING("dragenter"), this, true);
2321 mContent->RemoveEventListener(NS_LITERAL_STRING("dragover"), this, true);
2322 mContent->RemoveEventListener(NS_LITERAL_STRING("dragleave"), this, true);
2323 mContent->RemoveEventListener(NS_LITERAL_STRING("dragexit"), this, true);
2324 mContent->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, true);
2325 mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, true);
2326 mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true);
2328 #if MOZ_WIDGET_ANDROID
2329 RemovePluginView();
2330 #endif
2332 if (mWidget) {
2333 if (mPluginWindow) {
2334 mPluginWindow->SetPluginWidget(nullptr);
2335 }
2337 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2338 if (pluginWidget) {
2339 pluginWidget->SetPluginInstanceOwner(nullptr);
2340 }
2341 mWidget->Destroy();
2342 }
2344 return NS_OK;
2345 }
2347 // Paints are handled differently, so we just simulate an update event.
2349 #ifdef XP_MACOSX
2350 void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
2351 {
2352 if (!mInstance || !mObjectFrame)
2353 return;
2355 gfxRect dirtyRectCopy = aDirtyRect;
2356 double scaleFactor = 1.0;
2357 GetContentsScaleFactor(&scaleFactor);
2358 if (scaleFactor != 1.0) {
2359 ::CGContextScaleCTM(cgContext, scaleFactor, scaleFactor);
2360 // Convert aDirtyRect from device pixels to "display pixels"
2361 // for HiDPI modes
2362 dirtyRectCopy.ScaleRoundOut(1.0 / scaleFactor);
2363 }
2365 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2366 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
2367 DoCocoaEventDrawRect(dirtyRectCopy, cgContext);
2368 pluginWidget->EndDrawPlugin();
2369 }
2370 }
2372 void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext)
2373 {
2374 if (!mInstance || !mObjectFrame)
2375 return;
2377 // The context given here is only valid during the HandleEvent call.
2378 NPCocoaEvent updateEvent;
2379 InitializeNPCocoaEvent(&updateEvent);
2380 updateEvent.type = NPCocoaEventDrawRect;
2381 updateEvent.data.draw.context = cgContext;
2382 updateEvent.data.draw.x = aDrawRect.X();
2383 updateEvent.data.draw.y = aDrawRect.Y();
2384 updateEvent.data.draw.width = aDrawRect.Width();
2385 updateEvent.data.draw.height = aDrawRect.Height();
2387 mInstance->HandleEvent(&updateEvent, nullptr);
2388 }
2389 #endif
2391 #ifdef XP_WIN
2392 void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
2393 {
2394 if (!mInstance || !mObjectFrame)
2395 return;
2397 NPEvent pluginEvent;
2398 pluginEvent.event = WM_PAINT;
2399 pluginEvent.wParam = WPARAM(aDC);
2400 pluginEvent.lParam = LPARAM(&aDirty);
2401 mInstance->HandleEvent(&pluginEvent, nullptr);
2402 }
2403 #endif
2405 #ifdef MOZ_WIDGET_ANDROID
2407 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
2408 const gfxRect& aFrameRect,
2409 const gfxRect& aDirtyRect)
2410 {
2411 if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState || mFullScreen)
2412 return;
2414 int32_t model = mInstance->GetANPDrawingModel();
2416 if (model == kSurface_ANPDrawingModel) {
2417 if (!AddPluginView(GetPluginRect())) {
2418 Invalidate();
2419 }
2420 return;
2421 }
2423 if (model != kBitmap_ANPDrawingModel)
2424 return;
2426 #ifdef ANP_BITMAP_DRAWING_MODEL
2427 static nsRefPtr<gfxImageSurface> pluginSurface;
2429 if (pluginSurface == nullptr ||
2430 aFrameRect.width != pluginSurface->Width() ||
2431 aFrameRect.height != pluginSurface->Height()) {
2433 pluginSurface = new gfxImageSurface(gfxIntSize(aFrameRect.width, aFrameRect.height),
2434 gfxImageFormat::ARGB32);
2435 if (!pluginSurface)
2436 return;
2437 }
2439 // Clears buffer. I think this is needed.
2440 nsRefPtr<gfxContext> ctx = new gfxContext(pluginSurface);
2441 ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
2442 ctx->Paint();
2444 ANPEvent event;
2445 event.inSize = sizeof(ANPEvent);
2446 event.eventType = 4;
2447 event.data.draw.model = 1;
2449 event.data.draw.clip.top = 0;
2450 event.data.draw.clip.left = 0;
2451 event.data.draw.clip.bottom = aFrameRect.width;
2452 event.data.draw.clip.right = aFrameRect.height;
2454 event.data.draw.data.bitmap.format = kRGBA_8888_ANPBitmapFormat;
2455 event.data.draw.data.bitmap.width = aFrameRect.width;
2456 event.data.draw.data.bitmap.height = aFrameRect.height;
2457 event.data.draw.data.bitmap.baseAddr = pluginSurface->Data();
2458 event.data.draw.data.bitmap.rowBytes = aFrameRect.width * 4;
2460 if (!mInstance)
2461 return;
2463 mInstance->HandleEvent(&event, nullptr);
2465 aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
2466 aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
2467 aContext->Clip(aFrameRect);
2468 aContext->Paint();
2469 #endif
2470 }
2471 #endif
2473 #if defined(MOZ_X11)
2474 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
2475 const gfxRect& aFrameRect,
2476 const gfxRect& aDirtyRect)
2477 {
2478 if (!mInstance || !mObjectFrame)
2479 return;
2481 // to provide crisper and faster drawing.
2482 gfxRect pluginRect = aFrameRect;
2483 if (aContext->UserToDevicePixelSnapped(pluginRect)) {
2484 pluginRect = aContext->DeviceToUser(pluginRect);
2485 }
2487 // Round out the dirty rect to plugin pixels to ensure the plugin draws
2488 // enough pixels for interpolation to device pixels.
2489 gfxRect dirtyRect = aDirtyRect - pluginRect.TopLeft();
2490 dirtyRect.RoundOut();
2492 // Plugins can only draw an integer number of pixels.
2493 //
2494 // With translation-only transformation matrices, pluginRect is already
2495 // pixel-aligned.
2496 //
2497 // With more complex transformations, modifying the scales in the
2498 // transformation matrix could retain subpixel accuracy and let the plugin
2499 // draw a suitable number of pixels for interpolation to device pixels in
2500 // Renderer::Draw, but such cases are not common enough to warrant the
2501 // effort now.
2502 nsIntSize pluginSize(NS_lround(pluginRect.width),
2503 NS_lround(pluginRect.height));
2505 // Determine what the plugin needs to draw.
2506 nsIntRect pluginDirtyRect(int32_t(dirtyRect.x),
2507 int32_t(dirtyRect.y),
2508 int32_t(dirtyRect.width),
2509 int32_t(dirtyRect.height));
2510 if (!pluginDirtyRect.
2511 IntersectRect(nsIntRect(0, 0, pluginSize.width, pluginSize.height),
2512 pluginDirtyRect))
2513 return;
2515 NPWindow* window;
2516 GetWindow(window);
2518 uint32_t rendererFlags = 0;
2519 if (!mFlash10Quirks) {
2520 rendererFlags |=
2521 Renderer::DRAW_SUPPORTS_CLIP_RECT |
2522 Renderer::DRAW_SUPPORTS_ALTERNATE_VISUAL;
2523 }
2525 bool transparent;
2526 mInstance->IsTransparent(&transparent);
2527 if (!transparent)
2528 rendererFlags |= Renderer::DRAW_IS_OPAQUE;
2530 // Renderer::Draw() draws a rectangle with top-left at the aContext origin.
2531 gfxContextAutoSaveRestore autoSR(aContext);
2532 aContext->Translate(pluginRect.TopLeft());
2534 Renderer renderer(window, this, pluginSize, pluginDirtyRect);
2536 Display* dpy = mozilla::DefaultXDisplay();
2537 Screen* screen = DefaultScreenOfDisplay(dpy);
2538 Visual* visual = DefaultVisualOfScreen(screen);
2540 renderer.Draw(aContext, nsIntSize(window->width, window->height),
2541 rendererFlags, screen, visual);
2542 }
2543 nsresult
2544 nsPluginInstanceOwner::Renderer::DrawWithXlib(cairo_surface_t* xsurface,
2545 nsIntPoint offset,
2546 nsIntRect *clipRects,
2547 uint32_t numClipRects)
2548 {
2549 Screen *screen = cairo_xlib_surface_get_screen(xsurface);
2550 Colormap colormap;
2551 Visual* visual;
2552 if (!gfxXlibSurface::GetColormapAndVisual(xsurface, &colormap, &visual)) {
2553 NS_ERROR("Failed to get visual and colormap");
2554 return NS_ERROR_UNEXPECTED;
2555 }
2557 nsNPAPIPluginInstance *instance = mInstanceOwner->mInstance;
2558 if (!instance)
2559 return NS_ERROR_FAILURE;
2561 // See if the plugin must be notified of new window parameters.
2562 bool doupdatewindow = false;
2564 if (mWindow->x != offset.x || mWindow->y != offset.y) {
2565 mWindow->x = offset.x;
2566 mWindow->y = offset.y;
2567 doupdatewindow = true;
2568 }
2570 if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) {
2571 mWindow->width = mPluginSize.width;
2572 mWindow->height = mPluginSize.height;
2573 doupdatewindow = true;
2574 }
2576 // The clip rect is relative to drawable top-left.
2577 NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!");
2578 nsIntRect clipRect;
2579 if (numClipRects) {
2580 clipRect.x = clipRects[0].x;
2581 clipRect.y = clipRects[0].y;
2582 clipRect.width = clipRects[0].width;
2583 clipRect.height = clipRects[0].height;
2584 // NPRect members are unsigned, but clip rectangles should be contained by
2585 // the surface.
2586 NS_ASSERTION(clipRect.x >= 0 && clipRect.y >= 0,
2587 "Clip rectangle offsets are negative!");
2588 }
2589 else {
2590 clipRect.x = offset.x;
2591 clipRect.y = offset.y;
2592 clipRect.width = mWindow->width;
2593 clipRect.height = mWindow->height;
2594 // Don't ask the plugin to draw outside the drawable.
2595 // This also ensures that the unsigned clip rectangle offsets won't be -ve.
2596 clipRect.IntersectRect(clipRect,
2597 nsIntRect(0, 0,
2598 cairo_xlib_surface_get_width(xsurface),
2599 cairo_xlib_surface_get_height(xsurface)));
2600 }
2602 NPRect newClipRect;
2603 newClipRect.left = clipRect.x;
2604 newClipRect.top = clipRect.y;
2605 newClipRect.right = clipRect.XMost();
2606 newClipRect.bottom = clipRect.YMost();
2607 if (mWindow->clipRect.left != newClipRect.left ||
2608 mWindow->clipRect.top != newClipRect.top ||
2609 mWindow->clipRect.right != newClipRect.right ||
2610 mWindow->clipRect.bottom != newClipRect.bottom) {
2611 mWindow->clipRect = newClipRect;
2612 doupdatewindow = true;
2613 }
2615 NPSetWindowCallbackStruct* ws_info =
2616 static_cast<NPSetWindowCallbackStruct*>(mWindow->ws_info);
2617 #ifdef MOZ_X11
2618 if (ws_info->visual != visual || ws_info->colormap != colormap) {
2619 ws_info->visual = visual;
2620 ws_info->colormap = colormap;
2621 ws_info->depth = gfxXlibSurface::DepthOfVisual(screen, visual);
2622 doupdatewindow = true;
2623 }
2624 #endif
2626 {
2627 if (doupdatewindow)
2628 instance->SetWindow(mWindow);
2629 }
2631 // Translate the dirty rect to drawable coordinates.
2632 nsIntRect dirtyRect = mDirtyRect + offset;
2633 if (mInstanceOwner->mFlash10Quirks) {
2634 // Work around a bug in Flash up to 10.1 d51 at least, where expose event
2635 // top left coordinates within the plugin-rect and not at the drawable
2636 // origin are misinterpreted. (We can move the top left coordinate
2637 // provided it is within the clipRect.)
2638 dirtyRect.SetRect(offset.x, offset.y,
2639 mDirtyRect.XMost(), mDirtyRect.YMost());
2640 }
2641 // Intersect the dirty rect with the clip rect to ensure that it lies within
2642 // the drawable.
2643 if (!dirtyRect.IntersectRect(dirtyRect, clipRect))
2644 return NS_OK;
2646 {
2647 XEvent pluginEvent = XEvent();
2648 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
2649 // set the drawing info
2650 exposeEvent.type = GraphicsExpose;
2651 exposeEvent.display = DisplayOfScreen(screen);
2652 exposeEvent.drawable = cairo_xlib_surface_get_drawable(xsurface);
2653 exposeEvent.x = dirtyRect.x;
2654 exposeEvent.y = dirtyRect.y;
2655 exposeEvent.width = dirtyRect.width;
2656 exposeEvent.height = dirtyRect.height;
2657 exposeEvent.count = 0;
2658 // information not set:
2659 exposeEvent.serial = 0;
2660 exposeEvent.send_event = False;
2661 exposeEvent.major_code = 0;
2662 exposeEvent.minor_code = 0;
2664 instance->HandleEvent(&pluginEvent, nullptr);
2665 }
2666 return NS_OK;
2667 }
2668 #endif
2670 nsresult nsPluginInstanceOwner::Init(nsIContent* aContent)
2671 {
2672 mLastEventloopNestingLevel = GetEventloopNestingLevel();
2674 mContent = aContent;
2676 // Get a frame, don't reflow. If a reflow was necessary it should have been
2677 // done at a higher level than this (content).
2678 nsIFrame* frame = aContent->GetPrimaryFrame();
2679 nsIObjectFrame* iObjFrame = do_QueryFrame(frame);
2680 nsObjectFrame* objFrame = static_cast<nsObjectFrame*>(iObjFrame);
2681 if (objFrame) {
2682 SetFrame(objFrame);
2683 // Some plugins require a specific sequence of shutdown and startup when
2684 // a page is reloaded. Shutdown happens usually when the last instance
2685 // is destroyed. Here we make sure the plugin instance in the old
2686 // document is destroyed before we try to create the new one.
2687 objFrame->PresContext()->EnsureVisible();
2688 } else {
2689 NS_NOTREACHED("Should not be initializing plugin without a frame");
2690 return NS_ERROR_FAILURE;
2691 }
2693 // register context menu listener
2694 mCXMenuListener = new nsPluginDOMContextMenuListener(aContent);
2696 mContent->AddEventListener(NS_LITERAL_STRING("focus"), this, false,
2697 false);
2698 mContent->AddEventListener(NS_LITERAL_STRING("blur"), this, false,
2699 false);
2700 mContent->AddEventListener(NS_LITERAL_STRING("mouseup"), this, false,
2701 false);
2702 mContent->AddEventListener(NS_LITERAL_STRING("mousedown"), this, false,
2703 false);
2704 mContent->AddEventListener(NS_LITERAL_STRING("mousemove"), this, false,
2705 false);
2706 mContent->AddEventListener(NS_LITERAL_STRING("click"), this, false,
2707 false);
2708 mContent->AddEventListener(NS_LITERAL_STRING("dblclick"), this, false,
2709 false);
2710 mContent->AddEventListener(NS_LITERAL_STRING("mouseover"), this, false,
2711 false);
2712 mContent->AddEventListener(NS_LITERAL_STRING("mouseout"), this, false,
2713 false);
2714 mContent->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
2715 mContent->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
2716 mContent->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
2717 mContent->AddEventListener(NS_LITERAL_STRING("drop"), this, true);
2718 mContent->AddEventListener(NS_LITERAL_STRING("dragdrop"), this, true);
2719 mContent->AddEventListener(NS_LITERAL_STRING("drag"), this, true);
2720 mContent->AddEventListener(NS_LITERAL_STRING("dragenter"), this, true);
2721 mContent->AddEventListener(NS_LITERAL_STRING("dragover"), this, true);
2722 mContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, true);
2723 mContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, true);
2724 mContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, true);
2725 mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, true);
2726 mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, true);
2728 return NS_OK;
2729 }
2731 void* nsPluginInstanceOwner::GetPluginPortFromWidget()
2732 {
2733 //!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
2735 void* result = nullptr;
2736 if (mWidget) {
2737 #ifdef XP_WIN
2738 if (mPluginWindow && (mPluginWindow->type == NPWindowTypeDrawable))
2739 result = mWidget->GetNativeData(NS_NATIVE_GRAPHIC);
2740 else
2741 #endif
2742 #ifdef XP_MACOSX
2743 if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
2744 GetDrawingModel() == NPDrawingModelCoreAnimation ||
2745 GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
2746 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT_CG);
2747 else
2748 #endif
2749 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
2750 }
2751 return result;
2752 }
2754 void nsPluginInstanceOwner::ReleasePluginPort(void * pluginPort)
2755 {
2756 #ifdef XP_WIN
2757 if (mWidget && mPluginWindow &&
2758 mPluginWindow->type == NPWindowTypeDrawable) {
2759 mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC);
2760 }
2761 #endif
2762 }
2764 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
2765 {
2766 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
2768 nsresult rv = NS_ERROR_FAILURE;
2770 // Can't call this twice!
2771 if (mWidget) {
2772 NS_WARNING("Trying to create a plugin widget twice!");
2773 return NS_ERROR_FAILURE;
2774 }
2776 bool windowless = false;
2777 mInstance->IsWindowless(&windowless);
2778 if (!windowless && !nsIWidget::UsePuppetWidgets()) {
2779 // Try to get a parent widget, on some platforms widget creation will fail without
2780 // a parent.
2781 nsCOMPtr<nsIWidget> parentWidget;
2782 nsIDocument *doc = nullptr;
2783 if (mContent) {
2784 doc = mContent->OwnerDoc();
2785 parentWidget = nsContentUtils::WidgetForDocument(doc);
2786 }
2788 mWidget = do_CreateInstance(kWidgetCID, &rv);
2789 if (NS_FAILED(rv)) {
2790 return rv;
2791 }
2793 nsWidgetInitData initData;
2794 initData.mWindowType = eWindowType_plugin;
2795 initData.mUnicode = false;
2796 initData.clipChildren = true;
2797 initData.clipSiblings = true;
2798 rv = mWidget->Create(parentWidget.get(), nullptr, nsIntRect(0,0,0,0),
2799 nullptr, &initData);
2800 if (NS_FAILED(rv)) {
2801 mWidget->Destroy();
2802 mWidget = nullptr;
2803 return rv;
2804 }
2806 mWidget->EnableDragDrop(true);
2807 mWidget->Show(false);
2808 mWidget->Enable(false);
2810 #ifdef XP_MACOSX
2811 // Now that we have a widget we want to set the event model before
2812 // any events are processed.
2813 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2814 if (!pluginWidget) {
2815 return NS_ERROR_FAILURE;
2816 }
2817 pluginWidget->SetPluginEventModel(GetEventModel());
2818 pluginWidget->SetPluginDrawingModel(GetDrawingModel());
2820 if (GetDrawingModel() == NPDrawingModelCoreAnimation) {
2821 AddToCARefreshTimer();
2822 }
2823 #endif
2824 }
2826 if (mObjectFrame) {
2827 // nullptr widget is fine, will result in windowless setup.
2828 mObjectFrame->PrepForDrawing(mWidget);
2829 }
2831 if (windowless) {
2832 mPluginWindow->type = NPWindowTypeDrawable;
2834 // this needs to be a HDC according to the spec, but I do
2835 // not see the right way to release it so let's postpone
2836 // passing HDC till paint event when it is really
2837 // needed. Change spec?
2838 mPluginWindow->window = nullptr;
2839 #ifdef MOZ_X11
2840 // Fill in the display field.
2841 NPSetWindowCallbackStruct* ws_info =
2842 static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
2843 ws_info->display = DefaultXDisplay();
2845 nsAutoCString description;
2846 GetPluginDescription(description);
2847 NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
2848 mFlash10Quirks = StringBeginsWith(description, flash10Head);
2849 #endif
2850 } else if (mWidget) {
2851 // mPluginWindow->type is used in |GetPluginPort| so it must
2852 // be initialized first
2853 mPluginWindow->type = NPWindowTypeWindow;
2854 mPluginWindow->window = GetPluginPortFromWidget();
2855 // tell the plugin window about the widget
2856 mPluginWindow->SetPluginWidget(mWidget);
2858 // tell the widget about the current plugin instance owner.
2859 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2860 if (pluginWidget) {
2861 pluginWidget->SetPluginInstanceOwner(this);
2862 }
2863 }
2865 mWidgetCreationComplete = true;
2867 return NS_OK;
2868 }
2870 // Mac specific code to fix up the port location and clipping region
2871 #ifdef XP_MACOSX
2873 void* nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
2874 {
2875 if (!mWidget || !mPluginWindow || !mInstance || !mObjectFrame)
2876 return nullptr;
2878 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2879 if (!pluginWidget)
2880 return nullptr;
2882 // If we've already set up a CGContext in nsObjectFrame::PaintPlugin(), we
2883 // don't want calls to SetPluginPortAndDetectChange() to step on our work.
2884 if (mInCGPaintLevel < 1) {
2885 SetPluginPortAndDetectChange();
2886 }
2888 // We'll need the top-level Cocoa window for the Cocoa event model.
2889 nsIWidget* widget = mObjectFrame->GetNearestWidget();
2890 if (!widget)
2891 return nullptr;
2892 void *cocoaTopLevelWindow = widget->GetNativeData(NS_NATIVE_WINDOW);
2893 if (!cocoaTopLevelWindow)
2894 return nullptr;
2896 nsIntPoint pluginOrigin;
2897 nsIntRect widgetClip;
2898 bool widgetVisible;
2899 pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, widgetVisible);
2900 mWidgetVisible = widgetVisible;
2902 // printf("GetPluginClipRect returning visible %d\n", widgetVisible);
2904 // This would be a lot easier if we could use obj-c here,
2905 // but we can't. Since we have only nsIWidget and we can't
2906 // use its native widget (an obj-c object) we have to go
2907 // from the widget's screen coordinates to its window coords
2908 // instead of straight to window coords.
2909 nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset();
2911 nsRect windowRect;
2912 NS_NPAPI_CocoaWindowFrame(cocoaTopLevelWindow, windowRect);
2914 double scaleFactor = 1.0;
2915 GetContentsScaleFactor(&scaleFactor);
2916 int intScaleFactor = ceil(scaleFactor);
2918 // Convert geckoScreenCoords from device pixels to "display pixels"
2919 // for HiDPI modes.
2920 mPluginWindow->x = geckoScreenCoords.x/intScaleFactor - windowRect.x;
2921 mPluginWindow->y = geckoScreenCoords.y/intScaleFactor - windowRect.y;
2923 NPRect oldClipRect = mPluginWindow->clipRect;
2925 // fix up the clipping region
2926 mPluginWindow->clipRect.top = widgetClip.y;
2927 mPluginWindow->clipRect.left = widgetClip.x;
2929 if (!mWidgetVisible || inPaintState == ePluginPaintDisable) {
2930 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
2931 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
2932 }
2933 else if (inPaintState == ePluginPaintEnable)
2934 {
2935 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
2936 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width;
2937 }
2939 // if the clip rect changed, call SetWindow()
2940 // (RealPlayer needs this to draw correctly)
2941 if (mPluginWindow->clipRect.left != oldClipRect.left ||
2942 mPluginWindow->clipRect.top != oldClipRect.top ||
2943 mPluginWindow->clipRect.right != oldClipRect.right ||
2944 mPluginWindow->clipRect.bottom != oldClipRect.bottom ||
2945 mPluginPortChanged)
2946 {
2947 if (UseAsyncRendering()) {
2948 mInstance->AsyncSetWindow(mPluginWindow);
2949 }
2950 else {
2951 mPluginWindow->CallSetWindow(mInstance);
2952 }
2953 mPluginPortChanged = false;
2954 }
2956 // After the first NPP_SetWindow call we need to send an initial
2957 // top-level window focus event.
2958 if (!mSentInitialTopLevelWindowEvent) {
2959 // Set this before calling ProcessEvent to avoid endless recursion.
2960 mSentInitialTopLevelWindowEvent = true;
2962 WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, nullptr);
2963 NPCocoaEvent cocoaEvent;
2964 InitializeNPCocoaEvent(&cocoaEvent);
2965 cocoaEvent.type = NPCocoaEventWindowFocusChanged;
2966 cocoaEvent.data.focus.hasFocus = NS_NPAPI_CocoaWindowIsMain(cocoaTopLevelWindow);
2967 pluginEvent.pluginEvent = &cocoaEvent;
2968 ProcessEvent(pluginEvent);
2969 }
2971 return nullptr;
2972 }
2974 void
2975 nsPluginInstanceOwner::HidePluginWindow()
2976 {
2977 if (!mPluginWindow || !mInstance) {
2978 return;
2979 }
2981 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
2982 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
2983 mWidgetVisible = false;
2984 if (UseAsyncRendering()) {
2985 mInstance->AsyncSetWindow(mPluginWindow);
2986 } else {
2987 mInstance->SetWindow(mPluginWindow);
2988 }
2989 }
2991 #else // XP_MACOSX
2993 void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
2994 {
2995 if (!mPluginWindow)
2996 return;
2998 // For windowless plugins a non-empty clip rectangle will be
2999 // passed to the plugin during paint, an additional update
3000 // of the the clip rectangle here is not required
3001 if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering())
3002 return;
3004 const NPWindow oldWindow = *mPluginWindow;
3006 bool windowless = (mPluginWindow->type == NPWindowTypeDrawable);
3007 nsIntPoint origin = mObjectFrame->GetWindowOriginInPixels(windowless);
3009 mPluginWindow->x = origin.x;
3010 mPluginWindow->y = origin.y;
3012 mPluginWindow->clipRect.left = 0;
3013 mPluginWindow->clipRect.top = 0;
3015 if (mPluginWindowVisible && mPluginDocumentActiveState) {
3016 mPluginWindow->clipRect.right = mPluginWindow->width;
3017 mPluginWindow->clipRect.bottom = mPluginWindow->height;
3018 } else {
3019 mPluginWindow->clipRect.right = 0;
3020 mPluginWindow->clipRect.bottom = 0;
3021 }
3023 if (!aSetWindow)
3024 return;
3026 if (mPluginWindow->x != oldWindow.x ||
3027 mPluginWindow->y != oldWindow.y ||
3028 mPluginWindow->clipRect.left != oldWindow.clipRect.left ||
3029 mPluginWindow->clipRect.top != oldWindow.clipRect.top ||
3030 mPluginWindow->clipRect.right != oldWindow.clipRect.right ||
3031 mPluginWindow->clipRect.bottom != oldWindow.clipRect.bottom) {
3032 CallSetWindow();
3033 }
3034 }
3036 void
3037 nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible)
3038 {
3039 mPluginWindowVisible = aVisible;
3040 UpdateWindowPositionAndClipRect(true);
3041 }
3043 void
3044 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
3045 {
3046 mPluginDocumentActiveState = aIsActive;
3047 UpdateWindowPositionAndClipRect(true);
3049 #ifdef MOZ_WIDGET_ANDROID
3050 if (mInstance) {
3051 if (!mPluginDocumentActiveState)
3052 RemovePluginView();
3054 mInstance->NotifyOnScreen(mPluginDocumentActiveState);
3056 // This is, perhaps, incorrect. It is supposed to be sent
3057 // when "the webview has paused or resumed". The side effect
3058 // is that Flash video players pause or resume (if they were
3059 // playing before) based on the value here. I personally think
3060 // we want that on Android when switching to another tab, so
3061 // that's why we call it here.
3062 mInstance->NotifyForeground(mPluginDocumentActiveState);
3063 }
3064 #endif
3065 }
3066 #endif // XP_MACOSX
3068 NS_IMETHODIMP
3069 nsPluginInstanceOwner::CallSetWindow()
3070 {
3071 if (mObjectFrame) {
3072 mObjectFrame->CallSetWindow(false);
3073 } else if (mInstance) {
3074 if (UseAsyncRendering()) {
3075 mInstance->AsyncSetWindow(mPluginWindow);
3076 } else {
3077 mInstance->SetWindow(mPluginWindow);
3078 }
3079 }
3081 return NS_OK;
3082 }
3084 NS_IMETHODIMP
3085 nsPluginInstanceOwner::GetContentsScaleFactor(double *result)
3086 {
3087 NS_ENSURE_ARG_POINTER(result);
3088 double scaleFactor = 1.0;
3089 // On Mac, device pixels need to be translated to (and from) "display pixels"
3090 // for plugins. On other platforms, plugin coordinates are always in device
3091 // pixels.
3092 #if defined(XP_MACOSX)
3093 nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(mContent->OwnerDoc());
3094 if (presShell) {
3095 scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
3096 presShell->GetPresContext()->DeviceContext()->UnscaledAppUnitsPerDevPixel();
3097 }
3098 #endif
3099 *result = scaleFactor;
3100 return NS_OK;
3101 }
3103 void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
3104 {
3105 // Don't do anything if the frame situation hasn't changed.
3106 if (mObjectFrame == aFrame) {
3107 return;
3108 }
3110 // If we already have a frame that is changing or going away...
3111 if (mObjectFrame) {
3112 // Make sure the old frame isn't holding a reference to us.
3113 mObjectFrame->SetInstanceOwner(nullptr);
3114 }
3116 // Swap in the new frame (or no frame)
3117 mObjectFrame = aFrame;
3119 // Set up a new frame
3120 if (mObjectFrame) {
3121 mObjectFrame->SetInstanceOwner(this);
3122 // Can only call PrepForDrawing on an object frame once. Don't do it here unless
3123 // widget creation is complete. Doesn't matter if we actually have a widget.
3124 if (mWidgetCreationComplete) {
3125 mObjectFrame->PrepForDrawing(mWidget);
3126 }
3127 mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
3128 mObjectFrame->InvalidateFrame();
3130 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3131 const nsIContent* content = aFrame->GetContent();
3132 if (fm && content) {
3133 mContentFocused = (content == fm->GetFocusedContent());
3134 }
3135 }
3136 }
3138 nsObjectFrame* nsPluginInstanceOwner::GetFrame()
3139 {
3140 return mObjectFrame;
3141 }
3143 // Little helper function to resolve relative URL in
3144 // |value| for certain inputs of |name|
3145 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
3146 {
3147 if (name.LowerCaseEqualsLiteral("pluginspage")) {
3148 nsCOMPtr<nsIURI> baseURI = GetBaseURI();
3149 nsAutoString newURL;
3150 NS_MakeAbsoluteURI(newURL, value, baseURI);
3151 if (!newURL.IsEmpty())
3152 value = newURL;
3153 }
3154 }
3156 NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled)
3157 {
3158 return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK;
3159 }
3161 already_AddRefed<nsIURI> nsPluginInstanceOwner::GetBaseURI() const
3162 {
3163 if (!mContent) {
3164 return nullptr;
3165 }
3166 return mContent->GetBaseURI();
3167 }
3169 // nsPluginDOMContextMenuListener class implementation
3171 nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener(nsIContent* aContent)
3172 {
3173 aContent->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
3174 }
3176 nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
3177 {
3178 }
3180 NS_IMPL_ISUPPORTS(nsPluginDOMContextMenuListener,
3181 nsIDOMEventListener)
3183 NS_IMETHODIMP
3184 nsPluginDOMContextMenuListener::HandleEvent(nsIDOMEvent* aEvent)
3185 {
3186 aEvent->PreventDefault(); // consume event
3188 return NS_OK;
3189 }
3191 void nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
3192 {
3193 // Unregister context menu listener
3194 aContent->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
3195 }