gecko-dev/layout/painting/nsImageRenderer.h
Andrew Osmond e501ee889d Bug 1409773 - Use WebRender instead of fallback for border raster images. r=jrmuizel
Before this patch, we would use fallback for all border images. Now for
all but vector images we will use the WebRender border images
primitives. Vector images are an exception because the fallback is
clever in that it upscales the vector image and clips to only draw the
region it requires. This avoids artifacting but to do something similar
for WebRender as it is currently defined, we would increase our CPU and
memory footprint as we would need to produce the entire vector image
upscaled, not just the parts we need. In the future we should change
WebRender to accept different image resources for each of the segments.

Differential Revision: https://phabricator.services.mozilla.com/D37093
2019-07-08 12:54:44 -04:00

312 lines
12 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/. */
#ifndef nsImageRenderer_h__
#define nsImageRenderer_h__
#include "nsLayoutUtils.h"
#include "nsStyleStruct.h"
#include "Units.h"
#include "mozilla/AspectRatio.h"
class gfxDrawable;
namespace mozilla {
namespace layers {
class StackingContextHelper;
class WebRenderParentCommand;
class RenderRootStateManager;
} // namespace layers
namespace wr {
class DisplayListBuilder;
class IpcResourceUpdateQueue;
} // namespace wr
// A CSSSizeOrRatio represents a (possibly partially specified) size for use
// in computing image sizes. Either or both of the width and height might be
// given. A ratio of width to height may also be given. If we at least two
// of these then we can compute a concrete size, that is a width and height.
struct CSSSizeOrRatio {
CSSSizeOrRatio()
: mWidth(0), mHeight(0), mHasWidth(false), mHasHeight(false) {}
bool CanComputeConcreteSize() const {
return mHasWidth + mHasHeight + HasRatio() >= 2;
}
bool IsConcrete() const { return mHasWidth && mHasHeight; }
bool HasRatio() const { return !!mRatio; }
bool IsEmpty() const {
return (mHasWidth && mWidth <= 0) || (mHasHeight && mHeight <= 0) ||
!mRatio;
}
// CanComputeConcreteSize must return true when ComputeConcreteSize is
// called.
nsSize ComputeConcreteSize() const;
void SetWidth(nscoord aWidth) {
mWidth = aWidth;
mHasWidth = true;
if (mHasHeight) {
mRatio = AspectRatio::FromSize(mWidth, mHeight);
}
}
void SetHeight(nscoord aHeight) {
mHeight = aHeight;
mHasHeight = true;
if (mHasWidth) {
mRatio = AspectRatio::FromSize(mWidth, mHeight);
}
}
void SetSize(const nsSize& aSize) {
mWidth = aSize.width;
mHeight = aSize.height;
mHasWidth = true;
mHasHeight = true;
mRatio = AspectRatio::FromSize(mWidth, mHeight);
}
void SetRatio(const AspectRatio& aRatio) {
MOZ_ASSERT(
!mHasWidth || !mHasHeight,
"Probably shouldn't be setting a ratio if we have a concrete size");
mRatio = aRatio;
}
AspectRatio mRatio;
nscoord mWidth;
nscoord mHeight;
bool mHasWidth;
bool mHasHeight;
};
/**
* This is a small wrapper class to encapsulate image drawing that can draw an
* nsStyleImage image, which may internally be a real image, a sub image, or a
* CSS gradient.
*
* @note Always call the member functions in the order of PrepareImage(),
* SetSize(), and Draw*().
*/
class nsImageRenderer {
public:
typedef mozilla::image::ImgDrawResult ImgDrawResult;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::ImageContainer ImageContainer;
enum { FLAG_SYNC_DECODE_IMAGES = 0x01, FLAG_PAINTING_TO_WINDOW = 0x02 };
enum FitType { CONTAIN, COVER };
nsImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage,
uint32_t aFlags);
~nsImageRenderer() = default;
/**
* Populates member variables to get ready for rendering.
* @return true iff the image is ready, and there is at least a pixel to
* draw.
*/
bool PrepareImage();
/**
* The three Compute*Size functions correspond to the sizing algorthms and
* definitions from the CSS Image Values and Replaced Content spec. See
* http://dev.w3.org/csswg/css-images-3/#sizing .
*/
/**
* Compute the intrinsic size of the image as defined in the CSS Image Values
* spec. The intrinsic size is the unscaled size which the image would ideally
* like to be in app units.
*/
mozilla::CSSSizeOrRatio ComputeIntrinsicSize();
/**
* Computes the placement for a background image, or for the image data
* inside of a replaced element.
*
* @param aPos The CSS <position> value that specifies the image's position.
* @param aOriginBounds The box to which the tiling position should be
* relative. For background images, this should correspond to
* 'background-origin' for the frame, except when painting on the
* canvas, in which case the origin bounds should be the bounds
* of the root element's frame. For a replaced element, this should
* be the element's content-box.
* @param aTopLeft [out] The top-left corner where an image tile should be
* drawn.
* @param aAnchorPoint [out] A point which should be pixel-aligned by
* nsLayoutUtils::DrawImage. This is the same as aTopLeft, unless
* CSS specifies a percentage (including 'right' or 'bottom'), in
* which case it's that percentage within of aOriginBounds. So
* 'right' would set aAnchorPoint.x to aOriginBounds.XMost().
*
* Points are returned relative to aOriginBounds.
*/
static void ComputeObjectAnchorPoint(const mozilla::Position& aPos,
const nsSize& aOriginBounds,
const nsSize& aImageSize,
nsPoint* aTopLeft,
nsPoint* aAnchorPoint);
/**
* Compute the size of the rendered image using either the 'cover' or
* 'contain' constraints (aFitType).
*/
static nsSize ComputeConstrainedSize(
const nsSize& aConstrainingSize,
const mozilla::AspectRatio& aIntrinsicRatio, FitType aFitType);
/**
* Compute the size of the rendered image (the concrete size) where no cover/
* contain constraints are given. The 'default algorithm' from the CSS Image
* Values spec.
*/
static nsSize ComputeConcreteSize(
const mozilla::CSSSizeOrRatio& aSpecifiedSize,
const mozilla::CSSSizeOrRatio& aIntrinsicSize,
const nsSize& aDefaultSize);
/**
* Set this image's preferred size. This will be its intrinsic size where
* specified and the default size where it is not. Used as the unscaled size
* when rendering the image.
*/
void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize,
const nsSize& aDefaultSize);
/**
* Draws the image to the target rendering context using
* {background|mask}-specific arguments.
* @see nsLayoutUtils::DrawImage() for parameters.
*/
ImgDrawResult DrawLayer(nsPresContext* aPresContext,
gfxContext& aRenderingContext, const nsRect& aDest,
const nsRect& aFill, const nsPoint& aAnchor,
const nsRect& aDirty, const nsSize& aRepeatSize,
float aOpacity);
/**
* Builds WebRender DisplayItems for an image using
* {background|mask}-specific arguments.
* @see nsLayoutUtils::DrawImage() for parameters.
*/
ImgDrawResult BuildWebRenderDisplayItemsForLayer(
nsPresContext* aPresContext, mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResource,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager, nsDisplayItem* aItem,
const nsRect& aDest, const nsRect& aFill, const nsPoint& aAnchor,
const nsRect& aDirty, const nsSize& aRepeatSize, float aOpacity);
/**
* Draw the image to a single component of a border-image style rendering.
* aFill The destination rect to be drawn into
* aSrc is the part of the image to be rendered into a tile (aUnitSize in
* aFill), if aSrc and the dest tile are different sizes, the image will be
* scaled to map aSrc onto the dest tile.
* aHFill and aVFill are the repeat patterns for the component -
* NS_STYLE_BORDER_IMAGE_REPEAT_*
* aUnitSize The scaled size of a single source rect (in destination coords)
* aIndex identifies the component: 0 1 2
* 3 4 5
* 6 7 8
* aSVGViewportSize The image size evaluated by default sizing algorithm.
* Pass Nothing() if we can read a valid viewport size or aspect-ratio from
* the drawing image directly, otherwise, pass Some() with viewport size
* evaluated from default sizing algorithm.
* aHasIntrinsicRatio is used to record if the source image has fixed
* intrinsic ratio.
*/
ImgDrawResult DrawBorderImageComponent(
nsPresContext* aPresContext, gfxContext& aRenderingContext,
const nsRect& aDirtyRect, const nsRect& aFill,
const mozilla::CSSIntRect& aSrc, mozilla::StyleBorderImageRepeat aHFill,
mozilla::StyleBorderImageRepeat aVFill, const nsSize& aUnitSize,
uint8_t aIndex, const mozilla::Maybe<nsSize>& aSVGViewportSize,
const bool aHasIntrinsicRatio);
/**
* Draw the image to aRenderingContext which can be used to define the
* float area in the presence of "shape-outside: <image>".
*/
ImgDrawResult DrawShapeImage(nsPresContext* aPresContext,
gfxContext& aRenderingContext);
bool IsRasterImage();
bool IsAnimatedImage();
/// Retrieves the image associated with this nsImageRenderer, if there is one.
already_AddRefed<imgIContainer> GetImage();
bool IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags);
bool IsReady() const { return mPrepareResult == ImgDrawResult::SUCCESS; }
ImgDrawResult PrepareResult() const { return mPrepareResult; }
void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; }
void SetMaskOp(mozilla::StyleMaskMode aMaskOp) { mMaskOp = aMaskOp; }
void PurgeCacheForViewportChange(
const mozilla::Maybe<nsSize>& aSVGViewportSize, const bool aHasRatio);
const nsSize& GetSize() const { return mSize; }
nsStyleImageType GetType() const { return mType; }
const mozilla::StyleGradient* GetGradientData() const {
return mGradientData;
}
private:
/**
* Draws the image to the target rendering context.
* aSrc is a rect on the source image which will be mapped to aDest; it's
* currently only used for gradients.
*
* @see nsLayoutUtils::DrawImage() for other parameters.
*/
ImgDrawResult Draw(nsPresContext* aPresContext, gfxContext& aRenderingContext,
const nsRect& aDirtyRect, const nsRect& aDest,
const nsRect& aFill, const nsPoint& aAnchor,
const nsSize& aRepeatSize, const mozilla::CSSIntRect& aSrc,
float aOpacity = 1.0);
/**
* Builds WebRender DisplayItems for the image.
* aSrc is a rect on the source image which will be mapped to aDest; it's
* currently only used for gradients.
*
* @see nsLayoutUtils::DrawImage() for other parameters.
*/
ImgDrawResult BuildWebRenderDisplayItems(
nsPresContext* aPresContext, mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager, nsDisplayItem* aItem,
const nsRect& aDirtyRect, const nsRect& aDest, const nsRect& aFill,
const nsPoint& aAnchor, const nsSize& aRepeatSize,
const mozilla::CSSIntRect& aSrc, float aOpacity = 1.0);
/**
* Helper method for creating a gfxDrawable from mPaintServerFrame or
* mImageElementSurface.
* Requires mType is eStyleImageType_Element.
* Returns null if we cannot create the drawable.
*/
already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
gfxContext& aContext);
nsIFrame* mForFrame;
const nsStyleImage* mImage;
nsStyleImageType mType;
nsCOMPtr<imgIContainer> mImageContainer;
const mozilla::StyleGradient* mGradientData;
nsIFrame* mPaintServerFrame;
nsLayoutUtils::SurfaceFromElementResult mImageElementSurface;
ImgDrawResult mPrepareResult;
nsSize mSize; // unscaled size of the image, in app units
uint32_t mFlags;
mozilla::gfx::ExtendMode mExtendMode;
mozilla::StyleMaskMode mMaskOp;
};
} // namespace mozilla
#endif /* nsImageRenderer_h__ */