gecko-dev/layout/generic/nsPluginFrame.h
Emilio Cobos Álvarez a5a514eff4 Bug 1534914 - Improve blocked cursor behavior to fall back to next image. r=smaug
Right now we just block the image returned from nsIFrame::GetCursor, which is
the first loading cursor image.

I think we should do the same we do when the image fails to load, which is to
fall back to the next image instead.

This patch moves all the custom cursor code selection logic to
EventStateManager, and lets the frame return a CursorKind and whether custom
images are allowed.

Differential Revision: https://phabricator.services.mozilla.com/D23289

--HG--
extra : moz-landing-system : lando
2019-03-13 18:38:09 +00:00

404 lines
14 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 */
#ifndef nsPluginFrame_h___
#define nsPluginFrame_h___
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/UniquePtr.h"
#include "nsIObjectFrame.h"
#include "nsFrame.h"
#include "nsRegion.h"
#include "nsDisplayList.h"
#include "nsIReflowCallback.h"
#include "Units.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/webrender/WebRenderAPI.h"
#ifdef XP_WIN
# include <windows.h> // For HWND :(
// Undo the windows.h damage
# undef GetMessage
# undef CreateEvent
# undef GetClassName
# undef GetBinaryType
# undef RemoveDirectory
# undef LoadIcon
# undef LoadImage
# undef GetObject
#endif
class nsPresContext;
class nsRootPresContext;
class nsDisplayPlugin;
class PluginBackgroundSink;
class nsPluginInstanceOwner;
namespace mozilla {
namespace layers {
class ImageContainer;
class Layer;
class LayerManager;
} // namespace layers
} // namespace mozilla
class PluginFrameDidCompositeObserver;
class nsPluginFrame final : public nsFrame,
public nsIObjectFrame,
public nsIReflowCallback {
public:
typedef mozilla::LayerState LayerState;
typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::ImageContainer ImageContainer;
typedef mozilla::layers::StackingContextHelper StackingContextHelper;
typedef mozilla::layers::RenderRootStateManager RenderRootStateManager;
typedef mozilla::layers::WebRenderParentCommand WebRenderParentCommand;
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
NS_DECL_FRAMEARENA_HELPERS(nsPluginFrame)
NS_DECL_QUERYFRAME
friend nsIFrame* NS_NewObjectFrame(nsIPresShell* aPresShell,
ComputedStyle* aStyle);
virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;
virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
virtual void DidReflow(nsPresContext* aPresContext,
const ReflowInput* aReflowInput) override;
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
virtual nsresult HandleEvent(nsPresContext* aPresContext,
mozilla::WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus) override;
virtual bool IsFrameOfType(uint32_t aFlags) const override {
return nsFrame::IsFrameOfType(
aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
}
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override;
#endif
virtual void DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) override;
virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
nsNPAPIPluginInstance* GetPluginInstance() override;
virtual void SetIsDocumentActive(bool aIsActive) override;
mozilla::Maybe<Cursor> GetCursor(const nsPoint&) override;
// APIs used by nsRootPresContext to set up the widget position/size/clip
// region.
/**
* Set the next widget configuration for the plugin to the desired
* position of the plugin's widget, on the assumption that it is not visible
* (clipped out or covered by opaque content).
* This will only be called for plugins which have been registered
* with the root pres context for geometry updates.
* If there is no widget associated with the plugin, this will have no effect.
*/
void SetEmptyWidgetConfiguration() {
mNextConfigurationBounds = LayoutDeviceIntRect(0, 0, 0, 0);
mNextConfigurationClipRegion.Clear();
}
/**
* Append the desired widget configuration to aConfigurations.
*/
void GetWidgetConfiguration(
nsTArray<nsIWidget::Configuration>* aConfigurations);
LayoutDeviceIntRect GetWidgetlessClipRect() {
return RegionFromArray(mNextConfigurationClipRegion).GetBounds();
}
/**
* Called after all widget position/size/clip regions have been changed
* (even if there isn't a widget for this plugin).
*/
void DidSetWidgetGeometry();
// accessibility support
#ifdef ACCESSIBILITY
virtual mozilla::a11y::AccType AccessibleType() override;
# ifdef XP_WIN
NS_IMETHOD GetPluginPort(HWND* aPort);
# endif
#endif
// local methods
nsresult PrepForDrawing(nsIWidget* aWidget);
// for a given aRoot, this walks the frame tree looking for the next outFrame
static nsIObjectFrame* GetNextObjectFrame(nsPresContext* aPresContext,
nsIFrame* aRoot);
// nsIReflowCallback
virtual bool ReflowFinished() override;
virtual void ReflowCallbackCanceled() override;
/**
* Builds either an ImageLayer or a ReadbackLayer, depending on the type
* of aItem (TYPE_PLUGIN or TYPE_PLUGIN_READBACK respectively).
*/
already_AddRefed<Layer> BuildLayer(
nsDisplayListBuilder* aBuilder, LayerManager* aManager,
nsDisplayItem* aItem,
const ContainerLayerParameters& aContainerParameters);
LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
/**
* Get the rectangle (relative to this frame) which it will paint. Normally
* the frame's content-box but may be smaller if the plugin is rendering
* asynchronously and has a different-sized image temporarily.
*/
nsRect GetPaintedRect(const nsDisplayPlugin* aItem) const;
/**
* If aSupports has a nsPluginFrame, then prepare it for a DocShell swap.
* @see nsSubDocumentFrame::BeginSwapDocShells.
* There will be a call to EndSwapDocShells after we were moved to the
* new view tree.
*/
static void BeginSwapDocShells(nsISupports* aSupports, void*);
/**
* If aSupports has a nsPluginFrame, then set it up after a DocShell swap.
* @see nsSubDocumentFrame::EndSwapDocShells.
*/
static void EndSwapDocShells(nsISupports* aSupports, void*);
nsIWidget* GetWidget() override {
if (!mInnerView) {
return nullptr;
}
return mWidget;
}
/**
* Adjust the plugin's idea of its size, using aSize as its new size.
* (aSize must be in twips)
*/
void FixupWindow(const nsSize& aSize);
/*
* Sets up the plugin window and calls SetWindow on the plugin.
*/
nsresult CallSetWindow(bool aCheckIsHidden = true);
void SetInstanceOwner(nsPluginInstanceOwner* aOwner);
/**
* HandleWheelEventAsDefaultAction() handles eWheel event as default action.
* This should be called only when WantsToHandleWheelEventAsDefaultAction()
* returns true.
*/
void HandleWheelEventAsDefaultAction(mozilla::WidgetWheelEvent* aEvent);
/**
* WantsToHandleWheelEventAsDefaultAction() returns true if the plugin
* may want to handle wheel events as default action.
*/
bool WantsToHandleWheelEventAsDefaultAction() const;
bool CreateWebRenderCommands(
nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder);
protected:
explicit nsPluginFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
virtual ~nsPluginFrame();
// NOTE: This frame class does not inherit from |nsLeafFrame|, so
// this is not a virtual method implementation.
void GetDesiredSize(nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
ReflowOutput& aDesiredSize);
bool IsFocusable(int32_t* aTabIndex = nullptr,
bool aWithMouse = false) override;
// check attributes and optionally CSS to see if we should display anything
bool IsHidden(bool aCheckVisibilityStyle = true) const;
bool IsOpaque() const;
bool IsTransparentMode() const;
bool IsPaintedByGecko() const;
nsIntPoint GetWindowOriginInPixels(bool aWindowless);
/*
* If this frame is in a remote tab, return the tab offset to
* the origin of the chrome window. In non-e10s, this return 0,0.
* This api sends a sync ipc request so be careful about use.
*/
LayoutDeviceIntPoint GetRemoteTabChromeOffset();
static void PaintPrintPlugin(nsIFrame* aFrame, gfxContext* aRenderingContext,
const nsRect& aDirtyRect, nsPoint aPt);
void PrintPlugin(gfxContext& aRenderingContext, const nsRect& aDirtyRect);
void PaintPlugin(nsDisplayListBuilder* aBuilder,
gfxContext& aRenderingContext, const nsRect& aDirtyRect,
const nsRect& aPluginRect);
void NotifyPluginReflowObservers();
friend class nsPluginInstanceOwner;
friend class nsDisplayPlugin;
friend class PluginBackgroundSink;
nsView* GetViewInternal() const override { return mOuterView; }
void SetViewInternal(nsView* aView) override { mOuterView = aView; }
bool GetBounds(nsDisplayItem* aItem, mozilla::gfx::IntSize& aSize,
gfxRect& aRect);
private:
// Registers the plugin for a geometry update, and requests a geometry
// update. This caches the root pres context in
// mRootPresContextRegisteredWith, so that we can be sure we unregister
// from the right root prest context in UnregisterPluginForGeometryUpdates.
void RegisterPluginForGeometryUpdates();
// Unregisters the plugin for geometry updated with the root pres context
// stored in mRootPresContextRegisteredWith.
void UnregisterPluginForGeometryUpdates();
static const LayoutDeviceIntRegion RegionFromArray(
const nsTArray<LayoutDeviceIntRect>& aRects) {
LayoutDeviceIntRegion region;
for (uint32_t i = 0; i < aRects.Length(); ++i) {
region.Or(region, aRects[i]);
}
return region;
}
class PluginEventNotifier : public mozilla::Runnable {
public:
explicit PluginEventNotifier(const nsString& aEventType)
: mozilla::Runnable("nsPluginFrame::PluginEventNotifier"),
mEventType(aEventType) {}
NS_IMETHOD Run() override;
private:
nsString mEventType;
};
nsPluginInstanceOwner* mInstanceOwner; // WEAK
nsView* mOuterView;
nsView* mInnerView;
nsCOMPtr<nsIWidget> mWidget;
nsIntRect mWindowlessRect;
/**
* This is owned by the ReadbackLayer for this nsPluginFrame. It is
* automatically cleared if the PluginBackgroundSink is destroyed.
*/
PluginBackgroundSink* mBackgroundSink;
/**
* Bounds that we should set the plugin's widget to in the next composite,
* for plugins with widgets. For plugins without widgets, bounds in device
* pixels relative to the nearest frame that's a display list reference frame.
*/
LayoutDeviceIntRect mNextConfigurationBounds;
/**
* Clip region that we should set the plugin's widget to
* in the next composite. Only meaningful for plugins with widgets.
*/
nsTArray<LayoutDeviceIntRect> mNextConfigurationClipRegion;
bool mReflowCallbackPosted;
// We keep this reference to ensure we can always unregister the
// plugins we register on the root PresContext.
// This is only non-null while we have a plugin registered for geometry
// updates.
RefPtr<nsRootPresContext> mRootPresContextRegisteredWith;
mozilla::UniquePtr<PluginFrameDidCompositeObserver> mDidCompositeObserver;
};
class nsDisplayPluginGeometry : public nsDisplayItemGenericGeometry {
public:
nsDisplayPluginGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
: nsDisplayItemGenericGeometry(aItem, aBuilder) {}
// Plugins MozPaintWait event depends on sync decode, so we always want
// to rebuild the display list when sync decoding.
virtual bool InvalidateForSyncDecodeImages() const override { return true; }
};
class nsDisplayPlugin final : public nsDisplayItem {
public:
nsDisplayPlugin(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame) {
MOZ_COUNT_CTOR(nsDisplayPlugin);
aBuilder->SetContainsPluginItem();
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayPlugin() { MOZ_COUNT_DTOR(nsDisplayPlugin); }
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override;
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override;
virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion) override;
NS_DISPLAY_DECL_NAME("Plugin", TYPE_PLUGIN)
virtual already_AddRefed<Layer> BuildLayer(
nsDisplayListBuilder* aBuilder, LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override {
return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(
aBuilder, aManager, this, aContainerParameters);
}
virtual LayerState GetLayerState(
nsDisplayListBuilder* aBuilder, LayerManager* aManager,
const ContainerLayerParameters& aParameters) override {
return static_cast<nsPluginFrame*>(mFrame)->GetLayerState(aBuilder,
aManager);
}
virtual nsDisplayItemGeometry* AllocateGeometry(
nsDisplayListBuilder* aBuilder) override {
return new nsDisplayPluginGeometry(this, aBuilder);
}
virtual bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override;
};
#endif /* nsPluginFrame_h___ */