diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index bfc5481a1941..0896a55eaba4 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -3714,11 +3714,18 @@ ImageRenderer::ComputeSize(const nsSize& aDefault) case eStyleImageType_Image: { nsIntSize imageIntSize; - mImageContainer->GetWidth(&imageIntSize.width); - mImageContainer->GetHeight(&imageIntSize.height); + PRBool gotHeight, gotWidth; + nsLayoutUtils::ComputeSizeForDrawing(mImageContainer, imageIntSize, + gotWidth, gotHeight); + + mSize.width = gotWidth ? + nsPresContext::CSSPixelsToAppUnits(imageIntSize.width) : + aDefault.width; + + mSize.height = gotHeight ? + nsPresContext::CSSPixelsToAppUnits(imageIntSize.height) : + aDefault.height; - mSize.width = nsPresContext::CSSPixelsToAppUnits(imageIntSize.width); - mSize.height = nsPresContext::CSSPixelsToAppUnits(imageIntSize.height); break; } case eStyleImageType_Gradient: diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 6a158b81655d..9bc80d917fce 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3043,7 +3043,8 @@ DrawImageInternal(nsIRenderingContext* aRenderingContext, } aImage->Draw(ctx, aGraphicsFilter, drawingParams.mUserSpaceToImageSpace, - drawingParams.mFillRect, drawingParams.mSubimage, aImageFlags); + drawingParams.mFillRect, drawingParams.mSubimage, aImageSize, + aImageFlags); return NS_OK; } @@ -3134,8 +3135,13 @@ nsLayoutUtils::DrawSingleImage(nsIRenderingContext* aRenderingContext, const nsRect* aSourceArea) { nsIntSize imageSize; - aImage->GetWidth(&imageSize.width); - aImage->GetHeight(&imageSize.height); + if (aImage->GetType() == imgIContainer::TYPE_VECTOR) { + imageSize.width = nsPresContext::AppUnitsToIntCSSPixels(aDest.width); + imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aDest.height); + } else { + aImage->GetWidth(&imageSize.width); + aImage->GetHeight(&imageSize.height); + } NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE); nsRect source; @@ -3158,6 +3164,49 @@ nsLayoutUtils::DrawSingleImage(nsIRenderingContext* aRenderingContext, fill.TopLeft(), aDirty, imageSize, aImageFlags); } +/* static */ void +nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage, + nsIntSize& aImageSize, /*outparam*/ + PRBool& aGotWidth, /*outparam*/ + PRBool& aGotHeight /*outparam*/) +{ + aGotWidth = NS_SUCCEEDED(aImage->GetWidth(&aImageSize.width)); + aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height)); + + if ((aGotWidth && aGotHeight) || // Trivial success! + (!aGotWidth && !aGotHeight)) { // Trivial failure! + return; + } + + // If we get here, we succeeded at querying *either* the width *or* the + // height, but not both. + NS_ASSERTION(aImage->GetType() == imgIContainer::TYPE_VECTOR, + "GetWidth and GetHeight should only fail for vector images"); + + nsIFrame* rootFrame = aImage->GetRootLayoutFrame(); + NS_ASSERTION(rootFrame, + "We should have a VectorImage, which should have a rootFrame"); + + // This falls back on failure, if we somehow end up without a rootFrame. + nsSize ratio = rootFrame ? rootFrame->GetIntrinsicRatio() : nsSize(0,0); + if (!aGotWidth) { // Have height, missing width + if (ratio.height != 0) { // don't divide by zero + aImageSize.width = NSToCoordRound(aImageSize.height * + float(ratio.width) / + float(ratio.height)); + aGotWidth = PR_TRUE; + } + } else { // Have width, missing height + if (ratio.width != 0) { // don't divide by zero + aImageSize.height = NSToCoordRound(aImageSize.width * + float(ratio.height) / + float(ratio.width)); + aGotHeight = PR_TRUE; + } + } +} + + /* static */ nsresult nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext, imgIContainer* aImage, @@ -3169,9 +3218,16 @@ nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext, PRUint32 aImageFlags) { nsIntSize imageSize; - aImage->GetWidth(&imageSize.width); - aImage->GetHeight(&imageSize.height); - NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE); + PRBool gotHeight, gotWidth; + ComputeSizeForDrawing(aImage, imageSize, gotWidth, gotHeight); + + // fallback size based on aFill. + if (!gotWidth) { + imageSize.width = nsPresContext::AppUnitsToIntCSSPixels(aFill.width); + } + if (!gotHeight) { + imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aFill.height); + } return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter, aDest, aFill, aAnchor, aDirty, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 335d21901d92..2efa39f720a4 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1016,6 +1016,25 @@ public: PRUint32 aImageFlags, const nsRect* aSourceArea = nsnull); + /** + * Given an imgIContainer, this method attempts to obtain an intrinsic + * px-valued height & width for it. If the imgIContainer has a non-pixel + * value for either height or width, this method tries to generate a pixel + * value for that dimension using the intrinsic ratio (if available). + * + * This method will always set aGotWidth and aGotHeight to indicate whether + * we were able to successfully obtain (or compute) a value for each + * dimension. + * + * NOTE: This method is similar to ComputeSizeWithIntrinsicDimensions. The + * difference is that this one is simpler and is suited to places where we + * have less information about the frame tree. + */ + static void ComputeSizeForDrawing(imgIContainer* aImage, + nsIntSize& aImageSize, + PRBool& aGotWidth, + PRBool& aGotHeight); + /** * Given a source area of an image (in appunits) and a destination area * that we want to map that source area too, computes the area that diff --git a/modules/libpr0n/public/imgIContainer.idl b/modules/libpr0n/public/imgIContainer.idl index 470c8ea8175f..e4026099c5e7 100644 --- a/modules/libpr0n/public/imgIContainer.idl +++ b/modules/libpr0n/public/imgIContainer.idl @@ -52,6 +52,7 @@ interface imgIDecoderObserver; #include "gfxPattern.h" #include "gfxASurface.h" #include "nsRect.h" +#include "nsSize.h" #include "limits.h" class nsIFrame; @@ -76,6 +77,7 @@ native gfxImageFormat(gfxASurface::gfxImageFormat); [ref] native gfxRect(gfxRect); native gfxGraphicsFilter(gfxPattern::GraphicsFilter); [ref] native nsIntRect(nsIntRect); +[ref] native nsIntSize(nsIntSize); [ptr] native nsIFrame(nsIFrame); /** @@ -86,7 +88,7 @@ native gfxGraphicsFilter(gfxPattern::GraphicsFilter); * * Internally, imgIContainer also manages animation of images. */ -[scriptable, uuid(8bb94fa2-f57a-482c-bef8-e0b0424b0b3c)] +[scriptable, uuid(239dfa70-2285-4d63-99cd-e9b7ff9555c7)] interface imgIContainer : nsISupports { /** @@ -205,6 +207,13 @@ interface imgIContainer : nsISupports * automatically tiled as necessary. * @param aSubimage The area of the image, in pixels, that we are allowed to * sample from. + * @param aViewportSize + * The size (in CSS pixels) of the viewport that would be available + * for the full image to occupy, if we were drawing the full image. + * (Note that we might not actually be drawing the full image -- we + * might be restricted by aSubimage -- but we still need the full + * image's viewport-size in order for SVG images with the "viewBox" + * attribute to position their content correctly.) * @param aFlags Flags of the FLAG_* variety */ [noscript] void draw(in gfxContext aContext, @@ -212,6 +221,7 @@ interface imgIContainer : nsISupports [const] in gfxMatrix aUserSpaceToImageSpace, [const] in gfxRect aFill, [const] in nsIntRect aSubimage, + [const] in nsIntSize aViewportSize, in PRUint32 aFlags); /** diff --git a/modules/libpr0n/src/RasterImage.cpp b/modules/libpr0n/src/RasterImage.cpp index 9f9666fb5766..5c154f76646d 100644 --- a/modules/libpr0n/src/RasterImage.cpp +++ b/modules/libpr0n/src/RasterImage.cpp @@ -2425,6 +2425,7 @@ RasterImage::SyncDecode() * [const] in gfxMatrix aUserSpaceToImageSpace, * [const] in gfxRect aFill, * [const] in nsIntRect aSubimage, + * [const] in nsIntSize aViewportSize, * in PRUint32 aFlags); */ NS_IMETHODIMP RasterImage::Draw(gfxContext *aContext, @@ -2432,6 +2433,7 @@ RasterImage::Draw(gfxContext *aContext, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect &aFill, const nsIntRect &aSubimage, + const nsIntSize& /*aViewportSize - ignored*/, PRUint32 aFlags) { if (mError) diff --git a/widget/src/xpwidgets/nsBaseDragService.cpp b/widget/src/xpwidgets/nsBaseDragService.cpp index 93db52ccde11..4534707686e6 100644 --- a/widget/src/xpwidgets/nsBaseDragService.cpp +++ b/widget/src/xpwidgets/nsBaseDragService.cpp @@ -628,7 +628,7 @@ nsBaseDragService::DrawDragForImage(nsPresContext* aPresContext, gfxMatrix().Scale(srcSize.width/outRect.Width(), srcSize.height/outRect.Height()); nsIntRect imgSize(0, 0, srcSize.width, srcSize.height); imgContainer->Draw(ctx, gfxPattern::FILTER_GOOD, scale, outRect, imgSize, - imgIContainer::FLAG_SYNC_DECODE); + destSize, imgIContainer::FLAG_SYNC_DECODE); return NS_OK; } else { return aCanvas->RenderContextsExternal(ctx, gfxPattern::FILTER_GOOD);