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