forked from mirrors/gecko-dev
		
	Differential Revision: https://phabricator.services.mozilla.com/D29196 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			1698 lines
		
	
	
	
		
			56 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1698 lines
		
	
	
	
		
			56 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
/* rendering objects for replaced elements implemented by a plugin */
 | 
						|
 | 
						|
#include "nsPluginFrame.h"
 | 
						|
 | 
						|
#include "gfx2DGlue.h"
 | 
						|
#include "gfxContext.h"
 | 
						|
#include "gfxMatrix.h"
 | 
						|
#include "mozilla/gfx/2D.h"
 | 
						|
#include "mozilla/BasicEvents.h"
 | 
						|
#include "mozilla/MouseEvents.h"
 | 
						|
#include "mozilla/PresShell.h"
 | 
						|
#ifdef XP_WIN
 | 
						|
// This is needed for DoublePassRenderingEvent.
 | 
						|
#  include "mozilla/plugins/PluginMessageUtils.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "nscore.h"
 | 
						|
#include "nsCOMPtr.h"
 | 
						|
#include "nsPresContext.h"
 | 
						|
#include "nsWidgetsCID.h"
 | 
						|
#include "nsView.h"
 | 
						|
#include "nsViewManager.h"
 | 
						|
#include "nsString.h"
 | 
						|
#include "nsGkAtoms.h"
 | 
						|
#include "nsIPluginInstanceOwner.h"
 | 
						|
#include "nsNPAPIPluginInstance.h"
 | 
						|
#include "npapi.h"
 | 
						|
#include "nsIObjectLoadingContent.h"
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsDisplayList.h"
 | 
						|
#include "nsFocusManager.h"
 | 
						|
#include "nsLayoutUtils.h"
 | 
						|
#include "nsFrameManager.h"
 | 
						|
#include "nsIObserverService.h"
 | 
						|
#include "GeckoProfiler.h"
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
#include "nsIObjectFrame.h"
 | 
						|
#include "nsPluginNativeWindow.h"
 | 
						|
#include "FrameLayerBuilder.h"
 | 
						|
 | 
						|
#include "ImageLayers.h"
 | 
						|
#include "nsPluginInstanceOwner.h"
 | 
						|
 | 
						|
#ifdef XP_WIN
 | 
						|
#  include "gfxWindowsNativeDrawing.h"
 | 
						|
#  include "gfxWindowsSurface.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "Layers.h"
 | 
						|
#include "ReadbackLayer.h"
 | 
						|
#include "ImageContainer.h"
 | 
						|
#include "mozilla/layers/RenderRootStateManager.h"
 | 
						|
 | 
						|
// accessibility support
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
#  include "nsAccessibilityService.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "mozilla/Logging.h"
 | 
						|
 | 
						|
#ifdef XP_MACOSX
 | 
						|
#  include "gfxQuartzNativeDrawing.h"
 | 
						|
#  include "mozilla/gfx/QuartzSupport.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef MOZ_X11
 | 
						|
#  include "mozilla/X11Util.h"
 | 
						|
using mozilla::DefaultXDisplay;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef XP_WIN
 | 
						|
#  include <wtypes.h>
 | 
						|
#  include <winuser.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "mozilla/dom/BrowserChild.h"
 | 
						|
 | 
						|
#ifdef CreateEvent  // Thank you MS.
 | 
						|
#  undef CreateEvent
 | 
						|
#endif
 | 
						|
 | 
						|
static mozilla::LazyLogModule sPluginFrameLog("nsPluginFrame");
 | 
						|
 | 
						|
using namespace mozilla;
 | 
						|
using namespace mozilla::gfx;
 | 
						|
using namespace mozilla::layers;
 | 
						|
 | 
						|
class PluginBackgroundSink : public ReadbackSink {
 | 
						|
 public:
 | 
						|
  PluginBackgroundSink(nsPluginFrame* aFrame, uint64_t aStartSequenceNumber)
 | 
						|
      : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
 | 
						|
  ~PluginBackgroundSink() override {
 | 
						|
    if (mFrame) {
 | 
						|
      mFrame->mBackgroundSink = nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void SetUnknown(uint64_t aSequenceNumber) override {
 | 
						|
    if (!AcceptUpdate(aSequenceNumber)) return;
 | 
						|
    mFrame->mInstanceOwner->SetBackgroundUnknown();
 | 
						|
  }
 | 
						|
 | 
						|
  already_AddRefed<DrawTarget> BeginUpdate(const nsIntRect& aRect,
 | 
						|
                                           uint64_t aSequenceNumber) override {
 | 
						|
    if (!AcceptUpdate(aSequenceNumber)) return nullptr;
 | 
						|
    return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
 | 
						|
  }
 | 
						|
 | 
						|
  void EndUpdate(const nsIntRect& aRect) override {
 | 
						|
    return mFrame->mInstanceOwner->EndUpdateBackground(aRect);
 | 
						|
  }
 | 
						|
 | 
						|
  void Destroy() { mFrame = nullptr; }
 | 
						|
 | 
						|
 protected:
 | 
						|
  bool AcceptUpdate(uint64_t aSequenceNumber) {
 | 
						|
    if (aSequenceNumber > mLastSequenceNumber && mFrame &&
 | 
						|
        mFrame->mInstanceOwner) {
 | 
						|
      mLastSequenceNumber = aSequenceNumber;
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  uint64_t mLastSequenceNumber;
 | 
						|
  nsPluginFrame* mFrame;
 | 
						|
};
 | 
						|
 | 
						|
nsPluginFrame::nsPluginFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
 | 
						|
    : nsFrame(aStyle, aPresContext, kClassID),
 | 
						|
      mInstanceOwner(nullptr),
 | 
						|
      mOuterView(nullptr),
 | 
						|
      mInnerView(nullptr),
 | 
						|
      mBackgroundSink(nullptr),
 | 
						|
      mReflowCallbackPosted(false) {
 | 
						|
  MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
 | 
						|
          ("Created new nsPluginFrame %p\n", this));
 | 
						|
}
 | 
						|
 | 
						|
nsPluginFrame::~nsPluginFrame() {
 | 
						|
  MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
 | 
						|
          ("nsPluginFrame %p deleted\n", this));
 | 
						|
}
 | 
						|
 | 
						|
NS_QUERYFRAME_HEAD(nsPluginFrame)
 | 
						|
  NS_QUERYFRAME_ENTRY(nsPluginFrame)
 | 
						|
  NS_QUERYFRAME_ENTRY(nsIObjectFrame)
 | 
						|
NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
a11y::AccType nsPluginFrame::AccessibleType() { return a11y::ePluginType; }
 | 
						|
 | 
						|
#  ifdef XP_WIN
 | 
						|
NS_IMETHODIMP nsPluginFrame::GetPluginPort(HWND* aPort) {
 | 
						|
  *aPort = (HWND)mInstanceOwner->GetPluginPort();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
#  endif
 | 
						|
#endif
 | 
						|
 | 
						|
void nsPluginFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
 | 
						|
                         nsIFrame* aPrevInFlow) {
 | 
						|
  MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
 | 
						|
          ("Initializing nsPluginFrame %p for content %p\n", this, aContent));
 | 
						|
 | 
						|
  nsFrame::Init(aContent, aParent, aPrevInFlow);
 | 
						|
  CreateView();
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot,
 | 
						|
                                PostDestroyData& aPostDestroyData) {
 | 
						|
  if (mReflowCallbackPosted) {
 | 
						|
    PresShell()->CancelReflowCallback(this);
 | 
						|
  }
 | 
						|
 | 
						|
  // Ensure our DidComposite observer is gone.
 | 
						|
  mDidCompositeObserver = nullptr;
 | 
						|
 | 
						|
  // Tell content owner of the instance to disconnect its frame.
 | 
						|
  nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
 | 
						|
  NS_ASSERTION(objContent, "Why not an object loading content?");
 | 
						|
 | 
						|
  // The content might not have a reference to the instance owner any longer in
 | 
						|
  // the case of re-entry during instantiation or teardown, so make sure we're
 | 
						|
  // dissociated.
 | 
						|
  if (mInstanceOwner) {
 | 
						|
    mInstanceOwner->SetFrame(nullptr);
 | 
						|
  }
 | 
						|
  objContent->HasNewFrame(nullptr);
 | 
						|
 | 
						|
  if (mBackgroundSink) {
 | 
						|
    mBackgroundSink->Destroy();
 | 
						|
  }
 | 
						|
 | 
						|
  nsFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
 | 
						|
}
 | 
						|
 | 
						|
/* virtual */
 | 
						|
void nsPluginFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
 | 
						|
  if (HasView()) {
 | 
						|
    nsView* view = GetView();
 | 
						|
    nsViewManager* vm = view->GetViewManager();
 | 
						|
    if (vm) {
 | 
						|
      nsViewVisibility visibility =
 | 
						|
          IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
 | 
						|
      vm->SetViewVisibility(view, visibility);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsFrame::DidSetComputedStyle(aOldComputedStyle);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef DEBUG_FRAME_DUMP
 | 
						|
nsresult nsPluginFrame::GetFrameName(nsAString& aResult) const {
 | 
						|
  return MakeFrameName(NS_LITERAL_STRING("PluginFrame"), aResult);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
nsresult nsPluginFrame::PrepForDrawing(nsIWidget* aWidget) {
 | 
						|
  mWidget = aWidget;
 | 
						|
 | 
						|
  nsView* view = GetView();
 | 
						|
  NS_ASSERTION(view, "Object frames must have views");
 | 
						|
  if (!view) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  nsViewManager* viewMan = view->GetViewManager();
 | 
						|
  // mark the view as hidden since we don't know the (x,y) until Paint
 | 
						|
  // XXX is the above comment correct?
 | 
						|
  viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
 | 
						|
 | 
						|
  // this is ugly. it was ripped off from didreflow(). MMP
 | 
						|
  // Position and size view relative to its parent, not relative to our
 | 
						|
  // parent frame (our parent frame may not have a view).
 | 
						|
 | 
						|
  nsView* parentWithView;
 | 
						|
  nsPoint origin;
 | 
						|
  nsRect r(0, 0, mRect.width, mRect.height);
 | 
						|
 | 
						|
  GetOffsetFromView(origin, &parentWithView);
 | 
						|
  viewMan->ResizeView(view, r);
 | 
						|
  viewMan->MoveViewTo(view, origin.x, origin.y);
 | 
						|
 | 
						|
  nsPresContext* presContext = PresContext();
 | 
						|
  nsRootPresContext* rpc = presContext->GetRootPresContext();
 | 
						|
  if (!rpc) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mWidget) {
 | 
						|
    // Disallow windowed plugins in popups
 | 
						|
    nsIFrame* rootFrame = rpc->PresShell()->GetRootFrame();
 | 
						|
    nsIWidget* parentWidget = rootFrame->GetNearestWidget();
 | 
						|
    if (!parentWidget ||
 | 
						|
        nsLayoutUtils::GetDisplayRootFrame(this) != rootFrame) {
 | 
						|
      return NS_ERROR_FAILURE;
 | 
						|
    }
 | 
						|
 | 
						|
    // We can already have mInnerView if our instance owner went away and then
 | 
						|
    // came back. So clear the old one before creating a new one.
 | 
						|
    if (mInnerView) {
 | 
						|
      if (mInnerView->GetWidget()) {
 | 
						|
        // The widget listener should have already been cleared by
 | 
						|
        // SetInstanceOwner (with a null instance owner).
 | 
						|
        MOZ_RELEASE_ASSERT(mInnerView->GetWidget()->GetWidgetListener() ==
 | 
						|
                           nullptr);
 | 
						|
      }
 | 
						|
      mInnerView->Destroy();
 | 
						|
      mInnerView = nullptr;
 | 
						|
    }
 | 
						|
    mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
 | 
						|
    if (!mInnerView) {
 | 
						|
      NS_ERROR("Could not create inner view");
 | 
						|
      return NS_ERROR_OUT_OF_MEMORY;
 | 
						|
    }
 | 
						|
    viewMan->InsertChild(view, mInnerView, nullptr, true);
 | 
						|
 | 
						|
    mWidget->SetParent(parentWidget);
 | 
						|
    mWidget->Enable(true);
 | 
						|
    mWidget->Show(true);
 | 
						|
 | 
						|
    // Set the plugin window to have an empty clip region until we know
 | 
						|
    // what our true position, size and clip region are. These
 | 
						|
    // will be reset when nsRootPresContext computes our true
 | 
						|
    // geometry. The plugin window does need to have a good size here, so
 | 
						|
    // set the size explicitly to a reasonable guess.
 | 
						|
    AutoTArray<nsIWidget::Configuration, 1> configurations;
 | 
						|
    nsIWidget::Configuration* configuration = configurations.AppendElement();
 | 
						|
    nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 | 
						|
    configuration->mChild = mWidget;
 | 
						|
    configuration->mBounds.width =
 | 
						|
        NSAppUnitsToIntPixels(mRect.width, appUnitsPerDevPixel);
 | 
						|
    configuration->mBounds.height =
 | 
						|
        NSAppUnitsToIntPixels(mRect.height, appUnitsPerDevPixel);
 | 
						|
    parentWidget->ConfigureChildren(configurations);
 | 
						|
 | 
						|
    mInnerView->AttachWidgetEventHandler(mWidget);
 | 
						|
 | 
						|
#ifdef XP_MACOSX
 | 
						|
    // On Mac, we need to invalidate ourselves since even windowed
 | 
						|
    // plugins are painted through Thebes and we need to ensure
 | 
						|
    // the PaintedLayer containing the plugin is updated.
 | 
						|
    if (parentWidget == GetNearestWidget()) {
 | 
						|
      InvalidateFrame();
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    RegisterPluginForGeometryUpdates();
 | 
						|
 | 
						|
    // Here we set the background color for this widget because some plugins
 | 
						|
    // will use the child window background color when painting. If it's not
 | 
						|
    // set, it may default to gray Sometimes, a frame doesn't have a background
 | 
						|
    // color or is transparent. In this case, walk up the frame tree until we do
 | 
						|
    // find a frame with a background color
 | 
						|
    for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
 | 
						|
      nscolor bgcolor =
 | 
						|
          frame->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
 | 
						|
      if (NS_GET_A(bgcolor) > 0) {  // make sure we got an actual color
 | 
						|
        mWidget->SetBackgroundColor(bgcolor);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    // Changing to windowless mode changes the NPWindow geometry.
 | 
						|
    FixupWindow(GetContentRectRelativeToSelf().Size());
 | 
						|
    RegisterPluginForGeometryUpdates();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsHidden()) {
 | 
						|
    viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  ;
 | 
						|
  if (nsAccessibilityService* accService =
 | 
						|
          PresShell::GetAccessibilityService()) {
 | 
						|
    accService->RecreateAccessible(PresShell(), mContent);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
#define EMBED_DEF_WIDTH 240
 | 
						|
#define EMBED_DEF_HEIGHT 200
 | 
						|
 | 
						|
/* virtual */
 | 
						|
nscoord nsPluginFrame::GetMinISize(gfxContext* aRenderingContext) {
 | 
						|
  nscoord result = 0;
 | 
						|
 | 
						|
  if (!IsHidden(false)) {
 | 
						|
    if (mContent->IsHTMLElement(nsGkAtoms::embed)) {
 | 
						|
      bool vertical = GetWritingMode().IsVertical();
 | 
						|
      result = nsPresContext::CSSPixelsToAppUnits(vertical ? EMBED_DEF_HEIGHT
 | 
						|
                                                           : EMBED_DEF_WIDTH);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DISPLAY_MIN_INLINE_SIZE(this, result);
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
/* virtual */
 | 
						|
nscoord nsPluginFrame::GetPrefISize(gfxContext* aRenderingContext) {
 | 
						|
  return nsPluginFrame::GetMinISize(aRenderingContext);
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::GetWidgetConfiguration(
 | 
						|
    nsTArray<nsIWidget::Configuration>* aConfigurations) {
 | 
						|
  if (!mWidget) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!mWidget->GetParent()) {
 | 
						|
    // Plugin widgets should not be toplevel except when they're out of the
 | 
						|
    // document, in which case the plugin should not be registered for
 | 
						|
    // geometry updates and this should not be called. But apparently we
 | 
						|
    // have bugs where mWidget sometimes is toplevel here. Bail out.
 | 
						|
    NS_ERROR(
 | 
						|
        "Plugin widgets registered for geometry updates should not be "
 | 
						|
        "toplevel");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
 | 
						|
  configuration->mChild = mWidget;
 | 
						|
  configuration->mBounds = mNextConfigurationBounds;
 | 
						|
  configuration->mClipRegion = mNextConfigurationClipRegion;
 | 
						|
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 | 
						|
  if (XRE_IsContentProcess()) {
 | 
						|
    configuration->mWindowID =
 | 
						|
        (uintptr_t)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
 | 
						|
    configuration->mVisible = mWidget->IsVisible();
 | 
						|
  }
 | 
						|
#endif  // defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::GetDesiredSize(nsPresContext* aPresContext,
 | 
						|
                                   const ReflowInput& aReflowInput,
 | 
						|
                                   ReflowOutput& aMetrics) {
 | 
						|
  // By default, we have no area
 | 
						|
  aMetrics.ClearSize();
 | 
						|
 | 
						|
  if (IsHidden(false)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  aMetrics.Width() = aReflowInput.ComputedWidth();
 | 
						|
  aMetrics.Height() = aReflowInput.ComputedHeight();
 | 
						|
 | 
						|
  // for EMBED, default to 240x200 for compatibility
 | 
						|
  if (mContent->IsHTMLElement(nsGkAtoms::embed)) {
 | 
						|
    if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) {
 | 
						|
      aMetrics.Width() = clamped(
 | 
						|
          nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
 | 
						|
          aReflowInput.ComputedMinWidth(), aReflowInput.ComputedMaxWidth());
 | 
						|
    }
 | 
						|
    if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) {
 | 
						|
      aMetrics.Height() = clamped(
 | 
						|
          nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
 | 
						|
          aReflowInput.ComputedMinHeight(), aReflowInput.ComputedMaxHeight());
 | 
						|
    }
 | 
						|
 | 
						|
#if defined(MOZ_WIDGET_GTK)
 | 
						|
    // We need to make sure that the size of the object frame does not
 | 
						|
    // exceed the maximum size of X coordinates.  See bug #225357 for
 | 
						|
    // more information.  In theory Gtk2 can handle large coordinates,
 | 
						|
    // but underlying plugins can't.
 | 
						|
    aMetrics.Height() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX),
 | 
						|
                                 aMetrics.Height());
 | 
						|
    aMetrics.Width() = std::min(aPresContext->DevPixelsToAppUnits(INT16_MAX),
 | 
						|
                                aMetrics.Width());
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
  // At this point, the width has an unconstrained value only if we have
 | 
						|
  // nothing to go on (no width set, no information from the plugin, nothing).
 | 
						|
  // Make up a number.
 | 
						|
  if (aMetrics.Width() == NS_UNCONSTRAINEDSIZE) {
 | 
						|
    aMetrics.Width() = (aReflowInput.ComputedMinWidth() != NS_UNCONSTRAINEDSIZE)
 | 
						|
                           ? aReflowInput.ComputedMinWidth()
 | 
						|
                           : 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // At this point, the height has an unconstrained value only in two cases:
 | 
						|
  // a) We are in standards mode with percent heights and parent is auto-height
 | 
						|
  // b) We have no height information at all.
 | 
						|
  // In either case, we have to make up a number.
 | 
						|
  if (aMetrics.Height() == NS_UNCONSTRAINEDSIZE) {
 | 
						|
    aMetrics.Height() =
 | 
						|
        (aReflowInput.ComputedMinHeight() != NS_UNCONSTRAINEDSIZE)
 | 
						|
            ? aReflowInput.ComputedMinHeight()
 | 
						|
            : 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // XXXbz don't add in the border and padding, because we screw up our
 | 
						|
  // plugin's size and positioning if we do...  Eventually we _do_ want to
 | 
						|
  // paint borders, though!  At that point, we will need to adjust the desired
 | 
						|
  // size either here or in Reflow....  Further, we will need to fix Paint() to
 | 
						|
  // call the superclass in all cases.
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
 | 
						|
                           const ReflowInput& aReflowInput,
 | 
						|
                           nsReflowStatus& aStatus) {
 | 
						|
  MarkInReflow();
 | 
						|
  DO_GLOBAL_REFLOW_COUNT("nsPluginFrame");
 | 
						|
  DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
 | 
						|
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
 | 
						|
 | 
						|
  // Get our desired size
 | 
						|
  GetDesiredSize(aPresContext, aReflowInput, aMetrics);
 | 
						|
  aMetrics.SetOverflowAreasToDesiredBounds();
 | 
						|
  FinishAndStoreOverflow(&aMetrics);
 | 
						|
 | 
						|
  // delay plugin instantiation until all children have
 | 
						|
  // arrived. Otherwise there may be PARAMs or other stuff that the
 | 
						|
  // plugin needs to see that haven't arrived yet.
 | 
						|
  if (!GetContent()->IsDoneAddingChildren()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // if we are printing or print previewing, bail for now
 | 
						|
  if (aPresContext->Medium() == nsGkAtoms::print) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsRect r(0, 0, aMetrics.Width(), aMetrics.Height());
 | 
						|
  r.Deflate(aReflowInput.ComputedPhysicalBorderPadding());
 | 
						|
 | 
						|
  if (mInnerView) {
 | 
						|
    nsViewManager* vm = mInnerView->GetViewManager();
 | 
						|
    vm->MoveViewTo(mInnerView, r.x, r.y);
 | 
						|
    vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), true);
 | 
						|
  }
 | 
						|
 | 
						|
  FixupWindow(r.Size());
 | 
						|
  if (!mReflowCallbackPosted) {
 | 
						|
    mReflowCallbackPosted = true;
 | 
						|
    aPresContext->PresShell()->PostReflowCallback(this);
 | 
						|
  }
 | 
						|
 | 
						|
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
 | 
						|
}
 | 
						|
 | 
						|
///////////// nsIReflowCallback ///////////////
 | 
						|
 | 
						|
bool nsPluginFrame::ReflowFinished() {
 | 
						|
  mReflowCallbackPosted = false;
 | 
						|
  CallSetWindow();
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::ReflowCallbackCanceled() { mReflowCallbackPosted = false; }
 | 
						|
 | 
						|
void nsPluginFrame::FixupWindow(const nsSize& aSize) {
 | 
						|
  nsPresContext* presContext = PresContext();
 | 
						|
 | 
						|
  if (!mInstanceOwner) return;
 | 
						|
 | 
						|
  NPWindow* window;
 | 
						|
  mInstanceOwner->GetWindow(window);
 | 
						|
 | 
						|
  NS_ENSURE_TRUE_VOID(window);
 | 
						|
 | 
						|
  bool windowless = (window->type == NPWindowTypeDrawable);
 | 
						|
 | 
						|
  nsIntPoint origin = GetWindowOriginInPixels(windowless);
 | 
						|
 | 
						|
  // window must be in "display pixels"
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
  // window must be in "display pixels"
 | 
						|
  double scaleFactor = 1.0;
 | 
						|
  if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
 | 
						|
    scaleFactor = 1.0;
 | 
						|
  }
 | 
						|
  int intScaleFactor = ceil(scaleFactor);
 | 
						|
  window->x = origin.x / intScaleFactor;
 | 
						|
  window->y = origin.y / intScaleFactor;
 | 
						|
  window->width =
 | 
						|
      presContext->AppUnitsToDevPixels(aSize.width) / intScaleFactor;
 | 
						|
  window->height =
 | 
						|
      presContext->AppUnitsToDevPixels(aSize.height) / intScaleFactor;
 | 
						|
#else
 | 
						|
  window->x = origin.x;
 | 
						|
  window->y = origin.y;
 | 
						|
  window->width = presContext->AppUnitsToDevPixels(aSize.width);
 | 
						|
  window->height = presContext->AppUnitsToDevPixels(aSize.height);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef XP_MACOSX
 | 
						|
  mInstanceOwner->UpdateWindowPositionAndClipRect(false);
 | 
						|
#endif
 | 
						|
 | 
						|
  NotifyPluginReflowObservers();
 | 
						|
}
 | 
						|
 | 
						|
nsresult nsPluginFrame::CallSetWindow(bool aCheckIsHidden) {
 | 
						|
  NPWindow* win = nullptr;
 | 
						|
 | 
						|
  nsresult rv = NS_ERROR_FAILURE;
 | 
						|
  RefPtr<nsNPAPIPluginInstance> pi;
 | 
						|
  if (!mInstanceOwner || !(pi = mInstanceOwner->GetInstance()) ||
 | 
						|
      NS_FAILED(rv = mInstanceOwner->GetWindow(win)) || !win)
 | 
						|
    return rv;
 | 
						|
 | 
						|
  nsPluginNativeWindow* window = (nsPluginNativeWindow*)win;
 | 
						|
 | 
						|
  if (aCheckIsHidden && IsHidden()) return NS_ERROR_FAILURE;
 | 
						|
 | 
						|
  // Calling either nsPluginInstanceOwner::FixUpPluginWindow() (here,
 | 
						|
  // on OS X) or SetWindow() (below, on all platforms) can destroy this
 | 
						|
  // frame.  (FixUpPluginWindow() calls SetWindow()).  So grab a safe
 | 
						|
  // reference to mInstanceOwner which we can use below, if needed.
 | 
						|
  RefPtr<nsPluginInstanceOwner> instanceOwnerRef(mInstanceOwner);
 | 
						|
 | 
						|
  // refresh the plugin port as well
 | 
						|
#ifdef XP_MACOSX
 | 
						|
  mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable);
 | 
						|
  // Bail now if our frame has been destroyed.
 | 
						|
  if (!instanceOwnerRef->GetFrame()) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  window->window = mInstanceOwner->GetPluginPort();
 | 
						|
 | 
						|
  // Adjust plugin dimensions according to pixel snap results
 | 
						|
  // and reduce amount of SetWindow calls
 | 
						|
  nsPresContext* presContext = PresContext();
 | 
						|
  nsRootPresContext* rootPC = presContext->GetRootPresContext();
 | 
						|
  if (!rootPC) return NS_ERROR_FAILURE;
 | 
						|
  int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 | 
						|
  nsIFrame* rootFrame = rootPC->PresShell()->GetRootFrame();
 | 
						|
  nsRect bounds =
 | 
						|
      GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
 | 
						|
  nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
 | 
						|
 | 
						|
  // In e10s, this returns the offset to the top level window, in non-e10s
 | 
						|
  // it return 0,0.
 | 
						|
  LayoutDeviceIntPoint intOffset = GetRemoteTabChromeOffset();
 | 
						|
  intBounds.x += intOffset.x;
 | 
						|
  intBounds.y += intOffset.y;
 | 
						|
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
  // window must be in "display pixels"
 | 
						|
  double scaleFactor = 1.0;
 | 
						|
  if (NS_FAILED(instanceOwnerRef->GetContentsScaleFactor(&scaleFactor))) {
 | 
						|
    scaleFactor = 1.0;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t intScaleFactor = ceil(scaleFactor);
 | 
						|
  window->x = intBounds.x / intScaleFactor;
 | 
						|
  window->y = intBounds.y / intScaleFactor;
 | 
						|
  window->width = intBounds.width / intScaleFactor;
 | 
						|
  window->height = intBounds.height / intScaleFactor;
 | 
						|
#else
 | 
						|
  window->x = intBounds.x;
 | 
						|
  window->y = intBounds.y;
 | 
						|
  window->width = intBounds.width;
 | 
						|
  window->height = intBounds.height;
 | 
						|
#endif
 | 
						|
  // BE CAREFUL: By the time we get here the PluginFrame is sometimes destroyed
 | 
						|
  // and poisoned. If we reference local fields (implicit this deref),
 | 
						|
  // we will crash.
 | 
						|
  instanceOwnerRef->ResolutionMayHaveChanged();
 | 
						|
 | 
						|
  // This will call pi->SetWindow and take care of window subclassing
 | 
						|
  // if needed, see bug 132759. Calling SetWindow can destroy this frame
 | 
						|
  // so check for that before doing anything else with this frame's memory.
 | 
						|
  if (instanceOwnerRef->UseAsyncRendering()) {
 | 
						|
    rv = pi->AsyncSetWindow(window);
 | 
						|
  } else {
 | 
						|
    rv = window->CallSetWindow(pi);
 | 
						|
  }
 | 
						|
 | 
						|
  instanceOwnerRef->ReleasePluginPort(window->window);
 | 
						|
 | 
						|
  return rv;
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::RegisterPluginForGeometryUpdates() {
 | 
						|
  nsRootPresContext* rpc = PresContext()->GetRootPresContext();
 | 
						|
  NS_ASSERTION(rpc, "We should have a root pres context!");
 | 
						|
  if (mRootPresContextRegisteredWith == rpc || !rpc) {
 | 
						|
    // Already registered with current root pres context,
 | 
						|
    // or null root pres context...
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if (mRootPresContextRegisteredWith && mRootPresContextRegisteredWith != rpc) {
 | 
						|
    // Registered to some other root pres context. Unregister, and
 | 
						|
    // re-register with our current one...
 | 
						|
    UnregisterPluginForGeometryUpdates();
 | 
						|
  }
 | 
						|
  mRootPresContextRegisteredWith = rpc;
 | 
						|
  mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent);
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::UnregisterPluginForGeometryUpdates() {
 | 
						|
  if (!mRootPresContextRegisteredWith) {
 | 
						|
    // Not registered...
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mRootPresContextRegisteredWith->UnregisterPluginForGeometryUpdates(mContent);
 | 
						|
  mRootPresContextRegisteredWith = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner) {
 | 
						|
  // The ownership model here is historically fuzzy. This should only be called
 | 
						|
  // by nsPluginInstanceOwner when it is given a new frame, and
 | 
						|
  // nsObjectLoadingContent should be arbitrating frame-ownership via its
 | 
						|
  // HasNewFrame callback.
 | 
						|
  mInstanceOwner = aOwner;
 | 
						|
 | 
						|
  // Reset the DidCompositeObserver since the owner changed.
 | 
						|
  mDidCompositeObserver = nullptr;
 | 
						|
 | 
						|
  if (mInstanceOwner) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  UnregisterPluginForGeometryUpdates();
 | 
						|
  if (mWidget && mInnerView) {
 | 
						|
    mInnerView->DetachWidgetEventHandler(mWidget);
 | 
						|
    // Make sure the plugin is hidden in case an update of plugin geometry
 | 
						|
    // hasn't happened since this plugin became hidden.
 | 
						|
    nsIWidget* parent = mWidget->GetParent();
 | 
						|
    if (parent) {
 | 
						|
      nsTArray<nsIWidget::Configuration> configurations;
 | 
						|
      nsIWidget::Configuration* configuration = configurations.AppendElement();
 | 
						|
      configuration->mChild = mWidget;
 | 
						|
      parent->ConfigureChildren(configurations);
 | 
						|
 | 
						|
      mWidget->Show(false);
 | 
						|
      mWidget->Enable(false);
 | 
						|
      mWidget->SetParent(nullptr);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::IsFocusable(int32_t* aTabIndex, bool aWithMouse) {
 | 
						|
  if (aTabIndex) *aTabIndex = -1;
 | 
						|
  return nsFrame::IsFocusable(aTabIndex, aWithMouse);
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const {
 | 
						|
  if (aCheckVisibilityStyle) {
 | 
						|
    if (!StyleVisibility()->IsVisibleOrCollapsed()) return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // only <embed> tags support the HIDDEN attribute
 | 
						|
  if (mContent->IsHTMLElement(nsGkAtoms::embed)) {
 | 
						|
    // Yes, these are really the kooky ways that you could tell 4.x
 | 
						|
    // not to hide the <embed> once you'd put the 'hidden' attribute
 | 
						|
    // on the tag...
 | 
						|
 | 
						|
    // HIDDEN w/ no attributes gets translated as we are hidden for
 | 
						|
    // compatibility w/ 4.x and IE so we don't create a non-painting
 | 
						|
    // widget in layout. See bug 188959.
 | 
						|
    nsAutoString hidden;
 | 
						|
    if (mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden,
 | 
						|
                                       hidden) &&
 | 
						|
        (hidden.IsEmpty() || (!hidden.LowerCaseEqualsLiteral("false") &&
 | 
						|
                              !hidden.LowerCaseEqualsLiteral("no") &&
 | 
						|
                              !hidden.LowerCaseEqualsLiteral("off")))) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::LayoutDeviceIntPoint nsPluginFrame::GetRemoteTabChromeOffset() {
 | 
						|
  LayoutDeviceIntPoint offset;
 | 
						|
  if (XRE_IsContentProcess()) {
 | 
						|
    if (nsPIDOMWindowOuter* window = GetContent()->OwnerDoc()->GetWindow()) {
 | 
						|
      if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetTop()) {
 | 
						|
        dom::BrowserChild* tc = dom::BrowserChild::GetFrom(topWindow);
 | 
						|
        if (tc) {
 | 
						|
          offset += tc->GetChromeOffset();
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return offset;
 | 
						|
}
 | 
						|
 | 
						|
nsIntPoint nsPluginFrame::GetWindowOriginInPixels(bool aWindowless) {
 | 
						|
  nsView* parentWithView;
 | 
						|
  nsPoint origin(0, 0);
 | 
						|
 | 
						|
  GetOffsetFromView(origin, &parentWithView);
 | 
						|
 | 
						|
  // if it's windowless, let's make sure we have our origin set right
 | 
						|
  // it may need to be corrected, like after scrolling
 | 
						|
  if (aWindowless && parentWithView) {
 | 
						|
    nsPoint offsetToWidget;
 | 
						|
    parentWithView->GetNearestWidget(&offsetToWidget);
 | 
						|
    origin += offsetToWidget;
 | 
						|
  }
 | 
						|
  origin += GetContentRectRelativeToSelf().TopLeft();
 | 
						|
 | 
						|
  nsIntPoint pt(PresContext()->AppUnitsToDevPixels(origin.x),
 | 
						|
                PresContext()->AppUnitsToDevPixels(origin.y));
 | 
						|
 | 
						|
  // If we're in the content process offsetToWidget is tied to the top level
 | 
						|
  // widget we can access in the child process, which is the tab. We need the
 | 
						|
  // offset all the way up to the top level native window here. (If this is
 | 
						|
  // non-e10s this routine will return 0,0.)
 | 
						|
  if (aWindowless) {
 | 
						|
    mozilla::LayoutDeviceIntPoint lpt = GetRemoteTabChromeOffset();
 | 
						|
    pt += nsIntPoint(lpt.x, lpt.y);
 | 
						|
  }
 | 
						|
 | 
						|
  return pt;
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::DidReflow(nsPresContext* aPresContext,
 | 
						|
                              const ReflowInput* aReflowInput) {
 | 
						|
  // Do this check before calling the superclass, as that clears
 | 
						|
  // NS_FRAME_FIRST_REFLOW
 | 
						|
  if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
 | 
						|
    nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
 | 
						|
    NS_ASSERTION(objContent, "Why not an object loading content?");
 | 
						|
    objContent->HasNewFrame(this);
 | 
						|
  }
 | 
						|
 | 
						|
  nsFrame::DidReflow(aPresContext, aReflowInput);
 | 
						|
 | 
						|
  if (HasView()) {
 | 
						|
    nsView* view = GetView();
 | 
						|
    nsViewManager* vm = view->GetViewManager();
 | 
						|
    if (vm)
 | 
						|
      vm->SetViewVisibility(
 | 
						|
          view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void nsPluginFrame::PaintPrintPlugin(nsIFrame* aFrame, gfxContext* aCtx,
 | 
						|
                                     const nsRect& aDirtyRect, nsPoint aPt) {
 | 
						|
  // Translate the context:
 | 
						|
  nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft();
 | 
						|
  gfxPoint devPixelPt = nsLayoutUtils::PointToGfxPoint(
 | 
						|
      pt, aFrame->PresContext()->AppUnitsPerDevPixel());
 | 
						|
 | 
						|
  gfxContextMatrixAutoSaveRestore autoSR(aCtx);
 | 
						|
  aCtx->SetMatrixDouble(aCtx->CurrentMatrixDouble().PreTranslate(devPixelPt));
 | 
						|
 | 
						|
  // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
 | 
						|
 | 
						|
  static_cast<nsPluginFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * nsDisplayPluginReadback creates an active ReadbackLayer. The ReadbackLayer
 | 
						|
 * obtains from the compositor the contents of the window underneath
 | 
						|
 * the ReadbackLayer, which we then use as an opaque buffer for plugins to
 | 
						|
 * asynchronously draw onto.
 | 
						|
 */
 | 
						|
class nsDisplayPluginReadback : public nsDisplayItem {
 | 
						|
 public:
 | 
						|
  nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
 | 
						|
      : nsDisplayItem(aBuilder, aFrame) {
 | 
						|
    MOZ_COUNT_CTOR(nsDisplayPluginReadback);
 | 
						|
  }
 | 
						|
#ifdef NS_BUILD_REFCNT_LOGGING
 | 
						|
  ~nsDisplayPluginReadback() override {
 | 
						|
    MOZ_COUNT_DTOR(nsDisplayPluginReadback);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
 | 
						|
 | 
						|
  NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
 | 
						|
 | 
						|
  already_AddRefed<Layer> BuildLayer(
 | 
						|
      nsDisplayListBuilder* aBuilder, LayerManager* aManager,
 | 
						|
      const ContainerLayerParameters& aContainerParameters) override {
 | 
						|
    return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(
 | 
						|
        aBuilder, aManager, this, aContainerParameters);
 | 
						|
  }
 | 
						|
 | 
						|
  LayerState GetLayerState(
 | 
						|
      nsDisplayListBuilder* aBuilder, LayerManager* aManager,
 | 
						|
      const ContainerLayerParameters& aParameters) override {
 | 
						|
    return LAYER_ACTIVE;
 | 
						|
  }
 | 
						|
 | 
						|
  virtual nsDisplayItemGeometry* AllocateGeometry(
 | 
						|
      nsDisplayListBuilder* aBuilder) override {
 | 
						|
    return new nsDisplayPluginGeometry(this, aBuilder);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
static nsRect GetDisplayItemBounds(nsDisplayListBuilder* aBuilder,
 | 
						|
                                   const nsDisplayItem* aItem,
 | 
						|
                                   nsIFrame* aFrame) {
 | 
						|
  // XXX For slightly more accurate region computations we should pixel-snap
 | 
						|
  // this
 | 
						|
  return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
 | 
						|
}
 | 
						|
 | 
						|
nsRect nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder,
 | 
						|
                                          bool* aSnap) const {
 | 
						|
  *aSnap = false;
 | 
						|
  return GetDisplayItemBounds(aBuilder, this, mFrame);
 | 
						|
}
 | 
						|
 | 
						|
nsRect nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder,
 | 
						|
                                  bool* aSnap) const {
 | 
						|
  *aSnap = true;
 | 
						|
  return GetDisplayItemBounds(aBuilder, this, mFrame);
 | 
						|
}
 | 
						|
 | 
						|
void nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
 | 
						|
  nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
 | 
						|
  bool snap;
 | 
						|
  f->PaintPlugin(aBuilder, *aCtx, GetPaintRect(), GetBounds(aBuilder, &snap));
 | 
						|
}
 | 
						|
 | 
						|
static nsRect GetClippedBoundsIncludingAllScrollClips(
 | 
						|
    nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) {
 | 
						|
  nsRect r = aItem->GetClippedBounds(aBuilder);
 | 
						|
  for (auto* sc = aItem->GetClipChain(); sc; sc = sc->mParent) {
 | 
						|
    r = sc->mClip.ApplyNonRoundedIntersection(r);
 | 
						|
  }
 | 
						|
  return r;
 | 
						|
}
 | 
						|
 | 
						|
bool nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
 | 
						|
                                        nsRegion* aVisibleRegion) {
 | 
						|
  if (aBuilder->IsForPluginGeometry()) {
 | 
						|
    nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
 | 
						|
    if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) {
 | 
						|
      // Since transforms induce reference frames, we don't need to worry
 | 
						|
      // about this method fluffing out due to non-rectilinear transforms.
 | 
						|
      nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(
 | 
						|
          f, f->GetContentRectRelativeToSelf(), ReferenceFrame());
 | 
						|
      nscoord appUnitsPerDevPixel =
 | 
						|
          ReferenceFrame()->PresContext()->AppUnitsPerDevPixel();
 | 
						|
      f->mNextConfigurationBounds = LayoutDeviceIntRect::FromUnknownRect(
 | 
						|
          rAncestor.ToNearestPixels(appUnitsPerDevPixel));
 | 
						|
 | 
						|
      nsRegion visibleRegion;
 | 
						|
      // Apply all scroll clips when computing the clipped bounds of this item.
 | 
						|
      // We hide windowed plugins during APZ scrolling, so there never is an
 | 
						|
      // async transform that we need to take into account when clipping.
 | 
						|
      visibleRegion.And(
 | 
						|
          *aVisibleRegion,
 | 
						|
          GetClippedBoundsIncludingAllScrollClips(this, aBuilder));
 | 
						|
      // Make visibleRegion relative to f
 | 
						|
      visibleRegion.MoveBy(-ToReferenceFrame());
 | 
						|
 | 
						|
      f->mNextConfigurationClipRegion.Clear();
 | 
						|
      for (auto iter = visibleRegion.RectIter(); !iter.Done(); iter.Next()) {
 | 
						|
        nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(
 | 
						|
            f, iter.Get(), ReferenceFrame());
 | 
						|
        LayoutDeviceIntRect rPixels =
 | 
						|
            LayoutDeviceIntRect::FromUnknownRect(
 | 
						|
                rAncestor.ToNearestPixels(appUnitsPerDevPixel)) -
 | 
						|
            f->mNextConfigurationBounds.TopLeft();
 | 
						|
        if (!rPixels.IsEmpty()) {
 | 
						|
          f->mNextConfigurationClipRegion.AppendElement(rPixels);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (f->mInnerView) {
 | 
						|
      // This should produce basically the same rectangle (but not relative
 | 
						|
      // to the root frame). We only call this here for the side-effect of
 | 
						|
      // setting mViewToWidgetOffset on the view.
 | 
						|
      f->mInnerView->CalcWidgetBounds(eWindowType_plugin);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion);
 | 
						|
}
 | 
						|
 | 
						|
nsRegion nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
 | 
						|
                                          bool* aSnap) const {
 | 
						|
  *aSnap = false;
 | 
						|
  nsRegion result;
 | 
						|
  nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
 | 
						|
  if (!aBuilder->IsForPluginGeometry()) {
 | 
						|
    nsIWidget* widget = f->GetWidget();
 | 
						|
    if (widget) {
 | 
						|
      // Be conservative and treat plugins with widgets as not opaque,
 | 
						|
      // because that's simple and we might need the content under the widget
 | 
						|
      // if the widget is unexpectedly clipped away. (As can happen when
 | 
						|
      // chrome content over a plugin forces us to clip out the plugin for
 | 
						|
      // security reasons.)
 | 
						|
      // We shouldn't be repainting the content under plugins much anyway
 | 
						|
      // since there generally shouldn't be anything to invalidate or paint
 | 
						|
      // in PaintedLayers there.
 | 
						|
      return result;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (f->IsOpaque()) {
 | 
						|
    nsRect bounds = GetBounds(aBuilder, aSnap);
 | 
						|
    if (aBuilder->IsForPluginGeometry() ||
 | 
						|
        (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) {
 | 
						|
      // We can treat this as opaque
 | 
						|
      result = bounds;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
bool nsDisplayPlugin::CreateWebRenderCommands(
 | 
						|
    mozilla::wr::DisplayListBuilder& aBuilder,
 | 
						|
    mozilla::wr::IpcResourceUpdateQueue& aResources,
 | 
						|
    const StackingContextHelper& aSc,
 | 
						|
    mozilla::layers::RenderRootStateManager* aManager,
 | 
						|
    nsDisplayListBuilder* aDisplayListBuilder) {
 | 
						|
  return static_cast<nsPluginFrame*>(mFrame)->CreateWebRenderCommands(
 | 
						|
      this, aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
 | 
						|
}
 | 
						|
 | 
						|
nsresult nsPluginFrame::PluginEventNotifier::Run() {
 | 
						|
  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
 | 
						|
  obsSvc->NotifyObservers(nullptr, "plugin-changed-event", mEventType.get());
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::NotifyPluginReflowObservers() {
 | 
						|
  nsContentUtils::AddScriptRunner(
 | 
						|
      new PluginEventNotifier(NS_LITERAL_STRING("reflow")));
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::DidSetWidgetGeometry() {
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
  if (mInstanceOwner && !IsHidden()) {
 | 
						|
    mInstanceOwner->FixUpPluginWindow(
 | 
						|
        nsPluginInstanceOwner::ePluginPaintEnable);
 | 
						|
  }
 | 
						|
#else
 | 
						|
  if (!mWidget && mInstanceOwner) {
 | 
						|
    // UpdateWindowVisibility will notify the plugin of position changes
 | 
						|
    // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
 | 
						|
    // We treat windowless plugins inside popups as always visible, since
 | 
						|
    // plugins inside popups don't get valid mNextConfigurationBounds
 | 
						|
    // set up.
 | 
						|
    mInstanceOwner->UpdateWindowVisibility(
 | 
						|
        nsLayoutUtils::IsPopup(nsLayoutUtils::GetDisplayRootFrame(this)) ||
 | 
						|
        !mNextConfigurationBounds.IsEmpty());
 | 
						|
  }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::IsOpaque() const {
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
  return false;
 | 
						|
#else
 | 
						|
 | 
						|
  if (mInstanceOwner && mInstanceOwner->UseAsyncRendering()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return !IsTransparentMode();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::IsTransparentMode() const {
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
  return false;
 | 
						|
#else
 | 
						|
  if (!mInstanceOwner) return false;
 | 
						|
 | 
						|
  NPWindow* window = nullptr;
 | 
						|
  mInstanceOwner->GetWindow(window);
 | 
						|
  if (!window) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (window->type != NPWindowTypeDrawable) return false;
 | 
						|
 | 
						|
  RefPtr<nsNPAPIPluginInstance> pi = mInstanceOwner->GetInstance();
 | 
						|
  if (!pi) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  bool transparent = false;
 | 
						|
  pi->IsTransparent(&transparent);
 | 
						|
  return transparent;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
 | 
						|
                                     const nsDisplayListSet& aLists) {
 | 
						|
  // XXX why are we painting collapsed object frames?
 | 
						|
  if (!IsVisibleOrCollapsedForPainting()) return;
 | 
						|
 | 
						|
  DisplayBorderBackgroundOutline(aBuilder, aLists);
 | 
						|
 | 
						|
  nsPresContext::nsPresContextType type = PresContext()->Type();
 | 
						|
 | 
						|
  // If we are painting in Print Preview do nothing....
 | 
						|
  if (type == nsPresContext::eContext_PrintPreview) return;
 | 
						|
 | 
						|
  DO_GLOBAL_REFLOW_COUNT_DSP("nsPluginFrame");
 | 
						|
 | 
						|
#ifndef XP_MACOSX
 | 
						|
  if (mWidget && aBuilder->IsInTransform()) {
 | 
						|
    // Windowed plugins should not be rendered inside a transform.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if (aBuilder->IsForPainting() && mInstanceOwner) {
 | 
						|
    // Update plugin frame for both content scaling and full zoom changes.
 | 
						|
    mInstanceOwner->ResolutionMayHaveChanged();
 | 
						|
#ifdef XP_MACOSX
 | 
						|
    mInstanceOwner->WindowFocusMayHaveChanged();
 | 
						|
#endif
 | 
						|
    if (mInstanceOwner->UseAsyncRendering()) {
 | 
						|
      NPWindow* window = nullptr;
 | 
						|
      mInstanceOwner->GetWindow(window);
 | 
						|
      bool isVisible = window && window->width > 0 && window->height > 0;
 | 
						|
      if (isVisible && aBuilder->ShouldSyncDecodeImages()) {
 | 
						|
#ifndef XP_MACOSX
 | 
						|
        mInstanceOwner->UpdateWindowVisibility(true);
 | 
						|
#endif
 | 
						|
      }
 | 
						|
 | 
						|
      mInstanceOwner->NotifyPaintWaiter(aBuilder);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox clip(
 | 
						|
      aBuilder, this);
 | 
						|
 | 
						|
  // determine if we are printing
 | 
						|
  if (type == nsPresContext::eContext_Print) {
 | 
						|
    aLists.Content()->AppendNewToTop<nsDisplayGeneric>(
 | 
						|
        aBuilder, this, PaintPrintPlugin, "PrintPlugin",
 | 
						|
        DisplayItemType::TYPE_PRINT_PLUGIN);
 | 
						|
  } else {
 | 
						|
    LayerState state = GetLayerState(aBuilder, nullptr);
 | 
						|
    if (state == LAYER_INACTIVE && nsDisplayItem::ForceActiveLayers()) {
 | 
						|
      state = LAYER_ACTIVE;
 | 
						|
    }
 | 
						|
    if (aBuilder->IsPaintingToWindow() && state == LAYER_ACTIVE &&
 | 
						|
        IsTransparentMode()) {
 | 
						|
      aLists.Content()->AppendNewToTop<nsDisplayPluginReadback>(aBuilder, this);
 | 
						|
    }
 | 
						|
 | 
						|
    aLists.Content()->AppendNewToTop<nsDisplayPlugin>(aBuilder, this);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::PrintPlugin(gfxContext& aRenderingContext,
 | 
						|
                                const nsRect& aDirtyRect) {
 | 
						|
  nsCOMPtr<nsIObjectLoadingContent> obj(do_QueryInterface(mContent));
 | 
						|
  if (!obj) return;
 | 
						|
 | 
						|
  nsIFrame* frame = nullptr;
 | 
						|
  obj->GetPrintFrame(&frame);
 | 
						|
  if (!frame) return;
 | 
						|
 | 
						|
  nsPresContext* presContext = PresContext();
 | 
						|
  // make sure this is REALLY an nsIObjectFrame
 | 
						|
  // we may need to go through the children to get it
 | 
						|
  nsIObjectFrame* objectFrame = do_QueryFrame(frame);
 | 
						|
  if (!objectFrame) objectFrame = GetNextObjectFrame(presContext, frame);
 | 
						|
  if (!objectFrame) return;
 | 
						|
 | 
						|
  // finally we can get our plugin instance
 | 
						|
  RefPtr<nsNPAPIPluginInstance> pi = objectFrame->GetPluginInstance();
 | 
						|
  if (!pi) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // now we need to setup the correct location for printing
 | 
						|
  NPWindow window;
 | 
						|
  window.window = nullptr;
 | 
						|
 | 
						|
  // prepare embedded mode printing struct
 | 
						|
  NPPrint npprint;
 | 
						|
  npprint.mode = NP_EMBED;
 | 
						|
 | 
						|
  // we need to find out if we are windowless or not
 | 
						|
  bool windowless = false;
 | 
						|
  pi->IsWindowless(&windowless);
 | 
						|
  window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow;
 | 
						|
 | 
						|
  window.clipRect.bottom = 0;
 | 
						|
  window.clipRect.top = 0;
 | 
						|
  window.clipRect.left = 0;
 | 
						|
  window.clipRect.right = 0;
 | 
						|
 | 
						|
// platform specific printing code
 | 
						|
#if defined(XP_UNIX) || defined(XP_MACOSX)
 | 
						|
  // Doesn't work in a thebes world, or on OS X.
 | 
						|
  (void)window;
 | 
						|
  (void)npprint;
 | 
						|
#elif defined(XP_WIN)
 | 
						|
 | 
						|
  /* On Windows, we use the win32 printing surface to print.  This, in
 | 
						|
   * turn, uses the Cairo paginated surface, which in turn uses the
 | 
						|
   * meta surface to record all operations and then play them back.
 | 
						|
   * This doesn't work too well for plugins, because if plugins render
 | 
						|
   * directly into the DC, the meta surface won't have any knowledge
 | 
						|
   * of them, and so at the end when it actually does the replay step,
 | 
						|
   * it'll fill the background with white and draw over whatever was
 | 
						|
   * rendered before.
 | 
						|
   *
 | 
						|
   * So, to avoid this, we use PushGroup, which creates a new windows
 | 
						|
   * surface, the plugin renders to that, and then we use normal
 | 
						|
   * cairo methods to composite that in such that it's recorded using the
 | 
						|
   * meta surface.
 | 
						|
   */
 | 
						|
 | 
						|
  // we'll already be translated into the right spot by gfxWindowsNativeDrawing
 | 
						|
  nsSize contentSize = GetContentRectRelativeToSelf().Size();
 | 
						|
  window.x = 0;
 | 
						|
  window.y = 0;
 | 
						|
  window.width = presContext->AppUnitsToDevPixels(contentSize.width);
 | 
						|
  window.height = presContext->AppUnitsToDevPixels(contentSize.height);
 | 
						|
 | 
						|
  aRenderingContext.Save();
 | 
						|
 | 
						|
  // Make sure plugins don't do any damage outside of where they're supposed to
 | 
						|
  aRenderingContext.NewPath();
 | 
						|
  gfxRect r(window.x, window.y, window.width, window.height);
 | 
						|
  aRenderingContext.Rectangle(r);
 | 
						|
  aRenderingContext.Clip();
 | 
						|
 | 
						|
  gfxWindowsNativeDrawing nativeDraw(&aRenderingContext, r);
 | 
						|
  do {
 | 
						|
    HDC dc = nativeDraw.BeginNativeDrawing();
 | 
						|
    if (!dc) return;
 | 
						|
 | 
						|
    // XXX don't we need to call nativeDraw.TransformToNativeRect here?
 | 
						|
    npprint.print.embedPrint.platformPrint = dc;
 | 
						|
    npprint.print.embedPrint.window = window;
 | 
						|
    // send off print info to plugin
 | 
						|
    pi->Print(&npprint);
 | 
						|
 | 
						|
    nativeDraw.EndNativeDrawing();
 | 
						|
  } while (nativeDraw.ShouldRenderAgain());
 | 
						|
  nativeDraw.PaintToContext();
 | 
						|
 | 
						|
  aRenderingContext.Restore();
 | 
						|
#endif
 | 
						|
 | 
						|
  // XXX Nav 4.x always sent a SetWindow call after print. Should we do the
 | 
						|
  // same?
 | 
						|
  // XXX Calling DidReflow here makes no sense!!!
 | 
						|
  frame->DidReflow(presContext, nullptr);  // DidReflow will take care of it
 | 
						|
}
 | 
						|
 | 
						|
nsRect nsPluginFrame::GetPaintedRect(const nsDisplayPlugin* aItem) const {
 | 
						|
  if (!mInstanceOwner) return nsRect();
 | 
						|
  nsRect r = GetContentRectRelativeToSelf();
 | 
						|
  if (!mInstanceOwner->UseAsyncRendering()) return r;
 | 
						|
 | 
						|
  nsIntSize size = mInstanceOwner->GetCurrentImageSize();
 | 
						|
  nsPresContext* pc = PresContext();
 | 
						|
  r.IntersectRect(r, nsRect(0, 0, pc->DevPixelsToAppUnits(size.width),
 | 
						|
                            pc->DevPixelsToAppUnits(size.height)));
 | 
						|
  return r;
 | 
						|
}
 | 
						|
 | 
						|
LayerState nsPluginFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
 | 
						|
                                        LayerManager* aManager) {
 | 
						|
  if (!mInstanceOwner) return LAYER_NONE;
 | 
						|
 | 
						|
  if (mInstanceOwner->NeedsScrollImageLayer()) {
 | 
						|
    return LAYER_ACTIVE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!mInstanceOwner->UseAsyncRendering()) {
 | 
						|
    return LAYER_NONE;
 | 
						|
  }
 | 
						|
 | 
						|
  return LAYER_ACTIVE_FORCE;
 | 
						|
}
 | 
						|
 | 
						|
class PluginFrameDidCompositeObserver final : public DidCompositeObserver {
 | 
						|
 public:
 | 
						|
  PluginFrameDidCompositeObserver(nsPluginInstanceOwner* aOwner,
 | 
						|
                                  LayerManager* aLayerManager)
 | 
						|
      : mInstanceOwner(aOwner), mLayerManager(aLayerManager) {}
 | 
						|
  ~PluginFrameDidCompositeObserver() {
 | 
						|
    mLayerManager->RemoveDidCompositeObserver(this);
 | 
						|
  }
 | 
						|
  void DidComposite() override { mInstanceOwner->DidComposite(); }
 | 
						|
  bool IsValid(LayerManager* aLayerManager) {
 | 
						|
    return aLayerManager == mLayerManager;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  nsPluginInstanceOwner* mInstanceOwner;
 | 
						|
  RefPtr<LayerManager> mLayerManager;
 | 
						|
};
 | 
						|
 | 
						|
bool nsPluginFrame::GetBounds(nsDisplayItem* aItem, IntSize& aSize,
 | 
						|
                              gfxRect& aRect) {
 | 
						|
  if (!mInstanceOwner) return false;
 | 
						|
 | 
						|
  NPWindow* window = nullptr;
 | 
						|
  mInstanceOwner->GetWindow(window);
 | 
						|
  if (!window) return false;
 | 
						|
 | 
						|
  if (window->width <= 0 || window->height <= 0) return false;
 | 
						|
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
  // window is in "display pixels", but size needs to be in device pixels
 | 
						|
  // window must be in "display pixels"
 | 
						|
  double scaleFactor = 1.0;
 | 
						|
  if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
 | 
						|
    scaleFactor = 1.0;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t intScaleFactor = ceil(scaleFactor);
 | 
						|
#else
 | 
						|
  size_t intScaleFactor = 1;
 | 
						|
#endif
 | 
						|
 | 
						|
  aSize =
 | 
						|
      IntSize(window->width * intScaleFactor, window->height * intScaleFactor);
 | 
						|
 | 
						|
  nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
 | 
						|
  aRect =
 | 
						|
      nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
 | 
						|
  // to provide crisper and faster drawing.
 | 
						|
  aRect.Round();
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::CreateWebRenderCommands(
 | 
						|
    nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
 | 
						|
    mozilla::wr::IpcResourceUpdateQueue& aResources,
 | 
						|
    const StackingContextHelper& aSc,
 | 
						|
    mozilla::layers::RenderRootStateManager* aManager,
 | 
						|
    nsDisplayListBuilder* aDisplayListBuilder) {
 | 
						|
  IntSize size;
 | 
						|
  gfxRect r;
 | 
						|
  if (!GetBounds(aItem, size, r)) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<ImageContainer> container;
 | 
						|
  // Image for Windowed plugins that support window capturing for scroll
 | 
						|
  // operations or async windowless rendering.
 | 
						|
  container = mInstanceOwner->GetImageContainer();
 | 
						|
  if (!container) {
 | 
						|
    // This can occur if our instance is gone or if the current plugin
 | 
						|
    // configuration does not require a backing image layer.
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef XP_MACOSX
 | 
						|
  if (!mInstanceOwner->UseAsyncRendering()) {
 | 
						|
    mInstanceOwner->DoCocoaEventDrawRect(r, nullptr);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  RefPtr<LayerManager> lm = aDisplayListBuilder->GetWidgetLayerManager();
 | 
						|
  if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) {
 | 
						|
    mDidCompositeObserver =
 | 
						|
        MakeUnique<PluginFrameDidCompositeObserver>(mInstanceOwner, lm);
 | 
						|
  }
 | 
						|
  lm->AddDidCompositeObserver(mDidCompositeObserver.get());
 | 
						|
 | 
						|
  // If the image container is empty, we don't want to fallback. Any other
 | 
						|
  // failure will be due to resource constraints and fallback is unlikely to
 | 
						|
  // help us. Hence we can ignore the return value from PushImage.
 | 
						|
  LayoutDeviceRect dest(r.x, r.y, size.width, size.height);
 | 
						|
  aManager->CommandBuilder().PushImage(aItem, container, aBuilder, aResources,
 | 
						|
                                       aSc, dest, dest);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<Layer> nsPluginFrame::BuildLayer(
 | 
						|
    nsDisplayListBuilder* aBuilder, LayerManager* aManager,
 | 
						|
    nsDisplayItem* aItem,
 | 
						|
    const ContainerLayerParameters& aContainerParameters) {
 | 
						|
  IntSize size;
 | 
						|
  gfxRect r;
 | 
						|
  if (!GetBounds(aItem, size, r)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<Layer> layer =
 | 
						|
      (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
 | 
						|
 | 
						|
  if (aItem->GetType() == DisplayItemType::TYPE_PLUGIN) {
 | 
						|
    RefPtr<ImageContainer> container;
 | 
						|
    // Image for Windowed plugins that support window capturing for scroll
 | 
						|
    // operations or async windowless rendering.
 | 
						|
    container = mInstanceOwner->GetImageContainer();
 | 
						|
    if (!container) {
 | 
						|
      // This can occur if our instance is gone or if the current plugin
 | 
						|
      // configuration does not require a backing image layer.
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!layer) {
 | 
						|
      mInstanceOwner->NotifyPaintWaiter(aBuilder);
 | 
						|
      // Initialize ImageLayer
 | 
						|
      layer = aManager->CreateImageLayer();
 | 
						|
      if (!layer) return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
 | 
						|
    ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
 | 
						|
#ifdef XP_MACOSX
 | 
						|
    if (!mInstanceOwner->UseAsyncRendering()) {
 | 
						|
      mInstanceOwner->DoCocoaEventDrawRect(r, nullptr);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    imglayer->SetScaleToSize(size, ScaleMode::STRETCH);
 | 
						|
    imglayer->SetContainer(container);
 | 
						|
    SamplingFilter samplingFilter =
 | 
						|
        nsLayoutUtils::GetSamplingFilterForFrame(this);
 | 
						|
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
 | 
						|
    if (!aManager->IsCompositingCheap()) {
 | 
						|
      // Pixman just horrible with bilinear filter scaling
 | 
						|
      samplingFilter = SamplingFilter::POINT;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    imglayer->SetSamplingFilter(samplingFilter);
 | 
						|
 | 
						|
    layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
 | 
						|
 | 
						|
    if (aBuilder->IsPaintingToWindow() && aBuilder->GetWidgetLayerManager() &&
 | 
						|
        (aBuilder->GetWidgetLayerManager()->GetBackendType() ==
 | 
						|
             LayersBackend::LAYERS_CLIENT ||
 | 
						|
         aBuilder->GetWidgetLayerManager()->GetBackendType() ==
 | 
						|
             LayersBackend::LAYERS_WR) &&
 | 
						|
        mInstanceOwner->UseAsyncRendering()) {
 | 
						|
      RefPtr<LayerManager> lm = aBuilder->GetWidgetLayerManager();
 | 
						|
      if (!mDidCompositeObserver || !mDidCompositeObserver->IsValid(lm)) {
 | 
						|
        mDidCompositeObserver =
 | 
						|
            MakeUnique<PluginFrameDidCompositeObserver>(mInstanceOwner, lm);
 | 
						|
      }
 | 
						|
      lm->AddDidCompositeObserver(mDidCompositeObserver.get());
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    NS_ASSERTION(aItem->GetType() == DisplayItemType::TYPE_PLUGIN_READBACK,
 | 
						|
                 "Unknown item type");
 | 
						|
    MOZ_ASSERT(!IsOpaque(), "Opaque plugins don't use backgrounds");
 | 
						|
 | 
						|
    if (!layer) {
 | 
						|
      layer = aManager->CreateReadbackLayer();
 | 
						|
      if (!layer) return nullptr;
 | 
						|
    }
 | 
						|
    NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
 | 
						|
 | 
						|
    ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
 | 
						|
    if (readback->GetSize() != size) {
 | 
						|
      // This will destroy any old background sink and notify us that the
 | 
						|
      // background is now unknown
 | 
						|
      readback->SetSink(nullptr);
 | 
						|
      readback->SetSize(size);
 | 
						|
 | 
						|
      if (mBackgroundSink) {
 | 
						|
        // Maybe we still have a background sink associated with another
 | 
						|
        // readback layer that wasn't recycled for some reason? Unhook it
 | 
						|
        // now so that if this frame goes away, it doesn't have a dangling
 | 
						|
        // reference to us.
 | 
						|
        mBackgroundSink->Destroy();
 | 
						|
      }
 | 
						|
      mBackgroundSink =
 | 
						|
          new PluginBackgroundSink(this, readback->AllocateSequenceNumber());
 | 
						|
      readback->SetSink(mBackgroundSink);
 | 
						|
      // The layer has taken ownership of our sink. When either the sink dies
 | 
						|
      // or the frame dies, the connection from the surviving object is nulled
 | 
						|
      // out.
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Set a transform on the layer to draw the plugin in the right place
 | 
						|
  gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
 | 
						|
  Matrix transform = Matrix::Translation(p.x, p.y);
 | 
						|
 | 
						|
  layer->SetBaseTransform(Matrix4x4::From2D(transform));
 | 
						|
  return layer.forget();
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
 | 
						|
                                gfxContext& aRenderingContext,
 | 
						|
                                const nsRect& aDirtyRect,
 | 
						|
                                const nsRect& aPluginRect) {
 | 
						|
#if defined(DEBUG)
 | 
						|
  // On Desktop, we should have built a layer as we no longer support in-process
 | 
						|
  // plugins or synchronous painting. We can only get here for windowed plugins
 | 
						|
  // (which draw themselves), or via some error/unload state.
 | 
						|
  if (mInstanceOwner) {
 | 
						|
    NPWindow* window = nullptr;
 | 
						|
    mInstanceOwner->GetWindow(window);
 | 
						|
    MOZ_ASSERT(!window || window->type == NPWindowTypeWindow);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
nsresult nsPluginFrame::HandleEvent(nsPresContext* aPresContext,
 | 
						|
                                    WidgetGUIEvent* anEvent,
 | 
						|
                                    nsEventStatus* anEventStatus) {
 | 
						|
  NS_ENSURE_ARG_POINTER(anEvent);
 | 
						|
  NS_ENSURE_ARG_POINTER(anEventStatus);
 | 
						|
  nsresult rv = NS_OK;
 | 
						|
 | 
						|
  if (!mInstanceOwner) return NS_ERROR_NULL_POINTER;
 | 
						|
 | 
						|
  mInstanceOwner->ConsiderNewEventloopNestingLevel();
 | 
						|
 | 
						|
  if (anEvent->mMessage == ePluginActivate) {
 | 
						|
    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
 | 
						|
    if (fm) {
 | 
						|
      RefPtr<Element> elem = GetContent()->AsElement();
 | 
						|
      return fm->SetFocus(elem, 0);
 | 
						|
    }
 | 
						|
  } else if (anEvent->mMessage == ePluginFocus) {
 | 
						|
    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
 | 
						|
    if (fm) {
 | 
						|
      RefPtr<Element> elem = GetContent()->AsElement();
 | 
						|
      return fm->FocusPlugin(elem);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (mInstanceOwner->SendNativeEvents() &&
 | 
						|
      anEvent->IsNativeEventDelivererForPlugin()) {
 | 
						|
    *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
 | 
						|
    // Due to plugin code reentering Gecko, this frame may be dead at this
 | 
						|
    // point.
 | 
						|
    return rv;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef XP_WIN
 | 
						|
  rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus);
 | 
						|
  return rv;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef XP_MACOSX
 | 
						|
  // we want to process some native mouse events in the cocoa event model
 | 
						|
  if ((anEvent->mMessage == eMouseEnterIntoWidget ||
 | 
						|
       anEvent->mMessage == eWheel) &&
 | 
						|
      mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
 | 
						|
    *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
 | 
						|
    // Due to plugin code reentering Gecko, this frame may be dead at this
 | 
						|
    // point.
 | 
						|
    return rv;
 | 
						|
  }
 | 
						|
 | 
						|
  // These two calls to PresShell::SetCapturingContent() (on mouse-down
 | 
						|
  // and mouse-up) are needed to make the routing of mouse events while
 | 
						|
  // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec.
 | 
						|
  // See bug 525078 and bug 909678.
 | 
						|
  if (anEvent->mMessage == eMouseDown) {
 | 
						|
    PresShell::SetCapturingContent(GetContent(),
 | 
						|
                                   CaptureFlags::IgnoreAllowedState);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus);
 | 
						|
 | 
						|
  // We need to be careful from this point because the call to
 | 
						|
  // nsFrame::HandleEvent() might have killed us.
 | 
						|
 | 
						|
#ifdef XP_MACOSX
 | 
						|
  if (anEvent->mMessage == eMouseUp) {
 | 
						|
    PresShell::ReleaseCapturingContent();
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  return rv;
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::HandleWheelEventAsDefaultAction(
 | 
						|
    WidgetWheelEvent* aWheelEvent) {
 | 
						|
  MOZ_ASSERT(WantsToHandleWheelEventAsDefaultAction());
 | 
						|
  MOZ_ASSERT(!aWheelEvent->DefaultPrevented());
 | 
						|
 | 
						|
  if (NS_WARN_IF(!mInstanceOwner) ||
 | 
						|
      NS_WARN_IF(aWheelEvent->mMessage != eWheel)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // If the wheel event has native message, it should may be handled by
 | 
						|
  // HandleEvent() in the future.  In such case, we should do nothing here.
 | 
						|
  if (NS_WARN_IF(!!aWheelEvent->mPluginEvent)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mInstanceOwner->ProcessEvent(*aWheelEvent);
 | 
						|
  // We need to assume that the event is always consumed/handled by the
 | 
						|
  // plugin.  There is no way to know if it's actually consumed/handled.
 | 
						|
  aWheelEvent->mViewPortIsOverscrolled = false;
 | 
						|
  aWheelEvent->mOverflowDeltaX = 0;
 | 
						|
  aWheelEvent->mOverflowDeltaY = 0;
 | 
						|
  // Consume the event explicitly.
 | 
						|
  aWheelEvent->PreventDefault();
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::WantsToHandleWheelEventAsDefaultAction() const {
 | 
						|
#ifdef XP_WIN
 | 
						|
  if (!mInstanceOwner) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  NPWindow* window = nullptr;
 | 
						|
  mInstanceOwner->GetWindow(window);
 | 
						|
  // On Windows, only when the plugin is windowless, we need to send wheel
 | 
						|
  // events as default action.
 | 
						|
  return window->type == NPWindowTypeDrawable;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
nsNPAPIPluginInstance* nsPluginFrame::GetPluginInstance() {
 | 
						|
  if (!mInstanceOwner) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return mInstanceOwner->GetInstance();
 | 
						|
}
 | 
						|
 | 
						|
Maybe<nsIFrame::Cursor> nsPluginFrame::GetCursor(const nsPoint& aPoint) {
 | 
						|
  if (!mInstanceOwner) {
 | 
						|
    return Nothing();
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<nsNPAPIPluginInstance> inst = mInstanceOwner->GetInstance();
 | 
						|
  if (!inst) {
 | 
						|
    return Nothing();
 | 
						|
  }
 | 
						|
 | 
						|
  bool useDOMCursor =
 | 
						|
      static_cast<nsNPAPIPluginInstance*>(inst.get())->UsesDOMForCursor();
 | 
						|
  if (!useDOMCursor) {
 | 
						|
    return Nothing();
 | 
						|
  }
 | 
						|
 | 
						|
  return nsFrame::GetCursor(aPoint);
 | 
						|
}
 | 
						|
 | 
						|
void nsPluginFrame::SetIsDocumentActive(bool aIsActive) {
 | 
						|
  if (mInstanceOwner) {
 | 
						|
    mInstanceOwner->UpdateDocumentActiveState(aIsActive);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
nsIObjectFrame* nsPluginFrame::GetNextObjectFrame(nsPresContext* aPresContext,
 | 
						|
                                                  nsIFrame* aRoot) {
 | 
						|
  for (nsIFrame* child : aRoot->PrincipalChildList()) {
 | 
						|
    nsIObjectFrame* outFrame = do_QueryFrame(child);
 | 
						|
    if (outFrame) {
 | 
						|
      if (outFrame->GetPluginInstance()) {  // make sure we have a REAL plugin
 | 
						|
        return outFrame;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    outFrame = GetNextObjectFrame(aPresContext, child);
 | 
						|
    if (outFrame) return outFrame;
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
void nsPluginFrame::BeginSwapDocShells(nsISupports* aSupports, void*) {
 | 
						|
  MOZ_ASSERT(aSupports, "null parameter");
 | 
						|
  nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
 | 
						|
  if (!content) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // This function is called from a document content enumerator so we need
 | 
						|
  // to filter out the nsPluginFrames and ignore the rest.
 | 
						|
  nsIObjectFrame* obj = do_QueryFrame(content->GetPrimaryFrame());
 | 
						|
  if (!obj) return;
 | 
						|
 | 
						|
  nsPluginFrame* objectFrame = static_cast<nsPluginFrame*>(obj);
 | 
						|
  NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(),
 | 
						|
               "Plugin windows must not be toplevel");
 | 
						|
  objectFrame->UnregisterPluginForGeometryUpdates();
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
void nsPluginFrame::EndSwapDocShells(nsISupports* aSupports, void*) {
 | 
						|
  MOZ_ASSERT(aSupports, "null parameter");
 | 
						|
  nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
 | 
						|
  if (!content) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // This function is called from a document content enumerator so we need
 | 
						|
  // to filter out the nsPluginFrames and ignore the rest.
 | 
						|
  nsIObjectFrame* obj = do_QueryFrame(content->GetPrimaryFrame());
 | 
						|
  if (!obj) return;
 | 
						|
 | 
						|
  nsPluginFrame* objectFrame = static_cast<nsPluginFrame*>(obj);
 | 
						|
  nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
 | 
						|
  NS_ASSERTION(rootPC, "unable to register the plugin frame");
 | 
						|
  nsIWidget* widget = objectFrame->mWidget;
 | 
						|
  if (widget) {
 | 
						|
    // Reparent the widget.
 | 
						|
    nsIWidget* parent = rootPC->PresShell()->GetRootFrame()->GetNearestWidget();
 | 
						|
    widget->SetParent(parent);
 | 
						|
    AutoWeakFrame weakFrame(objectFrame);
 | 
						|
    objectFrame->CallSetWindow();
 | 
						|
    if (!weakFrame.IsAlive()) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (objectFrame->mInstanceOwner) {
 | 
						|
    objectFrame->RegisterPluginForGeometryUpdates();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
nsIFrame* NS_NewObjectFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
 | 
						|
  return new (aPresShell) nsPluginFrame(aStyle, aPresShell->GetPresContext());
 | 
						|
}
 | 
						|
 | 
						|
bool nsPluginFrame::IsPaintedByGecko() const {
 | 
						|
#ifdef XP_MACOSX
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return !mWidget;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
NS_IMPL_FRAMEARENA_HELPERS(nsPluginFrame)
 |