Bug 1078337 - Correctly respect the source rect in DrawSingleImage. r=seth

This commit is contained in:
Matt Woodrow
2014-10-23 11:41:14 +13:00
parent ea3f762cc0
commit 8d847a7a2a
2 changed files with 36 additions and 13 deletions

View File

@@ -5310,31 +5310,39 @@ nsLayoutUtils::DrawSingleImage(nsRenderingContext* aRenderingContext,
uint32_t aImageFlags, uint32_t aImageFlags,
const nsRect* aSourceArea) const nsRect* aSourceArea)
{ {
nsIntSize imageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size())); nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE); nsIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size()));
NS_ENSURE_TRUE(pixelImageSize.width > 0 && pixelImageSize.height > 0, NS_ERROR_FAILURE);
nsSize imageSize(pixelImageSize.width * appUnitsPerCSSPixel,
pixelImageSize.height * appUnitsPerCSSPixel);
nsRect source; nsRect source;
nsCOMPtr<imgIContainer> image; nsCOMPtr<imgIContainer> image;
if (aSourceArea) { if (aSourceArea) {
source = *aSourceArea; source = *aSourceArea;
nsIntRect subRect(source.x, source.y, source.width, source.height); nsIntRect subRect(source.x, source.y, source.width, source.height);
subRect.ScaleInverseRoundOut(nsDeviceContext::AppUnitsPerCSSPixel()); subRect.ScaleInverseRoundOut(appUnitsPerCSSPixel);
image = ImageOps::Clip(aImage, subRect); image = ImageOps::Clip(aImage, subRect);
nsRect imageRect;
imageRect.SizeTo(imageSize);
nsRect clippedSource = imageRect.Intersect(source);
source -= clippedSource.TopLeft();
imageSize = clippedSource.Size();
} else { } else {
nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel(); source.SizeTo(imageSize);
source.SizeTo(imageSize.width*appUnitsPerCSSPixel,
imageSize.height*appUnitsPerCSSPixel);
image = aImage; image = aImage;
} }
nsRect dest = nsLayoutUtils::GetWholeImageDestination(imageSize, source, nsRect dest = GetWholeImageDestination(imageSize, source, aDest);
aDest);
// Ensure that only a single image tile is drawn. If aSourceArea extends // Ensure that only a single image tile is drawn. If aSourceArea extends
// outside the image bounds, we want to honor the aSourceArea-to-aDest // outside the image bounds, we want to honor the aSourceArea-to-aDest
// transform but we don't want to actually tile the image. // transform but we don't want to actually tile the image.
nsRect fill; nsRect fill;
fill.IntersectRect(aDest, dest); fill.IntersectRect(aDest, dest);
return DrawImageInternal(aRenderingContext, aPresContext, aImage, return DrawImageInternal(aRenderingContext, aPresContext, image,
aGraphicsFilter, dest, fill, fill.TopLeft(), aGraphicsFilter, dest, fill, fill.TopLeft(),
aDirty, aSVGContext, aImageFlags); aDirty, aSVGContext, aImageFlags);
} }
@@ -5445,7 +5453,7 @@ nsLayoutUtils::DrawImage(nsRenderingContext* aRenderingContext,
} }
/* static */ nsRect /* static */ nsRect
nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize, nsLayoutUtils::GetWholeImageDestination(const nsSize& aWholeImageSize,
const nsRect& aImageSourceArea, const nsRect& aImageSourceArea,
const nsRect& aDestArea) const nsRect& aDestArea)
{ {
@@ -5453,13 +5461,24 @@ nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
double scaleY = double(aDestArea.height)/aImageSourceArea.height; double scaleY = double(aDestArea.height)/aImageSourceArea.height;
nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX); nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX);
nscoord destOffsetY = NSToCoordRound(aImageSourceArea.y*scaleY); nscoord destOffsetY = NSToCoordRound(aImageSourceArea.y*scaleY);
nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel(); nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*scaleX);
nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*appUnitsPerCSSPixel*scaleX); nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*scaleY);
nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*appUnitsPerCSSPixel*scaleY);
return nsRect(aDestArea.TopLeft() - nsPoint(destOffsetX, destOffsetY), return nsRect(aDestArea.TopLeft() - nsPoint(destOffsetX, destOffsetY),
nsSize(wholeSizeX, wholeSizeY)); nsSize(wholeSizeX, wholeSizeY));
} }
/* static */ nsRect
nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
const nsRect& aImageSourceArea,
const nsRect& aDestArea)
{
nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
return GetWholeImageDestination(nsSize(aWholeImageSize.width * appUnitsPerCSSPixel,
aWholeImageSize.height * appUnitsPerCSSPixel),
aImageSourceArea,
aDestArea);
}
/* static */ already_AddRefed<imgIContainer> /* static */ already_AddRefed<imgIContainer>
nsLayoutUtils::OrientImage(imgIContainer* aContainer, nsLayoutUtils::OrientImage(imgIContainer* aContainer,
const nsStyleImageOrientation& aOrientation) const nsStyleImageOrientation& aOrientation)

View File

@@ -1613,6 +1613,10 @@ public:
const nsRect& aImageSourceArea, const nsRect& aImageSourceArea,
const nsRect& aDestArea); const nsRect& aDestArea);
static nsRect GetWholeImageDestination(const nsSize& aWholeImageSize,
const nsRect& aImageSourceArea,
const nsRect& aDestArea);
/** /**
* Given an image container and an orientation, returns an image container * Given an image container and an orientation, returns an image container
* that contains the same image, reoriented appropriately. May return the * that contains the same image, reoriented appropriately. May return the