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