Do background image scaling on the GPU. Part 1: Refactor nsCSSRendering to expose helpers we need in nsDisplayBackground::GetLayerState (bug 750172, r=roc).

This commit is contained in:
Andreas Gal 2012-05-03 13:11:57 -07:00
Родитель 578bae396e
Коммит b5904e703e
3 изменённых файлов: 205 добавлений и 181 удалений

Просмотреть файл

@ -87,81 +87,6 @@
using namespace mozilla;
/**
* 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(),
* ComputeSize(), and Draw().
*/
class ImageRenderer {
public:
enum {
FLAG_SYNC_DECODE_IMAGES = 0x01
};
ImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage, PRUint32 aFlags);
~ImageRenderer();
/**
* 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();
/**
* @return the image size in appunits when rendered, after accounting for the
* background positioning area, background-size, and the image's intrinsic
* dimensions (if any).
*/
nsSize ComputeSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea);
/**
* Draws the image to the target rendering context.
* @see nsLayoutUtils::DrawImage() for other parameters
*/
void Draw(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty);
private:
/*
* Compute the "unscaled" dimensions of the image in aUnscaled{Width,Height}
* and aRatio. Whether the image has a height and width are indicated by
* aHaveWidth and aHaveHeight. If the image doesn't have a ratio, aRatio will
* be (0, 0).
*/
void ComputeUnscaledDimensions(const nsSize& aBgPositioningArea,
nscoord& aUnscaledWidth, bool& aHaveWidth,
nscoord& aUnscaledHeight, bool& aHaveHeight,
nsSize& aRatio);
/*
* Using the previously-computed unscaled width and height (if each are
* valid, as indicated by aHaveWidth/aHaveHeight), compute the size at which
* the image should actually render.
*/
nsSize
ComputeDrawnSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea,
nscoord aUnscaledWidth, bool aHaveWidth,
nscoord aUnscaledHeight, bool aHaveHeight,
const nsSize& aIntrinsicRatio);
nsIFrame* mForFrame;
const nsStyleImage* mImage;
nsStyleImageType mType;
nsCOMPtr<imgIContainer> mImageContainer;
nsRefPtr<nsStyleGradient> mGradientData;
nsIFrame* mPaintServerFrame;
nsLayoutUtils::SurfaceFromElementResult mImageElementSurface;
bool mIsReady;
nsSize mSize; // unscaled size of the image, in app units
PRUint32 mFlags;
};
// To avoid storing this data on nsInlineFrame (bloat) and to avoid
// recalculating this for each frame in a continuation (perf), hold
// a cache of various coordinate information that we need in order
@ -1692,12 +1617,12 @@ DrawBackgroundColor(BackgroundClipState& aClipState, gfxContext *aCtx,
aCtx->Restore();
}
static nscolor
DetermineBackgroundColorInternal(nsPresContext* aPresContext,
nsStyleContext* aStyleContext,
nsIFrame* aFrame,
bool& aDrawBackgroundImage,
bool& aDrawBackgroundColor)
nscolor
nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
nsStyleContext* aStyleContext,
nsIFrame* aFrame,
bool& aDrawBackgroundImage,
bool& aDrawBackgroundColor)
{
aDrawBackgroundImage = true;
aDrawBackgroundColor = true;
@ -1729,20 +1654,6 @@ DetermineBackgroundColorInternal(nsPresContext* aPresContext,
return bgColor;
}
nscolor
nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
nsStyleContext* aStyleContext,
nsIFrame* aFrame)
{
bool drawBackgroundImage;
bool drawBackgroundColor;
return DetermineBackgroundColorInternal(aPresContext,
aStyleContext,
aFrame,
drawBackgroundImage,
drawBackgroundColor);
}
static gfxFloat
ConvertGradientValueToPixels(const nsStyleCoord& aCoord,
gfxFloat aFillLength,
@ -2226,51 +2137,6 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
}
}
/**
* A struct representing all the information needed to paint a background
* image to some target, taking into account all CSS background-* properties.
* See PrepareBackgroundLayer.
*/
struct BackgroundLayerState {
/**
* @param aFlags some combination of nsCSSRendering::PAINTBG_* flags
*/
BackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage, PRUint32 aFlags)
: mImageRenderer(aForFrame, aImage, aFlags) {}
/**
* The ImageRenderer that will be used to draw the background.
*/
ImageRenderer mImageRenderer;
/**
* A rectangle that one copy of the image tile is mapped onto. Same
* coordinate system as aBorderArea/aBGClipRect passed into
* PrepareBackgroundLayer.
*/
nsRect mDestArea;
/**
* The actual rectangle that should be filled with (complete or partial)
* image tiles. Same coordinate system as aBorderArea/aBGClipRect passed into
* PrepareBackgroundLayer.
*/
nsRect mFillArea;
/**
* The anchor point that should be snapped to a pixel corner. Same
* coordinate system as aBorderArea/aBGClipRect passed into
* PrepareBackgroundLayer.
*/
nsPoint mAnchor;
};
static BackgroundLayerState
PrepareBackgroundLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
PRUint32 aFlags,
const nsRect& aBorderArea,
const nsRect& aBGClipRect,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer);
void
nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
@ -2318,11 +2184,11 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
bool drawBackgroundImage;
bool drawBackgroundColor;
nscolor bgColor = DetermineBackgroundColorInternal(aPresContext,
aBackgroundSC,
aForFrame,
drawBackgroundImage,
drawBackgroundColor);
nscolor bgColor = DetermineBackgroundColor(aPresContext,
aBackgroundSC,
aForFrame,
drawBackgroundImage,
drawBackgroundColor);
// At this point, drawBackgroundImage and drawBackgroundColor are
// true if and only if we are actually supposed to paint an image or
@ -2452,7 +2318,7 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
}
}
if (!clipState.mDirtyRectGfx.IsEmpty()) {
BackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
nsBackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
aFlags, aBorderArea, clipState.mBGClipArea, *bg, layer);
if (!state.mFillArea.IsEmpty()) {
state.mImageRenderer.Draw(aPresContext, aRenderingContext,
@ -2476,14 +2342,14 @@ IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame)
return false;
}
static BackgroundLayerState
PrepareBackgroundLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
PRUint32 aFlags,
const nsRect& aBorderArea,
const nsRect& aBGClipRect,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer)
nsBackgroundLayerState
nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
PRUint32 aFlags,
const nsRect& aBorderArea,
const nsRect& aBGClipRect,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer)
{
/*
* The background properties we need to keep in mind when drawing background
@ -2542,10 +2408,10 @@ PrepareBackgroundLayer(nsPresContext* aPresContext,
PRUint32 irFlags = 0;
if (aFlags & nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES) {
irFlags |= ImageRenderer::FLAG_SYNC_DECODE_IMAGES;
irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
}
BackgroundLayerState state(aForFrame, &aLayer.mImage, irFlags);
nsBackgroundLayerState state(aForFrame, &aLayer.mImage, irFlags);
if (!state.mImageRenderer.PrepareImage()) {
// There's no image or it's not ready to be painted.
return state;
@ -2695,7 +2561,7 @@ nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer)
{
BackgroundLayerState state =
nsBackgroundLayerState state =
PrepareBackgroundLayer(aPresContext, aForFrame, 0, aBorderArea,
aBorderArea, aBackground, aLayer);
return state.mFillArea;
@ -3790,9 +3656,9 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
// ------------------
// ImageRenderer
// ------------------
ImageRenderer::ImageRenderer(nsIFrame* aForFrame,
const nsStyleImage* aImage,
PRUint32 aFlags)
nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame,
const nsStyleImage* aImage,
PRUint32 aFlags)
: mForFrame(aForFrame)
, mImage(aImage)
, mType(aImage->GetType())
@ -3805,12 +3671,12 @@ ImageRenderer::ImageRenderer(nsIFrame* aForFrame,
{
}
ImageRenderer::~ImageRenderer()
nsImageRenderer::~nsImageRenderer()
{
}
bool
ImageRenderer::PrepareImage()
nsImageRenderer::PrepareImage()
{
if (mImage->IsEmpty() || !mImage->IsComplete()) {
// Make sure the image is actually decoding
@ -3930,10 +3796,10 @@ ComputeContainCoverSizeFromRatio(const nsSize& aBgPositioningArea,
}
void
ImageRenderer::ComputeUnscaledDimensions(const nsSize& aBgPositioningArea,
nscoord& aUnscaledWidth, bool& aHaveWidth,
nscoord& aUnscaledHeight, bool& aHaveHeight,
nsSize& aRatio)
nsImageRenderer::ComputeUnscaledDimensions(const nsSize& aBgPositioningArea,
nscoord& aUnscaledWidth, bool& aHaveWidth,
nscoord& aUnscaledHeight, bool& aHaveHeight,
nsSize& aRatio)
{
NS_ASSERTION(mIsReady, "Ensure PrepareImage() has returned true "
"before calling me");
@ -4003,11 +3869,11 @@ ImageRenderer::ComputeUnscaledDimensions(const nsSize& aBgPositioningArea,
}
nsSize
ImageRenderer::ComputeDrawnSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea,
nscoord aUnscaledWidth, bool aHaveWidth,
nscoord aUnscaledHeight, bool aHaveHeight,
const nsSize& aIntrinsicRatio)
nsImageRenderer::ComputeDrawnSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea,
nscoord aUnscaledWidth, bool aHaveWidth,
nscoord aUnscaledHeight, bool aHaveHeight,
const nsSize& aIntrinsicRatio)
{
NS_ABORT_IF_FALSE(aIntrinsicRatio.width >= 0,
"image ratio with nonsense width");
@ -4171,8 +4037,8 @@ ImageRenderer::ComputeDrawnSize(const nsStyleBackground::Size& aLayerSize,
* width will be 4px, while in the second case the returned width will be 8px.
*/
nsSize
ImageRenderer::ComputeSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea)
nsImageRenderer::ComputeSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea)
{
bool haveWidth, haveHeight;
nsSize ratio;
@ -4191,12 +4057,12 @@ ImageRenderer::ComputeSize(const nsStyleBackground::Size& aLayerSize,
}
void
ImageRenderer::Draw(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty)
nsImageRenderer::Draw(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty)
{
if (!mIsReady) {
NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
@ -4248,6 +4114,31 @@ ImageRenderer::Draw(nsPresContext* aPresContext,
}
}
bool
nsImageRenderer::IsRasterImage()
{
if (mType != eStyleImageType_Image)
return false;
nsCOMPtr<imgIContainer> img;
nsresult rv = mImage->GetImageData()->GetImage(getter_AddRefs(img));
if (NS_FAILED(rv) || !img)
return false;
return img->GetType() == imgIContainer::TYPE_RASTER;
}
already_AddRefed<mozilla::layers::ImageContainer>
nsImageRenderer::GetContainer()
{
nsCOMPtr<imgIContainer> img;
nsresult rv = mImage->GetImageData()->GetImage(getter_AddRefs(img));
if (NS_FAILED(rv) || !img)
return nsnull;
nsRefPtr<ImageContainer> container;
rv = img->GetImageContainer(getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, nsnull);
return container.forget();
}
#define MAX_BLUR_RADIUS 300
#define MAX_SPREAD_RADIUS 50

Просмотреть файл

@ -44,12 +44,129 @@
#include "gfxBlur.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "nsLayoutUtils.h"
struct nsPoint;
class nsStyleContext;
class nsPresContext;
class nsRenderingContext;
/**
* 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(),
* ComputeSize(), and Draw().
*/
class nsImageRenderer {
public:
typedef mozilla::layers::ImageContainer ImageContainer;
enum {
FLAG_SYNC_DECODE_IMAGES = 0x01
};
nsImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage, PRUint32 aFlags);
~nsImageRenderer();
/**
* 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();
/**
* @return the image size in appunits when rendered, after accounting for the
* background positioning area, background-size, and the image's intrinsic
* dimensions (if any).
*/
nsSize ComputeSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea);
/**
* Draws the image to the target rendering context.
* @see nsLayoutUtils::DrawImage() for other parameters
*/
void Draw(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty);
bool IsRasterImage();
already_AddRefed<ImageContainer> GetContainer();
private:
/*
* Compute the "unscaled" dimensions of the image in aUnscaled{Width,Height}
* and aRatio. Whether the image has a height and width are indicated by
* aHaveWidth and aHaveHeight. If the image doesn't have a ratio, aRatio will
* be (0, 0).
*/
void ComputeUnscaledDimensions(const nsSize& aBgPositioningArea,
nscoord& aUnscaledWidth, bool& aHaveWidth,
nscoord& aUnscaledHeight, bool& aHaveHeight,
nsSize& aRatio);
/*
* Using the previously-computed unscaled width and height (if each are
* valid, as indicated by aHaveWidth/aHaveHeight), compute the size at which
* the image should actually render.
*/
nsSize
ComputeDrawnSize(const nsStyleBackground::Size& aLayerSize,
const nsSize& aBgPositioningArea,
nscoord aUnscaledWidth, bool aHaveWidth,
nscoord aUnscaledHeight, bool aHaveHeight,
const nsSize& aIntrinsicRatio);
nsIFrame* mForFrame;
const nsStyleImage* mImage;
nsStyleImageType mType;
nsCOMPtr<imgIContainer> mImageContainer;
nsRefPtr<nsStyleGradient> mGradientData;
nsIFrame* mPaintServerFrame;
nsLayoutUtils::SurfaceFromElementResult mImageElementSurface;
bool mIsReady;
nsSize mSize; // unscaled size of the image, in app units
PRUint32 mFlags;
};
/**
* A struct representing all the information needed to paint a background
* image to some target, taking into account all CSS background-* properties.
* See PrepareBackgroundLayer.
*/
struct nsBackgroundLayerState {
/**
* @param aFlags some combination of nsCSSRendering::PAINTBG_* flags
*/
nsBackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage, PRUint32 aFlags)
: mImageRenderer(aForFrame, aImage, aFlags) {}
/**
* The nsImageRenderer that will be used to draw the background.
*/
nsImageRenderer mImageRenderer;
/**
* A rectangle that one copy of the image tile is mapped onto. Same
* coordinate system as aBorderArea/aBGClipRect passed into
* PrepareBackgroundLayer.
*/
nsRect mDestArea;
/**
* The actual rectangle that should be filled with (complete or partial)
* image tiles. Same coordinate system as aBorderArea/aBGClipRect passed into
* PrepareBackgroundLayer.
*/
nsRect mFillArea;
/**
* The anchor point that should be snapped to a pixel corner. Same
* coordinate system as aBorderArea/aBGClipRect passed into
* PrepareBackgroundLayer.
*/
nsPoint mAnchor;
};
struct nsCSSRendering {
/**
* Initialize any static variables used by nsCSSRendering.
@ -211,7 +328,18 @@ struct nsCSSRendering {
static nscolor
DetermineBackgroundColor(nsPresContext* aPresContext,
nsStyleContext* aStyleContext,
nsIFrame* aFrame);
nsIFrame* aFrame,
bool& aDrawBackgroundImage,
bool& aDrawBackgroundColor);
static nsBackgroundLayerState
PrepareBackgroundLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
PRUint32 aFlags,
const nsRect& aBorderArea,
const nsRect& aBGClipRect,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer);
/**
* Render the background for an element using css rendering rules

Просмотреть файл

@ -5036,9 +5036,14 @@ void PresShell::UpdateCanvasBackground()
// style frame but we don't have access to the canvasframe here. It isn't
// a problem because only a few frames can return something other than true
// and none of them would be a canvas frame or root element style frame.
bool drawBackgroundImage;
bool drawBackgroundColor;
mCanvasBackgroundColor =
nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
rootStyleFrame);
rootStyleFrame,
drawBackgroundImage,
drawBackgroundColor);
if (GetPresContext()->IsRootContentDocument() &&
!IsTransparentContainerElement(mPresContext)) {
mCanvasBackgroundColor =