diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index cf15a246803..1d2ab65487f 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -783,7 +783,7 @@ static PRBool GetIntrinsicSizeFor(nsIFrame* aFrame, nsSize& aIntrinsicSize) { // See if it is an image frame - PRBool result = PR_FALSE; + PRBool success = PR_FALSE; // Currently the only type of replaced frame that we can get the intrinsic // size for is an image frame @@ -792,10 +792,11 @@ GetIntrinsicSizeFor(nsIFrame* aFrame, nsSize& aIntrinsicSize) if (aFrame->GetType() == nsGkAtoms::imageFrame) { nsImageFrame* imageFrame = (nsImageFrame*)aFrame; - imageFrame->GetIntrinsicImageSize(aIntrinsicSize); - result = (aIntrinsicSize != nsSize(0, 0)); + if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(aIntrinsicSize))) { + success = (aIntrinsicSize != nsSize(0, 0)); + } } - return result; + return success; } /** diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index d7fcd58e7e3..b2cea982e95 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1505,6 +1505,12 @@ public: IntrinsicSize& operator=(const IntrinsicSize& rhs) { width = rhs.width; height = rhs.height; return *this; } + PRBool operator==(const IntrinsicSize& rhs) { + return width == rhs.width && height == rhs.height; + } + PRBool operator!=(const IntrinsicSize& rhs) { + return !(*this == rhs); + } }; virtual IntrinsicSize GetIntrinsicSize() = 0; diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index dd5d31a7d3c..c5d41c5ad9a 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -54,6 +54,7 @@ #include "nsCSSAnonBoxes.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" +#include "nsStyleCoord.h" #include "nsImageMap.h" #include "nsILinkHandler.h" #include "nsIURL.h" @@ -164,11 +165,13 @@ NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame) nsImageFrame::nsImageFrame(nsStyleContext* aContext) : ImageFrameSuper(aContext), mComputedSize(0, 0), - mIntrinsicSize(0, 0), + mIntrinsicRatio(0, 0), mDisplayingIcon(PR_FALSE) { // We assume our size is not constrained and we haven't gotten an // initial reflow yet, so don't touch those flags. + mIntrinsicSize.width.SetCoordValue(0); + mIntrinsicSize.height.SetCoordValue(0); } nsImageFrame::~nsImageFrame() @@ -271,24 +274,55 @@ PRBool nsImageFrame::UpdateIntrinsicSize(imgIContainer* aImage) { NS_PRECONDITION(aImage, "null image"); + if (!aImage) + return PR_FALSE; - PRBool intrinsicSizeChanged = PR_FALSE; - - if (aImage) { + nsIFrame::IntrinsicSize oldIntrinsicSize = mIntrinsicSize; + + nsIFrame* rootFrame = aImage->GetRootLayoutFrame(); + if (rootFrame) { + // Set intrinsic size to match that of aImage's rootFrame. + mIntrinsicSize = rootFrame->GetIntrinsicSize(); + } else { + // Set intrinsic size to match aImage's reported width & height. nsIntSize imageSizeInPx; if (NS_FAILED(aImage->GetWidth(&imageSizeInPx.width)) || NS_FAILED(aImage->GetHeight(&imageSizeInPx.height))) { imageSizeInPx.SizeTo(0, 0); } - nsSize newSize(nsPresContext::CSSPixelsToAppUnits(imageSizeInPx.width), - nsPresContext::CSSPixelsToAppUnits(imageSizeInPx.height)); - if (mIntrinsicSize != newSize) { - intrinsicSizeChanged = PR_TRUE; - mIntrinsicSize = newSize; - } + mIntrinsicSize.width.SetCoordValue( + nsPresContext::CSSPixelsToAppUnits(imageSizeInPx.width)); + mIntrinsicSize.height.SetCoordValue( + nsPresContext::CSSPixelsToAppUnits(imageSizeInPx.height)); } - return intrinsicSizeChanged; + return mIntrinsicSize != oldIntrinsicSize; +} + +PRBool +nsImageFrame::UpdateIntrinsicRatio(imgIContainer* aImage) +{ + NS_PRECONDITION(aImage, "null image"); + + if (!aImage) + return PR_FALSE; + + nsSize oldIntrinsicRatio = mIntrinsicRatio; + + nsIFrame* rootFrame = aImage->GetRootLayoutFrame(); + if (rootFrame) { + // Set intrinsic ratio to match that of aImage's rootFrame. + mIntrinsicRatio = rootFrame->GetIntrinsicRatio(); + } else { + NS_ABORT_IF_FALSE(mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord && + mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord, + "since aImage doesn't have a rootFrame, our intrinsic " + "dimensions must have coord units (not percent units)"); + mIntrinsicRatio.width = mIntrinsicSize.width.GetCoordValue(); + mIntrinsicRatio.height = mIntrinsicSize.height.GetCoordValue(); + } + + return mIntrinsicRatio != oldIntrinsicRatio; } void @@ -308,10 +342,16 @@ nsImageFrame::RecalculateTransform(PRBool aInnerAreaChanged) } // Set the scale factors - if (mIntrinsicSize.width != 0 && mIntrinsicSize.height != 0 && - mIntrinsicSize != mComputedSize) { - mTransform.SetScale(float(mComputedSize.width) / float(mIntrinsicSize.width), - float(mComputedSize.height) / float(mIntrinsicSize.height)); + if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord && + mIntrinsicSize.width.GetCoordValue() != 0 && + mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord && + mIntrinsicSize.height.GetCoordValue() != 0 && + mIntrinsicSize.width.GetCoordValue() != mComputedSize.width && + mIntrinsicSize.height.GetCoordValue() != mComputedSize.height) { + mTransform.SetScale(float(mComputedSize.width) / + float(mIntrinsicSize.width.GetCoordValue()), + float(mComputedSize.height) / + float(mIntrinsicSize.height.GetCoordValue())); } else { mTransform.SetScale(1.0f, 1.0f); } @@ -485,9 +525,10 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) } UpdateIntrinsicSize(aImage); + UpdateIntrinsicRatio(aImage); if (mState & IMAGE_GOTINITIALREFLOW) { - // If we previously set the intrinsic size (in EnsureIntrinsicSize) + // If we previously set the intrinsic size (in EnsureIntrinsicSizeAndRatio) // to the size of the loading-image icon and reflowed the frame, // we'll have an mTransform computed from that intrinsic size. But // if we still have that transform when we get OnDataAvailable @@ -578,10 +619,14 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, aRequest->GetImage(getter_AddRefs(imageContainer)); NS_ASSERTION(imageContainer, "Successful load with no container?"); intrinsicSizeChanged = UpdateIntrinsicSize(imageContainer); + intrinsicSizeChanged = UpdateIntrinsicRatio(imageContainer) || + intrinsicSizeChanged; } else { // Have to size to 0,0 so that GetDesiredSize recalculates the size - mIntrinsicSize.SizeTo(0, 0); + mIntrinsicSize.width.SetCoordValue(0); + mIntrinsicSize.height.SetCoordValue(0); + mIntrinsicRatio.SizeTo(0, 0); } if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet @@ -623,11 +668,14 @@ nsImageFrame::FrameChanged(imgIContainer *aContainer, } void -nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext) +nsImageFrame::EnsureIntrinsicSizeAndRatio(nsPresContext* aPresContext) { // if mIntrinsicSize.width and height are 0, then we should // check to see if the size is already known by the image container. - if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0) { + if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord && + mIntrinsicSize.width.GetCoordValue() == 0 && + mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord && + mIntrinsicSize.height.GetCoordValue() == 0) { // Jump through all the hoops to get the status of the request nsCOMPtr currentRequest; @@ -645,6 +693,7 @@ nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext) currentRequest->GetImage(getter_AddRefs(imgCon)); NS_ABORT_IF_FALSE(imgCon, "SIZE_AVAILABLE, but no imgContainer?"); UpdateIntrinsicSize(imgCon); + UpdateIntrinsicRatio(imgCon); } else { // image request is null or image size not known, probably an // invalid image specified @@ -653,8 +702,12 @@ nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext) // XXX: we need this in composer, but it is also good for // XXX: general quirks mode to always have room for the icon if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) { - mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+(2*(ICON_PADDING+ALT_BORDER_WIDTH))), - nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+(2*(ICON_PADDING+ALT_BORDER_WIDTH)))); + nscoord edgeLengthToUse = + nsPresContext::CSSPixelsToAppUnits( + ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH))); + mIntrinsicSize.width.SetCoordValue(edgeLengthToUse); + mIntrinsicSize.height.SetCoordValue(edgeLengthToUse); + mIntrinsicRatio.SizeTo(1, 1); } } } @@ -667,17 +720,11 @@ nsImageFrame::ComputeSize(nsIRenderingContext *aRenderingContext, PRBool aShrinkWrap) { nsPresContext *presContext = PresContext(); - EnsureIntrinsicSize(presContext); - - IntrinsicSize intrinsicSize; - intrinsicSize.width.SetCoordValue(mIntrinsicSize.width); - intrinsicSize.height.SetCoordValue(mIntrinsicSize.height); - - nsSize& intrinsicRatio = mIntrinsicSize; // won't actually be used + EnsureIntrinsicSizeAndRatio(presContext); return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions( aRenderingContext, this, - intrinsicSize, intrinsicRatio, aCBSize, + mIntrinsicSize, mIntrinsicRatio, aCBSize, aMargin, aBorder, aPadding); } @@ -707,9 +754,9 @@ nsImageFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) nscoord result; DISPLAY_MIN_WIDTH(this, result); nsPresContext *presContext = PresContext(); - EnsureIntrinsicSize(presContext); - result = mIntrinsicSize.width; - return result; + EnsureIntrinsicSizeAndRatio(presContext); + return mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord ? + mIntrinsicSize.width.GetCoordValue() : 0; } /* virtual */ nscoord @@ -720,17 +767,16 @@ nsImageFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) nscoord result; DISPLAY_PREF_WIDTH(this, result); nsPresContext *presContext = PresContext(); - EnsureIntrinsicSize(presContext); + EnsureIntrinsicSizeAndRatio(presContext); // convert from normal twips to scaled twips (printing...) - result = mIntrinsicSize.width; - return result; + return mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord ? + mIntrinsicSize.width.GetCoordValue() : 0; } /* virtual */ nsSize nsImageFrame::GetIntrinsicRatio() { - EnsureIntrinsicSize(PresContext()); - return mIntrinsicSize; + return mIntrinsicRatio; } NS_IMETHODIMP @@ -1630,8 +1676,14 @@ nsImageFrame::GetSkipSides() const NS_IMETHODIMP nsImageFrame::GetIntrinsicImageSize(nsSize& aSize) { - aSize = mIntrinsicSize; - return NS_OK; + if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord && + mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord) { + aSize.SizeTo(mIntrinsicSize.width.GetCoordValue(), + mIntrinsicSize.height.GetCoordValue()); + return NS_OK; + } + + return NS_ERROR_FAILURE; } nsresult diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 757340adb9c..ae8e845f978 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -181,7 +181,7 @@ public: protected: virtual ~nsImageFrame(); - void EnsureIntrinsicSize(nsPresContext* aPresContext); + void EnsureIntrinsicSizeAndRatio(nsPresContext* aPresContext); virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext, nsSize aCBSize, nscoord aAvailableWidth, @@ -244,10 +244,18 @@ private: * Recalculate mIntrinsicSize from the image. * * @return whether aImage's size did _not_ - * match our previous intrinsic size + * match our previous intrinsic size. */ PRBool UpdateIntrinsicSize(imgIContainer* aImage); + /** + * Recalculate mIntrinsicRatio from the image. + * + * @return whether aImage's ratio did _not_ + * match our previous intrinsic ratio. + */ + PRBool UpdateIntrinsicRatio(imgIContainer* aImage); + /** * This function will recalculate mTransform. */ @@ -272,7 +280,9 @@ private: nsCOMPtr mListener; nsSize mComputedSize; - nsSize mIntrinsicSize; + nsIFrame::IntrinsicSize mIntrinsicSize; + nsSize mIntrinsicRatio; + nsTransform2D mTransform; PRBool mDisplayingIcon; diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index 89af8440546..d5b6566a2f4 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -554,8 +554,9 @@ nsVideoFrame::GetVideoIntrinsicSize(nsIRenderingContext *aRenderingContext) if (child && child->GetType() == nsGkAtoms::imageFrame) { nsImageFrame* imageFrame = static_cast(child); nsSize imgsize; - imageFrame->GetIntrinsicImageSize(imgsize); - return imgsize; + if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(imgsize))) { + return imgsize; + } } }