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