зеркало из https://github.com/mozilla/pjs.git
Bug 572680 - Pull the image snapping algorithm out of DrawImageInternal. r=roc
--HG-- extra : rebase_source : 05c59b5bd230ec54c81d34e58ce030366ebf1546
This commit is contained in:
Родитель
f980da2b9d
Коммит
a42fdadc7d
|
@ -2921,47 +2921,79 @@ MapToFloatUserPixels(const gfxSize& aSize,
|
|||
aPt.y*aDest.size.height/aSize.height + aDest.pos.y);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
DrawImageInternal(nsIRenderingContext* aRenderingContext,
|
||||
imgIContainer* aImage,
|
||||
gfxPattern::GraphicsFilter aGraphicsFilter,
|
||||
const nsRect& aDest,
|
||||
const nsRect& aFill,
|
||||
const nsPoint& aAnchor,
|
||||
const nsRect& aDirty,
|
||||
const nsIntSize& aImageSize,
|
||||
PRUint32 aImageFlags)
|
||||
// helper function to convert a nsRect to a gfxRect
|
||||
// borrowed from nsCSSRendering.cpp
|
||||
static gfxRect
|
||||
RectToGfxRect(const nsRect& aRect, PRInt32 aAppUnitsPerDevPixel)
|
||||
{
|
||||
return gfxRect(gfxFloat(aRect.x) / aAppUnitsPerDevPixel,
|
||||
gfxFloat(aRect.y) / aAppUnitsPerDevPixel,
|
||||
gfxFloat(aRect.width) / aAppUnitsPerDevPixel,
|
||||
gfxFloat(aRect.height) / aAppUnitsPerDevPixel);
|
||||
}
|
||||
|
||||
struct SnappedImageDrawingParameters {
|
||||
// A transform from either device space or user space (depending on mResetCTM)
|
||||
// to image space
|
||||
gfxMatrix mUserSpaceToImageSpace;
|
||||
// A device-space, pixel-aligned rectangle to fill
|
||||
gfxRect mFillRect;
|
||||
// A pixel rectangle in tiled image space outside of which gfx should not
|
||||
// sample (using EXTEND_PAD as necessary)
|
||||
nsIntRect mSubimage;
|
||||
// Whether there's anything to draw at all
|
||||
PRPackedBool mShouldDraw;
|
||||
// PR_TRUE iff the CTM of the rendering context needs to be reset to the
|
||||
// identity matrix before drawing
|
||||
PRPackedBool mResetCTM;
|
||||
|
||||
SnappedImageDrawingParameters()
|
||||
: mShouldDraw(PR_FALSE)
|
||||
, mResetCTM(PR_FALSE)
|
||||
{}
|
||||
|
||||
SnappedImageDrawingParameters(const gfxMatrix& aUserSpaceToImageSpace,
|
||||
const gfxRect& aFillRect,
|
||||
const nsIntRect& aSubimage,
|
||||
PRBool aResetCTM)
|
||||
: mUserSpaceToImageSpace(aUserSpaceToImageSpace)
|
||||
, mFillRect(aFillRect)
|
||||
, mSubimage(aSubimage)
|
||||
, mShouldDraw(PR_TRUE)
|
||||
, mResetCTM(aResetCTM)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a set of input parameters, compute certain output parameters
|
||||
* for drawing an image with the image snapping algorithm.
|
||||
* See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
|
||||
*
|
||||
* @see nsLayoutUtils::DrawImage() for the descriptions of input parameters
|
||||
*/
|
||||
static SnappedImageDrawingParameters
|
||||
ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
|
||||
PRInt32 aAppUnitsPerDevPixel,
|
||||
const nsRect aDest,
|
||||
const nsRect aFill,
|
||||
const nsPoint aAnchor,
|
||||
const nsRect aDirty,
|
||||
const nsIntSize aImageSize)
|
||||
|
||||
{
|
||||
if (aDest.IsEmpty() || aFill.IsEmpty())
|
||||
return NS_OK;
|
||||
return SnappedImageDrawingParameters();
|
||||
|
||||
nsCOMPtr<nsIDeviceContext> dc;
|
||||
aRenderingContext->GetDeviceContext(*getter_AddRefs(dc));
|
||||
gfxFloat appUnitsPerDevPixel = dc->AppUnitsPerDevPixel();
|
||||
gfxContext *ctx = aRenderingContext->ThebesContext();
|
||||
gfxRect devPixelDest = RectToGfxRect(aDest, aAppUnitsPerDevPixel);
|
||||
gfxRect devPixelFill = RectToGfxRect(aFill, aAppUnitsPerDevPixel);
|
||||
gfxRect devPixelDirty = RectToGfxRect(aDirty, aAppUnitsPerDevPixel);
|
||||
|
||||
gfxRect devPixelDest(aDest.x/appUnitsPerDevPixel,
|
||||
aDest.y/appUnitsPerDevPixel,
|
||||
aDest.width/appUnitsPerDevPixel,
|
||||
aDest.height/appUnitsPerDevPixel);
|
||||
|
||||
// Compute the pixel-snapped area that should be drawn
|
||||
gfxRect devPixelFill(aFill.x/appUnitsPerDevPixel,
|
||||
aFill.y/appUnitsPerDevPixel,
|
||||
aFill.width/appUnitsPerDevPixel,
|
||||
aFill.height/appUnitsPerDevPixel);
|
||||
PRBool ignoreScale = PR_FALSE;
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
ignoreScale = PR_TRUE;
|
||||
#endif
|
||||
gfxRect fill = devPixelFill;
|
||||
PRBool didSnap = ctx->UserToDevicePixelSnapped(fill, ignoreScale);
|
||||
|
||||
// Compute dirty rect in gfx space
|
||||
gfxRect dirty(aDirty.x/appUnitsPerDevPixel,
|
||||
aDirty.y/appUnitsPerDevPixel,
|
||||
aDirty.width/appUnitsPerDevPixel,
|
||||
aDirty.height/appUnitsPerDevPixel);
|
||||
PRBool didSnap = aCtx->UserToDevicePixelSnapped(fill, ignoreScale);
|
||||
|
||||
gfxSize imageSize(aImageSize.width, aImageSize.height);
|
||||
|
||||
|
@ -2979,35 +3011,33 @@ DrawImageInternal(nsIRenderingContext* aRenderingContext,
|
|||
// Compute the anchor point and compute final fill rect.
|
||||
// This code assumes that pixel-based devices have one pixel per
|
||||
// device unit!
|
||||
gfxPoint anchorPoint(aAnchor.x/appUnitsPerDevPixel,
|
||||
aAnchor.y/appUnitsPerDevPixel);
|
||||
gfxPoint anchorPoint(gfxFloat(aAnchor.x)/aAppUnitsPerDevPixel,
|
||||
gfxFloat(aAnchor.y)/aAppUnitsPerDevPixel);
|
||||
gfxPoint imageSpaceAnchorPoint =
|
||||
MapToFloatImagePixels(imageSize, devPixelDest, anchorPoint);
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(ctx);
|
||||
gfxMatrix currentMatrix = aCtx->CurrentMatrix();
|
||||
|
||||
if (didSnap) {
|
||||
NS_ASSERTION(!saveMatrix.Matrix().HasNonAxisAlignedTransform(),
|
||||
NS_ASSERTION(!currentMatrix.HasNonAxisAlignedTransform(),
|
||||
"How did we snap, then?");
|
||||
imageSpaceAnchorPoint.Round();
|
||||
anchorPoint = imageSpaceAnchorPoint;
|
||||
anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
|
||||
anchorPoint = saveMatrix.Matrix().Transform(anchorPoint);
|
||||
anchorPoint = currentMatrix.Transform(anchorPoint);
|
||||
anchorPoint.Round();
|
||||
|
||||
// This form of Transform is safe to call since non-axis-aligned
|
||||
// transforms wouldn't be snapped.
|
||||
dirty = saveMatrix.Matrix().Transform(dirty);
|
||||
|
||||
ctx->IdentityMatrix();
|
||||
devPixelDirty = currentMatrix.Transform(devPixelDirty);
|
||||
}
|
||||
|
||||
gfxFloat scaleX = imageSize.width*appUnitsPerDevPixel/aDest.width;
|
||||
gfxFloat scaleY = imageSize.height*appUnitsPerDevPixel/aDest.height;
|
||||
gfxFloat scaleX = imageSize.width*aAppUnitsPerDevPixel/aDest.width;
|
||||
gfxFloat scaleY = imageSize.height*aAppUnitsPerDevPixel/aDest.height;
|
||||
if (didSnap) {
|
||||
// ctx now has the identity matrix, so we need to adjust our
|
||||
// scales to match
|
||||
scaleX /= saveMatrix.Matrix().xx;
|
||||
scaleY /= saveMatrix.Matrix().yy;
|
||||
// We'll reset aCTX to the identity matrix before drawing, so we need to
|
||||
// adjust our scales to match.
|
||||
scaleX /= currentMatrix.xx;
|
||||
scaleY /= currentMatrix.yy;
|
||||
}
|
||||
gfxFloat translateX = imageSpaceAnchorPoint.x - anchorPoint.x*scaleX;
|
||||
gfxFloat translateY = imageSpaceAnchorPoint.y - anchorPoint.y*scaleY;
|
||||
|
@ -3018,18 +3048,51 @@ DrawImageInternal(nsIRenderingContext* aRenderingContext,
|
|||
// translation by integers, then filtering will occur, and
|
||||
// restricting the fill rect to the dirty rect would change the values
|
||||
// computed for edge pixels, which we can't allow.
|
||||
// Also, if didSnap is false then rounding out 'dirty' might not
|
||||
// Also, if didSnap is false then rounding out 'devPixelDirty' might not
|
||||
// produce pixel-aligned coordinates, which would also break the values
|
||||
// computed for edge pixels.
|
||||
if (didSnap && !transform.HasNonIntegerTranslation()) {
|
||||
dirty.RoundOut();
|
||||
finalFillRect = fill.Intersect(dirty);
|
||||
devPixelDirty.RoundOut();
|
||||
finalFillRect = fill.Intersect(devPixelDirty);
|
||||
}
|
||||
if (finalFillRect.IsEmpty())
|
||||
return SnappedImageDrawingParameters();
|
||||
|
||||
return SnappedImageDrawingParameters(transform, finalFillRect, intSubimage,
|
||||
didSnap);
|
||||
}
|
||||
|
||||
|
||||
static nsresult
|
||||
DrawImageInternal(nsIRenderingContext* aRenderingContext,
|
||||
imgIContainer* aImage,
|
||||
gfxPattern::GraphicsFilter aGraphicsFilter,
|
||||
const nsRect& aDest,
|
||||
const nsRect& aFill,
|
||||
const nsPoint& aAnchor,
|
||||
const nsRect& aDirty,
|
||||
const nsIntSize& aImageSize,
|
||||
PRUint32 aImageFlags)
|
||||
{
|
||||
nsCOMPtr<nsIDeviceContext> dc;
|
||||
aRenderingContext->GetDeviceContext(*getter_AddRefs(dc));
|
||||
PRInt32 appUnitsPerDevPixel = dc->AppUnitsPerDevPixel();
|
||||
gfxContext* ctx = aRenderingContext->ThebesContext();
|
||||
|
||||
SnappedImageDrawingParameters drawingParams =
|
||||
ComputeSnappedImageDrawingParameters(ctx, appUnitsPerDevPixel, aDest, aFill,
|
||||
aAnchor, aDirty, aImageSize);
|
||||
|
||||
if (!drawingParams.mShouldDraw)
|
||||
return NS_OK;
|
||||
|
||||
aImage->Draw(ctx, aGraphicsFilter, transform, finalFillRect, intSubimage,
|
||||
aImageFlags);
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(ctx);
|
||||
if (drawingParams.mResetCTM) {
|
||||
ctx->IdentityMatrix();
|
||||
}
|
||||
|
||||
aImage->Draw(ctx, aGraphicsFilter, drawingParams.mUserSpaceToImageSpace,
|
||||
drawingParams.mFillRect, drawingParams.mSubimage, aImageFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче