michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: // vim:set ts=2 sts=2 sw=2 et cin: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* rendering objects for replaced elements implemented by a plugin */ michael@0: michael@0: #include "nsObjectFrame.h" michael@0: michael@0: #include "gfx2DGlue.h" michael@0: #include "mozilla/BasicEvents.h" michael@0: #ifdef XP_WIN michael@0: // This is needed for DoublePassRenderingEvent. michael@0: #include "mozilla/plugins/PluginMessageUtils.h" michael@0: #endif michael@0: michael@0: #include "nscore.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsView.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsString.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsIPluginInstanceOwner.h" michael@0: #include "nsNPAPIPluginInstance.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "npapi.h" michael@0: #include "nsIObjectLoadingContent.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsFocusManager.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "nsFrameManager.h" michael@0: #include "nsIObserverService.h" michael@0: #include "GeckoProfiler.h" michael@0: #include michael@0: michael@0: #include "nsIObjectFrame.h" michael@0: #include "nsPluginNativeWindow.h" michael@0: #include "FrameLayerBuilder.h" michael@0: michael@0: #include "ImageLayers.h" michael@0: #include "nsPluginInstanceOwner.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include "gfxWindowsNativeDrawing.h" michael@0: #include "gfxWindowsSurface.h" michael@0: #endif michael@0: michael@0: #include "Layers.h" michael@0: #include "ReadbackLayer.h" michael@0: #include "ImageContainer.h" michael@0: michael@0: // accessibility support michael@0: #ifdef ACCESSIBILITY michael@0: #include "nsAccessibilityService.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG 1 /* Allow logging in the release build */ michael@0: #endif /* MOZ_LOGGING */ michael@0: #include "prlog.h" michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include "gfxQuartzNativeDrawing.h" michael@0: #include "nsPluginUtilsOSX.h" michael@0: #include "mozilla/gfx/QuartzSupport.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_X11 michael@0: #include "mozilla/X11Util.h" michael@0: using mozilla::DefaultXDisplay; michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "AndroidBridge.h" michael@0: #include "GLContext.h" michael@0: #endif michael@0: michael@0: #ifdef CreateEvent // Thank you MS. michael@0: #undef CreateEvent michael@0: #endif michael@0: michael@0: #ifdef PR_LOGGING michael@0: static PRLogModuleInfo * michael@0: GetObjectFrameLog() michael@0: { michael@0: static PRLogModuleInfo *sLog; michael@0: if (!sLog) michael@0: sLog = PR_NewLogModule("nsObjectFrame"); michael@0: return sLog; michael@0: } michael@0: #endif /* PR_LOGGING */ michael@0: michael@0: #if defined(XP_MACOSX) && !defined(__LP64__) michael@0: michael@0: // The header files QuickdrawAPI.h and QDOffscreen.h are missing on OS X 10.7 michael@0: // and up (though the QuickDraw APIs defined in them are still present) -- so michael@0: // we need to supply the relevant parts of their contents here. It's likely michael@0: // that Apple will eventually remove the APIs themselves (probably in OS X michael@0: // 10.8), so we need to make them weak imports, and test for their presence michael@0: // before using them. michael@0: extern "C" { michael@0: #if !defined(__QUICKDRAWAPI__) michael@0: extern void SetRect( michael@0: Rect * r, michael@0: short left, michael@0: short top, michael@0: short right, michael@0: short bottom) michael@0: __attribute__((weak_import)); michael@0: #endif /* __QUICKDRAWAPI__ */ michael@0: michael@0: #if !defined(__QDOFFSCREEN__) michael@0: extern QDErr NewGWorldFromPtr( michael@0: GWorldPtr * offscreenGWorld, michael@0: UInt32 PixelFormat, michael@0: const Rect * boundsRect, michael@0: CTabHandle cTable, /* can be nullptr */ michael@0: GDHandle aGDevice, /* can be nullptr */ michael@0: GWorldFlags flags, michael@0: Ptr newBuffer, michael@0: SInt32 rowBytes) michael@0: __attribute__((weak_import)); michael@0: extern void DisposeGWorld(GWorldPtr offscreenGWorld) michael@0: __attribute__((weak_import)); michael@0: #endif /* __QDOFFSCREEN__ */ michael@0: } michael@0: michael@0: #endif /* #if defined(XP_MACOSX) && !defined(__LP64__) */ michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::gfx; michael@0: using namespace mozilla::layers; michael@0: michael@0: class PluginBackgroundSink : public ReadbackSink { michael@0: public: michael@0: PluginBackgroundSink(nsObjectFrame* aFrame, uint64_t aStartSequenceNumber) michael@0: : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {} michael@0: ~PluginBackgroundSink() michael@0: { michael@0: if (mFrame) { michael@0: mFrame->mBackgroundSink = nullptr; michael@0: } michael@0: } michael@0: michael@0: virtual void SetUnknown(uint64_t aSequenceNumber) michael@0: { michael@0: if (!AcceptUpdate(aSequenceNumber)) michael@0: return; michael@0: mFrame->mInstanceOwner->SetBackgroundUnknown(); michael@0: } michael@0: michael@0: virtual already_AddRefed michael@0: BeginUpdate(const nsIntRect& aRect, uint64_t aSequenceNumber) michael@0: { michael@0: if (!AcceptUpdate(aSequenceNumber)) michael@0: return nullptr; michael@0: return mFrame->mInstanceOwner->BeginUpdateBackground(aRect); michael@0: } michael@0: michael@0: virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect) michael@0: { michael@0: return mFrame->mInstanceOwner->EndUpdateBackground(aContext, aRect); michael@0: } michael@0: michael@0: void Destroy() { mFrame = nullptr; } michael@0: michael@0: protected: michael@0: bool AcceptUpdate(uint64_t aSequenceNumber) { michael@0: if (aSequenceNumber > mLastSequenceNumber && mFrame && michael@0: mFrame->mInstanceOwner) { michael@0: mLastSequenceNumber = aSequenceNumber; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: uint64_t mLastSequenceNumber; michael@0: nsObjectFrame* mFrame; michael@0: }; michael@0: michael@0: nsObjectFrame::nsObjectFrame(nsStyleContext* aContext) michael@0: : nsObjectFrameSuper(aContext) michael@0: , mReflowCallbackPosted(false) michael@0: { michael@0: PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG, michael@0: ("Created new nsObjectFrame %p\n", this)); michael@0: } michael@0: michael@0: nsObjectFrame::~nsObjectFrame() michael@0: { michael@0: PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG, michael@0: ("nsObjectFrame %p deleted\n", this)); michael@0: } michael@0: michael@0: NS_QUERYFRAME_HEAD(nsObjectFrame) michael@0: NS_QUERYFRAME_ENTRY(nsObjectFrame) michael@0: NS_QUERYFRAME_ENTRY(nsIObjectFrame) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsObjectFrameSuper) michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: a11y::AccType michael@0: nsObjectFrame::AccessibleType() michael@0: { michael@0: return a11y::ePluginType; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort) michael@0: { michael@0: *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget(); michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: #endif michael@0: michael@0: void michael@0: nsObjectFrame::Init(nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) michael@0: { michael@0: PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG, michael@0: ("Initializing nsObjectFrame %p for content %p\n", this, aContent)); michael@0: michael@0: nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow); michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot) michael@0: { michael@0: if (mReflowCallbackPosted) { michael@0: PresContext()->PresShell()->CancelReflowCallback(this); michael@0: } michael@0: michael@0: // Tell content owner of the instance to disconnect its frame. michael@0: nsCOMPtr objContent(do_QueryInterface(mContent)); michael@0: NS_ASSERTION(objContent, "Why not an object loading content?"); michael@0: michael@0: // The content might not have a reference to the instance owner any longer in michael@0: // the case of re-entry during instantiation or teardown, so make sure we're michael@0: // dissociated. michael@0: if (mInstanceOwner) { michael@0: mInstanceOwner->SetFrame(nullptr); michael@0: } michael@0: objContent->HasNewFrame(nullptr); michael@0: michael@0: if (mBackgroundSink) { michael@0: mBackgroundSink->Destroy(); michael@0: } michael@0: michael@0: nsObjectFrameSuper::DestroyFrom(aDestructRoot); michael@0: } michael@0: michael@0: /* virtual */ void michael@0: nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) michael@0: { michael@0: if (HasView()) { michael@0: nsView* view = GetView(); michael@0: nsViewManager* vm = view->GetViewManager(); michael@0: if (vm) { michael@0: nsViewVisibility visibility = michael@0: IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow; michael@0: vm->SetViewVisibility(view, visibility); michael@0: } michael@0: } michael@0: michael@0: nsObjectFrameSuper::DidSetStyleContext(aOldStyleContext); michael@0: } michael@0: michael@0: nsIAtom* michael@0: nsObjectFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::objectFrame; michael@0: } michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: nsresult michael@0: nsObjectFrame::GetFrameName(nsAString& aResult) const michael@0: { michael@0: return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult); michael@0: } michael@0: #endif michael@0: michael@0: nsresult michael@0: nsObjectFrame::PrepForDrawing(nsIWidget *aWidget) michael@0: { michael@0: mWidget = aWidget; michael@0: michael@0: nsView* view = GetView(); michael@0: NS_ASSERTION(view, "Object frames must have views"); michael@0: if (!view) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsViewManager* viewMan = view->GetViewManager(); michael@0: // mark the view as hidden since we don't know the (x,y) until Paint michael@0: // XXX is the above comment correct? michael@0: viewMan->SetViewVisibility(view, nsViewVisibility_kHide); michael@0: michael@0: //this is ugly. it was ripped off from didreflow(). MMP michael@0: // Position and size view relative to its parent, not relative to our michael@0: // parent frame (our parent frame may not have a view). michael@0: michael@0: nsView* parentWithView; michael@0: nsPoint origin; michael@0: nsRect r(0, 0, mRect.width, mRect.height); michael@0: michael@0: GetOffsetFromView(origin, &parentWithView); michael@0: viewMan->ResizeView(view, r); michael@0: viewMan->MoveViewTo(view, origin.x, origin.y); michael@0: michael@0: nsPresContext* presContext = PresContext(); michael@0: nsRootPresContext* rpc = presContext->GetRootPresContext(); michael@0: if (!rpc) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (mWidget) { michael@0: // Disallow windowed plugins in popups michael@0: nsIFrame* rootFrame = rpc->PresShell()->FrameManager()->GetRootFrame(); michael@0: nsIWidget* parentWidget = rootFrame->GetNearestWidget(); michael@0: if (!parentWidget || nsLayoutUtils::GetDisplayRootFrame(this) != rootFrame) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view); michael@0: if (!mInnerView) { michael@0: NS_ERROR("Could not create inner view"); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: viewMan->InsertChild(view, mInnerView, nullptr, true); michael@0: michael@0: mWidget->SetParent(parentWidget); michael@0: mWidget->Show(true); michael@0: mWidget->Enable(true); michael@0: michael@0: // Set the plugin window to have an empty clip region until we know michael@0: // what our true position, size and clip region are. These michael@0: // will be reset when nsRootPresContext computes our true michael@0: // geometry. The plugin window does need to have a good size here, so michael@0: // set the size explicitly to a reasonable guess. michael@0: nsAutoTArray configurations; michael@0: nsIWidget::Configuration* configuration = configurations.AppendElement(); michael@0: nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); michael@0: configuration->mChild = mWidget; michael@0: configuration->mBounds.width = NSAppUnitsToIntPixels(mRect.width, appUnitsPerDevPixel); michael@0: configuration->mBounds.height = NSAppUnitsToIntPixels(mRect.height, appUnitsPerDevPixel); michael@0: parentWidget->ConfigureChildren(configurations); michael@0: michael@0: nsRefPtr dx = viewMan->GetDeviceContext(); michael@0: mInnerView->AttachWidgetEventHandler(mWidget); michael@0: michael@0: #ifdef XP_MACOSX michael@0: // On Mac, we need to invalidate ourselves since even windowed michael@0: // plugins are painted through Thebes and we need to ensure michael@0: // the Thebes layer containing the plugin is updated. michael@0: if (parentWidget == GetNearestWidget()) { michael@0: InvalidateFrame(); michael@0: } michael@0: #endif michael@0: michael@0: RegisterPluginForGeometryUpdates(); michael@0: michael@0: // Here we set the background color for this widget because some plugins will use michael@0: // the child window background color when painting. If it's not set, it may default to gray michael@0: // Sometimes, a frame doesn't have a background color or is transparent. In this michael@0: // case, walk up the frame tree until we do find a frame with a background color michael@0: for (nsIFrame* frame = this; frame; frame = frame->GetParent()) { michael@0: nscolor bgcolor = michael@0: frame->GetVisitedDependentColor(eCSSProperty_background_color); michael@0: if (NS_GET_A(bgcolor) > 0) { // make sure we got an actual color michael@0: mWidget->SetBackgroundColor(bgcolor); michael@0: break; michael@0: } michael@0: } michael@0: } else { michael@0: // Changing to windowless mode changes the NPWindow geometry. michael@0: FixupWindow(GetContentRectRelativeToSelf().Size()); michael@0: michael@0: #ifndef XP_MACOSX michael@0: RegisterPluginForGeometryUpdates(); michael@0: #endif michael@0: } michael@0: michael@0: if (!IsHidden()) { michael@0: viewMan->SetViewVisibility(view, nsViewVisibility_kShow); michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: nsAccessibilityService* accService = nsIPresShell::AccService(); michael@0: if (accService) { michael@0: accService->RecreateAccessible(PresContext()->PresShell(), mContent); michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: #define EMBED_DEF_WIDTH 240 michael@0: #define EMBED_DEF_HEIGHT 200 michael@0: michael@0: /* virtual */ nscoord michael@0: nsObjectFrame::GetMinWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result = 0; michael@0: michael@0: if (!IsHidden(false)) { michael@0: nsIAtom *atom = mContent->Tag(); michael@0: if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) { michael@0: result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH); michael@0: } michael@0: } michael@0: michael@0: DISPLAY_MIN_WIDTH(this, result); michael@0: return result; michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: nsObjectFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: return nsObjectFrame::GetMinWidth(aRenderingContext); michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsHTMLReflowMetrics& aMetrics) michael@0: { michael@0: // By default, we have no area michael@0: aMetrics.Width() = 0; michael@0: aMetrics.Height() = 0; michael@0: michael@0: if (IsHidden(false)) { michael@0: return; michael@0: } michael@0: michael@0: aMetrics.Width() = aReflowState.ComputedWidth(); michael@0: aMetrics.Height() = aReflowState.ComputedHeight(); michael@0: michael@0: // for EMBED and APPLET, default to 240x200 for compatibility michael@0: nsIAtom *atom = mContent->Tag(); michael@0: if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) { michael@0: if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) { michael@0: aMetrics.Width() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH), michael@0: aReflowState.ComputedMinWidth(), michael@0: aReflowState.ComputedMaxWidth()); michael@0: } michael@0: if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) { michael@0: aMetrics.Height() = clamped(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT), michael@0: aReflowState.ComputedMinHeight(), michael@0: aReflowState.ComputedMaxHeight()); michael@0: } michael@0: michael@0: #if defined(MOZ_WIDGET_GTK) michael@0: // We need to make sure that the size of the object frame does not michael@0: // exceed the maximum size of X coordinates. See bug #225357 for michael@0: // more information. In theory Gtk2 can handle large coordinates, michael@0: // but underlying plugins can't. michael@0: aMetrics.Height() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Height()); michael@0: aMetrics.Width() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX), aMetrics.Width()); michael@0: #endif michael@0: } michael@0: michael@0: // At this point, the width has an unconstrained value only if we have michael@0: // nothing to go on (no width set, no information from the plugin, nothing). michael@0: // Make up a number. michael@0: if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) { michael@0: aMetrics.Width() = michael@0: (aReflowState.ComputedMinWidth() != NS_UNCONSTRAINEDSIZE) ? michael@0: aReflowState.ComputedMinWidth() : 0; michael@0: } michael@0: michael@0: // At this point, the height has an unconstrained value only in two cases: michael@0: // a) We are in standards mode with percent heights and parent is auto-height michael@0: // b) We have no height information at all. michael@0: // In either case, we have to make up a number. michael@0: if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) { michael@0: aMetrics.Height() = michael@0: (aReflowState.ComputedMinHeight() != NS_UNCONSTRAINEDSIZE) ? michael@0: aReflowState.ComputedMinHeight() : 0; michael@0: } michael@0: michael@0: // XXXbz don't add in the border and padding, because we screw up our michael@0: // plugin's size and positioning if we do... Eventually we _do_ want to michael@0: // paint borders, though! At that point, we will need to adjust the desired michael@0: // size either here or in Reflow.... Further, we will need to fix Paint() to michael@0: // call the superclass in all cases. michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aMetrics, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) michael@0: { michael@0: DO_GLOBAL_REFLOW_COUNT("nsObjectFrame"); michael@0: DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); michael@0: michael@0: // Get our desired size michael@0: GetDesiredSize(aPresContext, aReflowState, aMetrics); michael@0: aMetrics.SetOverflowAreasToDesiredBounds(); michael@0: FinishAndStoreOverflow(&aMetrics); michael@0: michael@0: // delay plugin instantiation until all children have michael@0: // arrived. Otherwise there may be PARAMs or other stuff that the michael@0: // plugin needs to see that haven't arrived yet. michael@0: if (!GetContent()->IsDoneAddingChildren()) { michael@0: aStatus = NS_FRAME_COMPLETE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // if we are printing or print previewing, bail for now michael@0: if (aPresContext->Medium() == nsGkAtoms::print) { michael@0: aStatus = NS_FRAME_COMPLETE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsRect r(0, 0, aMetrics.Width(), aMetrics.Height()); michael@0: r.Deflate(aReflowState.ComputedPhysicalBorderPadding()); michael@0: michael@0: if (mInnerView) { michael@0: nsViewManager* vm = mInnerView->GetViewManager(); michael@0: vm->MoveViewTo(mInnerView, r.x, r.y); michael@0: vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), true); michael@0: } michael@0: michael@0: FixupWindow(r.Size()); michael@0: if (!mReflowCallbackPosted) { michael@0: mReflowCallbackPosted = true; michael@0: aPresContext->PresShell()->PostReflowCallback(this); michael@0: } michael@0: michael@0: aStatus = NS_FRAME_COMPLETE; michael@0: michael@0: NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); michael@0: return NS_OK; michael@0: } michael@0: michael@0: ///////////// nsIReflowCallback /////////////// michael@0: michael@0: bool michael@0: nsObjectFrame::ReflowFinished() michael@0: { michael@0: mReflowCallbackPosted = false; michael@0: CallSetWindow(); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::ReflowCallbackCanceled() michael@0: { michael@0: mReflowCallbackPosted = false; michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::FixupWindow(const nsSize& aSize) michael@0: { michael@0: nsPresContext* presContext = PresContext(); michael@0: michael@0: if (!mInstanceOwner) michael@0: return; michael@0: michael@0: NPWindow *window; michael@0: mInstanceOwner->GetWindow(window); michael@0: michael@0: NS_ENSURE_TRUE_VOID(window); michael@0: michael@0: #ifdef XP_MACOSX michael@0: nsWeakFrame weakFrame(this); michael@0: mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintDisable); michael@0: if (!weakFrame.IsAlive()) { michael@0: return; michael@0: } michael@0: #endif michael@0: michael@0: bool windowless = (window->type == NPWindowTypeDrawable); michael@0: michael@0: nsIntPoint origin = GetWindowOriginInPixels(windowless); michael@0: michael@0: // window must be in "display pixels" michael@0: double scaleFactor = 1.0; michael@0: if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) { michael@0: scaleFactor = 1.0; michael@0: } michael@0: int intScaleFactor = ceil(scaleFactor); michael@0: window->x = origin.x / intScaleFactor; michael@0: window->y = origin.y / intScaleFactor; michael@0: window->width = presContext->AppUnitsToDevPixels(aSize.width) / intScaleFactor; michael@0: window->height = presContext->AppUnitsToDevPixels(aSize.height) / intScaleFactor; michael@0: michael@0: // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep michael@0: // us from drawing on screen until the widget is properly positioned, which will not michael@0: // happen until we have finished the reflow process. michael@0: #ifdef XP_MACOSX michael@0: window->clipRect.top = 0; michael@0: window->clipRect.left = 0; michael@0: window->clipRect.bottom = 0; michael@0: window->clipRect.right = 0; michael@0: #else michael@0: mInstanceOwner->UpdateWindowPositionAndClipRect(false); michael@0: #endif michael@0: michael@0: NotifyPluginReflowObservers(); michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::CallSetWindow(bool aCheckIsHidden) michael@0: { michael@0: NPWindow *win = nullptr; michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: nsRefPtr pi; michael@0: if (!mInstanceOwner || michael@0: NS_FAILED(rv = mInstanceOwner->GetInstance(getter_AddRefs(pi))) || michael@0: !pi || michael@0: NS_FAILED(rv = mInstanceOwner->GetWindow(win)) || michael@0: !win) michael@0: return rv; michael@0: michael@0: nsPluginNativeWindow *window = (nsPluginNativeWindow *)win; michael@0: #ifdef XP_MACOSX michael@0: nsWeakFrame weakFrame(this); michael@0: mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintDisable); michael@0: if (!weakFrame.IsAlive()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: #endif michael@0: michael@0: if (aCheckIsHidden && IsHidden()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // refresh the plugin port as well michael@0: window->window = mInstanceOwner->GetPluginPortFromWidget(); michael@0: michael@0: // Adjust plugin dimensions according to pixel snap results michael@0: // and reduce amount of SetWindow calls michael@0: nsPresContext* presContext = PresContext(); michael@0: nsRootPresContext* rootPC = presContext->GetRootPresContext(); michael@0: if (!rootPC) michael@0: return NS_ERROR_FAILURE; michael@0: int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); michael@0: nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame(); michael@0: nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame); michael@0: nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel); michael@0: michael@0: // window must be in "display pixels" michael@0: double scaleFactor = 1.0; michael@0: if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) { michael@0: scaleFactor = 1.0; michael@0: } michael@0: size_t intScaleFactor = ceil(scaleFactor); michael@0: window->x = intBounds.x / intScaleFactor; michael@0: window->y = intBounds.y / intScaleFactor; michael@0: window->width = intBounds.width / intScaleFactor; michael@0: window->height = intBounds.height / intScaleFactor; michael@0: michael@0: // Calling SetWindow might destroy this frame. We need to use the instance michael@0: // owner to clean up so hold a ref. michael@0: nsRefPtr instanceOwnerRef(mInstanceOwner); michael@0: michael@0: // This will call pi->SetWindow and take care of window subclassing michael@0: // if needed, see bug 132759. Calling SetWindow can destroy this frame michael@0: // so check for that before doing anything else with this frame's memory. michael@0: if (mInstanceOwner->UseAsyncRendering()) { michael@0: rv = pi->AsyncSetWindow(window); michael@0: } michael@0: else { michael@0: rv = window->CallSetWindow(pi); michael@0: } michael@0: michael@0: instanceOwnerRef->ReleasePluginPort(window->window); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::RegisterPluginForGeometryUpdates() michael@0: { michael@0: nsRootPresContext* rpc = PresContext()->GetRootPresContext(); michael@0: NS_ASSERTION(rpc, "We should have a root pres context!"); michael@0: if (mRootPresContextRegisteredWith == rpc || !rpc) { michael@0: // Already registered with current root pres context, michael@0: // or null root pres context... michael@0: return; michael@0: } michael@0: if (mRootPresContextRegisteredWith && mRootPresContextRegisteredWith != rpc) { michael@0: // Registered to some other root pres context. Unregister, and michael@0: // re-register with our current one... michael@0: UnregisterPluginForGeometryUpdates(); michael@0: } michael@0: mRootPresContextRegisteredWith = rpc; michael@0: mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent); michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::UnregisterPluginForGeometryUpdates() michael@0: { michael@0: if (!mRootPresContextRegisteredWith) { michael@0: // Not registered... michael@0: return; michael@0: } michael@0: mRootPresContextRegisteredWith->UnregisterPluginForGeometryUpdates(mContent); michael@0: mRootPresContextRegisteredWith = nullptr; michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner) michael@0: { michael@0: // The ownership model here is historically fuzzy. This should only be called michael@0: // by nsPluginInstanceOwner when it is given a new frame, and michael@0: // nsObjectLoadingContent should be arbitrating frame-ownership via its michael@0: // HasNewFrame callback. michael@0: mInstanceOwner = aOwner; michael@0: if (mInstanceOwner) { michael@0: return; michael@0: } michael@0: UnregisterPluginForGeometryUpdates(); michael@0: if (mWidget && mInnerView) { michael@0: mInnerView->DetachWidgetEventHandler(mWidget); michael@0: // Make sure the plugin is hidden in case an update of plugin geometry michael@0: // hasn't happened since this plugin became hidden. michael@0: nsIWidget* parent = mWidget->GetParent(); michael@0: if (parent) { michael@0: nsTArray configurations; michael@0: nsIWidget::Configuration* configuration = configurations.AppendElement(); michael@0: configuration->mChild = mWidget; michael@0: parent->ConfigureChildren(configurations); michael@0: michael@0: mWidget->Show(false); michael@0: mWidget->Enable(false); michael@0: mWidget->SetParent(nullptr); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsObjectFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse) michael@0: { michael@0: if (aTabIndex) michael@0: *aTabIndex = -1; michael@0: return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse); michael@0: } michael@0: michael@0: bool michael@0: nsObjectFrame::IsHidden(bool aCheckVisibilityStyle) const michael@0: { michael@0: if (aCheckVisibilityStyle) { michael@0: if (!StyleVisibility()->IsVisibleOrCollapsed()) michael@0: return true; michael@0: } michael@0: michael@0: // only tags support the HIDDEN attribute michael@0: if (mContent->Tag() == nsGkAtoms::embed) { michael@0: // Yes, these are really the kooky ways that you could tell 4.x michael@0: // not to hide the once you'd put the 'hidden' attribute michael@0: // on the tag... michael@0: michael@0: // HIDDEN w/ no attributes gets translated as we are hidden for michael@0: // compatibility w/ 4.x and IE so we don't create a non-painting michael@0: // widget in layout. See bug 188959. michael@0: nsAutoString hidden; michael@0: if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) && michael@0: (hidden.IsEmpty() || michael@0: (!hidden.LowerCaseEqualsLiteral("false") && michael@0: !hidden.LowerCaseEqualsLiteral("no") && michael@0: !hidden.LowerCaseEqualsLiteral("off")))) { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: nsIntPoint nsObjectFrame::GetWindowOriginInPixels(bool aWindowless) michael@0: { michael@0: nsView * parentWithView; michael@0: nsPoint origin(0,0); michael@0: michael@0: GetOffsetFromView(origin, &parentWithView); michael@0: michael@0: // if it's windowless, let's make sure we have our origin set right michael@0: // it may need to be corrected, like after scrolling michael@0: if (aWindowless && parentWithView) { michael@0: nsPoint offsetToWidget; michael@0: parentWithView->GetNearestWidget(&offsetToWidget); michael@0: origin += offsetToWidget; michael@0: } michael@0: origin += GetContentRectRelativeToSelf().TopLeft(); michael@0: michael@0: return nsIntPoint(PresContext()->AppUnitsToDevPixels(origin.x), michael@0: PresContext()->AppUnitsToDevPixels(origin.y)); michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::DidReflow(nsPresContext* aPresContext, michael@0: const nsHTMLReflowState* aReflowState, michael@0: nsDidReflowStatus aStatus) michael@0: { michael@0: // Do this check before calling the superclass, as that clears michael@0: // NS_FRAME_FIRST_REFLOW michael@0: if (aStatus == nsDidReflowStatus::FINISHED && michael@0: (GetStateBits() & NS_FRAME_FIRST_REFLOW)) { michael@0: nsCOMPtr objContent(do_QueryInterface(mContent)); michael@0: NS_ASSERTION(objContent, "Why not an object loading content?"); michael@0: objContent->HasNewFrame(this); michael@0: } michael@0: michael@0: nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus); michael@0: michael@0: // The view is created hidden; once we have reflowed it and it has been michael@0: // positioned then we show it. michael@0: if (aStatus != nsDidReflowStatus::FINISHED) michael@0: return rv; michael@0: michael@0: if (HasView()) { michael@0: nsView* view = GetView(); michael@0: nsViewManager* vm = view->GetViewManager(); michael@0: if (vm) michael@0: vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* static */ void michael@0: nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx, michael@0: const nsRect& aDirtyRect, nsPoint aPt) michael@0: { michael@0: nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft(); michael@0: nsRenderingContext::AutoPushTranslation translate(aCtx, pt); michael@0: // FIXME - Bug 385435: Doesn't aDirtyRect need translating too? michael@0: static_cast(aFrame)->PrintPlugin(*aCtx, aDirtyRect); michael@0: } michael@0: michael@0: class nsDisplayPluginReadback : public nsDisplayItem { michael@0: public: michael@0: nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayPluginReadback); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayPluginReadback() { michael@0: MOZ_COUNT_DTOR(nsDisplayPluginReadback); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: michael@0: NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK) michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE michael@0: { michael@0: return static_cast(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters); michael@0: } michael@0: michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return LAYER_ACTIVE; michael@0: } michael@0: }; michael@0: michael@0: static nsRect michael@0: GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame) michael@0: { michael@0: // XXX For slightly more accurate region computations we should pixel-snap this michael@0: return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame(); michael@0: } michael@0: michael@0: nsRect michael@0: nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) michael@0: { michael@0: *aSnap = false; michael@0: return GetDisplayItemBounds(aBuilder, this, mFrame); michael@0: } michael@0: michael@0: bool michael@0: nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) michael@0: { michael@0: if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, michael@0: aAllowVisibleRegionExpansion)) michael@0: return false; michael@0: michael@0: nsRect expand; michael@0: bool snap; michael@0: expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder, &snap)); michael@0: // *Add* our bounds to the visible region so that stuff underneath us is michael@0: // likely to be made visible, so we can use it for a background! This is michael@0: // a bit crazy since we normally only subtract from the visible region. michael@0: aVisibleRegion->Or(*aVisibleRegion, expand); michael@0: return true; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: michael@0: class nsDisplayPluginVideo : public nsDisplayItem { michael@0: public: michael@0: nsDisplayPluginVideo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsNPAPIPluginInstance::VideoInfo* aVideoInfo) michael@0: : nsDisplayItem(aBuilder, aFrame), mVideoInfo(aVideoInfo) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayPluginVideo); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayPluginVideo() { michael@0: MOZ_COUNT_DTOR(nsDisplayPluginVideo); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: michael@0: NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO) michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE michael@0: { michael@0: return static_cast(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters); michael@0: } michael@0: michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return LAYER_ACTIVE; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance::VideoInfo* VideoInfo() { return mVideoInfo; } michael@0: michael@0: private: michael@0: nsNPAPIPluginInstance::VideoInfo* mVideoInfo; michael@0: }; michael@0: michael@0: nsRect michael@0: nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) michael@0: { michael@0: *aSnap = false; michael@0: return GetDisplayItemBounds(aBuilder, this, mFrame); michael@0: } michael@0: michael@0: bool michael@0: nsDisplayPluginVideo::ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) michael@0: { michael@0: return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, michael@0: aAllowVisibleRegionExpansion); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: nsRect michael@0: nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) michael@0: { michael@0: *aSnap = true; michael@0: return GetDisplayItemBounds(aBuilder, this, mFrame); michael@0: } michael@0: michael@0: void michael@0: nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx) michael@0: { michael@0: nsObjectFrame* f = static_cast(mFrame); michael@0: bool snap; michael@0: f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap)); michael@0: } michael@0: michael@0: bool michael@0: nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) michael@0: { michael@0: if (aBuilder->IsForPluginGeometry()) { michael@0: nsObjectFrame* f = static_cast(mFrame); michael@0: if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) { michael@0: // Since transforms induce reference frames, we don't need to worry michael@0: // about this method fluffing out due to non-rectilinear transforms. michael@0: nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f, michael@0: f->GetContentRectRelativeToSelf(), ReferenceFrame()); michael@0: nscoord appUnitsPerDevPixel = michael@0: ReferenceFrame()->PresContext()->AppUnitsPerDevPixel(); michael@0: f->mNextConfigurationBounds = rAncestor.ToNearestPixels(appUnitsPerDevPixel); michael@0: michael@0: nsRegion visibleRegion; michael@0: visibleRegion.And(*aVisibleRegion, GetClippedBounds(aBuilder)); michael@0: // Make visibleRegion relative to f michael@0: visibleRegion.MoveBy(-ToReferenceFrame()); michael@0: michael@0: f->mNextConfigurationClipRegion.Clear(); michael@0: nsRegionRectIterator iter(visibleRegion); michael@0: for (const nsRect* r = iter.Next(); r; r = iter.Next()) { michael@0: nsRect rAncestor = michael@0: nsLayoutUtils::TransformFrameRectToAncestor(f, *r, ReferenceFrame()); michael@0: nsIntRect rPixels = rAncestor.ToNearestPixels(appUnitsPerDevPixel) michael@0: - f->mNextConfigurationBounds.TopLeft(); michael@0: if (!rPixels.IsEmpty()) { michael@0: f->mNextConfigurationClipRegion.AppendElement(rPixels); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (f->mInnerView) { michael@0: // This should produce basically the same rectangle (but not relative michael@0: // to the root frame). We only call this here for the side-effect of michael@0: // setting mViewToWidgetOffset on the view. michael@0: f->mInnerView->CalcWidgetBounds(eWindowType_plugin); michael@0: } michael@0: } michael@0: michael@0: return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, michael@0: aAllowVisibleRegionExpansion); michael@0: } michael@0: michael@0: nsRegion michael@0: nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) michael@0: { michael@0: *aSnap = false; michael@0: nsRegion result; michael@0: nsObjectFrame* f = static_cast(mFrame); michael@0: if (!aBuilder->IsForPluginGeometry()) { michael@0: nsIWidget* widget = f->GetWidget(); michael@0: if (widget) { michael@0: // Be conservative and treat plugins with widgets as not opaque, michael@0: // because that's simple and we might need the content under the widget michael@0: // if the widget is unexpectedly clipped away. (As can happen when michael@0: // chrome content over a plugin forces us to clip out the plugin for michael@0: // security reasons.) michael@0: // We shouldn't be repainting the content under plugins much anyway michael@0: // since there generally shouldn't be anything to invalidate or paint michael@0: // in ThebesLayers there. michael@0: return result; michael@0: } michael@0: } michael@0: michael@0: if (f->IsOpaque()) { michael@0: nsRect bounds = GetBounds(aBuilder, aSnap); michael@0: if (aBuilder->IsForPluginGeometry() || michael@0: (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) { michael@0: // We can treat this as opaque michael@0: result = bounds; michael@0: } michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::PluginEventNotifier::Run() { michael@0: nsCOMPtr obsSvc = michael@0: mozilla::services::GetObserverService(); michael@0: obsSvc->NotifyObservers(nullptr, "plugin-changed-event", mEventType.get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::NotifyPluginReflowObservers() michael@0: { michael@0: nsContentUtils::AddScriptRunner(new PluginEventNotifier(NS_LITERAL_STRING("reflow"))); michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::DidSetWidgetGeometry() michael@0: { michael@0: #if defined(XP_MACOSX) michael@0: if (mInstanceOwner) { michael@0: mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable); michael@0: } michael@0: #else michael@0: if (!mWidget && mInstanceOwner) { michael@0: // UpdateWindowVisibility will notify the plugin of position changes michael@0: // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow. michael@0: // We treat windowless plugins inside popups as always visible, since michael@0: // plugins inside popups don't get valid mNextConfigurationBounds michael@0: // set up. michael@0: mInstanceOwner->UpdateWindowVisibility( michael@0: nsLayoutUtils::IsPopup(nsLayoutUtils::GetDisplayRootFrame(this)) || michael@0: !mNextConfigurationBounds.IsEmpty()); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: nsObjectFrame::IsOpaque() const michael@0: { michael@0: #if defined(XP_MACOSX) michael@0: // ??? michael@0: return false; michael@0: #elif defined(MOZ_WIDGET_ANDROID) michael@0: // We don't know, so just assume transparent michael@0: return false; michael@0: #else michael@0: return !IsTransparentMode(); michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: nsObjectFrame::IsTransparentMode() const michael@0: { michael@0: #if defined(XP_MACOSX) michael@0: // ??? michael@0: return false; michael@0: #else michael@0: if (!mInstanceOwner) michael@0: return false; michael@0: michael@0: NPWindow *window = nullptr; michael@0: mInstanceOwner->GetWindow(window); michael@0: if (!window) { michael@0: return false; michael@0: } michael@0: michael@0: if (window->type != NPWindowTypeDrawable) michael@0: return false; michael@0: michael@0: nsresult rv; michael@0: nsRefPtr pi; michael@0: rv = mInstanceOwner->GetInstance(getter_AddRefs(pi)); michael@0: if (NS_FAILED(rv) || !pi) michael@0: return false; michael@0: michael@0: bool transparent = false; michael@0: pi->IsTransparent(&transparent); michael@0: return transparent; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // XXX why are we painting collapsed object frames? michael@0: if (!IsVisibleOrCollapsedForPainting(aBuilder)) michael@0: return; michael@0: michael@0: DisplayBorderBackgroundOutline(aBuilder, aLists); michael@0: michael@0: nsPresContext::nsPresContextType type = PresContext()->Type(); michael@0: michael@0: // If we are painting in Print Preview do nothing.... michael@0: if (type == nsPresContext::eContext_PrintPreview) michael@0: return; michael@0: michael@0: DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame"); michael@0: michael@0: #ifndef XP_MACOSX michael@0: if (mWidget && aBuilder->IsInTransform()) { michael@0: // Windowed plugins should not be rendered inside a transform. michael@0: return; michael@0: } michael@0: #endif michael@0: michael@0: if (aBuilder->IsForPainting() && mInstanceOwner && mInstanceOwner->UseAsyncRendering()) { michael@0: NPWindow* window = nullptr; michael@0: mInstanceOwner->GetWindow(window); michael@0: bool isVisible = window && window->width > 0 && window->height > 0; michael@0: if (isVisible && aBuilder->ShouldSyncDecodeImages()) { michael@0: #ifndef XP_MACOSX michael@0: mInstanceOwner->UpdateWindowVisibility(true); michael@0: #endif michael@0: } michael@0: michael@0: mInstanceOwner->NotifyPaintWaiter(aBuilder); michael@0: } michael@0: michael@0: DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox michael@0: clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT); michael@0: michael@0: // determine if we are printing michael@0: if (type == nsPresContext::eContext_Print) { michael@0: aLists.Content()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin", michael@0: nsDisplayItem::TYPE_PRINT_PLUGIN)); michael@0: } else { michael@0: LayerState state = GetLayerState(aBuilder, nullptr); michael@0: if (state == LAYER_INACTIVE && michael@0: nsDisplayItem::ForceActiveLayers()) { michael@0: state = LAYER_ACTIVE; michael@0: } michael@0: // We don't need this on Android, and it just confuses things michael@0: #if !MOZ_WIDGET_ANDROID michael@0: if (aBuilder->IsPaintingToWindow() && michael@0: state == LAYER_ACTIVE && michael@0: IsTransparentMode()) { michael@0: aLists.Content()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayPluginReadback(aBuilder, this)); michael@0: } michael@0: #endif michael@0: michael@0: #if MOZ_WIDGET_ANDROID michael@0: if (aBuilder->IsPaintingToWindow() && michael@0: state == LAYER_ACTIVE) { michael@0: michael@0: nsTArray videos; michael@0: mInstanceOwner->GetVideos(videos); michael@0: michael@0: for (uint32_t i = 0; i < videos.Length(); i++) { michael@0: aLists.Content()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayPluginVideo(aBuilder, this, videos[i])); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: aLists.Content()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayPlugin(aBuilder, this)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::PrintPlugin(nsRenderingContext& aRenderingContext, michael@0: const nsRect& aDirtyRect) michael@0: { michael@0: nsCOMPtr obj(do_QueryInterface(mContent)); michael@0: if (!obj) michael@0: return; michael@0: michael@0: nsIFrame* frame = nullptr; michael@0: obj->GetPrintFrame(&frame); michael@0: if (!frame) michael@0: return; michael@0: michael@0: nsPresContext* presContext = PresContext(); michael@0: // make sure this is REALLY an nsIObjectFrame michael@0: // we may need to go through the children to get it michael@0: nsIObjectFrame* objectFrame = do_QueryFrame(frame); michael@0: if (!objectFrame) michael@0: objectFrame = GetNextObjectFrame(presContext,frame); michael@0: if (!objectFrame) michael@0: return; michael@0: michael@0: // finally we can get our plugin instance michael@0: nsRefPtr pi; michael@0: if (NS_FAILED(objectFrame->GetPluginInstance(getter_AddRefs(pi))) || !pi) michael@0: return; michael@0: michael@0: // now we need to setup the correct location for printing michael@0: NPWindow window; michael@0: window.window = nullptr; michael@0: michael@0: // prepare embedded mode printing struct michael@0: NPPrint npprint; michael@0: npprint.mode = NP_EMBED; michael@0: michael@0: // we need to find out if we are windowless or not michael@0: bool windowless = false; michael@0: pi->IsWindowless(&windowless); michael@0: window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow; michael@0: michael@0: window.clipRect.bottom = 0; window.clipRect.top = 0; michael@0: window.clipRect.left = 0; window.clipRect.right = 0; michael@0: michael@0: // platform specific printing code michael@0: #if defined(XP_MACOSX) && !defined(__LP64__) michael@0: #pragma clang diagnostic ignored "-Wdeprecated-declarations" michael@0: // Don't use this code if any of the QuickDraw APIs it currently requires michael@0: // are missing (as they probably will be on OS X 10.8 and up). michael@0: if (!&::SetRect || !&::NewGWorldFromPtr || !&::DisposeGWorld) { michael@0: NS_WARNING("Cannot print plugin -- required QuickDraw APIs are missing!"); michael@0: return; michael@0: } michael@0: michael@0: nsSize contentSize = GetContentRectRelativeToSelf().Size(); michael@0: window.x = 0; michael@0: window.y = 0; michael@0: window.width = presContext->AppUnitsToDevPixels(contentSize.width); michael@0: window.height = presContext->AppUnitsToDevPixels(contentSize.height); michael@0: michael@0: gfxContext *ctx = aRenderingContext.ThebesContext(); michael@0: if (!ctx) michael@0: return; michael@0: gfxContextAutoSaveRestore save(ctx); michael@0: michael@0: ctx->NewPath(); michael@0: michael@0: gfxRect rect(window.x, window.y, window.width, window.height); michael@0: michael@0: ctx->Rectangle(rect); michael@0: ctx->Clip(); michael@0: michael@0: gfxQuartzNativeDrawing nativeDraw(ctx, rect); michael@0: CGContextRef cgContext = nativeDraw.BeginNativeDrawing(); michael@0: if (!cgContext) { michael@0: nativeDraw.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: michael@0: window.clipRect.right = window.width; michael@0: window.clipRect.bottom = window.height; michael@0: window.type = NPWindowTypeDrawable; michael@0: michael@0: ::Rect gwBounds; michael@0: ::SetRect(&gwBounds, 0, 0, window.width, window.height); michael@0: michael@0: nsTArray buffer(window.width * window.height * 4); michael@0: CGColorSpaceRef cspace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); michael@0: if (!cspace) { michael@0: nativeDraw.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: CGContextRef cgBuffer = michael@0: ::CGBitmapContextCreate(buffer.Elements(), michael@0: window.width, window.height, 8, window.width * 4, michael@0: cspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedFirst); michael@0: ::CGColorSpaceRelease(cspace); michael@0: if (!cgBuffer) { michael@0: nativeDraw.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: GWorldPtr gWorld; michael@0: if (::NewGWorldFromPtr(&gWorld, k32ARGBPixelFormat, &gwBounds, michael@0: nullptr, nullptr, 0, michael@0: buffer.Elements(), window.width * 4) != noErr) { michael@0: ::CGContextRelease(cgBuffer); michael@0: nativeDraw.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: michael@0: window.clipRect.right = window.width; michael@0: window.clipRect.bottom = window.height; michael@0: window.type = NPWindowTypeDrawable; michael@0: // Setting nsPluginPrint/NPPrint.print.embedPrint.window.window to michael@0: // &GWorldPtr and nsPluginPrint/NPPrint.print.embedPrint.platformPrint to michael@0: // GWorldPtr isn't any kind of standard (it's not documented anywhere). michael@0: // But that's what WebKit does. And it's what the Flash plugin (apparently michael@0: // the only NPAPI plugin on OS X to support printing) seems to expect. So michael@0: // we do the same. The Flash plugin uses the CoreGraphics drawing mode. michael@0: // But a GWorldPtr should be usable in either CoreGraphics or QuickDraw michael@0: // drawing mode. See bug 191046. michael@0: window.window = &gWorld; michael@0: npprint.print.embedPrint.platformPrint = gWorld; michael@0: npprint.print.embedPrint.window = window; michael@0: pi->Print(&npprint); michael@0: michael@0: ::CGContextTranslateCTM(cgContext, 0.0f, float(window.height)); michael@0: ::CGContextScaleCTM(cgContext, 1.0f, -1.0f); michael@0: CGImageRef image = ::CGBitmapContextCreateImage(cgBuffer); michael@0: if (!image) { michael@0: ::CGContextRestoreGState(cgContext); michael@0: ::CGContextRelease(cgBuffer); michael@0: ::DisposeGWorld(gWorld); michael@0: nativeDraw.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: ::CGContextDrawImage(cgContext, michael@0: ::CGRectMake(0, 0, window.width, window.height), michael@0: image); michael@0: ::CGImageRelease(image); michael@0: ::CGContextRelease(cgBuffer); michael@0: michael@0: ::DisposeGWorld(gWorld); michael@0: michael@0: nativeDraw.EndNativeDrawing(); michael@0: #pragma clang diagnostic warning "-Wdeprecated-declarations" michael@0: #elif defined(XP_UNIX) michael@0: michael@0: /* XXX this just flat-out doesn't work in a thebes world -- michael@0: * RenderEPS is a no-op. So don't bother to do any work here. michael@0: */ michael@0: (void)window; michael@0: (void)npprint; michael@0: michael@0: #elif defined(XP_WIN) michael@0: michael@0: /* On Windows, we use the win32 printing surface to print. This, in michael@0: * turn, uses the Cairo paginated surface, which in turn uses the michael@0: * meta surface to record all operations and then play them back. michael@0: * This doesn't work too well for plugins, because if plugins render michael@0: * directly into the DC, the meta surface won't have any knowledge michael@0: * of them, and so at the end when it actually does the replay step, michael@0: * it'll fill the background with white and draw over whatever was michael@0: * rendered before. michael@0: * michael@0: * So, to avoid this, we use PushGroup, which creates a new windows michael@0: * surface, the plugin renders to that, and then we use normal michael@0: * cairo methods to composite that in such that it's recorded using the michael@0: * meta surface. michael@0: */ michael@0: michael@0: /* we'll already be translated into the right spot by gfxWindowsNativeDrawing */ michael@0: nsSize contentSize = GetContentRectRelativeToSelf().Size(); michael@0: window.x = 0; michael@0: window.y = 0; michael@0: window.width = presContext->AppUnitsToDevPixels(contentSize.width); michael@0: window.height = presContext->AppUnitsToDevPixels(contentSize.height); michael@0: michael@0: gfxContext *ctx = aRenderingContext.ThebesContext(); michael@0: michael@0: ctx->Save(); michael@0: michael@0: /* Make sure plugins don't do any damage outside of where they're supposed to */ michael@0: ctx->NewPath(); michael@0: gfxRect r(window.x, window.y, window.width, window.height); michael@0: ctx->Rectangle(r); michael@0: ctx->Clip(); michael@0: michael@0: gfxWindowsNativeDrawing nativeDraw(ctx, r); michael@0: do { michael@0: HDC dc = nativeDraw.BeginNativeDrawing(); michael@0: if (!dc) michael@0: return; michael@0: michael@0: // XXX don't we need to call nativeDraw.TransformToNativeRect here? michael@0: npprint.print.embedPrint.platformPrint = dc; michael@0: npprint.print.embedPrint.window = window; michael@0: // send off print info to plugin michael@0: pi->Print(&npprint); michael@0: michael@0: nativeDraw.EndNativeDrawing(); michael@0: } while (nativeDraw.ShouldRenderAgain()); michael@0: nativeDraw.PaintToContext(); michael@0: michael@0: ctx->Restore(); michael@0: #endif michael@0: michael@0: // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same? michael@0: // XXX Calling DidReflow here makes no sense!!! michael@0: nsDidReflowStatus status = nsDidReflowStatus::FINISHED; // should we use a special status? michael@0: frame->DidReflow(presContext, michael@0: nullptr, status); // DidReflow will take care of it michael@0: } michael@0: michael@0: nsRect michael@0: nsObjectFrame::GetPaintedRect(nsDisplayPlugin* aItem) michael@0: { michael@0: if (!mInstanceOwner) michael@0: return nsRect(); michael@0: nsRect r = GetContentRectRelativeToSelf(); michael@0: if (!mInstanceOwner->UseAsyncRendering()) michael@0: return r; michael@0: michael@0: nsIntSize size = mInstanceOwner->GetCurrentImageSize(); michael@0: nsPresContext* pc = PresContext(); michael@0: r.IntersectRect(r, nsRect(0, 0, pc->DevPixelsToAppUnits(size.width), michael@0: pc->DevPixelsToAppUnits(size.height))); michael@0: return r; michael@0: } michael@0: michael@0: LayerState michael@0: nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager) michael@0: { michael@0: if (!mInstanceOwner) michael@0: return LAYER_NONE; michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // We always want a layer on Honeycomb and later michael@0: if (AndroidBridge::Bridge()->GetAPIVersion() >= 11) michael@0: return LAYER_ACTIVE; michael@0: #endif michael@0: michael@0: if (!mInstanceOwner->UseAsyncRendering()) { michael@0: return LAYER_NONE; michael@0: } michael@0: michael@0: return LAYER_ACTIVE; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: nsDisplayItem* aItem, michael@0: const ContainerLayerParameters& aContainerParameters) michael@0: { michael@0: if (!mInstanceOwner) michael@0: return nullptr; michael@0: michael@0: NPWindow* window = nullptr; michael@0: mInstanceOwner->GetWindow(window); michael@0: if (!window) michael@0: return nullptr; michael@0: michael@0: if (window->width <= 0 || window->height <= 0) michael@0: return nullptr; michael@0: michael@0: // window is in "display pixels", but size needs to be in device pixels michael@0: double scaleFactor = 1.0; michael@0: if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) { michael@0: scaleFactor = 1.0; michael@0: } michael@0: int intScaleFactor = ceil(scaleFactor); michael@0: IntSize size(window->width * intScaleFactor, window->height * intScaleFactor); michael@0: michael@0: nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame(); michael@0: gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel()); michael@0: // to provide crisper and faster drawing. michael@0: r.Round(); michael@0: nsRefPtr layer = michael@0: (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); michael@0: michael@0: if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) { michael@0: // Create image michael@0: nsRefPtr container = mInstanceOwner->GetImageContainer(); michael@0: if (!container) { michael@0: // This can occur if our instance is gone. michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!layer) { michael@0: mInstanceOwner->NotifyPaintWaiter(aBuilder); michael@0: // Initialize ImageLayer michael@0: layer = aManager->CreateImageLayer(); michael@0: if (!layer) michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type"); michael@0: ImageLayer* imglayer = static_cast(layer.get()); michael@0: #ifdef XP_MACOSX michael@0: if (!mInstanceOwner->UseAsyncRendering()) { michael@0: mInstanceOwner->DoCocoaEventDrawRect(r, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: imglayer->SetScaleToSize(size, ScaleMode::STRETCH); michael@0: imglayer->SetContainer(container); michael@0: GraphicsFilter filter = michael@0: nsLayoutUtils::GetGraphicsFilterForFrame(this); michael@0: #ifdef MOZ_GFX_OPTIMIZE_MOBILE michael@0: if (!aManager->IsCompositingCheap()) { michael@0: // Pixman just horrible with bilinear filter scaling michael@0: filter = GraphicsFilter::FILTER_NEAREST; michael@0: } michael@0: #endif michael@0: imglayer->SetFilter(filter); michael@0: michael@0: layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0); michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: } else if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_VIDEO) { michael@0: nsDisplayPluginVideo* videoItem = reinterpret_cast(aItem); michael@0: nsNPAPIPluginInstance::VideoInfo* videoInfo = videoItem->VideoInfo(); michael@0: michael@0: nsRefPtr container = mInstanceOwner->GetImageContainerForVideo(videoInfo); michael@0: if (!container) michael@0: return nullptr; michael@0: michael@0: if (!layer) { michael@0: // Initialize ImageLayer michael@0: layer = aManager->CreateImageLayer(); michael@0: if (!layer) michael@0: return nullptr; michael@0: } michael@0: michael@0: ImageLayer* imglayer = static_cast(layer.get()); michael@0: imglayer->SetContainer(container); michael@0: michael@0: layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0); michael@0: michael@0: // Set the offset and size according to the video dimensions michael@0: r.MoveBy(videoInfo->mDimensions.TopLeft()); michael@0: size.width = videoInfo->mDimensions.width; michael@0: size.height = videoInfo->mDimensions.height; michael@0: #endif michael@0: } else { michael@0: NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK, michael@0: "Unknown item type"); michael@0: NS_ABORT_IF_FALSE(!IsOpaque(), "Opaque plugins don't use backgrounds"); michael@0: michael@0: if (!layer) { michael@0: layer = aManager->CreateReadbackLayer(); michael@0: if (!layer) michael@0: return nullptr; michael@0: } michael@0: NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type"); michael@0: michael@0: ReadbackLayer* readback = static_cast(layer.get()); michael@0: if (readback->GetSize() != ThebesIntSize(size)) { michael@0: // This will destroy any old background sink and notify us that the michael@0: // background is now unknown michael@0: readback->SetSink(nullptr); michael@0: readback->SetSize(ThebesIntSize(size)); michael@0: michael@0: if (mBackgroundSink) { michael@0: // Maybe we still have a background sink associated with another michael@0: // readback layer that wasn't recycled for some reason? Unhook it michael@0: // now so that if this frame goes away, it doesn't have a dangling michael@0: // reference to us. michael@0: mBackgroundSink->Destroy(); michael@0: } michael@0: mBackgroundSink = michael@0: new PluginBackgroundSink(this, michael@0: readback->AllocateSequenceNumber()); michael@0: readback->SetSink(mBackgroundSink); michael@0: // The layer has taken ownership of our sink. When either the sink dies michael@0: // or the frame dies, the connection from the surviving object is nulled out. michael@0: } michael@0: } michael@0: michael@0: // Set a transform on the layer to draw the plugin in the right place michael@0: Matrix transform; michael@0: gfxPoint p = r.TopLeft() + aContainerParameters.mOffset; michael@0: transform.Translate(p.x, p.y); michael@0: michael@0: layer->SetBaseTransform(Matrix4x4::From2D(transform)); michael@0: layer->SetVisibleRegion(ThebesIntRect(IntRect(IntPoint(0, 0), size))); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext& aRenderingContext, michael@0: const nsRect& aDirtyRect, const nsRect& aPluginRect) michael@0: { michael@0: #if defined(MOZ_WIDGET_ANDROID) michael@0: if (mInstanceOwner) { michael@0: gfxRect frameGfxRect = michael@0: PresContext()->AppUnitsToGfxUnits(aPluginRect); michael@0: gfxRect dirtyGfxRect = michael@0: PresContext()->AppUnitsToGfxUnits(aDirtyRect); michael@0: michael@0: gfxContext* ctx = aRenderingContext.ThebesContext(); michael@0: michael@0: mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect); michael@0: return; michael@0: } michael@0: #endif michael@0: michael@0: // Screen painting code michael@0: #if defined(XP_MACOSX) michael@0: // delegate all painting to the plugin instance. michael@0: if (mInstanceOwner) { michael@0: if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics || michael@0: mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation || michael@0: mInstanceOwner->GetDrawingModel() == michael@0: NPDrawingModelInvalidatingCoreAnimation) { michael@0: int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel(); michael@0: // Clip to the content area where the plugin should be drawn. If michael@0: // we don't do this, the plugin can draw outside its bounds. michael@0: nsIntRect contentPixels = aPluginRect.ToNearestPixels(appUnitsPerDevPixel); michael@0: nsIntRect dirtyPixels = aDirtyRect.ToOutsidePixels(appUnitsPerDevPixel); michael@0: nsIntRect clipPixels; michael@0: clipPixels.IntersectRect(contentPixels, dirtyPixels); michael@0: michael@0: // Don't invoke the drawing code if the clip is empty. michael@0: if (clipPixels.IsEmpty()) michael@0: return; michael@0: michael@0: gfxRect nativeClipRect(clipPixels.x, clipPixels.y, michael@0: clipPixels.width, clipPixels.height); michael@0: gfxContext* ctx = aRenderingContext.ThebesContext(); michael@0: michael@0: gfxContextAutoSaveRestore save(ctx); michael@0: ctx->NewPath(); michael@0: ctx->Rectangle(nativeClipRect); michael@0: ctx->Clip(); michael@0: gfxPoint offset(contentPixels.x, contentPixels.y); michael@0: ctx->Translate(offset); michael@0: michael@0: gfxQuartzNativeDrawing nativeDrawing(ctx, nativeClipRect - offset); michael@0: michael@0: CGContextRef cgContext = nativeDrawing.BeginNativeDrawing(); michael@0: if (!cgContext) { michael@0: NS_WARNING("null CGContextRef during PaintPlugin"); michael@0: return; michael@0: } michael@0: michael@0: nsRefPtr inst; michael@0: GetPluginInstance(getter_AddRefs(inst)); michael@0: if (!inst) { michael@0: NS_WARNING("null plugin instance during PaintPlugin"); michael@0: nativeDrawing.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: NPWindow* window; michael@0: mInstanceOwner->GetWindow(window); michael@0: if (!window) { michael@0: NS_WARNING("null plugin window during PaintPlugin"); michael@0: nativeDrawing.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: NP_CGContext* cgPluginPortCopy = michael@0: static_cast(mInstanceOwner->GetPluginPortCopy()); michael@0: if (!cgPluginPortCopy) { michael@0: NS_WARNING("null plugin port copy during PaintPlugin"); michael@0: nativeDrawing.EndNativeDrawing(); michael@0: return; michael@0: } michael@0: michael@0: mInstanceOwner->BeginCGPaint(); michael@0: if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation || michael@0: mInstanceOwner->GetDrawingModel() == michael@0: NPDrawingModelInvalidatingCoreAnimation) { michael@0: // CoreAnimation is updated, render the layer and perform a readback. michael@0: mInstanceOwner->RenderCoreAnimation(cgContext, window->width, window->height); michael@0: } else { michael@0: mInstanceOwner->Paint(nativeClipRect - offset, cgContext); michael@0: } michael@0: mInstanceOwner->EndCGPaint(); michael@0: michael@0: nativeDrawing.EndNativeDrawing(); michael@0: } else { michael@0: // FIXME - Bug 385435: Doesn't aDirtyRect need translating too? michael@0: nsRenderingContext::AutoPushTranslation michael@0: translate(&aRenderingContext, aPluginRect.TopLeft()); michael@0: michael@0: // this rect is used only in the CoreGraphics drawing model michael@0: gfxRect tmpRect(0, 0, 0, 0); michael@0: mInstanceOwner->Paint(tmpRect, nullptr); michael@0: } michael@0: } michael@0: #elif defined(MOZ_X11) michael@0: if (mInstanceOwner) { michael@0: NPWindow *window; michael@0: mInstanceOwner->GetWindow(window); michael@0: if (window->type == NPWindowTypeDrawable) { michael@0: gfxRect frameGfxRect = michael@0: PresContext()->AppUnitsToGfxUnits(aPluginRect); michael@0: gfxRect dirtyGfxRect = michael@0: PresContext()->AppUnitsToGfxUnits(aDirtyRect); michael@0: gfxContext* ctx = aRenderingContext.ThebesContext(); michael@0: michael@0: mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect); michael@0: } michael@0: } michael@0: #elif defined(XP_WIN) michael@0: nsRefPtr inst; michael@0: GetPluginInstance(getter_AddRefs(inst)); michael@0: if (inst) { michael@0: gfxRect frameGfxRect = michael@0: PresContext()->AppUnitsToGfxUnits(aPluginRect); michael@0: gfxRect dirtyGfxRect = michael@0: PresContext()->AppUnitsToGfxUnits(aDirtyRect); michael@0: gfxContext *ctx = aRenderingContext.ThebesContext(); michael@0: gfxMatrix currentMatrix = ctx->CurrentMatrix(); michael@0: michael@0: if (ctx->UserToDevicePixelSnapped(frameGfxRect, false)) { michael@0: dirtyGfxRect = ctx->UserToDevice(dirtyGfxRect); michael@0: ctx->IdentityMatrix(); michael@0: } michael@0: dirtyGfxRect.RoundOut(); michael@0: michael@0: // Look if it's windowless michael@0: NPWindow *window; michael@0: mInstanceOwner->GetWindow(window); michael@0: michael@0: if (window->type == NPWindowTypeDrawable) { michael@0: // the offset of the DC michael@0: nsPoint origin; michael@0: michael@0: gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect); michael@0: if (nativeDraw.IsDoublePass()) { michael@0: // OOP plugin specific: let the shim know before we paint if we are doing a michael@0: // double pass render. If this plugin isn't oop, the register window message michael@0: // will be ignored. michael@0: NPEvent pluginEvent; michael@0: pluginEvent.event = plugins::DoublePassRenderingEvent(); michael@0: pluginEvent.wParam = 0; michael@0: pluginEvent.lParam = 0; michael@0: if (pluginEvent.event) michael@0: inst->HandleEvent(&pluginEvent, nullptr); michael@0: } michael@0: do { michael@0: HDC hdc = nativeDraw.BeginNativeDrawing(); michael@0: if (!hdc) michael@0: return; michael@0: michael@0: RECT dest; michael@0: nativeDraw.TransformToNativeRect(frameGfxRect, dest); michael@0: RECT dirty; michael@0: nativeDraw.TransformToNativeRect(dirtyGfxRect, dirty); michael@0: michael@0: window->window = hdc; michael@0: window->x = dest.left; michael@0: window->y = dest.top; michael@0: window->clipRect.left = 0; michael@0: window->clipRect.top = 0; michael@0: // if we're painting, we're visible. michael@0: window->clipRect.right = window->width; michael@0: window->clipRect.bottom = window->height; michael@0: michael@0: // Windowless plugins on windows need a special event to update their location, michael@0: // see bug 135737. michael@0: // michael@0: // bug 271442: note, the rectangle we send is now purely the bounds of the plugin michael@0: // relative to the window it is contained in, which is useful for the plugin to michael@0: // correctly translate mouse coordinates. michael@0: // michael@0: // this does not mesh with the comments for bug 135737 which imply that the rectangle michael@0: // must be clipped in some way to prevent the plugin attempting to paint over areas michael@0: // it shouldn't. michael@0: // michael@0: // since the two uses of the rectangle are mutually exclusive in some cases, and michael@0: // since I don't see any incorrect painting (at least with Flash and ViewPoint - michael@0: // the originator of bug 135737), it seems that windowless plugins are not relying michael@0: // on information here for clipping their drawing, and we can safely use this message michael@0: // to tell the plugin exactly where it is in all cases. michael@0: michael@0: nsIntPoint origin = GetWindowOriginInPixels(true); michael@0: nsIntRect winlessRect = nsIntRect(origin, nsIntSize(window->width, window->height)); michael@0: michael@0: if (!mWindowlessRect.IsEqualEdges(winlessRect)) { michael@0: mWindowlessRect = winlessRect; michael@0: michael@0: WINDOWPOS winpos; michael@0: memset(&winpos, 0, sizeof(winpos)); michael@0: winpos.x = mWindowlessRect.x; michael@0: winpos.y = mWindowlessRect.y; michael@0: winpos.cx = mWindowlessRect.width; michael@0: winpos.cy = mWindowlessRect.height; michael@0: michael@0: // finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event michael@0: NPEvent pluginEvent; michael@0: pluginEvent.event = WM_WINDOWPOSCHANGED; michael@0: pluginEvent.wParam = 0; michael@0: pluginEvent.lParam = (LPARAM)&winpos; michael@0: inst->HandleEvent(&pluginEvent, nullptr); michael@0: } michael@0: michael@0: inst->SetWindow(window); michael@0: michael@0: mInstanceOwner->Paint(dirty, hdc); michael@0: nativeDraw.EndNativeDrawing(); michael@0: } while (nativeDraw.ShouldRenderAgain()); michael@0: nativeDraw.PaintToContext(); michael@0: } michael@0: michael@0: ctx->SetMatrix(currentMatrix); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::HandleEvent(nsPresContext* aPresContext, michael@0: WidgetGUIEvent* anEvent, michael@0: nsEventStatus* anEventStatus) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(anEvent); michael@0: NS_ENSURE_ARG_POINTER(anEventStatus); michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (!mInstanceOwner) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: mInstanceOwner->ConsiderNewEventloopNestingLevel(); michael@0: michael@0: if (anEvent->message == NS_PLUGIN_ACTIVATE) { michael@0: nsIFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: nsCOMPtr elem = do_QueryInterface(GetContent()); michael@0: if (fm && elem) michael@0: return fm->SetFocus(elem, 0); michael@0: } michael@0: else if (anEvent->message == NS_PLUGIN_FOCUS) { michael@0: nsIFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: if (fm) michael@0: return fm->FocusPlugin(GetContent()); michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (anEvent->message == NS_PLUGIN_RESOLUTION_CHANGED) { michael@0: double scaleFactor = 1.0; michael@0: mInstanceOwner->GetContentsScaleFactor(&scaleFactor); michael@0: mInstanceOwner->ContentsScaleFactorChanged(scaleFactor); michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: if (mInstanceOwner->SendNativeEvents() && michael@0: anEvent->IsNativeEventDelivererForPlugin()) { michael@0: *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent); michael@0: // Due to plugin code reentering Gecko, this frame may be dead at this michael@0: // point. michael@0: return rv; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus); michael@0: return rv; michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: // we want to process some native mouse events in the cocoa event model michael@0: if ((anEvent->message == NS_MOUSE_ENTER || michael@0: anEvent->message == NS_WHEEL_WHEEL) && michael@0: mInstanceOwner->GetEventModel() == NPEventModelCocoa) { michael@0: *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent); michael@0: // Due to plugin code reentering Gecko, this frame may be dead at this michael@0: // point. michael@0: return rv; michael@0: } michael@0: michael@0: // These two calls to nsIPresShell::SetCapturingContext() (on mouse-down michael@0: // and mouse-up) are needed to make the routing of mouse events while michael@0: // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec. michael@0: // See bug 525078 and bug 909678. michael@0: if (anEvent->message == NS_MOUSE_BUTTON_DOWN) { michael@0: nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); michael@0: } michael@0: #endif michael@0: michael@0: rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus); michael@0: michael@0: // We need to be careful from this point because the call to michael@0: // nsObjectFrameSuper::HandleEvent() might have killed us. michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (anEvent->message == NS_MOUSE_BUTTON_UP) { michael@0: nsIPresShell::SetCapturingContent(nullptr, 0); michael@0: } michael@0: #endif michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance) michael@0: { michael@0: *aPluginInstance = nullptr; michael@0: michael@0: if (!mInstanceOwner) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: return mInstanceOwner->GetInstance(aPluginInstance); michael@0: } michael@0: michael@0: nsresult michael@0: nsObjectFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) michael@0: { michael@0: if (!mInstanceOwner) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsRefPtr inst; michael@0: mInstanceOwner->GetInstance(getter_AddRefs(inst)); michael@0: if (!inst) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: bool useDOMCursor = static_cast(inst.get())->UsesDOMForCursor(); michael@0: if (!useDOMCursor) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return nsObjectFrameSuper::GetCursor(aPoint, aCursor); michael@0: } michael@0: michael@0: void michael@0: nsObjectFrame::SetIsDocumentActive(bool aIsActive) michael@0: { michael@0: #ifndef XP_MACOSX michael@0: if (mInstanceOwner) { michael@0: mInstanceOwner->UpdateDocumentActiveState(aIsActive); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: // static michael@0: nsIObjectFrame * michael@0: nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot) michael@0: { michael@0: nsIFrame* child = aRoot->GetFirstPrincipalChild(); michael@0: michael@0: while (child) { michael@0: nsIObjectFrame* outFrame = do_QueryFrame(child); michael@0: if (outFrame) { michael@0: nsRefPtr pi; michael@0: outFrame->GetPluginInstance(getter_AddRefs(pi)); // make sure we have a REAL plugin michael@0: if (pi) michael@0: return outFrame; michael@0: } michael@0: michael@0: outFrame = GetNextObjectFrame(aPresContext, child); michael@0: if (outFrame) michael@0: return outFrame; michael@0: child = child->GetNextSibling(); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: /*static*/ void michael@0: nsObjectFrame::BeginSwapDocShells(nsIContent* aContent, void*) michael@0: { michael@0: NS_PRECONDITION(aContent, ""); michael@0: michael@0: // This function is called from a document content enumerator so we need michael@0: // to filter out the nsObjectFrames and ignore the rest. michael@0: nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame()); michael@0: if (!obj) michael@0: return; michael@0: michael@0: nsObjectFrame* objectFrame = static_cast(obj); michael@0: NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(), michael@0: "Plugin windows must not be toplevel"); michael@0: objectFrame->UnregisterPluginForGeometryUpdates(); michael@0: } michael@0: michael@0: /*static*/ void michael@0: nsObjectFrame::EndSwapDocShells(nsIContent* aContent, void*) michael@0: { michael@0: NS_PRECONDITION(aContent, ""); michael@0: michael@0: // This function is called from a document content enumerator so we need michael@0: // to filter out the nsObjectFrames and ignore the rest. michael@0: nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame()); michael@0: if (!obj) michael@0: return; michael@0: michael@0: nsObjectFrame* objectFrame = static_cast(obj); michael@0: nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext(); michael@0: NS_ASSERTION(rootPC, "unable to register the plugin frame"); michael@0: nsIWidget* widget = objectFrame->mWidget; michael@0: if (widget) { michael@0: // Reparent the widget. michael@0: nsIWidget* parent = michael@0: rootPC->PresShell()->GetRootFrame()->GetNearestWidget(); michael@0: widget->SetParent(parent); michael@0: nsWeakFrame weakFrame(objectFrame); michael@0: objectFrame->CallSetWindow(); michael@0: if (!weakFrame.IsAlive()) { michael@0: return; michael@0: } michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (objectFrame->mWidget) { michael@0: objectFrame->RegisterPluginForGeometryUpdates(); michael@0: } michael@0: #else michael@0: objectFrame->RegisterPluginForGeometryUpdates(); michael@0: #endif michael@0: } michael@0: michael@0: nsIFrame* michael@0: NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsObjectFrame(aContext); michael@0: } michael@0: michael@0: bool michael@0: nsObjectFrame::IsPaintedByGecko() const michael@0: { michael@0: #ifdef XP_MACOSX michael@0: return true; michael@0: #else michael@0: return !mWidget; michael@0: #endif michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsObjectFrame)