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
git-svn-id: svn://10.0.0.236/trunk@222053 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user