When drawing images, track full source and dest regions (unclipped) or use floats, to avoid rounding problems with advanced image resizing algorithms. b=371434 r=vlad r+sr=roc

This commit is contained in:
dbaron%dbaron.org 2007-03-20 00:58:20 +00:00
Родитель 0a483b237a
Коммит 260b595874
23 изменённых файлов: 335 добавлений и 321 удалений

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

@ -58,6 +58,7 @@ REQUIRES = \
imglib2 \
browsercomps \
gfx \
thebes \
widget \
pref \
layout \

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

@ -50,6 +50,7 @@ REQUIRES = xpcom \
string \
dom \
gfx \
thebes \
layout \
widget \
view \

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

@ -60,6 +60,7 @@ REQUIRES = xpcom \
necko \
pref \
gfx \
thebes \
widget \
view \
webshell \

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

@ -41,6 +41,7 @@
#include "nsISupports.h"
#include "nsIRenderingContext.h"
#include "nsRect.h"
#include "gfxRect.h"
#ifdef MOZ_CAIRO_GFX
class gfxASurface;
@ -79,9 +80,10 @@ typedef enum {
#endif
// IID for the nsIImage interface
#define NS_IIMAGE_IID \
{ 0xce91c93f, 0x532d, 0x470d, \
{ 0xbf, 0xa3, 0xc9, 0x6e, 0x56, 0x01, 0x52, 0xa4 } }
// ab6af421-9552-4d18-a3f4-a2bf9d2e44f7
#define NS_IIMAGE_IID \
{ 0xab6af421, 0x9552, 0x4d18, \
{ 0xa3, 0xf4, 0xa2, 0xbf, 0x9d, 0x2e, 0x44, 0xf7 } }
// Interface to Images
class nsIImage : public nsISupports
@ -193,36 +195,14 @@ public:
*/
virtual nsColorMap * GetColorMap() = 0;
/**
* BitBlit the nsIImage to a device, the source can be scaled to the dest
* @update - dwc 2/1/99
* @param aSurface the surface to blit to
* @param aX The destination horizontal location
* @param aY The destination vertical location
* @param aWidth The destination width of the pixelmap
* @param aHeight The destination height of the pixelmap
* @return if TRUE, no errors
*/
NS_IMETHOD Draw(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) = 0;
/**
* BitBlit the nsIImage to a device, the source and dest can be scaled
* @update - dwc 2/1/99
* @param aSurface the surface to blit to
* @param aSX The source width of the pixelmap
* @param aSY The source vertical location
* @param aSWidth The source width of the pixelmap
* @param aSHeight The source height of the pixelmap
* @param aDX The destination horizontal location
* @param aDY The destination vertical location
* @param aDWidth The destination width of the pixelmap
* @param aDHeight The destination height of the pixelmap
* @return if TRUE, no errors
* @param aSourceRect source rectangle, in image pixels
* @param aDestRect destination rectangle, in device pixels
*/
NS_IMETHOD Draw(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface,
PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight) = 0;
NS_IMETHOD Draw(nsIRenderingContext &aContext,
const gfxRect &aSourceRect,
const gfxRect &aDestRect) = 0;
NS_IMETHOD DrawTile(nsIRenderingContext &aContext,
nsIDrawingSurface* aSurface,

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

@ -116,7 +116,9 @@ public:
NS_IMETHOD SetRightToLeftText(PRBool aIsRTL);
NS_IMETHOD GetRightToLeftText(PRBool* aIsRTL);
#ifndef MOZ_CAIRO_GFX
NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect);
#endif
NS_IMETHOD DrawTile(imgIContainer *aImage, nscoord aXOffset, nscoord aYOffset, const nsRect * aTargetRect);
NS_IMETHOD GetClusterInfo(const PRUnichar *aText,

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

@ -58,6 +58,7 @@ REQUIRES= \
necko \
dom \
locale \
thebes \
$(NULL)
CPPSRCS = \

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

@ -306,6 +306,7 @@ nsRenderingContextImpl::GetRightToLeftText(PRBool* aIsRTL)
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#ifndef MOZ_CAIRO_GFX
NS_IMETHODIMP nsRenderingContextImpl::DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect)
{
nsRect dr = aDestRect;
@ -395,6 +396,7 @@ NS_IMETHODIMP nsRenderingContextImpl::DrawImage(imgIContainer *aImage, const nsR
return img->Draw(*this, surface, sr.x, sr.y, sr.width, sr.height,
dr.x, dr.y, dr.width, dr.height);
}
#endif
/* [noscript] void drawTile (in imgIContainer aImage, in nscoord aXImageStart, in nscoord aYImageStart, [const] in nsRect aTargetRect); */
NS_IMETHODIMP

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

@ -310,20 +310,11 @@ nsThebesImage::UnlockImagePixels(PRBool aMaskPixels)
/* NB: These are pixels, not twips. */
NS_IMETHODIMP
nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
nsThebesImage::Draw(nsIRenderingContext &aContext,
const gfxRect &aSourceRect,
const gfxRect &aDestRect)
{
return Draw(aContext, aSurface, 0, 0, mWidth, mHeight, aX, aY, aWidth, aHeight);
}
/* NB: These are pixels, not twips. */
/* BUT nsRenderingContextImpl's DrawImage calls this with twips. */
NS_IMETHODIMP
nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
{
if (NS_UNLIKELY(aDWidth == 0 || aDHeight == 0)) {
if (NS_UNLIKELY(aDestRect.IsEmpty())) {
NS_ERROR("nsThebesImage::Draw zero dest size - please fix caller.");
return NS_OK;
}
@ -333,7 +324,7 @@ nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
#if 0
fprintf (stderr, "nsThebesImage::Draw src [%d %d %d %d] dest [%d %d %d %d] tx [%f %f] dec [%d %d %d %d]\n",
aSX, aSY, aSWidth, aSHeight, aDX, aDY, aDWidth, aDHeight,
aSourceRect.pos.x, aSourceRect.pos.y, aSWidth, aSHeight, aDX, aDY, aDWidth, aDHeight,
ctx->CurrentMatrix().GetTranslation().x, ctx->CurrentMatrix().GetTranslation().y,
mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height);
#endif
@ -349,7 +340,7 @@ nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
// otherwise
ctx->SetColor(mSinglePixelColor);
ctx->NewPath();
ctx->Rectangle(gfxRect(aDX, aDY, aDWidth, aDHeight), PR_TRUE);
ctx->Rectangle(aDestRect, PR_TRUE);
ctx->Fill();
return NS_OK;
}
@ -362,49 +353,47 @@ nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
ctx->SetMatrix(roundedCTM);
}
gfxFloat xscale = gfxFloat(aDWidth) / aSWidth;
gfxFloat yscale = gfxFloat(aDHeight) / aSHeight;
gfxFloat xscale = aDestRect.size.width / aSourceRect.size.width;
gfxFloat yscale = aDestRect.size.height / aSourceRect.size.height;
gfxRect srcRect(aSourceRect);
gfxRect destRect(aDestRect);
if (!GetIsImageComplete()) {
nsRect srcRect(aSX, aSY, aSWidth, aSHeight);
srcRect.IntersectRect(srcRect, mDecoded);
srcRect.Intersect(gfxRect(mDecoded.x, mDecoded.y,
mDecoded.width, mDecoded.height));
// This happens when mDecoded.width or height is zero. bug 368427.
if (NS_UNLIKELY(srcRect.width == 0 || srcRect.height == 0))
if (NS_UNLIKELY(srcRect.size.width == 0 || srcRect.size.height == 0))
return NS_OK;
aDX += (PRInt32)((srcRect.x - aSX)*xscale);
aDY += (PRInt32)((srcRect.y - aSY)*yscale);
destRect.pos.x += (srcRect.pos.x - aSourceRect.pos.x)*xscale;
destRect.pos.y += (srcRect.pos.y - aSourceRect.pos.y)*yscale;
// use '+ 1 - *scale' to get rid of rounding errors
aDWidth = (PRInt32)((srcRect.width)*xscale + 1 - xscale);
aDHeight = (PRInt32)((srcRect.height)*yscale + 1 - yscale);
aSX = srcRect.x;
aSY = srcRect.y;
destRect.size.width = (srcRect.size.width)*xscale + 1 - xscale;
destRect.size.height = (srcRect.size.height)*yscale + 1 - yscale;
}
// Reject over-wide or over-tall images.
if (!AllowedImageSize(aDWidth, aDHeight))
if (!AllowedImageSize(destRect.size.width, destRect.size.height))
return NS_ERROR_FAILURE;
gfxRect dr(aDX, aDY, aDWidth, aDHeight);
gfxMatrix mat;
mat.Translate(gfxPoint(aSX, aSY));
mat.Translate(srcRect.pos);
mat.Scale(1.0/xscale, 1.0/yscale);
/* Translate the start point of the image (the aSX,aSY point)
/* Translate the start point of the image (srcRect.pos)
* to coincide with the destination rectangle origin
*/
mat.Translate(gfxPoint(-aDX, -aDY));
mat.Translate(-destRect.pos);
nsRefPtr<gfxPattern> pat = new gfxPattern(ThebesSurface());
pat->SetMatrix(mat);
ctx->NewPath();
ctx->SetPattern(pat);
ctx->Rectangle(dr, doSnap);
ctx->Rectangle(destRect, doSnap);
ctx->Fill();
if (doSnap)

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

@ -73,12 +73,8 @@ public:
virtual nsColorMap *GetColorMap();
NS_IMETHOD Draw(nsIRenderingContext &aContext,
nsIDrawingSurface *aSurface,
PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight);
NS_IMETHOD Draw(nsIRenderingContext &aContext,
nsIDrawingSurface *aSurface,
PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight);
const gfxRect &aSourceRect,
const gfxRect &aDestRect);
NS_IMETHOD DrawTile(nsIRenderingContext &aContext,
nsIDrawingSurface *aSurface,
PRInt32 aSXOffset, PRInt32 aSYOffset,

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

@ -975,91 +975,8 @@ nsThebesRenderingContext::DrawImage(imgIContainer *aImage,
mThebes->CurrentMatrix().GetTranslation().x, mThebes->CurrentMatrix().GetTranslation().y);
#endif
nsCOMPtr<gfxIImageFrame> imgFrame;
aImage->GetCurrentFrame(getter_AddRefs(imgFrame));
if (!imgFrame) return NS_ERROR_FAILURE;
nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
if (!img) return NS_ERROR_FAILURE;
// For Bug 87819
// imgFrame may want image to start at different position, so adjust
nsIntRect pxImgFrameRect;
imgFrame->GetRect(pxImgFrameRect);
// twSrcRect is always in appunits (twips),
// and has nothing to do with the current transform (it's a region
// of the image)
double p2a = nsIDeviceContext::AppUnitsPerCSSPixel();
nsIntRect pxSr;
pxSr.x = NSAppUnitsToIntPixels(twSrcRect.x, p2a);
pxSr.y = NSAppUnitsToIntPixels(twSrcRect.y, p2a);
pxSr.width = NSAppUnitsToIntPixels(twSrcRect.XMost(), p2a) - pxSr.x;
pxSr.height = NSAppUnitsToIntPixels(twSrcRect.YMost(), p2a) - pxSr.y;
// the dest rect is affected by the current transform; that'll be
// handled by Image::Draw(), when we actually set up the rectangle.
nsIntRect pxDr;
pxDr.x = FROM_TWIPS_INT(twDestRect.x);
pxDr.y = FROM_TWIPS_INT(twDestRect.y);
pxDr.width = FROM_TWIPS_INT(twDestRect.XMost()) - pxDr.x;
pxDr.height = FROM_TWIPS_INT(twDestRect.YMost()) - pxDr.y;
// If we were asked to draw a 0-width or 0-height image,
// as either the src or dst, just bail; we can't do anything
// useful with this.
if (pxSr.width == 0 || pxSr.height == 0 ||
pxDr.width == 0 || pxDr.height == 0)
{
return NS_OK;
}
if (pxImgFrameRect.x > 0) {
pxSr.x -= pxImgFrameRect.x;
nscoord scaled_x = pxSr.x;
if (pxDr.width != pxSr.width) {
PRFloat64 scale_ratio = PRFloat64(pxDr.width) / PRFloat64(pxSr.width);
scaled_x = NSToCoordRound(scaled_x * scale_ratio);
}
if (pxSr.x < 0) {
pxDr.x -= scaled_x;
pxSr.width += pxSr.x;
pxDr.width += scaled_x;
if (pxSr.width <= 0 || pxDr.width <= 0)
return NS_OK;
pxSr.x = 0;
} else if (pxSr.x > pxImgFrameRect.width) {
return NS_OK;
}
}
if (pxImgFrameRect.y > 0) {
pxSr.y -= pxImgFrameRect.y;
nscoord scaled_y = pxSr.y;
if (pxDr.height != pxSr.height) {
PRFloat64 scale_ratio = PRFloat64(pxDr.height) / PRFloat64(pxSr.height);
scaled_y = NSToCoordRound(scaled_y * scale_ratio);
}
if (pxSr.y < 0) {
pxDr.y -= scaled_y;
pxSr.height += pxSr.y;
pxDr.height += scaled_y;
if (pxSr.height <= 0 || pxDr.height <= 0)
return NS_OK;
pxSr.y = 0;
} else if (pxSr.y > pxImgFrameRect.height) {
return NS_OK;
}
}
return img->Draw(*this, mDrawingSurface,
pxSr.x, pxSr.y,
pxSr.width, pxSr.height,
pxDr.x, pxDr.y, pxDr.width, pxDr.height);
NS_NOTREACHED("DrawImage should no longer be called with thebes");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP

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

@ -3197,7 +3197,7 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
if (sourceRect.XMost() <= tileWidth && sourceRect.YMost() <= tileHeight) {
// The entire drawRect is contained inside a single tile; just
// draw the corresponding part of the image once.
aRenderingContext.DrawImage(image, sourceRect, drawRect);
nsLayoutUtils::DrawImage(&aRenderingContext, image, absTileRect, drawRect);
} else {
aRenderingContext.DrawTile(image, absTileRect.x, absTileRect.y, &drawRect);
}

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

@ -60,6 +60,11 @@
#include "nsFrameManager.h"
#include "nsBlockFrame.h"
#include "nsBidiPresUtils.h"
#include "gfxIImageFrame.h"
#include "imgIContainer.h"
#include "gfxRect.h"
#include "nsIImage.h"
#include "nsIInterfaceRequestorUtils.h"
#ifdef MOZ_SVG_FOREIGNOBJECT
#include "nsSVGForeignObjectFrame.h"
@ -1853,3 +1858,157 @@ nsLayoutUtils::GetClosestLayer(nsIFrame* aFrame)
return layer;
return aFrame->GetPresContext()->PresShell()->FrameManager()->GetRootFrame();
}
/* static */ nsresult
nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
imgIContainer* aImage,
const nsRect& aDestRect,
const nsRect& aDirtyRect,
const nsRect* aSourceRect)
{
#ifdef MOZ_CAIRO_GFX
nsRect dirtyRect;
dirtyRect.IntersectRect(aDirtyRect, aDestRect);
if (dirtyRect.IsEmpty())
return NS_OK;
nsCOMPtr<gfxIImageFrame> imgFrame;
aImage->GetCurrentFrame(getter_AddRefs(imgFrame));
if (!imgFrame) return NS_ERROR_FAILURE;
nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
if (!img) return NS_ERROR_FAILURE;
// twSrcRect is always in appunits (twips),
// and has nothing to do with the current transform (it's a region
// of the image)
gfxRect pxSrc;
if (aSourceRect) {
PRInt32 p2a = nsIDeviceContext::AppUnitsPerCSSPixel();
pxSrc.pos.x = NSAppUnitsToFloatPixels(aSourceRect->x, p2a);
pxSrc.pos.y = NSAppUnitsToFloatPixels(aSourceRect->y, p2a);
pxSrc.size.width = NSAppUnitsToFloatPixels(aSourceRect->width, p2a);
pxSrc.size.height = NSAppUnitsToFloatPixels(aSourceRect->height, p2a);
} else {
pxSrc.pos.x = pxSrc.pos.y = 0.0;
PRInt32 w = 0, h = 0;
aImage->GetWidth(&w);
aImage->GetHeight(&h);
pxSrc.size.width = gfxFloat(w);
pxSrc.size.height = gfxFloat(h);
}
nsCOMPtr<nsIDeviceContext> dc;
aRenderingContext->GetDeviceContext(*getter_AddRefs(dc));
PRInt32 d2a = dc->AppUnitsPerDevPixel();
// the dest rect is affected by the current transform; that'll be
// handled by Image::Draw(), when we actually set up the rectangle.
// Snap the edges of where layout wants the image to the nearest
// pixel, but then convert back to gfxFloats for the rest of the math.
gfxRect pxDest;
{
nsIntRect r;
r.x = NSAppUnitsToIntPixels(aDestRect.x, d2a);
r.y = NSAppUnitsToIntPixels(aDestRect.y, d2a);
r.width = NSAppUnitsToIntPixels(aDestRect.XMost(), d2a) - r.x;
r.height = NSAppUnitsToIntPixels(aDestRect.YMost(), d2a) - r.y;
pxDest.pos.x = gfxFloat(r.x);
pxDest.pos.y = gfxFloat(r.y);
pxDest.size.width = gfxFloat(r.width);
pxDest.size.height = gfxFloat(r.height);
}
// And likewise for the dirty rect. (Is should be OK to round to
// nearest rather than outwards, since any dirty rects coming from the
// OS should be on pixel boundaries; the rest is other things it's
// been intersected with, and we should be rounding those consistently.)
gfxRect pxDirty;
{
nsIntRect r;
r.x = NSAppUnitsToIntPixels(aDirtyRect.x, d2a);
r.y = NSAppUnitsToIntPixels(aDirtyRect.y, d2a);
r.width = NSAppUnitsToIntPixels(aDirtyRect.XMost(), d2a) - r.x;
r.height = NSAppUnitsToIntPixels(aDirtyRect.YMost(), d2a) - r.y;
pxDirty.pos.x = gfxFloat(r.x);
pxDirty.pos.y = gfxFloat(r.y);
pxDirty.size.width = gfxFloat(r.width);
pxDirty.size.height = gfxFloat(r.height);
}
// Reduce the src rect to what's needed for the dirty rect.
if (pxDirty.size.width != pxDest.size.width) {
const gfxFloat ratio = pxSrc.size.width / pxDest.size.width;
pxSrc.pos.x += (pxDirty.pos.x - pxDest.pos.x) * ratio;
pxSrc.size.width = pxDirty.size.width * ratio;
}
if (pxDirty.size.height != pxDest.size.height) {
const gfxFloat ratio = pxSrc.size.height / pxDest.size.height;
pxSrc.pos.y += (pxDirty.pos.y - pxDest.pos.y) * ratio;
pxSrc.size.height = pxDirty.size.height * ratio;
}
// If we were asked to draw a 0-width or 0-height image,
// as either the src or dst, just bail; we can't do anything
// useful with this.
if (pxSrc.IsEmpty() || pxDirty.IsEmpty())
{
return NS_OK;
}
// For Bug 87819
// imgFrame may want image to start at different position, so adjust
nsIntRect pxImgFrameRect;
imgFrame->GetRect(pxImgFrameRect);
if (pxImgFrameRect.x > 0) {
pxSrc.pos.x -= gfxFloat(pxImgFrameRect.x);
gfxFloat scaled_x = pxSrc.pos.x;
if (pxDirty.size.width != pxSrc.size.width) {
scaled_x = scaled_x * (pxDirty.size.width / pxSrc.size.width);
}
if (pxSrc.pos.x < 0.0) {
pxDirty.pos.x -= scaled_x;
pxSrc.size.width += pxSrc.pos.x;
pxDirty.size.width += scaled_x;
if (pxSrc.size.width <= 0.0 || pxDirty.size.width <= 0.0)
return NS_OK;
pxSrc.pos.x = 0.0;
}
}
if (pxSrc.pos.x > gfxFloat(pxImgFrameRect.width)) {
return NS_OK;
}
if (pxImgFrameRect.y > 0) {
pxSrc.pos.y -= gfxFloat(pxImgFrameRect.y);
gfxFloat scaled_y = pxSrc.pos.y;
if (pxDirty.size.height != pxSrc.size.height) {
scaled_y = scaled_y * (pxDirty.size.height / pxSrc.size.height);
}
if (pxSrc.pos.y < 0.0) {
pxDirty.pos.y -= scaled_y;
pxSrc.size.height += pxSrc.pos.y;
pxDirty.size.height += scaled_y;
if (pxSrc.size.height <= 0.0 || pxDirty.size.height <= 0.0)
return NS_OK;
pxSrc.pos.y = 0.0;
}
}
if (pxSrc.pos.y > gfxFloat(pxImgFrameRect.height)) {
return NS_OK;
}
return img->Draw(*aRenderingContext, pxSrc, pxDirty);
#else
/*
* If somebody wants non-cairo GFX to work again, they could write
* appropriate code to call nsIRenderingContext::DrawImage here
*/
#endif
}

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

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Boris Zbarsky <bzbarsky@mit.edu> (original author)
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -584,6 +586,28 @@ public:
* going away, so this is a cleaner definition.
*/
static nsIFrame* GetClosestLayer(nsIFrame* aFrame);
/**
* Draw a single image.
* @param aImage The image.
* @param aRenderingContext Where to draw the image, set up with an
* appropriate scale and transform for drawing in
* app units (aDestRect).
* @param aDestRect Where to draw the image (app units).
* @param aDirtyRect Draw only within this region (rounded to the
* nearest pixel); the intersection of
* invalidation and clipping.
* @param aSourceRect If null, draw the entire image so it fits in
* aDestRect. If non-null, the subregion of the
* image that should be drawn (in app units, such
* that converting it to CSS pixels yields image
* pixels).
*/
static nsresult DrawImage(nsIRenderingContext* aRenderingContext,
imgIContainer* aImage,
const nsRect& aDestRect,
const nsRect& aDirtyRect,
const nsRect* aSourceRect = nsnull);
};
#endif // nsLayoutUtils_h__

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

@ -51,6 +51,7 @@ REQUIRES = xpcom \
locale \
content \
gfx \
thebes \
widget \
view \
dom \

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

@ -195,7 +195,7 @@ void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
{
NS_STATIC_CAST(nsBulletFrame*, mFrame)->
PaintBullet(*aCtx, aBuilder->ToReferenceFrame(mFrame));
PaintBullet(*aCtx, aBuilder->ToReferenceFrame(mFrame), aDirtyRect);
}
NS_IMETHODIMP
@ -212,7 +212,8 @@ nsBulletFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
void
nsBulletFrame::PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt)
nsBulletFrame::PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect)
{
const nsStyleList* myList = GetStyleList();
PRUint8 listStyleType = myList->mListStyleType;
@ -225,11 +226,11 @@ nsBulletFrame::PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt)
nsCOMPtr<imgIContainer> imageCon;
mImageRequest->GetImage(getter_AddRefs(imageCon));
if (imageCon) {
nsRect innerArea(0, 0,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
nsRect dest(mPadding.left, mPadding.top, innerArea.width, innerArea.height);
aRenderingContext.DrawImage(imageCon, innerArea, dest + aPt);
nsRect dest(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
nsLayoutUtils::DrawImage(&aRenderingContext, imageCon,
dest + aPt, aDirtyRect);
return;
}
}

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

@ -99,7 +99,8 @@ public:
PRBool GetListItemText(const nsStyleList& aStyleList,
nsString& aResult);
void PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt);
void PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect);
protected:
void GetDesiredSize(nsPresContext* aPresContext,

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

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -308,8 +309,10 @@ nsImageFrame::Init(nsIContent* aContent,
}
PRBool
nsImageFrame::RecalculateTransform(imgIContainer* aImage)
nsImageFrame::UpdateIntrinsicSize(imgIContainer* aImage)
{
NS_PRECONDITION(aImage, "null image");
PRBool intrinsicSizeChanged = PR_FALSE;
if (aImage) {
@ -324,6 +327,12 @@ nsImageFrame::RecalculateTransform(imgIContainer* aImage)
}
}
return intrinsicSizeChanged;
}
void
nsImageFrame::RecalculateTransform()
{
// In any case, we need to translate this over appropriately. Set
// translation _before_ setting scaling so that it does not get
// scaled!
@ -331,8 +340,9 @@ nsImageFrame::RecalculateTransform(imgIContainer* aImage)
// XXXbz does this introduce rounding errors because of the cast to
// float? Should we just manually add that stuff in every time
// instead?
mTransform.SetToTranslate(float(mBorderPadding.left),
float(mBorderPadding.top - GetContinuationOffset()));
nsRect innerArea = GetInnerArea();
mTransform.SetToTranslate(float(innerArea.x),
float(innerArea.y - GetContinuationOffset()));
// Set the scale factors
if (mIntrinsicSize.width != 0 && mIntrinsicSize.height != 0 &&
@ -340,8 +350,6 @@ nsImageFrame::RecalculateTransform(imgIContainer* aImage)
mTransform.AddScale(float(mComputedSize.width) / float(mIntrinsicSize.width),
float(mComputedSize.height) / float(mIntrinsicSize.height));
}
return intrinsicSizeChanged;
}
/*
@ -518,7 +526,7 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage)
return NS_OK;
}
RecalculateTransform(aImage);
UpdateIntrinsicSize(aImage);
// Now we need to reflow if we have an unconstrained size and have
// already gotten the initial reflow
@ -577,6 +585,8 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
}
}
// XXX We really need to round this out, now that we're doing better
// image scaling!
nsRect r = SourceRectToDest(*aRect);
#ifdef DEBUG_decode
printf("Source rect (%d,%d,%d,%d) -> invalidate dest rect (%d,%d,%d,%d)\n",
@ -620,7 +630,7 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest,
nsCOMPtr<imgIContainer> imageContainer;
aRequest->GetImage(getter_AddRefs(imageContainer));
NS_ASSERTION(imageContainer, "Successful load with no container?");
intrinsicSizeChanged = RecalculateTransform(imageContainer);
intrinsicSizeChanged = UpdateIntrinsicSize(imageContainer);
}
else {
// Have to size to 0,0 so that GetDesiredSize recalculates the size
@ -686,7 +696,7 @@ nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext)
}
if (currentContainer) {
RecalculateTransform(currentContainer);
UpdateIntrinsicSize(currentContainer);
} else {
// image request is null or image size not known, probably an
// invalid image specified
@ -698,7 +708,6 @@ nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext)
mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+(2*(ICON_PADDING+ALT_BORDER_WIDTH))),
nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+(2*(ICON_PADDING+ALT_BORDER_WIDTH))));
}
RecalculateTransform(nsnull);
}
}
}
@ -721,36 +730,18 @@ nsImageFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
nsRect
nsImageFrame::GetInnerArea() const
{
nsRect r;
r.x = mBorderPadding.left;
r.y = GetPrevInFlow() ? 0 : mBorderPadding.top;
r.width = mRect.width - mBorderPadding.left - mBorderPadding.right;
r.height = mRect.height -
(GetPrevInFlow() ? 0 : mBorderPadding.top) -
(GetNextInFlow() ? 0 : mBorderPadding.bottom);
return r;
return GetContentRect() - GetPosition();
}
// get the offset into the content area of the image where aImg starts if it is a continuation.
nscoord
nsImageFrame::GetContinuationOffset(nscoord* aWidth) const
nsImageFrame::GetContinuationOffset() const
{
nscoord offset = 0;
if (aWidth) {
*aWidth = 0;
}
if (GetPrevInFlow()) {
for (nsIFrame* prevInFlow = GetPrevInFlow() ; prevInFlow; prevInFlow = prevInFlow->GetPrevInFlow()) {
nsRect rect = prevInFlow->GetRect();
if (aWidth) {
*aWidth = rect.width;
}
offset += rect.height;
}
offset -= mBorderPadding.top;
offset = PR_MAX(0, offset);
for (nsIFrame *f = GetPrevInFlow(); f; f = f->GetPrevInFlow()) {
offset += f->GetContentRect().height;
}
NS_ASSERTION(offset >= 0, "bogus GetContentRect");
return offset;
}
@ -810,26 +801,21 @@ nsImageFrame::Reflow(nsPresContext* aPresContext,
mState |= IMAGE_GOTINITIALREFLOW;
}
// Set our borderpadding so that if GetDesiredSize has to recalc the
// transform it can.
mBorderPadding = aReflowState.mComputedBorderPadding;
nsSize newSize(aReflowState.ComputedWidth(), aReflowState.mComputedHeight);
if (mComputedSize != newSize) {
mComputedSize = newSize;
RecalculateTransform(nsnull);
}
mComputedSize =
nsSize(aReflowState.ComputedWidth(), aReflowState.mComputedHeight);
RecalculateTransform();
aMetrics.width = mComputedSize.width;
aMetrics.height = mComputedSize.height;
// add borders and padding
aMetrics.width += mBorderPadding.left + mBorderPadding.right;
aMetrics.height += mBorderPadding.top + mBorderPadding.bottom;
aMetrics.width += aReflowState.mComputedBorderPadding.LeftRight();
aMetrics.height += aReflowState.mComputedBorderPadding.TopBottom();
if (GetPrevInFlow()) {
nscoord y = GetContinuationOffset(&aMetrics.width);
aMetrics.height -= y + mBorderPadding.top;
aMetrics.width = GetPrevInFlow()->GetSize().width;
nscoord y = GetContinuationOffset();
aMetrics.height -= y + aReflowState.mComputedBorderPadding.top;
aMetrics.height = PR_MAX(0, aMetrics.height);
}
@ -1028,6 +1014,7 @@ struct nsRecessedBorder : public nsStyleBorder {
void
nsImageFrame::DisplayAltFeedback(nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
imgIRequest* aRequest,
nsPoint aPt)
{
@ -1084,11 +1071,10 @@ nsImageFrame::DisplayAltFeedback(nsIRenderingContext& aRenderingContext,
}
if (imgCon) {
// draw it
nsRect source(0,0,size,size);
nsRect dest((vis->mDirection == NS_STYLE_DIRECTION_RTL) ?
inner.XMost() - size : inner.x,
inner.y, size, size);
aRenderingContext.DrawImage(imgCon, source, dest);
nsLayoutUtils::DrawImage(&aRenderingContext, imgCon, dest, aDirtyRect);
iconUsed = PR_TRUE;
}
}
@ -1134,6 +1120,7 @@ static void PaintAltFeedback(nsIFrame* aFrame, nsIRenderingContext* aCtx,
{
nsImageFrame* f = NS_STATIC_CAST(nsImageFrame*, aFrame);
f->DisplayAltFeedback(*aCtx,
aDirtyRect,
IMAGE_OK(f->GetContent()->IntrinsicState(), PR_TRUE)
? nsImageFrame::gIconLoad->mLoadingImage
: nsImageFrame::gIconLoad->mBrokenImage,
@ -1190,64 +1177,19 @@ nsImageFrame::PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
{
// Render the image into our content area (the area inside
// the borders and padding)
NS_ASSERTION(GetInnerArea().width == mComputedSize.width, "bad width");
nsRect inner = GetInnerArea() + aPt;
nsRect paintArea(inner);
nsRect clip;
clip.IntersectRect(inner, aDirtyRect);
nscoord offsetY = 0;
nsRect dest(inner.TopLeft(), mComputedSize);
dest.y -= GetContinuationOffset();
// if the image is split account for y-offset
if (GetPrevInFlow()) {
offsetY = GetContinuationOffset();
}
if (mIntrinsicSize == mComputedSize) {
// Find the actual rect to be painted to in the rendering context
paintArea.IntersectRect(paintArea, aDirtyRect);
// Rect in the image to paint
nsRect r(paintArea.x - inner.x,
paintArea.y - inner.y + offsetY,
paintArea.width,
paintArea.height);
aRenderingContext.DrawImage(aImage, r, paintArea);
} else {
// The computed size is the total size of all the continuations,
// including ourselves. Note that we're basically inverting
// mTransform here (would it too much to ask for
// nsTransform2D::Invert?), since we need to convert from
// rendering context coords to image coords...
nsTransform2D trans;
trans.SetToScale((float(mIntrinsicSize.width) / float(mComputedSize.width)),
(float(mIntrinsicSize.height) / float(mComputedSize.height)));
// XXXbz it looks like we should take
// IntersectRect(paintArea, aDirtyRect) here too, but things
// get very weird if I do that ....
// paintArea.IntersectRect(paintArea, aDirtyRect);
// dirty rect in image our coord size...
nsRect r(paintArea.x - inner.x,
paintArea.y - inner.y + offsetY,
paintArea.width,
paintArea.height);
// Transform that to image coords
trans.TransformCoord(&r.x, &r.y, &r.width, &r.height);
#ifdef DEBUG_decode
printf("IF draw src (%d,%d,%d,%d) -> dst (%d,%d,%d,%d)\n",
r.x, r.y, r.width, r.height, paintArea.x, paintArea.y,
paintArea.width, paintArea.height);
#endif
aRenderingContext.DrawImage(aImage, r, paintArea);
}
nsLayoutUtils::DrawImage(&aRenderingContext, aImage, dest, clip);
nsPresContext* presContext = GetPresContext();
nsImageMap* map = GetImageMap(presContext);
if (nsnull != map) {
nsRect inner = GetInnerArea() + aPt;
aRenderingContext.PushState();
aRenderingContext.SetColor(NS_RGB(0, 0, 0));
aRenderingContext.SetLineStyle(nsLineStyle_kDotted);
@ -1693,6 +1635,19 @@ mRect.height);
}
#endif
PRIntn
nsImageFrame::GetSkipSides() const
{
PRIntn skip = 0;
if (nsnull != GetPrevInFlow()) {
skip |= 1 << NS_SIDE_TOP;
}
if (nsnull != GetNextInFlow()) {
skip |= 1 << NS_SIDE_BOTTOM;
}
return skip;
}
NS_IMETHODIMP
nsImageFrame::GetIntrinsicImageSize(nsSize& aSize)
{

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

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -140,6 +141,8 @@ public:
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
#endif
virtual PRIntn GetSkipSides() const;
NS_IMETHOD GetImageMap(nsPresContext *aPresContext, nsIImageMap **aImageMap);
NS_IMETHOD GetIntrinsicImageSize(nsSize& aSize);
@ -161,6 +164,7 @@ public:
nsStyleContext* aStyleContext);
void DisplayAltFeedback(nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
imgIRequest* aRequest,
nsPoint aPt);
@ -238,19 +242,21 @@ private:
inline void GetLoadGroup(nsPresContext *aPresContext,
nsILoadGroup **aLoadGroup);
nscoord GetContinuationOffset(nscoord* aWidth = 0) const;
nscoord GetContinuationOffset() const;
void GetDocumentCharacterSet(nsACString& aCharset) const;
/**
* This function will recalculate mTransform. If a non-null image
* is passed in, mIntrinsicSize will be recalculated from the image
* size. Otherwise, mIntrinsicSize will not be touched.
* Recalculate mIntrinsicSize from the image.
*
* @return PR_TRUE if aImage is non-null and its size did _not_
* @return whether aImage's size did _not_
* match our previous intrinsic size
* @return PR_FALSE otherwise
*/
PRBool RecalculateTransform(imgIContainer* aImage);
PRBool UpdateIntrinsicSize(imgIContainer* aImage);
/**
* This function will recalculate mTransform.
*/
void RecalculateTransform();
/**
* Helper functions to check whether the request or image container
@ -274,8 +280,6 @@ private:
nsSize mIntrinsicSize;
nsTransform2D mTransform;
nsMargin mBorderPadding;
static nsIIOService* sIOService;
/* loading / broken image icon support */

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

@ -51,33 +51,33 @@ fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-6.html border-top-10-ref.htm
!= background-image-base.html background-image-height-10-ref.html
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-height-4.html background-image-base.html # bug 371316 + bug 371434
fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") == background-image-height-5.html background-image-height-10-ref.html # bug 371316 + bug 371434
== background-image-height-4.html background-image-base.html
== background-image-height-5.html background-image-height-10-ref.html
== background-image-height-6.html background-image-height-10-ref.html
!= background-image-base.html background-image-top-10-ref.html
== background-image-top-4.html background-image-base.html
== background-image-top-5.html background-image-top-10-ref.html
== background-image-top-6.html background-image-top-10-ref.html
!= background-image-base.html background-image-width-10-ref.html
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-width-4.html background-image-base.html # bug 371316 + bug 371434
fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") == background-image-width-5.html background-image-width-10-ref.html # bug 371316 + bug 371434
== background-image-width-4.html background-image-base.html
== background-image-width-5.html background-image-width-10-ref.html
== background-image-width-6.html background-image-width-10-ref.html
!= background-image-base.html background-image-left-10-ref.html
== background-image-left-4.html background-image-base.html
== background-image-left-5.html background-image-left-10-ref.html
== background-image-left-6.html background-image-left-10-ref.html
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-top-height-4.html background-image-height-4.html # bug 371316 + bug 371434
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") fails-if(MOZ_WIDGET_TOOLKIT=="windows") == background-image-top-height-5.html background-image-height-5.html # bug 371316 + bug 371434
== background-image-top-height-4.html background-image-height-4.html
== background-image-top-height-5.html background-image-height-5.html
== background-image-top-height-6.html background-image-height-6.html
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-left-width-4.html background-image-width-4.html # bug 371316 + bug 371434
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") fails-if(MOZ_WIDGET_TOOLKIT=="windows") == background-image-left-width-5.html background-image-width-5.html # bug 371316 + bug 371434
== background-image-left-width-4.html background-image-width-4.html
== background-image-left-width-5.html background-image-width-5.html
== background-image-left-width-6.html background-image-width-6.html
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-height-top-4.html background-image-height-4.html # bug 371316 + bug 371434
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == background-image-height-top-5.html background-image-height-5.html # bug 371316 + bug 371434
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") fails-if(MOZ_WIDGET_TOOLKIT=="windows") == background-image-height-top-6.html background-image-height-6.html # bug 371316 + bug 371434
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-width-left-4.html background-image-width-4.html # bug 371316 + bug 371434
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == background-image-width-left-5.html background-image-width-5.html # bug 371316 + bug 371434
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") fails-if(MOZ_WIDGET_TOOLKIT=="windows") == background-image-width-left-6.html background-image-width-6.html # bug 371316 + bug 371434
== background-image-height-top-4.html background-image-height-4.html
== background-image-height-top-5.html background-image-height-5.html
== background-image-height-top-6.html background-image-height-6.html
== background-image-width-left-4.html background-image-width-4.html
== background-image-width-left-5.html background-image-width-5.html
== background-image-width-left-6.html background-image-width-6.html
# These all fail due to bug 155955, and maybe also bug 371180, plus a

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

@ -53,6 +53,7 @@ REQUIRES = xpcom \
content \
xul \
gfx \
thebes \
widget \
view \
docshell \

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

@ -370,7 +370,8 @@ nsImageBoxFrame::PaintImage(nsIRenderingContext& aRenderingContext,
return;
// don't draw if the image is not dirty
if (!aDirtyRect.Intersects(rect))
nsRect dirty;
if (!dirty.IntersectRect(aDirtyRect, rect))
return;
nsCOMPtr<imgIContainer> imgCon;
@ -378,30 +379,8 @@ nsImageBoxFrame::PaintImage(nsIRenderingContext& aRenderingContext,
if (imgCon) {
PRBool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
PRBool sizeMatch = hasSubRect ?
mSubRect.width == rect.width && mSubRect.height == rect.height :
mImageSize.width == rect.width && mImageSize.height == rect.height;
if (sizeMatch) {
nsRect dest(rect);
if (hasSubRect)
rect = mSubRect;
else {
rect.x = 0;
rect.y = 0;
}
// XXXdwh do dirty rect intersection like the HTML image frame does,
// so that we don't always repaint the entire image!
aRenderingContext.DrawImage(imgCon, rect, dest);
}
else {
nsRect src(0, 0, mImageSize.width, mImageSize.height);
if (hasSubRect)
src = mSubRect;
aRenderingContext.DrawImage(imgCon, src, rect);
}
nsLayoutUtils::DrawImage(&aRenderingContext, imgCon,
rect, dirty, hasSubRect ? &mSubRect : nsnull);
}
}

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

@ -3218,7 +3218,8 @@ nsTreeBodyFrame::PaintTwisty(PRInt32 aRowIndex,
}
// Paint the image.
aRenderingContext.DrawImage(image, imageSize, r);
nsLayoutUtils::DrawImage(&aRenderingContext, image,
r, aDirtyRect, &imageSize);
}
}
}
@ -3339,15 +3340,11 @@ nsTreeBodyFrame::PaintImage(PRInt32 aRowIndex,
// Essentially, we are scaling the image as dictated by the CSS destination
// height and width, and we are then clipping the scaled image by the cell
// width and height.
if (destRect.width != imageDestSize.width) {
sourceRect.width = sourceRect.width * destRect.width / imageDestSize.width;
}
if (destRect.height != imageDestSize.height) {
sourceRect.height = sourceRect.height * destRect.height / imageDestSize.height;
}
// Finally we can paint the image.
aRenderingContext.DrawImage(image, sourceRect, destRect);
nsRect clip;
clip.IntersectRect(aDirtyRect, destRect);
nsLayoutUtils::DrawImage(&aRenderingContext, image,
nsRect(destRect.TopLeft(), imageDestSize),
clip, &sourceRect);
}
// Update the aRemainingWidth and aCurrX values.
@ -3506,7 +3503,8 @@ nsTreeBodyFrame::PaintCheckbox(PRInt32 aRowIndex,
}
// Paint the image.
aRenderingContext.DrawImage(image, imageSize, r);
nsLayoutUtils::DrawImage(&aRenderingContext, image,
r, aDirtyRect, &imageSize);
}
}

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

@ -51,6 +51,7 @@ LIBXUL_LIBRARY = 1
REQUIRES = xpcom \
string \
gfx \
thebes \
imglib2 \
$(JPEG_REQUIRES) \
$(NULL)