--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5715,91 +5715,98 @@ ComputeSnappedImageDrawingParameters(gfx
GraphicsFilter aGraphicsFilter,
uint32_t aImageFlags)
{
if (aDest.IsEmpty() || aFill.IsEmpty())
return SnappedImageDrawingParameters();
// Avoid unnecessarily large offsets.
bool doTile = !aDest.Contains(aFill);
- nsRect dest = doTile ? TileNearRect(aDest, aFill.Intersect(aDirty)) : aDest;
- nsPoint anchor = aAnchor + (dest.TopLeft() - aDest.TopLeft());
+ nsRect appUnitDest = doTile ? TileNearRect(aDest, aFill.Intersect(aDirty))
+ : aDest;
+ nsPoint anchor = aAnchor + (appUnitDest.TopLeft() - aDest.TopLeft());
gfxRect devPixelDest =
- nsLayoutUtils::RectToGfxRect(dest, aAppUnitsPerDevPixel);
+ nsLayoutUtils::RectToGfxRect(appUnitDest, aAppUnitsPerDevPixel);
gfxRect devPixelFill =
nsLayoutUtils::RectToGfxRect(aFill, aAppUnitsPerDevPixel);
gfxRect devPixelDirty =
nsLayoutUtils::RectToGfxRect(aDirty, aAppUnitsPerDevPixel);
gfxMatrix currentMatrix = aCtx->CurrentMatrix();
gfxRect fill = devPixelFill;
+ gfxRect dest = devPixelDest;
bool didSnap;
// Snap even if we have a scale in the context. But don't snap if
// we have something that's not translation+scale, or if the scale flips in
// the X or Y direction, because snapped image drawing can't handle that yet.
if (!currentMatrix.HasNonAxisAlignedTransform() &&
currentMatrix._11 > 0.0 && currentMatrix._22 > 0.0 &&
- aCtx->UserToDevicePixelSnapped(fill, true)) {
+ aCtx->UserToDevicePixelSnapped(fill, true) &&
+ aCtx->UserToDevicePixelSnapped(dest, true)) {
+ // We snapped. On this code path, |fill| and |dest| take into account
+ // currentMatrix's transform.
didSnap = true;
- if (fill.IsEmpty()) {
- return SnappedImageDrawingParameters();
- }
} else {
+ // We didn't snap. On this code path, |fill| and |dest| do not take into
+ // account currentMatrix's transform.
didSnap = false;
fill = devPixelFill;
- }
-
- // Apply the context's scale to the dest rect.
- gfxSize destScale = didSnap ? gfxSize(currentMatrix._11, currentMatrix._22)
- : gfxSize(1.0, 1.0);
- gfxSize appUnitScaledDest(dest.width * destScale.width,
- dest.height * destScale.height);
- gfxSize scaledDest = appUnitScaledDest / aAppUnitsPerDevPixel;
- if (scaledDest.IsEmpty()) {
+ dest = devPixelDest;
+ }
+
+ // If we snapped above, |dest| already takes into account |currentMatrix|'s scale
+ // and has integer coordinates. If not, we need these properties to compute
+ // the optimal drawn image size, so compute |snappedDestSize| here.
+ gfxSize snappedDestSize = dest.Size();
+ if (!didSnap) {
+ gfxSize scaleFactors = gfxSize(1.0, 1.0);
+ snappedDestSize.Scale(scaleFactors.width, scaleFactors.height);
+ snappedDestSize.width = NS_round(snappedDestSize.width);
+ snappedDestSize.height = NS_round(snappedDestSize.height);
+ }
+
+ // We need to be sure that this is at least one pixel in width and height,
+ // or we'll end up drawing nothing even if we have a nonempty fill.
+ snappedDestSize.width = std::max(snappedDestSize.width, 1.0);
+ snappedDestSize.height = std::max(snappedDestSize.height, 1.0);
+
+ // Bail if we're not going to end up drawing anything.
+ if (fill.IsEmpty() || snappedDestSize.IsEmpty()) {
return SnappedImageDrawingParameters();
}
- // Compute a snapped version of the scaled dest rect, which we'll use to
- // determine the optimal image size to draw with. We need to be sure that
- // this rect is at least one pixel in width and height, or we'll end up
- // drawing nothing even if we have a nonempty fill.
- gfxSize snappedScaledDest =
- gfxSize(NSAppUnitsToIntPixels(appUnitScaledDest.width, aAppUnitsPerDevPixel),
- NSAppUnitsToIntPixels(appUnitScaledDest.height, aAppUnitsPerDevPixel));
- snappedScaledDest.width = std::max(snappedScaledDest.width, 1.0);
- snappedScaledDest.height = std::max(snappedScaledDest.height, 1.0);
-
nsIntSize intImageSize =
- aImage->OptimalImageSizeForDest(snappedScaledDest,
+ aImage->OptimalImageSizeForDest(snappedDestSize,
imgIContainer::FRAME_CURRENT,
aGraphicsFilter, aImageFlags);
gfxSize imageSize(intImageSize.width, intImageSize.height);
+ // XXX(seth): May be buggy; see bug 1151016.
nsIntSize svgViewportSize = currentMatrix.IsIdentity()
? intImageSize
- : nsIntSize(NSAppUnitsToIntPixels(dest.width, aAppUnitsPerDevPixel),
- NSAppUnitsToIntPixels(dest.height, aAppUnitsPerDevPixel));
+ : nsIntSize(devPixelDest.width, devPixelDest.height);
// Compute the set of pixels that would be sampled by an ideal rendering
gfxPoint subimageTopLeft =
MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.TopLeft());
gfxPoint subimageBottomRight =
MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.BottomRight());
gfxRect subimage;
subimage.MoveTo(NSToIntFloor(subimageTopLeft.x),
NSToIntFloor(subimageTopLeft.y));
subimage.SizeTo(NSToIntCeil(subimageBottomRight.x) - subimage.x,
NSToIntCeil(subimageBottomRight.y) - subimage.y);
gfxMatrix transform;
gfxMatrix invTransform;
- bool anchorAtUpperLeft = anchor.x == dest.x && anchor.y == dest.y;
- bool exactlyOneImageCopy = aFill.IsEqualEdges(dest);
+ bool anchorAtUpperLeft = anchor.x == appUnitDest.x &&
+ anchor.y == appUnitDest.y;
+ bool exactlyOneImageCopy = aFill.IsEqualEdges(appUnitDest);
if (anchorAtUpperLeft && exactlyOneImageCopy) {
// The simple case: we can ignore the anchor point and compute the
// transformation from the sampled region (the subimage) to the fill rect.
// This approach is preferable when it works since it tends to produce
// less numerical error.
transform = TransformBetweenRects(subimage, fill);
invTransform = TransformBetweenRects(fill, subimage);
} else {
@@ -5817,17 +5824,24 @@ ComputeSnappedImageDrawingParameters(gfx
if (didSnap) {
imageSpaceAnchorPoint = StableRound(imageSpaceAnchorPoint);
anchorPoint = imageSpaceAnchorPoint;
anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
anchorPoint = currentMatrix.Transform(anchorPoint);
anchorPoint = StableRound(anchorPoint);
}
- gfxRect anchoredDestRect(anchorPoint, scaledDest);
+ // Compute an unsnapped version of the dest rect's size. We continue to
+ // follow the pattern that we take |currentMatrix| into account only if
+ // |didSnap| is true.
+ gfxSize unsnappedDestSize
+ = didSnap ? devPixelDest.Size() * currentMatrix.ScaleFactors(true)
+ : devPixelDest.Size();
+
+ gfxRect anchoredDestRect(anchorPoint, unsnappedDestSize);
gfxRect anchoredImageRect(imageSpaceAnchorPoint, imageSize);
// Calculate anchoredDestRect with snapped fill rect when the devPixelFill rect
// corresponds to just a single tile in that direction
if (fill.Width() != devPixelFill.Width() &&
devPixelDest.x == devPixelFill.x &&
devPixelDest.XMost() == devPixelFill.XMost()) {
anchoredDestRect.width = fill.width;