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 /* rendering objects for replaced elements implemented by a plugin */
8
9 #include "nsPluginFrame.h"
10
11 #include "gfx2DGlue.h"
12 #include "gfxMatrix.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/BasicEvents.h"
15 #include "mozilla/MouseEvents.h"
16 #ifdef XP_WIN
17 // This is needed for DoublePassRenderingEvent.
18 #include "mozilla/plugins/PluginMessageUtils.h"
19 #endif
20
21 #include "nscore.h"
22 #include "nsCOMPtr.h"
23 #include "nsPresContext.h"
24 #include "nsIPresShell.h"
25 #include "nsWidgetsCID.h"
26 #include "nsView.h"
27 #include "nsViewManager.h"
28 #include "nsString.h"
29 #include "nsGkAtoms.h"
30 #include "nsIPluginInstanceOwner.h"
31 #include "nsNPAPIPluginInstance.h"
32 #include "nsIDOMElement.h"
33 #include "nsRenderingContext.h"
34 #include "npapi.h"
35 #include "nsIObjectLoadingContent.h"
36 #include "nsContentUtils.h"
37 #include "nsDisplayList.h"
38 #include "nsFocusManager.h"
39 #include "nsLayoutUtils.h"
40 #include "nsFrameManager.h"
41 #include "nsIObserverService.h"
42 #include "GeckoProfiler.h"
43 #include <algorithm>
44
45 #include "nsIObjectFrame.h"
46 #include "nsPluginNativeWindow.h"
47 #include "FrameLayerBuilder.h"
48
49 #include "ImageLayers.h"
50 #include "nsPluginInstanceOwner.h"
51
52 #ifdef XP_WIN
53 #include "gfxWindowsNativeDrawing.h"
54 #include "gfxWindowsSurface.h"
55 #endif
56
57 #include "DisplayItemScrollClip.h"
58 #include "Layers.h"
59 #include "ReadbackLayer.h"
60 #include "ImageContainer.h"
61
62 // accessibility support
63 #ifdef ACCESSIBILITY
64 #include "nsAccessibilityService.h"
65 #endif
66
67 #ifdef MOZ_LOGGING
68 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
69 #endif /* MOZ_LOGGING */
70 #include "mozilla/Logging.h"
71
72 #ifdef XP_MACOSX
73 #include "gfxQuartzNativeDrawing.h"
74 #include "mozilla/gfx/QuartzSupport.h"
75 #endif
76
77 #ifdef MOZ_X11
78 #include "mozilla/X11Util.h"
79 using mozilla::DefaultXDisplay;
80 #endif
81
82 #ifdef XP_WIN
83 #include <wtypes.h>
84 #include <winuser.h>
85 #endif
86
87 #ifdef MOZ_WIDGET_ANDROID
88 #include "AndroidBridge.h"
89 #include "GLContext.h"
90 #endif
91
92 #include "mozilla/dom/TabChild.h"
93 #include "ClientLayerManager.h"
94
95 #ifdef CreateEvent // Thank you MS.
96 #undef CreateEvent
97 #endif
98
99 static mozilla::LazyLogModule sPluginFrameLog("nsPluginFrame");
100
101 using namespace mozilla;
102 using namespace mozilla::gfx;
103 using namespace mozilla::layers;
104
105 class PluginBackgroundSink : public ReadbackSink {
106 public:
PluginBackgroundSink(nsPluginFrame * aFrame,uint64_t aStartSequenceNumber)107 PluginBackgroundSink(nsPluginFrame* aFrame, uint64_t aStartSequenceNumber)
108 : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
~PluginBackgroundSink()109 ~PluginBackgroundSink() override
110 {
111 if (mFrame) {
112 mFrame->mBackgroundSink = nullptr;
113 }
114 }
115
SetUnknown(uint64_t aSequenceNumber)116 void SetUnknown(uint64_t aSequenceNumber) override
117 {
118 if (!AcceptUpdate(aSequenceNumber))
119 return;
120 mFrame->mInstanceOwner->SetBackgroundUnknown();
121 }
122
123 already_AddRefed<DrawTarget>
BeginUpdate(const nsIntRect & aRect,uint64_t aSequenceNumber)124 BeginUpdate(const nsIntRect& aRect, uint64_t aSequenceNumber) override
125 {
126 if (!AcceptUpdate(aSequenceNumber))
127 return nullptr;
128 return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
129 }
130
EndUpdate(const nsIntRect & aRect)131 void EndUpdate(const nsIntRect& aRect) override
132 {
133 return mFrame->mInstanceOwner->EndUpdateBackground(aRect);
134 }
135
Destroy()136 void Destroy() { mFrame = nullptr; }
137
138 protected:
AcceptUpdate(uint64_t aSequenceNumber)139 bool AcceptUpdate(uint64_t aSequenceNumber) {
140 if (aSequenceNumber > mLastSequenceNumber && mFrame &&
141 mFrame->mInstanceOwner) {
142 mLastSequenceNumber = aSequenceNumber;
143 return true;
144 }
145 return false;
146 }
147
148 uint64_t mLastSequenceNumber;
149 nsPluginFrame* mFrame;
150 };
151
nsPluginFrame(nsStyleContext * aContext)152 nsPluginFrame::nsPluginFrame(nsStyleContext* aContext)
153 : nsFrame(aContext)
154 , mInstanceOwner(nullptr)
155 , mReflowCallbackPosted(false)
156 {
157 MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
158 ("Created new nsPluginFrame %p\n", this));
159 }
160
~nsPluginFrame()161 nsPluginFrame::~nsPluginFrame()
162 {
163 MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
164 ("nsPluginFrame %p deleted\n", this));
165 }
166
167 NS_QUERYFRAME_HEAD(nsPluginFrame)
NS_QUERYFRAME_ENTRY(nsPluginFrame)168 NS_QUERYFRAME_ENTRY(nsPluginFrame)
169 NS_QUERYFRAME_ENTRY(nsIObjectFrame)
170 NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
171
172 #ifdef ACCESSIBILITY
173 a11y::AccType
174 nsPluginFrame::AccessibleType()
175 {
176 return a11y::ePluginType;
177 }
178
179 #ifdef XP_WIN
GetPluginPort(HWND * aPort)180 NS_IMETHODIMP nsPluginFrame::GetPluginPort(HWND *aPort)
181 {
182 *aPort = (HWND) mInstanceOwner->GetPluginPort();
183 return NS_OK;
184 }
185 #endif
186 #endif
187
188 void
Init(nsIContent * aContent,nsContainerFrame * aParent,nsIFrame * aPrevInFlow)189 nsPluginFrame::Init(nsIContent* aContent,
190 nsContainerFrame* aParent,
191 nsIFrame* aPrevInFlow)
192 {
193 MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
194 ("Initializing nsPluginFrame %p for content %p\n", this, aContent));
195
196 nsFrame::Init(aContent, aParent, aPrevInFlow);
197 }
198
199 void
DestroyFrom(nsIFrame * aDestructRoot)200 nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot)
201 {
202 if (mReflowCallbackPosted) {
203 PresContext()->PresShell()->CancelReflowCallback(this);
204 }
205
206 // Ensure our DidComposite observer is gone.
207 mDidCompositeObserver = nullptr;
208
209 // Tell content owner of the instance to disconnect its frame.
210 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
211 NS_ASSERTION(objContent, "Why not an object loading content?");
212
213 // The content might not have a reference to the instance owner any longer in
214 // the case of re-entry during instantiation or teardown, so make sure we're
215 // dissociated.
216 if (mInstanceOwner) {
217 mInstanceOwner->SetFrame(nullptr);
218 }
219 objContent->HasNewFrame(nullptr);
220
221 if (mBackgroundSink) {
222 mBackgroundSink->Destroy();
223 }
224
225 nsFrame::DestroyFrom(aDestructRoot);
226 }
227
228 /* virtual */ void
DidSetStyleContext(nsStyleContext * aOldStyleContext)229 nsPluginFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
230 {
231 if (HasView()) {
232 nsView* view = GetView();
233 nsViewManager* vm = view->GetViewManager();
234 if (vm) {
235 nsViewVisibility visibility =
236 IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
237 vm->SetViewVisibility(view, visibility);
238 }
239 }
240
241 nsFrame::DidSetStyleContext(aOldStyleContext);
242 }
243
244 nsIAtom*
GetType() const245 nsPluginFrame::GetType() const
246 {
247 return nsGkAtoms::objectFrame;
248 }
249
250 #ifdef DEBUG_FRAME_DUMP
251 nsresult
GetFrameName(nsAString & aResult) const252 nsPluginFrame::GetFrameName(nsAString& aResult) const
253 {
254 return MakeFrameName(NS_LITERAL_STRING("PluginFrame"), aResult);
255 }
256 #endif
257
258 nsresult
PrepForDrawing(nsIWidget * aWidget)259 nsPluginFrame::PrepForDrawing(nsIWidget *aWidget)
260 {
261 mWidget = aWidget;
262
263 nsView* view = GetView();
264 NS_ASSERTION(view, "Object frames must have views");
265 if (!view) {
266 return NS_ERROR_FAILURE;
267 }
268
269 nsViewManager* viewMan = view->GetViewManager();
270 // mark the view as hidden since we don't know the (x,y) until Paint
271 // XXX is the above comment correct?
272 viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
273
274 //this is ugly. it was ripped off from didreflow(). MMP
275 // Position and size view relative to its parent, not relative to our
276 // parent frame (our parent frame may not have a view).
277
278 nsView* parentWithView;
279 nsPoint origin;
280 nsRect r(0, 0, mRect.width, mRect.height);
281
282 GetOffsetFromView(origin, &parentWithView);
283 viewMan->ResizeView(view, r);
284 viewMan->MoveViewTo(view, origin.x, origin.y);
285
286 nsPresContext* presContext = PresContext();
287 nsRootPresContext* rpc = presContext->GetRootPresContext();
288 if (!rpc) {
289 return NS_ERROR_FAILURE;
290 }
291
292 if (mWidget) {
293 // Disallow windowed plugins in popups
294 nsIFrame* rootFrame = rpc->PresShell()->FrameManager()->GetRootFrame();
295 nsIWidget* parentWidget = rootFrame->GetNearestWidget();
296 if (!parentWidget || nsLayoutUtils::GetDisplayRootFrame(this) != rootFrame) {
297 return NS_ERROR_FAILURE;
298 }
299
300 mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
301 if (!mInnerView) {
302 NS_ERROR("Could not create inner view");
303 return NS_ERROR_OUT_OF_MEMORY;
304 }
305 viewMan->InsertChild(view, mInnerView, nullptr, true);
306
307 mWidget->SetParent(parentWidget);
308 mWidget->Enable(true);
309 mWidget->Show(true);
310
311 // Set the plugin window to have an empty clip region until we know
312 // what our true position, size and clip region are. These
313 // will be reset when nsRootPresContext computes our true
314 // geometry. The plugin window does need to have a good size here, so
315 // set the size explicitly to a reasonable guess.
316 AutoTArray<nsIWidget::Configuration,1> configurations;
317 nsIWidget::Configuration* configuration = configurations.AppendElement();
318 nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
319 configuration->mChild = mWidget;
320 configuration->mBounds.width = NSAppUnitsToIntPixels(mRect.width, appUnitsPerDevPixel);
321 configuration->mBounds.height = NSAppUnitsToIntPixels(mRect.height, appUnitsPerDevPixel);
322 parentWidget->ConfigureChildren(configurations);
323
324 mInnerView->AttachWidgetEventHandler(mWidget);
325
326 #ifdef XP_MACOSX
327 // On Mac, we need to invalidate ourselves since even windowed
328 // plugins are painted through Thebes and we need to ensure
329 // the PaintedLayer containing the plugin is updated.
330 if (parentWidget == GetNearestWidget()) {
331 InvalidateFrame();
332 }
333 #endif
334
335 RegisterPluginForGeometryUpdates();
336
337 // Here we set the background color for this widget because some plugins will use
338 // the child window background color when painting. If it's not set, it may default to gray
339 // Sometimes, a frame doesn't have a background color or is transparent. In this
340 // case, walk up the frame tree until we do find a frame with a background color
341 for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
342 nscolor bgcolor =
343 frame->GetVisitedDependentColor(eCSSProperty_background_color);
344 if (NS_GET_A(bgcolor) > 0) { // make sure we got an actual color
345 mWidget->SetBackgroundColor(bgcolor);
346 break;
347 }
348 }
349 } else {
350 // Changing to windowless mode changes the NPWindow geometry.
351 FixupWindow(GetContentRectRelativeToSelf().Size());
352 RegisterPluginForGeometryUpdates();
353 }
354
355 if (!IsHidden()) {
356 viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
357 }
358
359 #ifdef ACCESSIBILITY
360 nsAccessibilityService* accService = nsIPresShell::AccService();
361 if (accService) {
362 accService->RecreateAccessible(PresContext()->PresShell(), mContent);
363 }
364 #endif
365
366 return NS_OK;
367 }
368
369 #define EMBED_DEF_WIDTH 240
370 #define EMBED_DEF_HEIGHT 200
371
372 /* virtual */ nscoord
GetMinISize(nsRenderingContext * aRenderingContext)373 nsPluginFrame::GetMinISize(nsRenderingContext *aRenderingContext)
374 {
375 nscoord result = 0;
376
377 if (!IsHidden(false)) {
378 if (mContent->IsAnyOfHTMLElements(nsGkAtoms::applet,
379 nsGkAtoms::embed)) {
380 bool vertical = GetWritingMode().IsVertical();
381 result = nsPresContext::CSSPixelsToAppUnits(
382 vertical ? EMBED_DEF_HEIGHT : EMBED_DEF_WIDTH);
383 }
384 }
385
386 DISPLAY_MIN_WIDTH(this, result);
387 return result;
388 }
389
390 /* virtual */ nscoord
GetPrefISize(nsRenderingContext * aRenderingContext)391 nsPluginFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
392 {
393 return nsPluginFrame::GetMinISize(aRenderingContext);
394 }
395
396 void
GetWidgetConfiguration(nsTArray<nsIWidget::Configuration> * aConfigurations)397 nsPluginFrame::GetWidgetConfiguration(nsTArray<nsIWidget::Configuration>* aConfigurations)
398 {
399 if (!mWidget) {
400 return;
401 }
402
403 if (!mWidget->GetParent()) {
404 // Plugin widgets should not be toplevel except when they're out of the
405 // document, in which case the plugin should not be registered for
406 // geometry updates and this should not be called. But apparently we
407 // have bugs where mWidget sometimes is toplevel here. Bail out.
408 NS_ERROR("Plugin widgets registered for geometry updates should not be toplevel");
409 return;
410 }
411
412 nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
413 configuration->mChild = mWidget;
414 configuration->mBounds = mNextConfigurationBounds;
415 configuration->mClipRegion = mNextConfigurationClipRegion;
416 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
417 if (XRE_IsContentProcess()) {
418 configuration->mWindowID = (uintptr_t)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
419 configuration->mVisible = mWidget->IsVisible();
420
421 }
422 #endif // defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
423 }
424
425 void
GetDesiredSize(nsPresContext * aPresContext,const ReflowInput & aReflowInput,ReflowOutput & aMetrics)426 nsPluginFrame::GetDesiredSize(nsPresContext* aPresContext,
427 const ReflowInput& aReflowInput,
428 ReflowOutput& aMetrics)
429 {
430 // By default, we have no area
431 aMetrics.ClearSize();
432
433 if (IsHidden(false)) {
434 return;
435 }
436
437 aMetrics.Width() = aReflowInput.ComputedWidth();
438 aMetrics.Height() = aReflowInput.ComputedHeight();
439
440 // for EMBED and APPLET, default to 240x200 for compatibility
441 if (mContent->IsAnyOfHTMLElements(nsGkAtoms::applet,
442 nsGkAtoms::embed)) {
443 if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) {
444 aMetrics.Width() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
445 aReflowInput.ComputedMinWidth(),
446 aReflowInput.ComputedMaxWidth());
447 }
448 if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) {
449 aMetrics.Height() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
450 aReflowInput.ComputedMinHeight(),
451 aReflowInput.ComputedMaxHeight());
452 }
453
454 #if defined(MOZ_WIDGET_GTK)
455 // We need to make sure that the size of the object frame does not
456 // exceed the maximum size of X coordinates. See bug #225357 for
457 // more information. In theory Gtk2 can handle large coordinates,
458 // but underlying plugins can't.
459 aMetrics.Height() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Height());
460 aMetrics.Width() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Width());
461 #endif
462 }
463
464 // At this point, the width has an unconstrained value only if we have
465 // nothing to go on (no width set, no information from the plugin, nothing).
466 // Make up a number.
467 if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) {
468 aMetrics.Width() =
469 (aReflowInput.ComputedMinWidth() != NS_UNCONSTRAINEDSIZE) ?
470 aReflowInput.ComputedMinWidth() : 0;
471 }
472
473 // At this point, the height has an unconstrained value only in two cases:
474 // a) We are in standards mode with percent heights and parent is auto-height
475 // b) We have no height information at all.
476 // In either case, we have to make up a number.
477 if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) {
478 aMetrics.Height() =
479 (aReflowInput.ComputedMinHeight() != NS_UNCONSTRAINEDSIZE) ?
480 aReflowInput.ComputedMinHeight() : 0;
481 }
482
483 // XXXbz don't add in the border and padding, because we screw up our
484 // plugin's size and positioning if we do... Eventually we _do_ want to
485 // paint borders, though! At that point, we will need to adjust the desired
486 // size either here or in Reflow.... Further, we will need to fix Paint() to
487 // call the superclass in all cases.
488 }
489
490 void
Reflow(nsPresContext * aPresContext,ReflowOutput & aMetrics,const ReflowInput & aReflowInput,nsReflowStatus & aStatus)491 nsPluginFrame::Reflow(nsPresContext* aPresContext,
492 ReflowOutput& aMetrics,
493 const ReflowInput& aReflowInput,
494 nsReflowStatus& aStatus)
495 {
496 MarkInReflow();
497 DO_GLOBAL_REFLOW_COUNT("nsPluginFrame");
498 DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
499
500 // Get our desired size
501 GetDesiredSize(aPresContext, aReflowInput, aMetrics);
502 aMetrics.SetOverflowAreasToDesiredBounds();
503 FinishAndStoreOverflow(&aMetrics);
504
505 // delay plugin instantiation until all children have
506 // arrived. Otherwise there may be PARAMs or other stuff that the
507 // plugin needs to see that haven't arrived yet.
508 if (!GetContent()->IsDoneAddingChildren()) {
509 aStatus = NS_FRAME_COMPLETE;
510 return;
511 }
512
513 // if we are printing or print previewing, bail for now
514 if (aPresContext->Medium() == nsGkAtoms::print) {
515 aStatus = NS_FRAME_COMPLETE;
516 return;
517 }
518
519 nsRect r(0, 0, aMetrics.Width(), aMetrics.Height());
520 r.Deflate(aReflowInput.ComputedPhysicalBorderPadding());
521
522 if (mInnerView) {
523 nsViewManager* vm = mInnerView->GetViewManager();
524 vm->MoveViewTo(mInnerView, r.x, r.y);
525 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), true);
526 }
527
528 FixupWindow(r.Size());
529 if (!mReflowCallbackPosted) {
530 mReflowCallbackPosted = true;
531 aPresContext->PresShell()->PostReflowCallback(this);
532 }
533
534 aStatus = NS_FRAME_COMPLETE;
535
536 NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
537 }
538
539 ///////////// nsIReflowCallback ///////////////
540
541 bool
ReflowFinished()542 nsPluginFrame::ReflowFinished()
543 {
544 mReflowCallbackPosted = false;
545 CallSetWindow();
546 return true;
547 }
548
549 void
ReflowCallbackCanceled()550 nsPluginFrame::ReflowCallbackCanceled()
551 {
552 mReflowCallbackPosted = false;
553 }
554
555 void
FixupWindow(const nsSize & aSize)556 nsPluginFrame::FixupWindow(const nsSize& aSize)
557 {
558 nsPresContext* presContext = PresContext();
559
560 if (!mInstanceOwner)
561 return;
562
563 NPWindow *window;
564 mInstanceOwner->GetWindow(window);
565
566 NS_ENSURE_TRUE_VOID(window);
567
568 bool windowless = (window->type == NPWindowTypeDrawable);
569
570 nsIntPoint origin = GetWindowOriginInPixels(windowless);
571
572 // window must be in "display pixels"
573 #if defined(XP_MACOSX)
574 // window must be in "display pixels"
575 double scaleFactor = 1.0;
576 if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
577 scaleFactor = 1.0;
578 }
579 int intScaleFactor = ceil(scaleFactor);
580 window->x = origin.x / intScaleFactor;
581 window->y = origin.y / intScaleFactor;
582 window->width = presContext->AppUnitsToDevPixels(aSize.width) / intScaleFactor;
583 window->height = presContext->AppUnitsToDevPixels(aSize.height) / intScaleFactor;
584 #else
585 window->x = origin.x;
586 window->y = origin.y;
587 window->width = presContext->AppUnitsToDevPixels(aSize.width);
588 window->height = presContext->AppUnitsToDevPixels(aSize.height);
589 #endif
590
591 #ifndef XP_MACOSX
592 mInstanceOwner->UpdateWindowPositionAndClipRect(false);
593 #endif
594
595 NotifyPluginReflowObservers();
596 }
597
598 nsresult
CallSetWindow(bool aCheckIsHidden)599 nsPluginFrame::CallSetWindow(bool aCheckIsHidden)
600 {
601 NPWindow *win = nullptr;
602
603 nsresult rv = NS_ERROR_FAILURE;
604 RefPtr<nsNPAPIPluginInstance> pi;
605 if (!mInstanceOwner ||
606 NS_FAILED(rv = mInstanceOwner->GetInstance(getter_AddRefs(pi))) ||
607 !pi ||
608 NS_FAILED(rv = mInstanceOwner->GetWindow(win)) ||
609 !win)
610 return rv;
611
612 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
613
614 if (aCheckIsHidden && IsHidden())
615 return NS_ERROR_FAILURE;
616
617 // Calling either nsPluginInstanceOwner::FixUpPluginWindow() (here,
618 // on OS X) or SetWindow() (below, on all platforms) can destroy this
619 // frame. (FixUpPluginWindow() calls SetWindow()). So grab a safe
620 // reference to mInstanceOwner which we can use below, if needed.
621 RefPtr<nsPluginInstanceOwner> instanceOwnerRef(mInstanceOwner);
622
623 // refresh the plugin port as well
624 #ifdef XP_MACOSX
625 mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable);
626 // Bail now if our frame has been destroyed.
627 if (!instanceOwnerRef->GetFrame()) {
628 return NS_ERROR_FAILURE;
629 }
630 #endif
631 window->window = mInstanceOwner->GetPluginPort();
632
633 // Adjust plugin dimensions according to pixel snap results
634 // and reduce amount of SetWindow calls
635 nsPresContext* presContext = PresContext();
636 nsRootPresContext* rootPC = presContext->GetRootPresContext();
637 if (!rootPC)
638 return NS_ERROR_FAILURE;
639 int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
640 nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
641 nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
642 nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
643
644 // In e10s, this returns the offset to the top level window, in non-e10s
645 // it return 0,0.
646 LayoutDeviceIntPoint intOffset = GetRemoteTabChromeOffset();
647 intBounds.x += intOffset.x;
648 intBounds.y += intOffset.y;
649
650 #if defined(XP_MACOSX)
651 // window must be in "display pixels"
652 double scaleFactor = 1.0;
653 if (NS_FAILED(instanceOwnerRef->GetContentsScaleFactor(&scaleFactor))) {
654 scaleFactor = 1.0;
655 }
656
657 size_t intScaleFactor = ceil(scaleFactor);
658 window->x = intBounds.x / intScaleFactor;
659 window->y = intBounds.y / intScaleFactor;
660 window->width = intBounds.width / intScaleFactor;
661 window->height = intBounds.height / intScaleFactor;
662 #else
663 window->x = intBounds.x;
664 window->y = intBounds.y;
665 window->width = intBounds.width;
666 window->height = intBounds.height;
667 #endif
668 // BE CAREFUL: By the time we get here the PluginFrame is sometimes destroyed
669 // and poisoned. If we reference local fields (implicit this deref),
670 // we will crash.
671 instanceOwnerRef->ResolutionMayHaveChanged();
672
673 // This will call pi->SetWindow and take care of window subclassing
674 // if needed, see bug 132759. Calling SetWindow can destroy this frame
675 // so check for that before doing anything else with this frame's memory.
676 if (instanceOwnerRef->UseAsyncRendering()) {
677 rv = pi->AsyncSetWindow(window);
678 }
679 else {
680 rv = window->CallSetWindow(pi);
681 }
682
683 instanceOwnerRef->ReleasePluginPort(window->window);
684
685 return rv;
686 }
687
688 void
RegisterPluginForGeometryUpdates()689 nsPluginFrame::RegisterPluginForGeometryUpdates()
690 {
691 nsRootPresContext* rpc = PresContext()->GetRootPresContext();
692 NS_ASSERTION(rpc, "We should have a root pres context!");
693 if (mRootPresContextRegisteredWith == rpc || !rpc) {
694 // Already registered with current root pres context,
695 // or null root pres context...
696 return;
697 }
698 if (mRootPresContextRegisteredWith && mRootPresContextRegisteredWith != rpc) {
699 // Registered to some other root pres context. Unregister, and
700 // re-register with our current one...
701 UnregisterPluginForGeometryUpdates();
702 }
703 mRootPresContextRegisteredWith = rpc;
704 mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent);
705 }
706
707 void
UnregisterPluginForGeometryUpdates()708 nsPluginFrame::UnregisterPluginForGeometryUpdates()
709 {
710 if (!mRootPresContextRegisteredWith) {
711 // Not registered...
712 return;
713 }
714 mRootPresContextRegisteredWith->UnregisterPluginForGeometryUpdates(mContent);
715 mRootPresContextRegisteredWith = nullptr;
716 }
717
718 void
SetInstanceOwner(nsPluginInstanceOwner * aOwner)719 nsPluginFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
720 {
721 // The ownership model here is historically fuzzy. This should only be called
722 // by nsPluginInstanceOwner when it is given a new frame, and
723 // nsObjectLoadingContent should be arbitrating frame-ownership via its
724 // HasNewFrame callback.
725 mInstanceOwner = aOwner;
726
727 // Reset the DidCompositeObserver since the owner changed.
728 mDidCompositeObserver = nullptr;
729
730 if (mInstanceOwner) {
731 return;
732 }
733
734 UnregisterPluginForGeometryUpdates();
735 if (mWidget && mInnerView) {
736 mInnerView->DetachWidgetEventHandler(mWidget);
737 // Make sure the plugin is hidden in case an update of plugin geometry
738 // hasn't happened since this plugin became hidden.
739 nsIWidget* parent = mWidget->GetParent();
740 if (parent) {
741 nsTArray<nsIWidget::Configuration> configurations;
742 nsIWidget::Configuration* configuration = configurations.AppendElement();
743 configuration->mChild = mWidget;
744 parent->ConfigureChildren(configurations);
745
746 mWidget->Show(false);
747 mWidget->Enable(false);
748 mWidget->SetParent(nullptr);
749 }
750 }
751 }
752
753 bool
IsFocusable(int32_t * aTabIndex,bool aWithMouse)754 nsPluginFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
755 {
756 if (aTabIndex)
757 *aTabIndex = -1;
758 return nsFrame::IsFocusable(aTabIndex, aWithMouse);
759 }
760
761 bool
IsHidden(bool aCheckVisibilityStyle) const762 nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const
763 {
764 if (aCheckVisibilityStyle) {
765 if (!StyleVisibility()->IsVisibleOrCollapsed())
766 return true;
767 }
768
769 // only <embed> tags support the HIDDEN attribute
770 if (mContent->IsHTMLElement(nsGkAtoms::embed)) {
771 // Yes, these are really the kooky ways that you could tell 4.x
772 // not to hide the <embed> once you'd put the 'hidden' attribute
773 // on the tag...
774
775 // HIDDEN w/ no attributes gets translated as we are hidden for
776 // compatibility w/ 4.x and IE so we don't create a non-painting
777 // widget in layout. See bug 188959.
778 nsAutoString hidden;
779 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) &&
780 (hidden.IsEmpty() ||
781 (!hidden.LowerCaseEqualsLiteral("false") &&
782 !hidden.LowerCaseEqualsLiteral("no") &&
783 !hidden.LowerCaseEqualsLiteral("off")))) {
784 return true;
785 }
786 }
787
788 return false;
789 }
790
791 mozilla::LayoutDeviceIntPoint
GetRemoteTabChromeOffset()792 nsPluginFrame::GetRemoteTabChromeOffset()
793 {
794 LayoutDeviceIntPoint offset;
795 if (XRE_IsContentProcess()) {
796 if (nsPIDOMWindowOuter* window = GetContent()->OwnerDoc()->GetWindow()) {
797 if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetTop()) {
798 dom::TabChild* tc = dom::TabChild::GetFrom(topWindow);
799 if (tc) {
800 offset += tc->GetChromeDisplacement();
801 }
802 }
803 }
804 }
805 return offset;
806 }
807
808 nsIntPoint
GetWindowOriginInPixels(bool aWindowless)809 nsPluginFrame::GetWindowOriginInPixels(bool aWindowless)
810 {
811 nsView * parentWithView;
812 nsPoint origin(0,0);
813
814 GetOffsetFromView(origin, &parentWithView);
815
816 // if it's windowless, let's make sure we have our origin set right
817 // it may need to be corrected, like after scrolling
818 if (aWindowless && parentWithView) {
819 nsPoint offsetToWidget;
820 parentWithView->GetNearestWidget(&offsetToWidget);
821 origin += offsetToWidget;
822 }
823 origin += GetContentRectRelativeToSelf().TopLeft();
824
825 nsIntPoint pt(PresContext()->AppUnitsToDevPixels(origin.x),
826 PresContext()->AppUnitsToDevPixels(origin.y));
827
828 // If we're in the content process offsetToWidget is tied to the top level
829 // widget we can access in the child process, which is the tab. We need the
830 // offset all the way up to the top level native window here. (If this is
831 // non-e10s this routine will return 0,0.)
832 if (aWindowless) {
833 mozilla::LayoutDeviceIntPoint lpt = GetRemoteTabChromeOffset();
834 pt += nsIntPoint(lpt.x, lpt.y);
835 }
836
837 return pt;
838 }
839
840 void
DidReflow(nsPresContext * aPresContext,const ReflowInput * aReflowInput,nsDidReflowStatus aStatus)841 nsPluginFrame::DidReflow(nsPresContext* aPresContext,
842 const ReflowInput* aReflowInput,
843 nsDidReflowStatus aStatus)
844 {
845 // Do this check before calling the superclass, as that clears
846 // NS_FRAME_FIRST_REFLOW
847 if (aStatus == nsDidReflowStatus::FINISHED &&
848 (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
849 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
850 NS_ASSERTION(objContent, "Why not an object loading content?");
851 objContent->HasNewFrame(this);
852 }
853
854 nsFrame::DidReflow(aPresContext, aReflowInput, aStatus);
855
856 // The view is created hidden; once we have reflowed it and it has been
857 // positioned then we show it.
858 if (aStatus != nsDidReflowStatus::FINISHED)
859 return;
860
861 if (HasView()) {
862 nsView* view = GetView();
863 nsViewManager* vm = view->GetViewManager();
864 if (vm)
865 vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
866 }
867 }
868
869 /* static */ void
PaintPrintPlugin(nsIFrame * aFrame,nsRenderingContext * aCtx,const nsRect & aDirtyRect,nsPoint aPt)870 nsPluginFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx,
871 const nsRect& aDirtyRect, nsPoint aPt)
872 {
873 gfxContext* ctx = aCtx->ThebesContext();
874
875 // Translate the context:
876 nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft();
877 gfxPoint devPixelPt =
878 nsLayoutUtils::PointToGfxPoint(pt, aFrame->PresContext()->AppUnitsPerDevPixel());
879
880 gfxContextMatrixAutoSaveRestore autoSR(ctx);
881 ctx->SetMatrix(ctx->CurrentMatrix().Translate(devPixelPt));
882
883 // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
884
885 static_cast<nsPluginFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
886 }
887
888 /**
889 * nsDisplayPluginReadback creates an active ReadbackLayer. The ReadbackLayer
890 * obtains from the compositor the contents of the window underneath
891 * the ReadbackLayer, which we then use as an opaque buffer for plugins to
892 * asynchronously draw onto.
893 */
894 class nsDisplayPluginReadback : public nsDisplayItem {
895 public:
nsDisplayPluginReadback(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)896 nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
897 : nsDisplayItem(aBuilder, aFrame)
898 {
899 MOZ_COUNT_CTOR(nsDisplayPluginReadback);
900 }
901 #ifdef NS_BUILD_REFCNT_LOGGING
~nsDisplayPluginReadback()902 ~nsDisplayPluginReadback() override {
903 MOZ_COUNT_DTOR(nsDisplayPluginReadback);
904 }
905 #endif
906
907 nsRect GetBounds(nsDisplayListBuilder* aBuilder,
908 bool* aSnap) override;
909
910 NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
911
BuildLayer(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aContainerParameters)912 already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
913 LayerManager* aManager,
914 const ContainerLayerParameters& aContainerParameters) override
915 {
916 return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
917 }
918
GetLayerState(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aParameters)919 LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
920 LayerManager* aManager,
921 const ContainerLayerParameters& aParameters) override
922 {
923 return LAYER_ACTIVE;
924 }
925 };
926
927 static nsRect
GetDisplayItemBounds(nsDisplayListBuilder * aBuilder,nsDisplayItem * aItem,nsIFrame * aFrame)928 GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
929 {
930 // XXX For slightly more accurate region computations we should pixel-snap this
931 return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
932 }
933
934 nsRect
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)935 nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
936 {
937 *aSnap = false;
938 return GetDisplayItemBounds(aBuilder, this, mFrame);
939 }
940
941 #ifdef MOZ_WIDGET_ANDROID
942
943 class nsDisplayPluginVideo : public nsDisplayItem {
944 public:
nsDisplayPluginVideo(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsNPAPIPluginInstance::VideoInfo * aVideoInfo)945 nsDisplayPluginVideo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
946 : nsDisplayItem(aBuilder, aFrame), mVideoInfo(aVideoInfo)
947 {
948 MOZ_COUNT_CTOR(nsDisplayPluginVideo);
949 }
950 #ifdef NS_BUILD_REFCNT_LOGGING
~nsDisplayPluginVideo()951 virtual ~nsDisplayPluginVideo() {
952 MOZ_COUNT_DTOR(nsDisplayPluginVideo);
953 }
954 #endif
955
956 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
957 bool* aSnap) override;
958
959 NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO)
960
BuildLayer(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aContainerParameters)961 virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
962 LayerManager* aManager,
963 const ContainerLayerParameters& aContainerParameters) override
964 {
965 return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
966 }
967
GetLayerState(nsDisplayListBuilder * aBuilder,LayerManager * aManager,const ContainerLayerParameters & aParameters)968 virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
969 LayerManager* aManager,
970 const ContainerLayerParameters& aParameters) override
971 {
972 return LAYER_ACTIVE;
973 }
974
VideoInfo()975 nsNPAPIPluginInstance::VideoInfo* VideoInfo() { return mVideoInfo; }
976
977 private:
978 nsNPAPIPluginInstance::VideoInfo* mVideoInfo;
979 };
980
981 nsRect
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)982 nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
983 {
984 *aSnap = false;
985 return GetDisplayItemBounds(aBuilder, this, mFrame);
986 }
987
988 #endif
989
990 nsRect
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)991 nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
992 {
993 *aSnap = true;
994 return GetDisplayItemBounds(aBuilder, this, mFrame);
995 }
996
997 void
Paint(nsDisplayListBuilder * aBuilder,nsRenderingContext * aCtx)998 nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
999 nsRenderingContext* aCtx)
1000 {
1001 nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
1002 bool snap;
1003 f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));
1004 }
1005
1006 static nsRect
GetClippedBoundsIncludingAllScrollClips(nsDisplayItem * aItem,nsDisplayListBuilder * aBuilder)1007 GetClippedBoundsIncludingAllScrollClips(nsDisplayItem* aItem,
1008 nsDisplayListBuilder* aBuilder)
1009 {
1010 nsRect r = aItem->GetClippedBounds(aBuilder);
1011 for (auto* sc = aItem->ScrollClip(); sc; sc = sc->mParent) {
1012 if (sc->mClip) {
1013 r = sc->mClip->ApplyNonRoundedIntersection(r);
1014 }
1015 }
1016 return r;
1017 }
1018
1019 bool
ComputeVisibility(nsDisplayListBuilder * aBuilder,nsRegion * aVisibleRegion)1020 nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1021 nsRegion* aVisibleRegion)
1022 {
1023 if (aBuilder->IsForPluginGeometry()) {
1024 nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
1025 if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) {
1026 // Since transforms induce reference frames, we don't need to worry
1027 // about this method fluffing out due to non-rectilinear transforms.
1028 nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f,
1029 f->GetContentRectRelativeToSelf(), ReferenceFrame());
1030 nscoord appUnitsPerDevPixel =
1031 ReferenceFrame()->PresContext()->AppUnitsPerDevPixel();
1032 f->mNextConfigurationBounds = LayoutDeviceIntRect::FromUnknownRect(
1033 rAncestor.ToNearestPixels(appUnitsPerDevPixel));
1034
1035 nsRegion visibleRegion;
1036 // Apply all scroll clips when computing the clipped bounds of this item.
1037 // We hide windowed plugins during APZ scrolling, so there never is an
1038 // async transform that we need to take into account when clipping.
1039 visibleRegion.And(*aVisibleRegion, GetClippedBoundsIncludingAllScrollClips(this, aBuilder));
1040 // Make visibleRegion relative to f
1041 visibleRegion.MoveBy(-ToReferenceFrame());
1042
1043 f->mNextConfigurationClipRegion.Clear();
1044 for (auto iter = visibleRegion.RectIter(); !iter.Done(); iter.Next()) {
1045 nsRect rAncestor =
1046 nsLayoutUtils::TransformFrameRectToAncestor(f, iter.Get(), ReferenceFrame());
1047 LayoutDeviceIntRect rPixels =
1048 LayoutDeviceIntRect::FromUnknownRect(rAncestor.ToNearestPixels(appUnitsPerDevPixel)) -
1049 f->mNextConfigurationBounds.TopLeft();
1050 if (!rPixels.IsEmpty()) {
1051 f->mNextConfigurationClipRegion.AppendElement(rPixels);
1052 }
1053 }
1054 }
1055
1056 if (f->mInnerView) {
1057 // This should produce basically the same rectangle (but not relative
1058 // to the root frame). We only call this here for the side-effect of
1059 // setting mViewToWidgetOffset on the view.
1060 f->mInnerView->CalcWidgetBounds(eWindowType_plugin);
1061 }
1062 }
1063
1064 return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion);
1065 }
1066
1067 nsRegion
GetOpaqueRegion(nsDisplayListBuilder * aBuilder,bool * aSnap)1068 nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1069 bool* aSnap)
1070 {
1071 *aSnap = false;
1072 nsRegion result;
1073 nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
1074 if (!aBuilder->IsForPluginGeometry()) {
1075 nsIWidget* widget = f->GetWidget();
1076 if (widget) {
1077 // Be conservative and treat plugins with widgets as not opaque,
1078 // because that's simple and we might need the content under the widget
1079 // if the widget is unexpectedly clipped away. (As can happen when
1080 // chrome content over a plugin forces us to clip out the plugin for
1081 // security reasons.)
1082 // We shouldn't be repainting the content under plugins much anyway
1083 // since there generally shouldn't be anything to invalidate or paint
1084 // in PaintedLayers there.
1085 return result;
1086 }
1087 }
1088
1089 if (f->IsOpaque()) {
1090 nsRect bounds = GetBounds(aBuilder, aSnap);
1091 if (aBuilder->IsForPluginGeometry() ||
1092 (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) {
1093 // We can treat this as opaque
1094 result = bounds;
1095 }
1096 }
1097
1098 return result;
1099 }
1100
1101 nsresult
Run()1102 nsPluginFrame::PluginEventNotifier::Run() {
1103 nsCOMPtr<nsIObserverService> obsSvc =
1104 mozilla::services::GetObserverService();
1105 obsSvc->NotifyObservers(nullptr, "plugin-changed-event", mEventType.get());
1106 return NS_OK;
1107 }
1108
1109 void
NotifyPluginReflowObservers()1110 nsPluginFrame::NotifyPluginReflowObservers()
1111 {
1112 nsContentUtils::AddScriptRunner(new PluginEventNotifier(NS_LITERAL_STRING("reflow")));
1113 }
1114
1115 void
DidSetWidgetGeometry()1116 nsPluginFrame::DidSetWidgetGeometry()
1117 {
1118 #if defined(XP_MACOSX)
1119 if (mInstanceOwner && !IsHidden()) {
1120 mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable);
1121 }
1122 #else
1123 if (!mWidget && mInstanceOwner) {
1124 // UpdateWindowVisibility will notify the plugin of position changes
1125 // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
1126 // We treat windowless plugins inside popups as always visible, since
1127 // plugins inside popups don't get valid mNextConfigurationBounds
1128 // set up.
1129 mInstanceOwner->UpdateWindowVisibility(
1130 nsLayoutUtils::IsPopup(nsLayoutUtils::GetDisplayRootFrame(this)) ||
1131 !mNextConfigurationBounds.IsEmpty());
1132 }
1133 #endif
1134 }
1135
1136 bool
IsOpaque() const1137 nsPluginFrame::IsOpaque() const
1138 {
1139 #if defined(XP_MACOSX)
1140 return false;
1141 #elif defined(MOZ_WIDGET_ANDROID)
1142 // We don't know, so just assume transparent
1143 return false;
1144 #else
1145
1146 if (mInstanceOwner && mInstanceOwner->UseAsyncRendering()) {
1147 return false;
1148 }
1149 return !IsTransparentMode();
1150 #endif
1151 }
1152
1153 bool
IsTransparentMode() const1154 nsPluginFrame::IsTransparentMode() const
1155 {
1156 #if defined(XP_MACOSX)
1157 return false;
1158 #else
1159 if (!mInstanceOwner)
1160 return false;
1161
1162 NPWindow *window = nullptr;
1163 mInstanceOwner->GetWindow(window);
1164 if (!window) {
1165 return false;
1166 }
1167
1168 if (window->type != NPWindowTypeDrawable)
1169 return false;
1170
1171 nsresult rv;
1172 RefPtr<nsNPAPIPluginInstance> pi;
1173 rv = mInstanceOwner->GetInstance(getter_AddRefs(pi));
1174 if (NS_FAILED(rv) || !pi)
1175 return false;
1176
1177 bool transparent = false;
1178 pi->IsTransparent(&transparent);
1179 return transparent;
1180 #endif
1181 }
1182
1183 void
BuildDisplayList(nsDisplayListBuilder * aBuilder,const nsRect & aDirtyRect,const nsDisplayListSet & aLists)1184 nsPluginFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
1185 const nsRect& aDirtyRect,
1186 const nsDisplayListSet& aLists)
1187 {
1188 // XXX why are we painting collapsed object frames?
1189 if (!IsVisibleOrCollapsedForPainting(aBuilder))
1190 return;
1191
1192 DisplayBorderBackgroundOutline(aBuilder, aLists);
1193
1194 nsPresContext::nsPresContextType type = PresContext()->Type();
1195
1196 // If we are painting in Print Preview do nothing....
1197 if (type == nsPresContext::eContext_PrintPreview)
1198 return;
1199
1200 DO_GLOBAL_REFLOW_COUNT_DSP("nsPluginFrame");
1201
1202 #ifndef XP_MACOSX
1203 if (mWidget && aBuilder->IsInTransform()) {
1204 // Windowed plugins should not be rendered inside a transform.
1205 return;
1206 }
1207 #endif
1208
1209 if (aBuilder->IsForPainting() && mInstanceOwner) {
1210 // Update plugin frame for both content scaling and full zoom changes.
1211 mInstanceOwner->ResolutionMayHaveChanged();
1212 #ifdef XP_MACOSX
1213 mInstanceOwner->WindowFocusMayHaveChanged();
1214 #endif
1215 if (mInstanceOwner->UseAsyncRendering()) {
1216 NPWindow* window = nullptr;
1217 mInstanceOwner->GetWindow(window);
1218 bool isVisible = window && window->width > 0 && window->height > 0;
1219 if (isVisible && aBuilder->ShouldSyncDecodeImages()) {
1220 #ifndef XP_MACOSX
1221 mInstanceOwner->UpdateWindowVisibility(true);
1222 #endif
1223 }
1224
1225 mInstanceOwner->NotifyPaintWaiter(aBuilder);
1226 }
1227 }
1228
1229 DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
1230 clip(aBuilder, this);
1231
1232 // determine if we are printing
1233 if (type == nsPresContext::eContext_Print) {
1234 aLists.Content()->AppendNewToTop(new (aBuilder)
1235 nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
1236 nsDisplayItem::TYPE_PRINT_PLUGIN));
1237 } else {
1238 LayerState state = GetLayerState(aBuilder, nullptr);
1239 if (state == LAYER_INACTIVE &&
1240 nsDisplayItem::ForceActiveLayers()) {
1241 state = LAYER_ACTIVE;
1242 }
1243 // We don't need this on Android, and it just confuses things
1244 #if !MOZ_WIDGET_ANDROID
1245 if (aBuilder->IsPaintingToWindow() &&
1246 state == LAYER_ACTIVE &&
1247 IsTransparentMode()) {
1248 aLists.Content()->AppendNewToTop(new (aBuilder)
1249 nsDisplayPluginReadback(aBuilder, this));
1250 }
1251 #endif
1252
1253 #if MOZ_WIDGET_ANDROID
1254 if (aBuilder->IsPaintingToWindow() &&
1255 state == LAYER_ACTIVE) {
1256
1257 nsTArray<nsNPAPIPluginInstance::VideoInfo*> videos;
1258 mInstanceOwner->GetVideos(videos);
1259
1260 for (uint32_t i = 0; i < videos.Length(); i++) {
1261 aLists.Content()->AppendNewToTop(new (aBuilder)
1262 nsDisplayPluginVideo(aBuilder, this, videos[i]));
1263 }
1264 }
1265 #endif
1266
1267 aLists.Content()->AppendNewToTop(new (aBuilder)
1268 nsDisplayPlugin(aBuilder, this));
1269 }
1270 }
1271
1272 void
PrintPlugin(nsRenderingContext & aRenderingContext,const nsRect & aDirtyRect)1273 nsPluginFrame::PrintPlugin(nsRenderingContext& aRenderingContext,
1274 const nsRect& aDirtyRect)
1275 {
1276 nsCOMPtr<nsIObjectLoadingContent> obj(do_QueryInterface(mContent));
1277 if (!obj)
1278 return;
1279
1280 nsIFrame* frame = nullptr;
1281 obj->GetPrintFrame(&frame);
1282 if (!frame)
1283 return;
1284
1285 nsPresContext* presContext = PresContext();
1286 // make sure this is REALLY an nsIObjectFrame
1287 // we may need to go through the children to get it
1288 nsIObjectFrame* objectFrame = do_QueryFrame(frame);
1289 if (!objectFrame)
1290 objectFrame = GetNextObjectFrame(presContext,frame);
1291 if (!objectFrame)
1292 return;
1293
1294 // finally we can get our plugin instance
1295 RefPtr<nsNPAPIPluginInstance> pi;
1296 if (NS_FAILED(objectFrame->GetPluginInstance(getter_AddRefs(pi))) || !pi)
1297 return;
1298
1299 // now we need to setup the correct location for printing
1300 NPWindow window;
1301 window.window = nullptr;
1302
1303 // prepare embedded mode printing struct
1304 NPPrint npprint;
1305 npprint.mode = NP_EMBED;
1306
1307 // we need to find out if we are windowless or not
1308 bool windowless = false;
1309 pi->IsWindowless(&windowless);
1310 window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow;
1311
1312 window.clipRect.bottom = 0; window.clipRect.top = 0;
1313 window.clipRect.left = 0; window.clipRect.right = 0;
1314
1315 // platform specific printing code
1316 #if defined(XP_UNIX) || defined(XP_MACOSX)
1317 // Doesn't work in a thebes world, or on OS X.
1318 (void)window;
1319 (void)npprint;
1320 #elif defined(XP_WIN)
1321
1322 /* On Windows, we use the win32 printing surface to print. This, in
1323 * turn, uses the Cairo paginated surface, which in turn uses the
1324 * meta surface to record all operations and then play them back.
1325 * This doesn't work too well for plugins, because if plugins render
1326 * directly into the DC, the meta surface won't have any knowledge
1327 * of them, and so at the end when it actually does the replay step,
1328 * it'll fill the background with white and draw over whatever was
1329 * rendered before.
1330 *
1331 * So, to avoid this, we use PushGroup, which creates a new windows
1332 * surface, the plugin renders to that, and then we use normal
1333 * cairo methods to composite that in such that it's recorded using the
1334 * meta surface.
1335 */
1336
1337 /* we'll already be translated into the right spot by gfxWindowsNativeDrawing */
1338 nsSize contentSize = GetContentRectRelativeToSelf().Size();
1339 window.x = 0;
1340 window.y = 0;
1341 window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1342 window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1343
1344 gfxContext *ctx = aRenderingContext.ThebesContext();
1345
1346 ctx->Save();
1347
1348 /* Make sure plugins don't do any damage outside of where they're supposed to */
1349 ctx->NewPath();
1350 gfxRect r(window.x, window.y, window.width, window.height);
1351 ctx->Rectangle(r);
1352 ctx->Clip();
1353
1354 gfxWindowsNativeDrawing nativeDraw(ctx, r);
1355 do {
1356 HDC dc = nativeDraw.BeginNativeDrawing();
1357 if (!dc)
1358 return;
1359
1360 // XXX don't we need to call nativeDraw.TransformToNativeRect here?
1361 npprint.print.embedPrint.platformPrint = dc;
1362 npprint.print.embedPrint.window = window;
1363 // send off print info to plugin
1364 pi->Print(&npprint);
1365
1366 nativeDraw.EndNativeDrawing();
1367 } while (nativeDraw.ShouldRenderAgain());
1368 nativeDraw.PaintToContext();
1369
1370 ctx->Restore();
1371 #endif
1372
1373 // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
1374 // XXX Calling DidReflow here makes no sense!!!
1375 nsDidReflowStatus status = nsDidReflowStatus::FINISHED; // should we use a special status?
1376 frame->DidReflow(presContext,
1377 nullptr, status); // DidReflow will take care of it
1378 }
1379
1380 nsRect
GetPaintedRect(nsDisplayPlugin * aItem)1381 nsPluginFrame::GetPaintedRect(nsDisplayPlugin* aItem)
1382 {
1383 if (!mInstanceOwner)
1384 return nsRect();
1385 nsRect r = GetContentRectRelativeToSelf();
1386 if (!mInstanceOwner->UseAsyncRendering())
1387 return r;
1388
1389 nsIntSize size = mInstanceOwner->GetCurrentImageSize();
1390 nsPresContext* pc = PresContext();
1391 r.IntersectRect(r, nsRect(0, 0, pc->DevPixelsToAppUnits(size.width),
1392 pc->DevPixelsToAppUnits(size.height)));
1393 return r;
1394 }
1395
1396 LayerState
GetLayerState(nsDisplayListBuilder * aBuilder,LayerManager * aManager)1397 nsPluginFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
1398 LayerManager* aManager)
1399 {
1400 if (!mInstanceOwner)
1401 return LAYER_NONE;
1402
1403 #ifdef MOZ_WIDGET_ANDROID
1404 // We always want a layer on Honeycomb and later
1405 return LAYER_ACTIVE;
1406 #else
1407 if (mInstanceOwner->NeedsScrollImageLayer()) {
1408 return LAYER_ACTIVE;
1409 }
1410
1411 if (!mInstanceOwner->UseAsyncRendering()) {
1412 return LAYER_NONE;
1413 }
1414
1415 return LAYER_ACTIVE_FORCE;
1416 #endif
1417 }
1418
1419 class PluginFrameDidCompositeObserver final : public ClientLayerManager::
1420 DidCompositeObserver
1421 {
1422 public:
PluginFrameDidCompositeObserver(nsPluginInstanceOwner * aOwner,ClientLayerManager * aLayerManager)1423 PluginFrameDidCompositeObserver(nsPluginInstanceOwner* aOwner, ClientLayerManager* aLayerManager)
1424 : mInstanceOwner(aOwner),
1425 mLayerManager(aLayerManager)
1426 {
1427 }
~PluginFrameDidCompositeObserver()1428 ~PluginFrameDidCompositeObserver() {
1429 mLayerManager->RemoveDidCompositeObserver(this);
1430 }
DidComposite()1431 void DidComposite() override {
1432 mInstanceOwner->DidComposite();
1433 }
IsValid(ClientLayerManager * aLayerManager)1434 bool IsValid(ClientLayerManager* aLayerManager) {
1435 return aLayerManager == mLayerManager;
1436 }
1437
1438 private:
1439 nsPluginInstanceOwner* mInstanceOwner;
1440 RefPtr<ClientLayerManager> mLayerManager;
1441 };
1442
1443 already_AddRefed<Layer>
BuildLayer(nsDisplayListBuilder * aBuilder,LayerManager * aManager,nsDisplayItem * aItem,const ContainerLayerParameters & aContainerParameters)1444 nsPluginFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
1445 LayerManager* aManager,
1446 nsDisplayItem* aItem,
1447 const ContainerLayerParameters& aContainerParameters)
1448 {
1449 if (!mInstanceOwner)
1450 return nullptr;
1451
1452 NPWindow* window = nullptr;
1453 mInstanceOwner->GetWindow(window);
1454 if (!window)
1455 return nullptr;
1456
1457 if (window->width <= 0 || window->height <= 0)
1458 return nullptr;
1459
1460 #if defined(XP_MACOSX)
1461 // window is in "display pixels", but size needs to be in device pixels
1462 // window must be in "display pixels"
1463 double scaleFactor = 1.0;
1464 if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
1465 scaleFactor = 1.0;
1466 }
1467
1468 size_t intScaleFactor = ceil(scaleFactor);
1469 #else
1470 size_t intScaleFactor = 1;
1471 #endif
1472
1473 IntSize size(window->width * intScaleFactor, window->height * intScaleFactor);
1474
1475 nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
1476 gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
1477 // to provide crisper and faster drawing.
1478 r.Round();
1479 RefPtr<Layer> layer =
1480 (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
1481
1482 if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
1483 RefPtr<ImageContainer> container;
1484 // Image for Windowed plugins that support window capturing for scroll
1485 // operations or async windowless rendering.
1486 container = mInstanceOwner->GetImageContainer();
1487 if (!container) {
1488 // This can occur if our instance is gone or if the current plugin
1489 // configuration does not require a backing image layer.
1490 return nullptr;
1491 }
1492
1493 if (!layer) {
1494 mInstanceOwner->NotifyPaintWaiter(aBuilder);
1495 // Initialize ImageLayer
1496 layer = aManager->CreateImageLayer();
1497 if (!layer)
1498 return nullptr;
1499 }
1500
1501 NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
1502 ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
1503 #ifdef XP_MACOSX
1504 if (!mInstanceOwner->UseAsyncRendering()) {
1505 mInstanceOwner->DoCocoaEventDrawRect(r, nullptr);
1506 }
1507 #endif
1508
1509 imglayer->SetScaleToSize(size, ScaleMode::STRETCH);
1510 imglayer->SetContainer(container);
1511 SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(this);
1512 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
1513 if (!aManager->IsCompositingCheap()) {
1514 // Pixman just horrible with bilinear filter scaling
1515 samplingFilter = SamplingFilter::POINT;
1516 }
1517 #endif
1518 imglayer->SetSamplingFilter(samplingFilter);
1519
1520 layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
1521
1522 if (aBuilder->IsPaintingToWindow() &&
1523 aBuilder->GetWidgetLayerManager() &&
1524 aBuilder->GetWidgetLayerManager()->AsClientLayerManager() &&
1525 mInstanceOwner->UseAsyncRendering())
1526 {
1527 RefPtr<ClientLayerManager> lm = aBuilder->GetWidgetLayerManager()->AsClientLayerManager();
1528 if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) {
1529 mDidCompositeObserver = MakeUnique<PluginFrameDidCompositeObserver>(mInstanceOwner, lm);
1530 }
1531 lm->AddDidCompositeObserver(mDidCompositeObserver.get());
1532 }
1533 #ifdef MOZ_WIDGET_ANDROID
1534 } else if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_VIDEO) {
1535 nsDisplayPluginVideo* videoItem = reinterpret_cast<nsDisplayPluginVideo*>(aItem);
1536 nsNPAPIPluginInstance::VideoInfo* videoInfo = videoItem->VideoInfo();
1537
1538 RefPtr<ImageContainer> container = mInstanceOwner->GetImageContainerForVideo(videoInfo);
1539 if (!container)
1540 return nullptr;
1541
1542 if (!layer) {
1543 // Initialize ImageLayer
1544 layer = aManager->CreateImageLayer();
1545 if (!layer)
1546 return nullptr;
1547 }
1548
1549 ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
1550 imglayer->SetContainer(container);
1551
1552 layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
1553
1554 // Set the offset and size according to the video dimensions
1555 r.MoveBy(videoInfo->mDimensions.TopLeft());
1556 size.width = videoInfo->mDimensions.width;
1557 size.height = videoInfo->mDimensions.height;
1558 #endif
1559 } else {
1560 NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
1561 "Unknown item type");
1562 MOZ_ASSERT(!IsOpaque(), "Opaque plugins don't use backgrounds");
1563
1564 if (!layer) {
1565 layer = aManager->CreateReadbackLayer();
1566 if (!layer)
1567 return nullptr;
1568 }
1569 NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
1570
1571 ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
1572 if (readback->GetSize() != size) {
1573 // This will destroy any old background sink and notify us that the
1574 // background is now unknown
1575 readback->SetSink(nullptr);
1576 readback->SetSize(size);
1577
1578 if (mBackgroundSink) {
1579 // Maybe we still have a background sink associated with another
1580 // readback layer that wasn't recycled for some reason? Unhook it
1581 // now so that if this frame goes away, it doesn't have a dangling
1582 // reference to us.
1583 mBackgroundSink->Destroy();
1584 }
1585 mBackgroundSink =
1586 new PluginBackgroundSink(this,
1587 readback->AllocateSequenceNumber());
1588 readback->SetSink(mBackgroundSink);
1589 // The layer has taken ownership of our sink. When either the sink dies
1590 // or the frame dies, the connection from the surviving object is nulled out.
1591 }
1592 }
1593
1594 // Set a transform on the layer to draw the plugin in the right place
1595 gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
1596 Matrix transform = Matrix::Translation(p.x, p.y);
1597
1598 layer->SetBaseTransform(Matrix4x4::From2D(transform));
1599 return layer.forget();
1600 }
1601
1602 void
PaintPlugin(nsDisplayListBuilder * aBuilder,nsRenderingContext & aRenderingContext,const nsRect & aDirtyRect,const nsRect & aPluginRect)1603 nsPluginFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
1604 nsRenderingContext& aRenderingContext,
1605 const nsRect& aDirtyRect, const nsRect& aPluginRect)
1606 {
1607 #if defined(MOZ_WIDGET_ANDROID)
1608 if (mInstanceOwner) {
1609 gfxRect frameGfxRect =
1610 PresContext()->AppUnitsToGfxUnits(aPluginRect);
1611 gfxRect dirtyGfxRect =
1612 PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1613
1614 gfxContext* ctx = aRenderingContext.ThebesContext();
1615
1616 mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect);
1617 return;
1618 }
1619 #else
1620 # if defined(DEBUG)
1621 // On Desktop, we should have built a layer as we no longer support in-process
1622 // plugins or synchronous painting. We can only get here for windowed plugins
1623 // (which draw themselves), or via some error/unload state.
1624 if (mInstanceOwner) {
1625 NPWindow *window = nullptr;
1626 mInstanceOwner->GetWindow(window);
1627 MOZ_ASSERT(!window || window->type == NPWindowTypeWindow);
1628 }
1629 # endif
1630 #endif
1631 }
1632
1633 nsresult
HandleEvent(nsPresContext * aPresContext,WidgetGUIEvent * anEvent,nsEventStatus * anEventStatus)1634 nsPluginFrame::HandleEvent(nsPresContext* aPresContext,
1635 WidgetGUIEvent* anEvent,
1636 nsEventStatus* anEventStatus)
1637 {
1638 NS_ENSURE_ARG_POINTER(anEvent);
1639 NS_ENSURE_ARG_POINTER(anEventStatus);
1640 nsresult rv = NS_OK;
1641
1642 if (!mInstanceOwner)
1643 return NS_ERROR_NULL_POINTER;
1644
1645 mInstanceOwner->ConsiderNewEventloopNestingLevel();
1646
1647 if (anEvent->mMessage == ePluginActivate) {
1648 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1649 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(GetContent());
1650 if (fm && elem)
1651 return fm->SetFocus(elem, 0);
1652 }
1653 else if (anEvent->mMessage == ePluginFocus) {
1654 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1655 if (fm) {
1656 nsCOMPtr<nsIContent> content = GetContent();
1657 return fm->FocusPlugin(content);
1658 }
1659 }
1660
1661 if (mInstanceOwner->SendNativeEvents() &&
1662 anEvent->IsNativeEventDelivererForPlugin()) {
1663 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
1664 // Due to plugin code reentering Gecko, this frame may be dead at this
1665 // point.
1666 return rv;
1667 }
1668
1669 #ifdef XP_WIN
1670 rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus);
1671 return rv;
1672 #endif
1673
1674 #ifdef XP_MACOSX
1675 // we want to process some native mouse events in the cocoa event model
1676 if ((anEvent->mMessage == eMouseEnterIntoWidget ||
1677 anEvent->mMessage == eWheel) &&
1678 mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
1679 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
1680 // Due to plugin code reentering Gecko, this frame may be dead at this
1681 // point.
1682 return rv;
1683 }
1684
1685 // These two calls to nsIPresShell::SetCapturingContext() (on mouse-down
1686 // and mouse-up) are needed to make the routing of mouse events while
1687 // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec.
1688 // See bug 525078 and bug 909678.
1689 if (anEvent->mMessage == eMouseDown) {
1690 nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
1691 }
1692 #endif
1693
1694 rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus);
1695
1696 // We need to be careful from this point because the call to
1697 // nsFrame::HandleEvent() might have killed us.
1698
1699 #ifdef XP_MACOSX
1700 if (anEvent->mMessage == eMouseUp) {
1701 nsIPresShell::SetCapturingContent(nullptr, 0);
1702 }
1703 #endif
1704
1705 return rv;
1706 }
1707
1708 void
HandleWheelEventAsDefaultAction(WidgetWheelEvent * aWheelEvent)1709 nsPluginFrame::HandleWheelEventAsDefaultAction(WidgetWheelEvent* aWheelEvent)
1710 {
1711 MOZ_ASSERT(WantsToHandleWheelEventAsDefaultAction());
1712 MOZ_ASSERT(!aWheelEvent->DefaultPrevented());
1713
1714 if (NS_WARN_IF(!mInstanceOwner) ||
1715 NS_WARN_IF(aWheelEvent->mMessage != eWheel)) {
1716 return;
1717 }
1718
1719 // If the wheel event has native message, it should may be handled by
1720 // HandleEvent() in the future. In such case, we should do nothing here.
1721 if (NS_WARN_IF(!!aWheelEvent->mPluginEvent)) {
1722 return;
1723 }
1724
1725 mInstanceOwner->ProcessEvent(*aWheelEvent);
1726 // We need to assume that the event is always consumed/handled by the
1727 // plugin. There is no way to know if it's actually consumed/handled.
1728 aWheelEvent->mViewPortIsOverscrolled = false;
1729 aWheelEvent->mOverflowDeltaX = 0;
1730 aWheelEvent->mOverflowDeltaY = 0;
1731 // Consume the event explicitly.
1732 aWheelEvent->PreventDefault();
1733 }
1734
1735 bool
WantsToHandleWheelEventAsDefaultAction() const1736 nsPluginFrame::WantsToHandleWheelEventAsDefaultAction() const
1737 {
1738 #ifdef XP_WIN
1739 if (!mInstanceOwner) {
1740 return false;
1741 }
1742 NPWindow* window = nullptr;
1743 mInstanceOwner->GetWindow(window);
1744 // On Windows, only when the plugin is windowless, we need to send wheel
1745 // events as default action.
1746 return window->type == NPWindowTypeDrawable;
1747 #else
1748 return false;
1749 #endif
1750 }
1751
1752 nsresult
GetPluginInstance(nsNPAPIPluginInstance ** aPluginInstance)1753 nsPluginFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
1754 {
1755 *aPluginInstance = nullptr;
1756
1757 if (!mInstanceOwner) {
1758 return NS_OK;
1759 }
1760
1761 return mInstanceOwner->GetInstance(aPluginInstance);
1762 }
1763
1764 nsresult
GetCursor(const nsPoint & aPoint,nsIFrame::Cursor & aCursor)1765 nsPluginFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor)
1766 {
1767 if (!mInstanceOwner) {
1768 return NS_ERROR_FAILURE;
1769 }
1770
1771 RefPtr<nsNPAPIPluginInstance> inst;
1772 mInstanceOwner->GetInstance(getter_AddRefs(inst));
1773 if (!inst) {
1774 return NS_ERROR_FAILURE;
1775 }
1776
1777 bool useDOMCursor = static_cast<nsNPAPIPluginInstance*>(inst.get())->UsesDOMForCursor();
1778 if (!useDOMCursor) {
1779 return NS_ERROR_FAILURE;
1780 }
1781
1782 return nsFrame::GetCursor(aPoint, aCursor);
1783 }
1784
1785 void
SetIsDocumentActive(bool aIsActive)1786 nsPluginFrame::SetIsDocumentActive(bool aIsActive)
1787 {
1788 if (mInstanceOwner) {
1789 mInstanceOwner->UpdateDocumentActiveState(aIsActive);
1790 }
1791 }
1792
1793 // static
1794 nsIObjectFrame *
GetNextObjectFrame(nsPresContext * aPresContext,nsIFrame * aRoot)1795 nsPluginFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
1796 {
1797 for (nsIFrame* child : aRoot->PrincipalChildList()) {
1798 nsIObjectFrame* outFrame = do_QueryFrame(child);
1799 if (outFrame) {
1800 RefPtr<nsNPAPIPluginInstance> pi;
1801 outFrame->GetPluginInstance(getter_AddRefs(pi)); // make sure we have a REAL plugin
1802 if (pi)
1803 return outFrame;
1804 }
1805
1806 outFrame = GetNextObjectFrame(aPresContext, child);
1807 if (outFrame)
1808 return outFrame;
1809 }
1810
1811 return nullptr;
1812 }
1813
1814 /*static*/ void
BeginSwapDocShells(nsISupports * aSupports,void *)1815 nsPluginFrame::BeginSwapDocShells(nsISupports* aSupports, void*)
1816 {
1817 NS_PRECONDITION(aSupports, "");
1818 nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
1819 if (!content) {
1820 return;
1821 }
1822
1823 // This function is called from a document content enumerator so we need
1824 // to filter out the nsPluginFrames and ignore the rest.
1825 nsIObjectFrame* obj = do_QueryFrame(content->GetPrimaryFrame());
1826 if (!obj)
1827 return;
1828
1829 nsPluginFrame* objectFrame = static_cast<nsPluginFrame*>(obj);
1830 NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(),
1831 "Plugin windows must not be toplevel");
1832 objectFrame->UnregisterPluginForGeometryUpdates();
1833 }
1834
1835 /*static*/ void
EndSwapDocShells(nsISupports * aSupports,void *)1836 nsPluginFrame::EndSwapDocShells(nsISupports* aSupports, void*)
1837 {
1838 NS_PRECONDITION(aSupports, "");
1839 nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
1840 if (!content) {
1841 return;
1842 }
1843
1844 // This function is called from a document content enumerator so we need
1845 // to filter out the nsPluginFrames and ignore the rest.
1846 nsIObjectFrame* obj = do_QueryFrame(content->GetPrimaryFrame());
1847 if (!obj)
1848 return;
1849
1850 nsPluginFrame* objectFrame = static_cast<nsPluginFrame*>(obj);
1851 nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
1852 NS_ASSERTION(rootPC, "unable to register the plugin frame");
1853 nsIWidget* widget = objectFrame->mWidget;
1854 if (widget) {
1855 // Reparent the widget.
1856 nsIWidget* parent =
1857 rootPC->PresShell()->GetRootFrame()->GetNearestWidget();
1858 widget->SetParent(parent);
1859 nsWeakFrame weakFrame(objectFrame);
1860 objectFrame->CallSetWindow();
1861 if (!weakFrame.IsAlive()) {
1862 return;
1863 }
1864 }
1865
1866 if (objectFrame->mInstanceOwner) {
1867 objectFrame->RegisterPluginForGeometryUpdates();
1868 }
1869 }
1870
1871 nsIFrame*
NS_NewObjectFrame(nsIPresShell * aPresShell,nsStyleContext * aContext)1872 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1873 {
1874 return new (aPresShell) nsPluginFrame(aContext);
1875 }
1876
1877 bool
IsPaintedByGecko() const1878 nsPluginFrame::IsPaintedByGecko() const
1879 {
1880 #ifdef XP_MACOSX
1881 return true;
1882 #else
1883 return !mWidget;
1884 #endif
1885 }
1886
1887 NS_IMPL_FRAMEARENA_HELPERS(nsPluginFrame)
1888