Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
7 /* rendering objects for replaced elements implemented by a plugin */
9 #include "nsObjectFrame.h"
11 #include "gfx2DGlue.h"
12 #include "mozilla/BasicEvents.h"
13 #ifdef XP_WIN
14 // This is needed for DoublePassRenderingEvent.
15 #include "mozilla/plugins/PluginMessageUtils.h"
16 #endif
18 #include "nscore.h"
19 #include "nsCOMPtr.h"
20 #include "nsPresContext.h"
21 #include "nsIPresShell.h"
22 #include "nsWidgetsCID.h"
23 #include "nsView.h"
24 #include "nsViewManager.h"
25 #include "nsString.h"
26 #include "nsGkAtoms.h"
27 #include "nsIPluginInstanceOwner.h"
28 #include "nsNPAPIPluginInstance.h"
29 #include "nsIDOMElement.h"
30 #include "nsRenderingContext.h"
31 #include "npapi.h"
32 #include "nsIObjectLoadingContent.h"
33 #include "nsContentUtils.h"
34 #include "nsDisplayList.h"
35 #include "nsFocusManager.h"
36 #include "nsLayoutUtils.h"
37 #include "nsFrameManager.h"
38 #include "nsIObserverService.h"
39 #include "GeckoProfiler.h"
40 #include <algorithm>
42 #include "nsIObjectFrame.h"
43 #include "nsPluginNativeWindow.h"
44 #include "FrameLayerBuilder.h"
46 #include "ImageLayers.h"
47 #include "nsPluginInstanceOwner.h"
49 #ifdef XP_WIN
50 #include "gfxWindowsNativeDrawing.h"
51 #include "gfxWindowsSurface.h"
52 #endif
54 #include "Layers.h"
55 #include "ReadbackLayer.h"
56 #include "ImageContainer.h"
58 // accessibility support
59 #ifdef ACCESSIBILITY
60 #include "nsAccessibilityService.h"
61 #endif
63 #ifdef MOZ_LOGGING
64 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
65 #endif /* MOZ_LOGGING */
66 #include "prlog.h"
68 #ifdef XP_MACOSX
69 #include "gfxQuartzNativeDrawing.h"
70 #include "nsPluginUtilsOSX.h"
71 #include "mozilla/gfx/QuartzSupport.h"
72 #endif
74 #ifdef MOZ_X11
75 #include "mozilla/X11Util.h"
76 using mozilla::DefaultXDisplay;
77 #endif
79 #ifdef XP_WIN
80 #include <wtypes.h>
81 #include <winuser.h>
82 #endif
84 #ifdef MOZ_WIDGET_ANDROID
85 #include "AndroidBridge.h"
86 #include "GLContext.h"
87 #endif
89 #ifdef CreateEvent // Thank you MS.
90 #undef CreateEvent
91 #endif
93 #ifdef PR_LOGGING
94 static PRLogModuleInfo *
95 GetObjectFrameLog()
96 {
97 static PRLogModuleInfo *sLog;
98 if (!sLog)
99 sLog = PR_NewLogModule("nsObjectFrame");
100 return sLog;
101 }
102 #endif /* PR_LOGGING */
104 #if defined(XP_MACOSX) && !defined(__LP64__)
106 // The header files QuickdrawAPI.h and QDOffscreen.h are missing on OS X 10.7
107 // and up (though the QuickDraw APIs defined in them are still present) -- so
108 // we need to supply the relevant parts of their contents here. It's likely
109 // that Apple will eventually remove the APIs themselves (probably in OS X
110 // 10.8), so we need to make them weak imports, and test for their presence
111 // before using them.
112 extern "C" {
113 #if !defined(__QUICKDRAWAPI__)
114 extern void SetRect(
115 Rect * r,
116 short left,
117 short top,
118 short right,
119 short bottom)
120 __attribute__((weak_import));
121 #endif /* __QUICKDRAWAPI__ */
123 #if !defined(__QDOFFSCREEN__)
124 extern QDErr NewGWorldFromPtr(
125 GWorldPtr * offscreenGWorld,
126 UInt32 PixelFormat,
127 const Rect * boundsRect,
128 CTabHandle cTable, /* can be nullptr */
129 GDHandle aGDevice, /* can be nullptr */
130 GWorldFlags flags,
131 Ptr newBuffer,
132 SInt32 rowBytes)
133 __attribute__((weak_import));
134 extern void DisposeGWorld(GWorldPtr offscreenGWorld)
135 __attribute__((weak_import));
136 #endif /* __QDOFFSCREEN__ */
137 }
139 #endif /* #if defined(XP_MACOSX) && !defined(__LP64__) */
141 using namespace mozilla;
142 using namespace mozilla::gfx;
143 using namespace mozilla::layers;
145 class PluginBackgroundSink : public ReadbackSink {
146 public:
147 PluginBackgroundSink(nsObjectFrame* aFrame, uint64_t aStartSequenceNumber)
148 : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
149 ~PluginBackgroundSink()
150 {
151 if (mFrame) {
152 mFrame->mBackgroundSink = nullptr;
153 }
154 }
156 virtual void SetUnknown(uint64_t aSequenceNumber)
157 {
158 if (!AcceptUpdate(aSequenceNumber))
159 return;
160 mFrame->mInstanceOwner->SetBackgroundUnknown();
161 }
163 virtual already_AddRefed<gfxContext>
164 BeginUpdate(const nsIntRect& aRect, uint64_t aSequenceNumber)
165 {
166 if (!AcceptUpdate(aSequenceNumber))
167 return nullptr;
168 return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
169 }
171 virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect)
172 {
173 return mFrame->mInstanceOwner->EndUpdateBackground(aContext, aRect);
174 }
176 void Destroy() { mFrame = nullptr; }
178 protected:
179 bool AcceptUpdate(uint64_t aSequenceNumber) {
180 if (aSequenceNumber > mLastSequenceNumber && mFrame &&
181 mFrame->mInstanceOwner) {
182 mLastSequenceNumber = aSequenceNumber;
183 return true;
184 }
185 return false;
186 }
188 uint64_t mLastSequenceNumber;
189 nsObjectFrame* mFrame;
190 };
192 nsObjectFrame::nsObjectFrame(nsStyleContext* aContext)
193 : nsObjectFrameSuper(aContext)
194 , mReflowCallbackPosted(false)
195 {
196 PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG,
197 ("Created new nsObjectFrame %p\n", this));
198 }
200 nsObjectFrame::~nsObjectFrame()
201 {
202 PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG,
203 ("nsObjectFrame %p deleted\n", this));
204 }
206 NS_QUERYFRAME_HEAD(nsObjectFrame)
207 NS_QUERYFRAME_ENTRY(nsObjectFrame)
208 NS_QUERYFRAME_ENTRY(nsIObjectFrame)
209 NS_QUERYFRAME_TAIL_INHERITING(nsObjectFrameSuper)
211 #ifdef ACCESSIBILITY
212 a11y::AccType
213 nsObjectFrame::AccessibleType()
214 {
215 return a11y::ePluginType;
216 }
218 #ifdef XP_WIN
219 NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
220 {
221 *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget();
222 return NS_OK;
223 }
224 #endif
225 #endif
227 void
228 nsObjectFrame::Init(nsIContent* aContent,
229 nsIFrame* aParent,
230 nsIFrame* aPrevInFlow)
231 {
232 PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG,
233 ("Initializing nsObjectFrame %p for content %p\n", this, aContent));
235 nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
236 }
238 void
239 nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
240 {
241 if (mReflowCallbackPosted) {
242 PresContext()->PresShell()->CancelReflowCallback(this);
243 }
245 // Tell content owner of the instance to disconnect its frame.
246 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
247 NS_ASSERTION(objContent, "Why not an object loading content?");
249 // The content might not have a reference to the instance owner any longer in
250 // the case of re-entry during instantiation or teardown, so make sure we're
251 // dissociated.
252 if (mInstanceOwner) {
253 mInstanceOwner->SetFrame(nullptr);
254 }
255 objContent->HasNewFrame(nullptr);
257 if (mBackgroundSink) {
258 mBackgroundSink->Destroy();
259 }
261 nsObjectFrameSuper::DestroyFrom(aDestructRoot);
262 }
264 /* virtual */ void
265 nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
266 {
267 if (HasView()) {
268 nsView* view = GetView();
269 nsViewManager* vm = view->GetViewManager();
270 if (vm) {
271 nsViewVisibility visibility =
272 IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
273 vm->SetViewVisibility(view, visibility);
274 }
275 }
277 nsObjectFrameSuper::DidSetStyleContext(aOldStyleContext);
278 }
280 nsIAtom*
281 nsObjectFrame::GetType() const
282 {
283 return nsGkAtoms::objectFrame;
284 }
286 #ifdef DEBUG_FRAME_DUMP
287 nsresult
288 nsObjectFrame::GetFrameName(nsAString& aResult) const
289 {
290 return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
291 }
292 #endif
294 nsresult
295 nsObjectFrame::PrepForDrawing(nsIWidget *aWidget)
296 {
297 mWidget = aWidget;
299 nsView* view = GetView();
300 NS_ASSERTION(view, "Object frames must have views");
301 if (!view) {
302 return NS_ERROR_FAILURE;
303 }
305 nsViewManager* viewMan = view->GetViewManager();
306 // mark the view as hidden since we don't know the (x,y) until Paint
307 // XXX is the above comment correct?
308 viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
310 //this is ugly. it was ripped off from didreflow(). MMP
311 // Position and size view relative to its parent, not relative to our
312 // parent frame (our parent frame may not have a view).
314 nsView* parentWithView;
315 nsPoint origin;
316 nsRect r(0, 0, mRect.width, mRect.height);
318 GetOffsetFromView(origin, &parentWithView);
319 viewMan->ResizeView(view, r);
320 viewMan->MoveViewTo(view, origin.x, origin.y);
322 nsPresContext* presContext = PresContext();
323 nsRootPresContext* rpc = presContext->GetRootPresContext();
324 if (!rpc) {
325 return NS_ERROR_FAILURE;
326 }
328 if (mWidget) {
329 // Disallow windowed plugins in popups
330 nsIFrame* rootFrame = rpc->PresShell()->FrameManager()->GetRootFrame();
331 nsIWidget* parentWidget = rootFrame->GetNearestWidget();
332 if (!parentWidget || nsLayoutUtils::GetDisplayRootFrame(this) != rootFrame) {
333 return NS_ERROR_FAILURE;
334 }
336 mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
337 if (!mInnerView) {
338 NS_ERROR("Could not create inner view");
339 return NS_ERROR_OUT_OF_MEMORY;
340 }
341 viewMan->InsertChild(view, mInnerView, nullptr, true);
343 mWidget->SetParent(parentWidget);
344 mWidget->Show(true);
345 mWidget->Enable(true);
347 // Set the plugin window to have an empty clip region until we know
348 // what our true position, size and clip region are. These
349 // will be reset when nsRootPresContext computes our true
350 // geometry. The plugin window does need to have a good size here, so
351 // set the size explicitly to a reasonable guess.
352 nsAutoTArray<nsIWidget::Configuration,1> configurations;
353 nsIWidget::Configuration* configuration = configurations.AppendElement();
354 nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
355 configuration->mChild = mWidget;
356 configuration->mBounds.width = NSAppUnitsToIntPixels(mRect.width, appUnitsPerDevPixel);
357 configuration->mBounds.height = NSAppUnitsToIntPixels(mRect.height, appUnitsPerDevPixel);
358 parentWidget->ConfigureChildren(configurations);
360 nsRefPtr<nsDeviceContext> dx = viewMan->GetDeviceContext();
361 mInnerView->AttachWidgetEventHandler(mWidget);
363 #ifdef XP_MACOSX
364 // On Mac, we need to invalidate ourselves since even windowed
365 // plugins are painted through Thebes and we need to ensure
366 // the Thebes layer containing the plugin is updated.
367 if (parentWidget == GetNearestWidget()) {
368 InvalidateFrame();
369 }
370 #endif
372 RegisterPluginForGeometryUpdates();
374 // Here we set the background color for this widget because some plugins will use
375 // the child window background color when painting. If it's not set, it may default to gray
376 // Sometimes, a frame doesn't have a background color or is transparent. In this
377 // case, walk up the frame tree until we do find a frame with a background color
378 for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
379 nscolor bgcolor =
380 frame->GetVisitedDependentColor(eCSSProperty_background_color);
381 if (NS_GET_A(bgcolor) > 0) { // make sure we got an actual color
382 mWidget->SetBackgroundColor(bgcolor);
383 break;
384 }
385 }
386 } else {
387 // Changing to windowless mode changes the NPWindow geometry.
388 FixupWindow(GetContentRectRelativeToSelf().Size());
390 #ifndef XP_MACOSX
391 RegisterPluginForGeometryUpdates();
392 #endif
393 }
395 if (!IsHidden()) {
396 viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
397 }
399 #ifdef ACCESSIBILITY
400 nsAccessibilityService* accService = nsIPresShell::AccService();
401 if (accService) {
402 accService->RecreateAccessible(PresContext()->PresShell(), mContent);
403 }
404 #endif
406 return NS_OK;
407 }
409 #define EMBED_DEF_WIDTH 240
410 #define EMBED_DEF_HEIGHT 200
412 /* virtual */ nscoord
413 nsObjectFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
414 {
415 nscoord result = 0;
417 if (!IsHidden(false)) {
418 nsIAtom *atom = mContent->Tag();
419 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
420 result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH);
421 }
422 }
424 DISPLAY_MIN_WIDTH(this, result);
425 return result;
426 }
428 /* virtual */ nscoord
429 nsObjectFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
430 {
431 return nsObjectFrame::GetMinWidth(aRenderingContext);
432 }
434 void
435 nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext,
436 const nsHTMLReflowState& aReflowState,
437 nsHTMLReflowMetrics& aMetrics)
438 {
439 // By default, we have no area
440 aMetrics.Width() = 0;
441 aMetrics.Height() = 0;
443 if (IsHidden(false)) {
444 return;
445 }
447 aMetrics.Width() = aReflowState.ComputedWidth();
448 aMetrics.Height() = aReflowState.ComputedHeight();
450 // for EMBED and APPLET, default to 240x200 for compatibility
451 nsIAtom *atom = mContent->Tag();
452 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
453 if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) {
454 aMetrics.Width() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
455 aReflowState.ComputedMinWidth(),
456 aReflowState.ComputedMaxWidth());
457 }
458 if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) {
459 aMetrics.Height() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
460 aReflowState.ComputedMinHeight(),
461 aReflowState.ComputedMaxHeight());
462 }
464 #if defined(MOZ_WIDGET_GTK)
465 // We need to make sure that the size of the object frame does not
466 // exceed the maximum size of X coordinates. See bug #225357 for
467 // more information. In theory Gtk2 can handle large coordinates,
468 // but underlying plugins can't.
469 aMetrics.Height() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Height());
470 aMetrics.Width() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Width());
471 #endif
472 }
474 // At this point, the width has an unconstrained value only if we have
475 // nothing to go on (no width set, no information from the plugin, nothing).
476 // Make up a number.
477 if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) {
478 aMetrics.Width() =
479 (aReflowState.ComputedMinWidth() != NS_UNCONSTRAINEDSIZE) ?
480 aReflowState.ComputedMinWidth() : 0;
481 }
483 // At this point, the height has an unconstrained value only in two cases:
484 // a) We are in standards mode with percent heights and parent is auto-height
485 // b) We have no height information at all.
486 // In either case, we have to make up a number.
487 if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) {
488 aMetrics.Height() =
489 (aReflowState.ComputedMinHeight() != NS_UNCONSTRAINEDSIZE) ?
490 aReflowState.ComputedMinHeight() : 0;
491 }
493 // XXXbz don't add in the border and padding, because we screw up our
494 // plugin's size and positioning if we do... Eventually we _do_ want to
495 // paint borders, though! At that point, we will need to adjust the desired
496 // size either here or in Reflow.... Further, we will need to fix Paint() to
497 // call the superclass in all cases.
498 }
500 nsresult
501 nsObjectFrame::Reflow(nsPresContext* aPresContext,
502 nsHTMLReflowMetrics& aMetrics,
503 const nsHTMLReflowState& aReflowState,
504 nsReflowStatus& aStatus)
505 {
506 DO_GLOBAL_REFLOW_COUNT("nsObjectFrame");
507 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
509 // Get our desired size
510 GetDesiredSize(aPresContext, aReflowState, aMetrics);
511 aMetrics.SetOverflowAreasToDesiredBounds();
512 FinishAndStoreOverflow(&aMetrics);
514 // delay plugin instantiation until all children have
515 // arrived. Otherwise there may be PARAMs or other stuff that the
516 // plugin needs to see that haven't arrived yet.
517 if (!GetContent()->IsDoneAddingChildren()) {
518 aStatus = NS_FRAME_COMPLETE;
519 return NS_OK;
520 }
522 // if we are printing or print previewing, bail for now
523 if (aPresContext->Medium() == nsGkAtoms::print) {
524 aStatus = NS_FRAME_COMPLETE;
525 return NS_OK;
526 }
528 nsRect r(0, 0, aMetrics.Width(), aMetrics.Height());
529 r.Deflate(aReflowState.ComputedPhysicalBorderPadding());
531 if (mInnerView) {
532 nsViewManager* vm = mInnerView->GetViewManager();
533 vm->MoveViewTo(mInnerView, r.x, r.y);
534 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), true);
535 }
537 FixupWindow(r.Size());
538 if (!mReflowCallbackPosted) {
539 mReflowCallbackPosted = true;
540 aPresContext->PresShell()->PostReflowCallback(this);
541 }
543 aStatus = NS_FRAME_COMPLETE;
545 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
546 return NS_OK;
547 }
549 ///////////// nsIReflowCallback ///////////////
551 bool
552 nsObjectFrame::ReflowFinished()
553 {
554 mReflowCallbackPosted = false;
555 CallSetWindow();
556 return true;
557 }
559 void
560 nsObjectFrame::ReflowCallbackCanceled()
561 {
562 mReflowCallbackPosted = false;
563 }
565 void
566 nsObjectFrame::FixupWindow(const nsSize& aSize)
567 {
568 nsPresContext* presContext = PresContext();
570 if (!mInstanceOwner)
571 return;
573 NPWindow *window;
574 mInstanceOwner->GetWindow(window);
576 NS_ENSURE_TRUE_VOID(window);
578 #ifdef XP_MACOSX
579 nsWeakFrame weakFrame(this);
580 mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintDisable);
581 if (!weakFrame.IsAlive()) {
582 return;
583 }
584 #endif
586 bool windowless = (window->type == NPWindowTypeDrawable);
588 nsIntPoint origin = GetWindowOriginInPixels(windowless);
590 // window must be in "display pixels"
591 double scaleFactor = 1.0;
592 if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
593 scaleFactor = 1.0;
594 }
595 int intScaleFactor = ceil(scaleFactor);
596 window->x = origin.x / intScaleFactor;
597 window->y = origin.y / intScaleFactor;
598 window->width = presContext->AppUnitsToDevPixels(aSize.width) / intScaleFactor;
599 window->height = presContext->AppUnitsToDevPixels(aSize.height) / intScaleFactor;
601 // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
602 // us from drawing on screen until the widget is properly positioned, which will not
603 // happen until we have finished the reflow process.
604 #ifdef XP_MACOSX
605 window->clipRect.top = 0;
606 window->clipRect.left = 0;
607 window->clipRect.bottom = 0;
608 window->clipRect.right = 0;
609 #else
610 mInstanceOwner->UpdateWindowPositionAndClipRect(false);
611 #endif
613 NotifyPluginReflowObservers();
614 }
616 nsresult
617 nsObjectFrame::CallSetWindow(bool aCheckIsHidden)
618 {
619 NPWindow *win = nullptr;
621 nsresult rv = NS_ERROR_FAILURE;
622 nsRefPtr<nsNPAPIPluginInstance> pi;
623 if (!mInstanceOwner ||
624 NS_FAILED(rv = mInstanceOwner->GetInstance(getter_AddRefs(pi))) ||
625 !pi ||
626 NS_FAILED(rv = mInstanceOwner->GetWindow(win)) ||
627 !win)
628 return rv;
630 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
631 #ifdef XP_MACOSX
632 nsWeakFrame weakFrame(this);
633 mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintDisable);
634 if (!weakFrame.IsAlive()) {
635 return NS_ERROR_NOT_AVAILABLE;
636 }
637 #endif
639 if (aCheckIsHidden && IsHidden())
640 return NS_ERROR_FAILURE;
642 // refresh the plugin port as well
643 window->window = mInstanceOwner->GetPluginPortFromWidget();
645 // Adjust plugin dimensions according to pixel snap results
646 // and reduce amount of SetWindow calls
647 nsPresContext* presContext = PresContext();
648 nsRootPresContext* rootPC = presContext->GetRootPresContext();
649 if (!rootPC)
650 return NS_ERROR_FAILURE;
651 int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
652 nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
653 nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
654 nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
656 // window must be in "display pixels"
657 double scaleFactor = 1.0;
658 if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
659 scaleFactor = 1.0;
660 }
661 size_t intScaleFactor = ceil(scaleFactor);
662 window->x = intBounds.x / intScaleFactor;
663 window->y = intBounds.y / intScaleFactor;
664 window->width = intBounds.width / intScaleFactor;
665 window->height = intBounds.height / intScaleFactor;
667 // Calling SetWindow might destroy this frame. We need to use the instance
668 // owner to clean up so hold a ref.
669 nsRefPtr<nsPluginInstanceOwner> instanceOwnerRef(mInstanceOwner);
671 // This will call pi->SetWindow and take care of window subclassing
672 // if needed, see bug 132759. Calling SetWindow can destroy this frame
673 // so check for that before doing anything else with this frame's memory.
674 if (mInstanceOwner->UseAsyncRendering()) {
675 rv = pi->AsyncSetWindow(window);
676 }
677 else {
678 rv = window->CallSetWindow(pi);
679 }
681 instanceOwnerRef->ReleasePluginPort(window->window);
683 return rv;
684 }
686 void
687 nsObjectFrame::RegisterPluginForGeometryUpdates()
688 {
689 nsRootPresContext* rpc = PresContext()->GetRootPresContext();
690 NS_ASSERTION(rpc, "We should have a root pres context!");
691 if (mRootPresContextRegisteredWith == rpc || !rpc) {
692 // Already registered with current root pres context,
693 // or null root pres context...
694 return;
695 }
696 if (mRootPresContextRegisteredWith && mRootPresContextRegisteredWith != rpc) {
697 // Registered to some other root pres context. Unregister, and
698 // re-register with our current one...
699 UnregisterPluginForGeometryUpdates();
700 }
701 mRootPresContextRegisteredWith = rpc;
702 mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent);
703 }
705 void
706 nsObjectFrame::UnregisterPluginForGeometryUpdates()
707 {
708 if (!mRootPresContextRegisteredWith) {
709 // Not registered...
710 return;
711 }
712 mRootPresContextRegisteredWith->UnregisterPluginForGeometryUpdates(mContent);
713 mRootPresContextRegisteredWith = nullptr;
714 }
716 void
717 nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
718 {
719 // The ownership model here is historically fuzzy. This should only be called
720 // by nsPluginInstanceOwner when it is given a new frame, and
721 // nsObjectLoadingContent should be arbitrating frame-ownership via its
722 // HasNewFrame callback.
723 mInstanceOwner = aOwner;
724 if (mInstanceOwner) {
725 return;
726 }
727 UnregisterPluginForGeometryUpdates();
728 if (mWidget && mInnerView) {
729 mInnerView->DetachWidgetEventHandler(mWidget);
730 // Make sure the plugin is hidden in case an update of plugin geometry
731 // hasn't happened since this plugin became hidden.
732 nsIWidget* parent = mWidget->GetParent();
733 if (parent) {
734 nsTArray<nsIWidget::Configuration> configurations;
735 nsIWidget::Configuration* configuration = configurations.AppendElement();
736 configuration->mChild = mWidget;
737 parent->ConfigureChildren(configurations);
739 mWidget->Show(false);
740 mWidget->Enable(false);
741 mWidget->SetParent(nullptr);
742 }
743 }
744 }
746 bool
747 nsObjectFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
748 {
749 if (aTabIndex)
750 *aTabIndex = -1;
751 return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
752 }
754 bool
755 nsObjectFrame::IsHidden(bool aCheckVisibilityStyle) const
756 {
757 if (aCheckVisibilityStyle) {
758 if (!StyleVisibility()->IsVisibleOrCollapsed())
759 return true;
760 }
762 // only <embed> tags support the HIDDEN attribute
763 if (mContent->Tag() == nsGkAtoms::embed) {
764 // Yes, these are really the kooky ways that you could tell 4.x
765 // not to hide the <embed> once you'd put the 'hidden' attribute
766 // on the tag...
768 // HIDDEN w/ no attributes gets translated as we are hidden for
769 // compatibility w/ 4.x and IE so we don't create a non-painting
770 // widget in layout. See bug 188959.
771 nsAutoString hidden;
772 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) &&
773 (hidden.IsEmpty() ||
774 (!hidden.LowerCaseEqualsLiteral("false") &&
775 !hidden.LowerCaseEqualsLiteral("no") &&
776 !hidden.LowerCaseEqualsLiteral("off")))) {
777 return true;
778 }
779 }
781 return false;
782 }
784 nsIntPoint nsObjectFrame::GetWindowOriginInPixels(bool aWindowless)
785 {
786 nsView * parentWithView;
787 nsPoint origin(0,0);
789 GetOffsetFromView(origin, &parentWithView);
791 // if it's windowless, let's make sure we have our origin set right
792 // it may need to be corrected, like after scrolling
793 if (aWindowless && parentWithView) {
794 nsPoint offsetToWidget;
795 parentWithView->GetNearestWidget(&offsetToWidget);
796 origin += offsetToWidget;
797 }
798 origin += GetContentRectRelativeToSelf().TopLeft();
800 return nsIntPoint(PresContext()->AppUnitsToDevPixels(origin.x),
801 PresContext()->AppUnitsToDevPixels(origin.y));
802 }
804 nsresult
805 nsObjectFrame::DidReflow(nsPresContext* aPresContext,
806 const nsHTMLReflowState* aReflowState,
807 nsDidReflowStatus aStatus)
808 {
809 // Do this check before calling the superclass, as that clears
810 // NS_FRAME_FIRST_REFLOW
811 if (aStatus == nsDidReflowStatus::FINISHED &&
812 (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
813 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
814 NS_ASSERTION(objContent, "Why not an object loading content?");
815 objContent->HasNewFrame(this);
816 }
818 nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
820 // The view is created hidden; once we have reflowed it and it has been
821 // positioned then we show it.
822 if (aStatus != nsDidReflowStatus::FINISHED)
823 return rv;
825 if (HasView()) {
826 nsView* view = GetView();
827 nsViewManager* vm = view->GetViewManager();
828 if (vm)
829 vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
830 }
832 return rv;
833 }
835 /* static */ void
836 nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx,
837 const nsRect& aDirtyRect, nsPoint aPt)
838 {
839 nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft();
840 nsRenderingContext::AutoPushTranslation translate(aCtx, pt);
841 // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
842 static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
843 }
845 class nsDisplayPluginReadback : public nsDisplayItem {
846 public:
847 nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
848 : nsDisplayItem(aBuilder, aFrame)
849 {
850 MOZ_COUNT_CTOR(nsDisplayPluginReadback);
851 }
852 #ifdef NS_BUILD_REFCNT_LOGGING
853 virtual ~nsDisplayPluginReadback() {
854 MOZ_COUNT_DTOR(nsDisplayPluginReadback);
855 }
856 #endif
858 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
859 bool* aSnap) MOZ_OVERRIDE;
860 virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
861 nsRegion* aVisibleRegion,
862 const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
864 NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
866 virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
867 LayerManager* aManager,
868 const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
869 {
870 return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
871 }
873 virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
874 LayerManager* aManager,
875 const ContainerLayerParameters& aParameters) MOZ_OVERRIDE
876 {
877 return LAYER_ACTIVE;
878 }
879 };
881 static nsRect
882 GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
883 {
884 // XXX For slightly more accurate region computations we should pixel-snap this
885 return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
886 }
888 nsRect
889 nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
890 {
891 *aSnap = false;
892 return GetDisplayItemBounds(aBuilder, this, mFrame);
893 }
895 bool
896 nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
897 nsRegion* aVisibleRegion,
898 const nsRect& aAllowVisibleRegionExpansion)
899 {
900 if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
901 aAllowVisibleRegionExpansion))
902 return false;
904 nsRect expand;
905 bool snap;
906 expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder, &snap));
907 // *Add* our bounds to the visible region so that stuff underneath us is
908 // likely to be made visible, so we can use it for a background! This is
909 // a bit crazy since we normally only subtract from the visible region.
910 aVisibleRegion->Or(*aVisibleRegion, expand);
911 return true;
912 }
914 #ifdef MOZ_WIDGET_ANDROID
916 class nsDisplayPluginVideo : public nsDisplayItem {
917 public:
918 nsDisplayPluginVideo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
919 : nsDisplayItem(aBuilder, aFrame), mVideoInfo(aVideoInfo)
920 {
921 MOZ_COUNT_CTOR(nsDisplayPluginVideo);
922 }
923 #ifdef NS_BUILD_REFCNT_LOGGING
924 virtual ~nsDisplayPluginVideo() {
925 MOZ_COUNT_DTOR(nsDisplayPluginVideo);
926 }
927 #endif
929 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
930 bool* aSnap) MOZ_OVERRIDE;
931 virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
932 nsRegion* aVisibleRegion,
933 const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
935 NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO)
937 virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
938 LayerManager* aManager,
939 const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
940 {
941 return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
942 }
944 virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
945 LayerManager* aManager,
946 const ContainerLayerParameters& aParameters) MOZ_OVERRIDE
947 {
948 return LAYER_ACTIVE;
949 }
951 nsNPAPIPluginInstance::VideoInfo* VideoInfo() { return mVideoInfo; }
953 private:
954 nsNPAPIPluginInstance::VideoInfo* mVideoInfo;
955 };
957 nsRect
958 nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
959 {
960 *aSnap = false;
961 return GetDisplayItemBounds(aBuilder, this, mFrame);
962 }
964 bool
965 nsDisplayPluginVideo::ComputeVisibility(nsDisplayListBuilder* aBuilder,
966 nsRegion* aVisibleRegion,
967 const nsRect& aAllowVisibleRegionExpansion)
968 {
969 return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
970 aAllowVisibleRegionExpansion);
971 }
973 #endif
975 nsRect
976 nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
977 {
978 *aSnap = true;
979 return GetDisplayItemBounds(aBuilder, this, mFrame);
980 }
982 void
983 nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
984 nsRenderingContext* aCtx)
985 {
986 nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
987 bool snap;
988 f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));
989 }
991 bool
992 nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
993 nsRegion* aVisibleRegion,
994 const nsRect& aAllowVisibleRegionExpansion)
995 {
996 if (aBuilder->IsForPluginGeometry()) {
997 nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
998 if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) {
999 // Since transforms induce reference frames, we don't need to worry
1000 // about this method fluffing out due to non-rectilinear transforms.
1001 nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f,
1002 f->GetContentRectRelativeToSelf(), ReferenceFrame());
1003 nscoord appUnitsPerDevPixel =
1004 ReferenceFrame()->PresContext()->AppUnitsPerDevPixel();
1005 f->mNextConfigurationBounds = rAncestor.ToNearestPixels(appUnitsPerDevPixel);
1007 nsRegion visibleRegion;
1008 visibleRegion.And(*aVisibleRegion, GetClippedBounds(aBuilder));
1009 // Make visibleRegion relative to f
1010 visibleRegion.MoveBy(-ToReferenceFrame());
1012 f->mNextConfigurationClipRegion.Clear();
1013 nsRegionRectIterator iter(visibleRegion);
1014 for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
1015 nsRect rAncestor =
1016 nsLayoutUtils::TransformFrameRectToAncestor(f, *r, ReferenceFrame());
1017 nsIntRect rPixels = rAncestor.ToNearestPixels(appUnitsPerDevPixel)
1018 - f->mNextConfigurationBounds.TopLeft();
1019 if (!rPixels.IsEmpty()) {
1020 f->mNextConfigurationClipRegion.AppendElement(rPixels);
1021 }
1022 }
1023 }
1025 if (f->mInnerView) {
1026 // This should produce basically the same rectangle (but not relative
1027 // to the root frame). We only call this here for the side-effect of
1028 // setting mViewToWidgetOffset on the view.
1029 f->mInnerView->CalcWidgetBounds(eWindowType_plugin);
1030 }
1031 }
1033 return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1034 aAllowVisibleRegionExpansion);
1035 }
1037 nsRegion
1038 nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1039 bool* aSnap)
1040 {
1041 *aSnap = false;
1042 nsRegion result;
1043 nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
1044 if (!aBuilder->IsForPluginGeometry()) {
1045 nsIWidget* widget = f->GetWidget();
1046 if (widget) {
1047 // Be conservative and treat plugins with widgets as not opaque,
1048 // because that's simple and we might need the content under the widget
1049 // if the widget is unexpectedly clipped away. (As can happen when
1050 // chrome content over a plugin forces us to clip out the plugin for
1051 // security reasons.)
1052 // We shouldn't be repainting the content under plugins much anyway
1053 // since there generally shouldn't be anything to invalidate or paint
1054 // in ThebesLayers there.
1055 return result;
1056 }
1057 }
1059 if (f->IsOpaque()) {
1060 nsRect bounds = GetBounds(aBuilder, aSnap);
1061 if (aBuilder->IsForPluginGeometry() ||
1062 (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) {
1063 // We can treat this as opaque
1064 result = bounds;
1065 }
1066 }
1068 return result;
1069 }
1071 nsresult
1072 nsObjectFrame::PluginEventNotifier::Run() {
1073 nsCOMPtr<nsIObserverService> obsSvc =
1074 mozilla::services::GetObserverService();
1075 obsSvc->NotifyObservers(nullptr, "plugin-changed-event", mEventType.get());
1076 return NS_OK;
1077 }
1079 void
1080 nsObjectFrame::NotifyPluginReflowObservers()
1081 {
1082 nsContentUtils::AddScriptRunner(new PluginEventNotifier(NS_LITERAL_STRING("reflow")));
1083 }
1085 void
1086 nsObjectFrame::DidSetWidgetGeometry()
1087 {
1088 #if defined(XP_MACOSX)
1089 if (mInstanceOwner) {
1090 mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable);
1091 }
1092 #else
1093 if (!mWidget && mInstanceOwner) {
1094 // UpdateWindowVisibility will notify the plugin of position changes
1095 // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
1096 // We treat windowless plugins inside popups as always visible, since
1097 // plugins inside popups don't get valid mNextConfigurationBounds
1098 // set up.
1099 mInstanceOwner->UpdateWindowVisibility(
1100 nsLayoutUtils::IsPopup(nsLayoutUtils::GetDisplayRootFrame(this)) ||
1101 !mNextConfigurationBounds.IsEmpty());
1102 }
1103 #endif
1104 }
1106 bool
1107 nsObjectFrame::IsOpaque() const
1108 {
1109 #if defined(XP_MACOSX)
1110 // ???
1111 return false;
1112 #elif defined(MOZ_WIDGET_ANDROID)
1113 // We don't know, so just assume transparent
1114 return false;
1115 #else
1116 return !IsTransparentMode();
1117 #endif
1118 }
1120 bool
1121 nsObjectFrame::IsTransparentMode() const
1122 {
1123 #if defined(XP_MACOSX)
1124 // ???
1125 return false;
1126 #else
1127 if (!mInstanceOwner)
1128 return false;
1130 NPWindow *window = nullptr;
1131 mInstanceOwner->GetWindow(window);
1132 if (!window) {
1133 return false;
1134 }
1136 if (window->type != NPWindowTypeDrawable)
1137 return false;
1139 nsresult rv;
1140 nsRefPtr<nsNPAPIPluginInstance> pi;
1141 rv = mInstanceOwner->GetInstance(getter_AddRefs(pi));
1142 if (NS_FAILED(rv) || !pi)
1143 return false;
1145 bool transparent = false;
1146 pi->IsTransparent(&transparent);
1147 return transparent;
1148 #endif
1149 }
1151 void
1152 nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
1153 const nsRect& aDirtyRect,
1154 const nsDisplayListSet& aLists)
1155 {
1156 // XXX why are we painting collapsed object frames?
1157 if (!IsVisibleOrCollapsedForPainting(aBuilder))
1158 return;
1160 DisplayBorderBackgroundOutline(aBuilder, aLists);
1162 nsPresContext::nsPresContextType type = PresContext()->Type();
1164 // If we are painting in Print Preview do nothing....
1165 if (type == nsPresContext::eContext_PrintPreview)
1166 return;
1168 DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame");
1170 #ifndef XP_MACOSX
1171 if (mWidget && aBuilder->IsInTransform()) {
1172 // Windowed plugins should not be rendered inside a transform.
1173 return;
1174 }
1175 #endif
1177 if (aBuilder->IsForPainting() && mInstanceOwner && mInstanceOwner->UseAsyncRendering()) {
1178 NPWindow* window = nullptr;
1179 mInstanceOwner->GetWindow(window);
1180 bool isVisible = window && window->width > 0 && window->height > 0;
1181 if (isVisible && aBuilder->ShouldSyncDecodeImages()) {
1182 #ifndef XP_MACOSX
1183 mInstanceOwner->UpdateWindowVisibility(true);
1184 #endif
1185 }
1187 mInstanceOwner->NotifyPaintWaiter(aBuilder);
1188 }
1190 DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
1191 clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
1193 // determine if we are printing
1194 if (type == nsPresContext::eContext_Print) {
1195 aLists.Content()->AppendNewToTop(new (aBuilder)
1196 nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
1197 nsDisplayItem::TYPE_PRINT_PLUGIN));
1198 } else {
1199 LayerState state = GetLayerState(aBuilder, nullptr);
1200 if (state == LAYER_INACTIVE &&
1201 nsDisplayItem::ForceActiveLayers()) {
1202 state = LAYER_ACTIVE;
1203 }
1204 // We don't need this on Android, and it just confuses things
1205 #if !MOZ_WIDGET_ANDROID
1206 if (aBuilder->IsPaintingToWindow() &&
1207 state == LAYER_ACTIVE &&
1208 IsTransparentMode()) {
1209 aLists.Content()->AppendNewToTop(new (aBuilder)
1210 nsDisplayPluginReadback(aBuilder, this));
1211 }
1212 #endif
1214 #if MOZ_WIDGET_ANDROID
1215 if (aBuilder->IsPaintingToWindow() &&
1216 state == LAYER_ACTIVE) {
1218 nsTArray<nsNPAPIPluginInstance::VideoInfo*> videos;
1219 mInstanceOwner->GetVideos(videos);
1221 for (uint32_t i = 0; i < videos.Length(); i++) {
1222 aLists.Content()->AppendNewToTop(new (aBuilder)
1223 nsDisplayPluginVideo(aBuilder, this, videos[i]));
1224 }
1225 }
1226 #endif
1228 aLists.Content()->AppendNewToTop(new (aBuilder)
1229 nsDisplayPlugin(aBuilder, this));
1230 }
1231 }
1233 void
1234 nsObjectFrame::PrintPlugin(nsRenderingContext& aRenderingContext,
1235 const nsRect& aDirtyRect)
1236 {
1237 nsCOMPtr<nsIObjectLoadingContent> obj(do_QueryInterface(mContent));
1238 if (!obj)
1239 return;
1241 nsIFrame* frame = nullptr;
1242 obj->GetPrintFrame(&frame);
1243 if (!frame)
1244 return;
1246 nsPresContext* presContext = PresContext();
1247 // make sure this is REALLY an nsIObjectFrame
1248 // we may need to go through the children to get it
1249 nsIObjectFrame* objectFrame = do_QueryFrame(frame);
1250 if (!objectFrame)
1251 objectFrame = GetNextObjectFrame(presContext,frame);
1252 if (!objectFrame)
1253 return;
1255 // finally we can get our plugin instance
1256 nsRefPtr<nsNPAPIPluginInstance> pi;
1257 if (NS_FAILED(objectFrame->GetPluginInstance(getter_AddRefs(pi))) || !pi)
1258 return;
1260 // now we need to setup the correct location for printing
1261 NPWindow window;
1262 window.window = nullptr;
1264 // prepare embedded mode printing struct
1265 NPPrint npprint;
1266 npprint.mode = NP_EMBED;
1268 // we need to find out if we are windowless or not
1269 bool windowless = false;
1270 pi->IsWindowless(&windowless);
1271 window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow;
1273 window.clipRect.bottom = 0; window.clipRect.top = 0;
1274 window.clipRect.left = 0; window.clipRect.right = 0;
1276 // platform specific printing code
1277 #if defined(XP_MACOSX) && !defined(__LP64__)
1278 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1279 // Don't use this code if any of the QuickDraw APIs it currently requires
1280 // are missing (as they probably will be on OS X 10.8 and up).
1281 if (!&::SetRect || !&::NewGWorldFromPtr || !&::DisposeGWorld) {
1282 NS_WARNING("Cannot print plugin -- required QuickDraw APIs are missing!");
1283 return;
1284 }
1286 nsSize contentSize = GetContentRectRelativeToSelf().Size();
1287 window.x = 0;
1288 window.y = 0;
1289 window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1290 window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1292 gfxContext *ctx = aRenderingContext.ThebesContext();
1293 if (!ctx)
1294 return;
1295 gfxContextAutoSaveRestore save(ctx);
1297 ctx->NewPath();
1299 gfxRect rect(window.x, window.y, window.width, window.height);
1301 ctx->Rectangle(rect);
1302 ctx->Clip();
1304 gfxQuartzNativeDrawing nativeDraw(ctx, rect);
1305 CGContextRef cgContext = nativeDraw.BeginNativeDrawing();
1306 if (!cgContext) {
1307 nativeDraw.EndNativeDrawing();
1308 return;
1309 }
1311 window.clipRect.right = window.width;
1312 window.clipRect.bottom = window.height;
1313 window.type = NPWindowTypeDrawable;
1315 ::Rect gwBounds;
1316 ::SetRect(&gwBounds, 0, 0, window.width, window.height);
1318 nsTArray<char> buffer(window.width * window.height * 4);
1319 CGColorSpaceRef cspace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1320 if (!cspace) {
1321 nativeDraw.EndNativeDrawing();
1322 return;
1323 }
1324 CGContextRef cgBuffer =
1325 ::CGBitmapContextCreate(buffer.Elements(),
1326 window.width, window.height, 8, window.width * 4,
1327 cspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedFirst);
1328 ::CGColorSpaceRelease(cspace);
1329 if (!cgBuffer) {
1330 nativeDraw.EndNativeDrawing();
1331 return;
1332 }
1333 GWorldPtr gWorld;
1334 if (::NewGWorldFromPtr(&gWorld, k32ARGBPixelFormat, &gwBounds,
1335 nullptr, nullptr, 0,
1336 buffer.Elements(), window.width * 4) != noErr) {
1337 ::CGContextRelease(cgBuffer);
1338 nativeDraw.EndNativeDrawing();
1339 return;
1340 }
1342 window.clipRect.right = window.width;
1343 window.clipRect.bottom = window.height;
1344 window.type = NPWindowTypeDrawable;
1345 // Setting nsPluginPrint/NPPrint.print.embedPrint.window.window to
1346 // &GWorldPtr and nsPluginPrint/NPPrint.print.embedPrint.platformPrint to
1347 // GWorldPtr isn't any kind of standard (it's not documented anywhere).
1348 // But that's what WebKit does. And it's what the Flash plugin (apparently
1349 // the only NPAPI plugin on OS X to support printing) seems to expect. So
1350 // we do the same. The Flash plugin uses the CoreGraphics drawing mode.
1351 // But a GWorldPtr should be usable in either CoreGraphics or QuickDraw
1352 // drawing mode. See bug 191046.
1353 window.window = &gWorld;
1354 npprint.print.embedPrint.platformPrint = gWorld;
1355 npprint.print.embedPrint.window = window;
1356 pi->Print(&npprint);
1358 ::CGContextTranslateCTM(cgContext, 0.0f, float(window.height));
1359 ::CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1360 CGImageRef image = ::CGBitmapContextCreateImage(cgBuffer);
1361 if (!image) {
1362 ::CGContextRestoreGState(cgContext);
1363 ::CGContextRelease(cgBuffer);
1364 ::DisposeGWorld(gWorld);
1365 nativeDraw.EndNativeDrawing();
1366 return;
1367 }
1368 ::CGContextDrawImage(cgContext,
1369 ::CGRectMake(0, 0, window.width, window.height),
1370 image);
1371 ::CGImageRelease(image);
1372 ::CGContextRelease(cgBuffer);
1374 ::DisposeGWorld(gWorld);
1376 nativeDraw.EndNativeDrawing();
1377 #pragma clang diagnostic warning "-Wdeprecated-declarations"
1378 #elif defined(XP_UNIX)
1380 /* XXX this just flat-out doesn't work in a thebes world --
1381 * RenderEPS is a no-op. So don't bother to do any work here.
1382 */
1383 (void)window;
1384 (void)npprint;
1386 #elif defined(XP_WIN)
1388 /* On Windows, we use the win32 printing surface to print. This, in
1389 * turn, uses the Cairo paginated surface, which in turn uses the
1390 * meta surface to record all operations and then play them back.
1391 * This doesn't work too well for plugins, because if plugins render
1392 * directly into the DC, the meta surface won't have any knowledge
1393 * of them, and so at the end when it actually does the replay step,
1394 * it'll fill the background with white and draw over whatever was
1395 * rendered before.
1396 *
1397 * So, to avoid this, we use PushGroup, which creates a new windows
1398 * surface, the plugin renders to that, and then we use normal
1399 * cairo methods to composite that in such that it's recorded using the
1400 * meta surface.
1401 */
1403 /* we'll already be translated into the right spot by gfxWindowsNativeDrawing */
1404 nsSize contentSize = GetContentRectRelativeToSelf().Size();
1405 window.x = 0;
1406 window.y = 0;
1407 window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1408 window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1410 gfxContext *ctx = aRenderingContext.ThebesContext();
1412 ctx->Save();
1414 /* Make sure plugins don't do any damage outside of where they're supposed to */
1415 ctx->NewPath();
1416 gfxRect r(window.x, window.y, window.width, window.height);
1417 ctx->Rectangle(r);
1418 ctx->Clip();
1420 gfxWindowsNativeDrawing nativeDraw(ctx, r);
1421 do {
1422 HDC dc = nativeDraw.BeginNativeDrawing();
1423 if (!dc)
1424 return;
1426 // XXX don't we need to call nativeDraw.TransformToNativeRect here?
1427 npprint.print.embedPrint.platformPrint = dc;
1428 npprint.print.embedPrint.window = window;
1429 // send off print info to plugin
1430 pi->Print(&npprint);
1432 nativeDraw.EndNativeDrawing();
1433 } while (nativeDraw.ShouldRenderAgain());
1434 nativeDraw.PaintToContext();
1436 ctx->Restore();
1437 #endif
1439 // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
1440 // XXX Calling DidReflow here makes no sense!!!
1441 nsDidReflowStatus status = nsDidReflowStatus::FINISHED; // should we use a special status?
1442 frame->DidReflow(presContext,
1443 nullptr, status); // DidReflow will take care of it
1444 }
1446 nsRect
1447 nsObjectFrame::GetPaintedRect(nsDisplayPlugin* aItem)
1448 {
1449 if (!mInstanceOwner)
1450 return nsRect();
1451 nsRect r = GetContentRectRelativeToSelf();
1452 if (!mInstanceOwner->UseAsyncRendering())
1453 return r;
1455 nsIntSize size = mInstanceOwner->GetCurrentImageSize();
1456 nsPresContext* pc = PresContext();
1457 r.IntersectRect(r, nsRect(0, 0, pc->DevPixelsToAppUnits(size.width),
1458 pc->DevPixelsToAppUnits(size.height)));
1459 return r;
1460 }
1462 LayerState
1463 nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
1464 LayerManager* aManager)
1465 {
1466 if (!mInstanceOwner)
1467 return LAYER_NONE;
1469 #ifdef MOZ_WIDGET_ANDROID
1470 // We always want a layer on Honeycomb and later
1471 if (AndroidBridge::Bridge()->GetAPIVersion() >= 11)
1472 return LAYER_ACTIVE;
1473 #endif
1475 if (!mInstanceOwner->UseAsyncRendering()) {
1476 return LAYER_NONE;
1477 }
1479 return LAYER_ACTIVE;
1480 }
1482 already_AddRefed<Layer>
1483 nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
1484 LayerManager* aManager,
1485 nsDisplayItem* aItem,
1486 const ContainerLayerParameters& aContainerParameters)
1487 {
1488 if (!mInstanceOwner)
1489 return nullptr;
1491 NPWindow* window = nullptr;
1492 mInstanceOwner->GetWindow(window);
1493 if (!window)
1494 return nullptr;
1496 if (window->width <= 0 || window->height <= 0)
1497 return nullptr;
1499 // window is in "display pixels", but size needs to be in device pixels
1500 double scaleFactor = 1.0;
1501 if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
1502 scaleFactor = 1.0;
1503 }
1504 int intScaleFactor = ceil(scaleFactor);
1505 IntSize size(window->width * intScaleFactor, window->height * intScaleFactor);
1507 nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
1508 gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
1509 // to provide crisper and faster drawing.
1510 r.Round();
1511 nsRefPtr<Layer> layer =
1512 (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
1514 if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
1515 // Create image
1516 nsRefPtr<ImageContainer> container = mInstanceOwner->GetImageContainer();
1517 if (!container) {
1518 // This can occur if our instance is gone.
1519 return nullptr;
1520 }
1522 if (!layer) {
1523 mInstanceOwner->NotifyPaintWaiter(aBuilder);
1524 // Initialize ImageLayer
1525 layer = aManager->CreateImageLayer();
1526 if (!layer)
1527 return nullptr;
1528 }
1530 NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
1531 ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
1532 #ifdef XP_MACOSX
1533 if (!mInstanceOwner->UseAsyncRendering()) {
1534 mInstanceOwner->DoCocoaEventDrawRect(r, nullptr);
1535 }
1536 #endif
1538 imglayer->SetScaleToSize(size, ScaleMode::STRETCH);
1539 imglayer->SetContainer(container);
1540 GraphicsFilter filter =
1541 nsLayoutUtils::GetGraphicsFilterForFrame(this);
1542 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
1543 if (!aManager->IsCompositingCheap()) {
1544 // Pixman just horrible with bilinear filter scaling
1545 filter = GraphicsFilter::FILTER_NEAREST;
1546 }
1547 #endif
1548 imglayer->SetFilter(filter);
1550 layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
1551 #ifdef MOZ_WIDGET_ANDROID
1552 } else if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_VIDEO) {
1553 nsDisplayPluginVideo* videoItem = reinterpret_cast<nsDisplayPluginVideo*>(aItem);
1554 nsNPAPIPluginInstance::VideoInfo* videoInfo = videoItem->VideoInfo();
1556 nsRefPtr<ImageContainer> container = mInstanceOwner->GetImageContainerForVideo(videoInfo);
1557 if (!container)
1558 return nullptr;
1560 if (!layer) {
1561 // Initialize ImageLayer
1562 layer = aManager->CreateImageLayer();
1563 if (!layer)
1564 return nullptr;
1565 }
1567 ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
1568 imglayer->SetContainer(container);
1570 layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
1572 // Set the offset and size according to the video dimensions
1573 r.MoveBy(videoInfo->mDimensions.TopLeft());
1574 size.width = videoInfo->mDimensions.width;
1575 size.height = videoInfo->mDimensions.height;
1576 #endif
1577 } else {
1578 NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
1579 "Unknown item type");
1580 NS_ABORT_IF_FALSE(!IsOpaque(), "Opaque plugins don't use backgrounds");
1582 if (!layer) {
1583 layer = aManager->CreateReadbackLayer();
1584 if (!layer)
1585 return nullptr;
1586 }
1587 NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
1589 ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
1590 if (readback->GetSize() != ThebesIntSize(size)) {
1591 // This will destroy any old background sink and notify us that the
1592 // background is now unknown
1593 readback->SetSink(nullptr);
1594 readback->SetSize(ThebesIntSize(size));
1596 if (mBackgroundSink) {
1597 // Maybe we still have a background sink associated with another
1598 // readback layer that wasn't recycled for some reason? Unhook it
1599 // now so that if this frame goes away, it doesn't have a dangling
1600 // reference to us.
1601 mBackgroundSink->Destroy();
1602 }
1603 mBackgroundSink =
1604 new PluginBackgroundSink(this,
1605 readback->AllocateSequenceNumber());
1606 readback->SetSink(mBackgroundSink);
1607 // The layer has taken ownership of our sink. When either the sink dies
1608 // or the frame dies, the connection from the surviving object is nulled out.
1609 }
1610 }
1612 // Set a transform on the layer to draw the plugin in the right place
1613 Matrix transform;
1614 gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
1615 transform.Translate(p.x, p.y);
1617 layer->SetBaseTransform(Matrix4x4::From2D(transform));
1618 layer->SetVisibleRegion(ThebesIntRect(IntRect(IntPoint(0, 0), size)));
1619 return layer.forget();
1620 }
1622 void
1623 nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
1624 nsRenderingContext& aRenderingContext,
1625 const nsRect& aDirtyRect, const nsRect& aPluginRect)
1626 {
1627 #if defined(MOZ_WIDGET_ANDROID)
1628 if (mInstanceOwner) {
1629 gfxRect frameGfxRect =
1630 PresContext()->AppUnitsToGfxUnits(aPluginRect);
1631 gfxRect dirtyGfxRect =
1632 PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1634 gfxContext* ctx = aRenderingContext.ThebesContext();
1636 mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect);
1637 return;
1638 }
1639 #endif
1641 // Screen painting code
1642 #if defined(XP_MACOSX)
1643 // delegate all painting to the plugin instance.
1644 if (mInstanceOwner) {
1645 if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics ||
1646 mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
1647 mInstanceOwner->GetDrawingModel() ==
1648 NPDrawingModelInvalidatingCoreAnimation) {
1649 int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
1650 // Clip to the content area where the plugin should be drawn. If
1651 // we don't do this, the plugin can draw outside its bounds.
1652 nsIntRect contentPixels = aPluginRect.ToNearestPixels(appUnitsPerDevPixel);
1653 nsIntRect dirtyPixels = aDirtyRect.ToOutsidePixels(appUnitsPerDevPixel);
1654 nsIntRect clipPixels;
1655 clipPixels.IntersectRect(contentPixels, dirtyPixels);
1657 // Don't invoke the drawing code if the clip is empty.
1658 if (clipPixels.IsEmpty())
1659 return;
1661 gfxRect nativeClipRect(clipPixels.x, clipPixels.y,
1662 clipPixels.width, clipPixels.height);
1663 gfxContext* ctx = aRenderingContext.ThebesContext();
1665 gfxContextAutoSaveRestore save(ctx);
1666 ctx->NewPath();
1667 ctx->Rectangle(nativeClipRect);
1668 ctx->Clip();
1669 gfxPoint offset(contentPixels.x, contentPixels.y);
1670 ctx->Translate(offset);
1672 gfxQuartzNativeDrawing nativeDrawing(ctx, nativeClipRect - offset);
1674 CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
1675 if (!cgContext) {
1676 NS_WARNING("null CGContextRef during PaintPlugin");
1677 return;
1678 }
1680 nsRefPtr<nsNPAPIPluginInstance> inst;
1681 GetPluginInstance(getter_AddRefs(inst));
1682 if (!inst) {
1683 NS_WARNING("null plugin instance during PaintPlugin");
1684 nativeDrawing.EndNativeDrawing();
1685 return;
1686 }
1687 NPWindow* window;
1688 mInstanceOwner->GetWindow(window);
1689 if (!window) {
1690 NS_WARNING("null plugin window during PaintPlugin");
1691 nativeDrawing.EndNativeDrawing();
1692 return;
1693 }
1694 NP_CGContext* cgPluginPortCopy =
1695 static_cast<NP_CGContext*>(mInstanceOwner->GetPluginPortCopy());
1696 if (!cgPluginPortCopy) {
1697 NS_WARNING("null plugin port copy during PaintPlugin");
1698 nativeDrawing.EndNativeDrawing();
1699 return;
1700 }
1702 mInstanceOwner->BeginCGPaint();
1703 if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
1704 mInstanceOwner->GetDrawingModel() ==
1705 NPDrawingModelInvalidatingCoreAnimation) {
1706 // CoreAnimation is updated, render the layer and perform a readback.
1707 mInstanceOwner->RenderCoreAnimation(cgContext, window->width, window->height);
1708 } else {
1709 mInstanceOwner->Paint(nativeClipRect - offset, cgContext);
1710 }
1711 mInstanceOwner->EndCGPaint();
1713 nativeDrawing.EndNativeDrawing();
1714 } else {
1715 // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
1716 nsRenderingContext::AutoPushTranslation
1717 translate(&aRenderingContext, aPluginRect.TopLeft());
1719 // this rect is used only in the CoreGraphics drawing model
1720 gfxRect tmpRect(0, 0, 0, 0);
1721 mInstanceOwner->Paint(tmpRect, nullptr);
1722 }
1723 }
1724 #elif defined(MOZ_X11)
1725 if (mInstanceOwner) {
1726 NPWindow *window;
1727 mInstanceOwner->GetWindow(window);
1728 if (window->type == NPWindowTypeDrawable) {
1729 gfxRect frameGfxRect =
1730 PresContext()->AppUnitsToGfxUnits(aPluginRect);
1731 gfxRect dirtyGfxRect =
1732 PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1733 gfxContext* ctx = aRenderingContext.ThebesContext();
1735 mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect);
1736 }
1737 }
1738 #elif defined(XP_WIN)
1739 nsRefPtr<nsNPAPIPluginInstance> inst;
1740 GetPluginInstance(getter_AddRefs(inst));
1741 if (inst) {
1742 gfxRect frameGfxRect =
1743 PresContext()->AppUnitsToGfxUnits(aPluginRect);
1744 gfxRect dirtyGfxRect =
1745 PresContext()->AppUnitsToGfxUnits(aDirtyRect);
1746 gfxContext *ctx = aRenderingContext.ThebesContext();
1747 gfxMatrix currentMatrix = ctx->CurrentMatrix();
1749 if (ctx->UserToDevicePixelSnapped(frameGfxRect, false)) {
1750 dirtyGfxRect = ctx->UserToDevice(dirtyGfxRect);
1751 ctx->IdentityMatrix();
1752 }
1753 dirtyGfxRect.RoundOut();
1755 // Look if it's windowless
1756 NPWindow *window;
1757 mInstanceOwner->GetWindow(window);
1759 if (window->type == NPWindowTypeDrawable) {
1760 // the offset of the DC
1761 nsPoint origin;
1763 gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect);
1764 if (nativeDraw.IsDoublePass()) {
1765 // OOP plugin specific: let the shim know before we paint if we are doing a
1766 // double pass render. If this plugin isn't oop, the register window message
1767 // will be ignored.
1768 NPEvent pluginEvent;
1769 pluginEvent.event = plugins::DoublePassRenderingEvent();
1770 pluginEvent.wParam = 0;
1771 pluginEvent.lParam = 0;
1772 if (pluginEvent.event)
1773 inst->HandleEvent(&pluginEvent, nullptr);
1774 }
1775 do {
1776 HDC hdc = nativeDraw.BeginNativeDrawing();
1777 if (!hdc)
1778 return;
1780 RECT dest;
1781 nativeDraw.TransformToNativeRect(frameGfxRect, dest);
1782 RECT dirty;
1783 nativeDraw.TransformToNativeRect(dirtyGfxRect, dirty);
1785 window->window = hdc;
1786 window->x = dest.left;
1787 window->y = dest.top;
1788 window->clipRect.left = 0;
1789 window->clipRect.top = 0;
1790 // if we're painting, we're visible.
1791 window->clipRect.right = window->width;
1792 window->clipRect.bottom = window->height;
1794 // Windowless plugins on windows need a special event to update their location,
1795 // see bug 135737.
1796 //
1797 // bug 271442: note, the rectangle we send is now purely the bounds of the plugin
1798 // relative to the window it is contained in, which is useful for the plugin to
1799 // correctly translate mouse coordinates.
1800 //
1801 // this does not mesh with the comments for bug 135737 which imply that the rectangle
1802 // must be clipped in some way to prevent the plugin attempting to paint over areas
1803 // it shouldn't.
1804 //
1805 // since the two uses of the rectangle are mutually exclusive in some cases, and
1806 // since I don't see any incorrect painting (at least with Flash and ViewPoint -
1807 // the originator of bug 135737), it seems that windowless plugins are not relying
1808 // on information here for clipping their drawing, and we can safely use this message
1809 // to tell the plugin exactly where it is in all cases.
1811 nsIntPoint origin = GetWindowOriginInPixels(true);
1812 nsIntRect winlessRect = nsIntRect(origin, nsIntSize(window->width, window->height));
1814 if (!mWindowlessRect.IsEqualEdges(winlessRect)) {
1815 mWindowlessRect = winlessRect;
1817 WINDOWPOS winpos;
1818 memset(&winpos, 0, sizeof(winpos));
1819 winpos.x = mWindowlessRect.x;
1820 winpos.y = mWindowlessRect.y;
1821 winpos.cx = mWindowlessRect.width;
1822 winpos.cy = mWindowlessRect.height;
1824 // finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event
1825 NPEvent pluginEvent;
1826 pluginEvent.event = WM_WINDOWPOSCHANGED;
1827 pluginEvent.wParam = 0;
1828 pluginEvent.lParam = (LPARAM)&winpos;
1829 inst->HandleEvent(&pluginEvent, nullptr);
1830 }
1832 inst->SetWindow(window);
1834 mInstanceOwner->Paint(dirty, hdc);
1835 nativeDraw.EndNativeDrawing();
1836 } while (nativeDraw.ShouldRenderAgain());
1837 nativeDraw.PaintToContext();
1838 }
1840 ctx->SetMatrix(currentMatrix);
1841 }
1842 #endif
1843 }
1845 nsresult
1846 nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
1847 WidgetGUIEvent* anEvent,
1848 nsEventStatus* anEventStatus)
1849 {
1850 NS_ENSURE_ARG_POINTER(anEvent);
1851 NS_ENSURE_ARG_POINTER(anEventStatus);
1852 nsresult rv = NS_OK;
1854 if (!mInstanceOwner)
1855 return NS_ERROR_NULL_POINTER;
1857 mInstanceOwner->ConsiderNewEventloopNestingLevel();
1859 if (anEvent->message == NS_PLUGIN_ACTIVATE) {
1860 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1861 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(GetContent());
1862 if (fm && elem)
1863 return fm->SetFocus(elem, 0);
1864 }
1865 else if (anEvent->message == NS_PLUGIN_FOCUS) {
1866 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1867 if (fm)
1868 return fm->FocusPlugin(GetContent());
1869 }
1871 #ifdef XP_MACOSX
1872 if (anEvent->message == NS_PLUGIN_RESOLUTION_CHANGED) {
1873 double scaleFactor = 1.0;
1874 mInstanceOwner->GetContentsScaleFactor(&scaleFactor);
1875 mInstanceOwner->ContentsScaleFactorChanged(scaleFactor);
1876 return NS_OK;
1877 }
1878 #endif
1880 if (mInstanceOwner->SendNativeEvents() &&
1881 anEvent->IsNativeEventDelivererForPlugin()) {
1882 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
1883 // Due to plugin code reentering Gecko, this frame may be dead at this
1884 // point.
1885 return rv;
1886 }
1888 #ifdef XP_WIN
1889 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
1890 return rv;
1891 #endif
1893 #ifdef XP_MACOSX
1894 // we want to process some native mouse events in the cocoa event model
1895 if ((anEvent->message == NS_MOUSE_ENTER ||
1896 anEvent->message == NS_WHEEL_WHEEL) &&
1897 mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
1898 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
1899 // Due to plugin code reentering Gecko, this frame may be dead at this
1900 // point.
1901 return rv;
1902 }
1904 // These two calls to nsIPresShell::SetCapturingContext() (on mouse-down
1905 // and mouse-up) are needed to make the routing of mouse events while
1906 // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec.
1907 // See bug 525078 and bug 909678.
1908 if (anEvent->message == NS_MOUSE_BUTTON_DOWN) {
1909 nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
1910 }
1911 #endif
1913 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
1915 // We need to be careful from this point because the call to
1916 // nsObjectFrameSuper::HandleEvent() might have killed us.
1918 #ifdef XP_MACOSX
1919 if (anEvent->message == NS_MOUSE_BUTTON_UP) {
1920 nsIPresShell::SetCapturingContent(nullptr, 0);
1921 }
1922 #endif
1924 return rv;
1925 }
1927 nsresult
1928 nsObjectFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
1929 {
1930 *aPluginInstance = nullptr;
1932 if (!mInstanceOwner) {
1933 return NS_OK;
1934 }
1936 return mInstanceOwner->GetInstance(aPluginInstance);
1937 }
1939 nsresult
1940 nsObjectFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor)
1941 {
1942 if (!mInstanceOwner) {
1943 return NS_ERROR_FAILURE;
1944 }
1946 nsRefPtr<nsNPAPIPluginInstance> inst;
1947 mInstanceOwner->GetInstance(getter_AddRefs(inst));
1948 if (!inst) {
1949 return NS_ERROR_FAILURE;
1950 }
1952 bool useDOMCursor = static_cast<nsNPAPIPluginInstance*>(inst.get())->UsesDOMForCursor();
1953 if (!useDOMCursor) {
1954 return NS_ERROR_FAILURE;
1955 }
1957 return nsObjectFrameSuper::GetCursor(aPoint, aCursor);
1958 }
1960 void
1961 nsObjectFrame::SetIsDocumentActive(bool aIsActive)
1962 {
1963 #ifndef XP_MACOSX
1964 if (mInstanceOwner) {
1965 mInstanceOwner->UpdateDocumentActiveState(aIsActive);
1966 }
1967 #endif
1968 }
1970 // static
1971 nsIObjectFrame *
1972 nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
1973 {
1974 nsIFrame* child = aRoot->GetFirstPrincipalChild();
1976 while (child) {
1977 nsIObjectFrame* outFrame = do_QueryFrame(child);
1978 if (outFrame) {
1979 nsRefPtr<nsNPAPIPluginInstance> pi;
1980 outFrame->GetPluginInstance(getter_AddRefs(pi)); // make sure we have a REAL plugin
1981 if (pi)
1982 return outFrame;
1983 }
1985 outFrame = GetNextObjectFrame(aPresContext, child);
1986 if (outFrame)
1987 return outFrame;
1988 child = child->GetNextSibling();
1989 }
1991 return nullptr;
1992 }
1994 /*static*/ void
1995 nsObjectFrame::BeginSwapDocShells(nsIContent* aContent, void*)
1996 {
1997 NS_PRECONDITION(aContent, "");
1999 // This function is called from a document content enumerator so we need
2000 // to filter out the nsObjectFrames and ignore the rest.
2001 nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame());
2002 if (!obj)
2003 return;
2005 nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
2006 NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(),
2007 "Plugin windows must not be toplevel");
2008 objectFrame->UnregisterPluginForGeometryUpdates();
2009 }
2011 /*static*/ void
2012 nsObjectFrame::EndSwapDocShells(nsIContent* aContent, void*)
2013 {
2014 NS_PRECONDITION(aContent, "");
2016 // This function is called from a document content enumerator so we need
2017 // to filter out the nsObjectFrames and ignore the rest.
2018 nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame());
2019 if (!obj)
2020 return;
2022 nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
2023 nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
2024 NS_ASSERTION(rootPC, "unable to register the plugin frame");
2025 nsIWidget* widget = objectFrame->mWidget;
2026 if (widget) {
2027 // Reparent the widget.
2028 nsIWidget* parent =
2029 rootPC->PresShell()->GetRootFrame()->GetNearestWidget();
2030 widget->SetParent(parent);
2031 nsWeakFrame weakFrame(objectFrame);
2032 objectFrame->CallSetWindow();
2033 if (!weakFrame.IsAlive()) {
2034 return;
2035 }
2036 }
2038 #ifdef XP_MACOSX
2039 if (objectFrame->mWidget) {
2040 objectFrame->RegisterPluginForGeometryUpdates();
2041 }
2042 #else
2043 objectFrame->RegisterPluginForGeometryUpdates();
2044 #endif
2045 }
2047 nsIFrame*
2048 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
2049 {
2050 return new (aPresShell) nsObjectFrame(aContext);
2051 }
2053 bool
2054 nsObjectFrame::IsPaintedByGecko() const
2055 {
2056 #ifdef XP_MACOSX
2057 return true;
2058 #else
2059 return !mWidget;
2060 #endif
2061 }
2063 NS_IMPL_FRAMEARENA_HELPERS(nsObjectFrame)