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