diff --git a/content/shared/public/nsLayoutAtomList.h b/content/shared/public/nsLayoutAtomList.h index 261803162aee..38ffba7f214a 100644 --- a/content/shared/public/nsLayoutAtomList.h +++ b/content/shared/public/nsLayoutAtomList.h @@ -107,6 +107,7 @@ LAYOUT_ATOM(hrFrame, "HRFrame") LAYOUT_ATOM(htmlFrameInnerFrame, "htmlFrameInnerFrame") LAYOUT_ATOM(htmlFrameOuterFrame, "htmlFrameOuterFrame") LAYOUT_ATOM(imageFrame, "ImageFrame") +LAYOUT_ATOM(imageControlFrame, "ImageControlFrame") LAYOUT_ATOM(inlineFrame, "InlineFrame") LAYOUT_ATOM(letterFrame, "LetterFrame") LAYOUT_ATOM(lineFrame, "LineFrame") diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index a015d1bb237f..5e7393b66c95 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -10923,6 +10923,12 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsIPresShell* aPresShell, styleContext, nsnull, PR_FALSE); } + } else if (nsLayoutAtoms::imageFrame == frameType) { + rv = NS_NewImageFrame(aPresShell, &newFrame); + if (NS_SUCCEEDED(rv)) { + newFrame->Init(aPresContext, content, aParentFrame, styleContext, aFrame); + } + } else { NS_ASSERTION(PR_FALSE, "unexpected frame type"); rv = NS_ERROR_UNEXPECTED; diff --git a/layout/base/nsLayoutAtomList.h b/layout/base/nsLayoutAtomList.h index 261803162aee..38ffba7f214a 100644 --- a/layout/base/nsLayoutAtomList.h +++ b/layout/base/nsLayoutAtomList.h @@ -107,6 +107,7 @@ LAYOUT_ATOM(hrFrame, "HRFrame") LAYOUT_ATOM(htmlFrameInnerFrame, "htmlFrameInnerFrame") LAYOUT_ATOM(htmlFrameOuterFrame, "htmlFrameOuterFrame") LAYOUT_ATOM(imageFrame, "ImageFrame") +LAYOUT_ATOM(imageControlFrame, "ImageControlFrame") LAYOUT_ATOM(inlineFrame, "InlineFrame") LAYOUT_ATOM(letterFrame, "LetterFrame") LAYOUT_ATOM(lineFrame, "LineFrame") diff --git a/layout/forms/nsImageControlFrame.cpp b/layout/forms/nsImageControlFrame.cpp index bece11bc0c17..cd60491b0567 100644 --- a/layout/forms/nsImageControlFrame.cpp +++ b/layout/forms/nsImageControlFrame.cpp @@ -60,6 +60,7 @@ #include "nsFormFrame.h" #include "nsFormControlFrame.h" #include "nsGUIEvent.h" +#include "nsLayoutAtoms.h" #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif @@ -101,6 +102,8 @@ public: nsGUIEvent* aEvent, nsEventStatus* aEventStatus); + NS_IMETHOD GetFrameType(nsIAtom** aType) const; + #ifdef ACCESSIBILITY NS_IMETHOD GetAccessible(nsIAccessible** aAccessible); #endif @@ -252,6 +255,15 @@ nsrefcnt nsImageControlFrame::Release(void) return 1; } +NS_IMETHODIMP +nsImageControlFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::imageControlFrame; + NS_ADDREF(*aType); + return NS_OK; +} + NS_IMETHODIMP nsImageControlFrame::Init(nsIPresContext* aPresContext, nsIContent* aContent, diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 7e7c0806c12a..6b63a9e6df02 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -2079,9 +2079,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If we're supposed to update our maximum width, then we'll also need to // reflow this line if it's line wrapped and any of the continuing lines - // are dirty - if (!line->IsDirty() && - (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && + // are dirty. If we are printing (constrained height), always reflow the line + if ((NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight) || + (!line->IsDirty() && + aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line, line_end))) { line->MarkDirty(); } diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index c9c1350a73c3..6aae55d900ab 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -236,7 +236,7 @@ nsImageFrame::Destroy(nsIPresContext* aPresContext) mListener = nsnull; - return nsLeafFrame::Destroy(aPresContext); + return nsSplittableFrame::Destroy(aPresContext); } @@ -248,9 +248,8 @@ nsImageFrame::Init(nsIPresContext* aPresContext, nsIStyleContext* aContext, nsIFrame* aPrevInFlow) { - nsresult rv = nsLeafFrame::Init(aPresContext, aContent, aParent, - aContext, aPrevInFlow); - + nsresult rv = nsSplittableFrame::Init(aPresContext, aContent, aParent, + aContext, aPrevInFlow); // See if we have a SRC attribute nsAutoString src; nsresult ca; @@ -761,8 +760,43 @@ nsImageFrame::GetInnerArea(nsIPresContext* aPresContext, aInnerArea.y = mBorderPadding.top; aInnerArea.width = mRect.width - (mBorderPadding.left + mBorderPadding.right); - aInnerArea.height = mRect.height - - (mBorderPadding.top + mBorderPadding.bottom); + aInnerArea.height = (!mPrevInFlow && !mNextInFlow) + ? mRect.height - mBorderPadding.top - mBorderPadding.bottom : mComputedSize.height; +} + +NS_IMETHODIMP +nsImageFrame::ContentChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsISupports* aSubContent) +{ + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + mState |= NS_FRAME_IS_DIRTY; + return mParent->ReflowDirtyChild(shell, this); +} + +// get the offset into the content area of the image where aImg starts if it is a continuation. +nscoord +nsImageFrame::GetContinuationOffset(nscoord* aWidth) const +{ + nscoord offset = 0; + if (aWidth) { + *aWidth = 0; + } + + if (mPrevInFlow) { + for (nsIFrame* prevInFlow = mPrevInFlow ; prevInFlow; prevInFlow->GetPrevInFlow(&prevInFlow)) { + nsRect rect; + prevInFlow->GetRect(rect); + if (aWidth) { + *aWidth = rect.width; + } + offset += rect.height; + } + offset -= mBorderPadding.top; + offset = PR_MAX(0, offset); + } + return offset; } NS_IMETHODIMP @@ -779,14 +813,41 @@ nsImageFrame::Reflow(nsIPresContext* aPresContext, NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); + aStatus = NS_FRAME_COMPLETE; + // see if we have a frozen size (i.e. a fixed width and height) HaveFixedSize(aReflowState, mSizeConstrained); if (aReflowState.reason == eReflowReason_Initial) mGotInitialReflow = PR_TRUE; + // get the desired size of the complete image GetDesiredSize(aPresContext, aReflowState, aMetrics); - AddBordersAndPadding(aPresContext, aReflowState, aMetrics, mBorderPadding); + + // add borders and padding + mBorderPadding = aReflowState.mComputedBorderPadding; + aMetrics.width += mBorderPadding.left + mBorderPadding.right; + aMetrics.height += mBorderPadding.top + mBorderPadding.bottom; + + if (mPrevInFlow) { + nscoord y = GetContinuationOffset(&aMetrics.width); + aMetrics.height -= y + mBorderPadding.top; + aMetrics.height = PR_MAX(0, aMetrics.height); + } + + if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) && + (aMetrics.height > aReflowState.availableHeight)) { + nsCOMPtr fType; + GetFrameType(getter_AddRefs(fType)); + // split an image frame but not an image control frame + if (nsLayoutAtoms::imageFrame == fType.get()) { + aMetrics.height = aReflowState.availableHeight; + aStatus = NS_FRAME_NOT_COMPLETE; + } + } + aMetrics.ascent = aMetrics.height; + aMetrics.descent = 0; + if (nsnull != aMetrics.maxElementSize) { // If we have a percentage based width, then our MES width is 0 if (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit()) { @@ -799,7 +860,6 @@ nsImageFrame::Reflow(nsIPresContext* aPresContext, if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { aMetrics.mMaximumWidth = aMetrics.width; } - aStatus = NS_FRAME_COMPLETE; NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsImageFrame::Reflow: size=%d,%d", @@ -1038,8 +1098,27 @@ nsImageFrame::Paint(nsIPresContext* aPresContext, // First paint background and borders - nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, - aWhichLayer); + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { + const nsStyleVisibility* vis = + (const nsStyleVisibility*)mStyleContext->GetStyleData(eStyleStruct_Visibility); + if (vis->IsVisibleOrCollapsed()) { + const nsStyleBackground* myColor = (const nsStyleBackground*) + mStyleContext->GetStyleData(eStyleStruct_Background); + const nsStyleBorder* myBorder = (const nsStyleBorder*) + mStyleContext->GetStyleData(eStyleStruct_Border); + const nsStyleOutline* myOutline = (const nsStyleOutline*) + mStyleContext->GetStyleData(eStyleStruct_Outline); + nsRect rect(0, 0, mRect.width, mRect.height); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myColor, *myBorder, 0, 0); + + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myBorder, mStyleContext, 0); + + nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myBorder, *myOutline, mStyleContext, 0); + } + } nsCOMPtr imgCon; @@ -1078,23 +1157,51 @@ nsImageFrame::Paint(nsIPresContext* aPresContext, } if (imgCon) { - nsPoint p(inner.x, inner.y); + nscoord offsetY = 0; + nsSize size(inner.width, inner.height); + // if the image is split account for y-offset, border, padding + if (mPrevInFlow || mNextInFlow) { + if (mPrevInFlow) { + offsetY = GetContinuationOffset(); + } + size.height = mRect.height; + if (!mPrevInFlow) { + size.height -= mBorderPadding.top; + } + if (!mNextInFlow) { + size.height -= mBorderPadding.bottom; + } + } + if (mLoads[0].mIntrinsicSize == mComputedSize) { + nsPoint p(inner.x, inner.y); inner.IntersectRect(inner, aDirtyRect); nsRect r(inner.x, inner.y, inner.width, inner.height); r.x -= mBorderPadding.left; r.y -= mBorderPadding.top; + if (mPrevInFlow) { + r.y = offsetY; + p.y = 0; + } aRenderingContext.DrawImage(imgCon, &r, &p); } else { nsTransform2D trans; trans.SetToScale((float(mLoads[0].mIntrinsicSize.width) / float(inner.width)), (float(mLoads[0].mIntrinsicSize.height) / float(inner.height))); - nsRect r(0, 0, inner.width, inner.height); + nsRect r(0, offsetY, size.width, size.height); trans.TransformCoord(&r.x, &r.y, &r.width, &r.height); nsRect d(inner.x, inner.y, mComputedSize.width, mComputedSize.height); + // if the image is split account for y-offset, border, padding + if (mPrevInFlow || mNextInFlow) { + if (mPrevInFlow) { + d.y -= mBorderPadding.top; + } + d.height = size.height; + } + aRenderingContext.DrawScaledImage(imgCon, &r, &d); } } @@ -1421,7 +1528,7 @@ nsImageFrame::HandleEvent(nsIPresContext* aPresContext, break; } - return nsLeafFrame::HandleEvent(aPresContext, aEvent, aEventStatus); + return nsSplittableFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } //XXX This will need to be rewritten once we have content for areas @@ -1458,8 +1565,8 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext, PRInt32 aModType, PRInt32 aHint) { - nsresult rv = nsLeafFrame::AttributeChanged(aPresContext, aChild, - aNameSpaceID, aAttribute, aModType, aHint); + nsresult rv = nsSplittableFrame::AttributeChanged(aPresContext, aChild, + aNameSpaceID, aAttribute, aModType, aHint); if (NS_OK != rv) { return rv; } diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 6a59a4cfb763..3758972cd734 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -37,7 +37,7 @@ #ifndef nsImageFrame_h___ #define nsImageFrame_h___ -#include "nsLeafFrame.h" +#include "nsSplittableFrame.h" #include "nsString.h" #include "nsAReadableString.h" #include "nsIPresContext.h" @@ -83,7 +83,7 @@ struct ImageLoad { nsTransform2D mTransform; }; -#define ImageFrameSuper nsLeafFrame +#define ImageFrameSuper nsSplittableFrame class nsImageFrame : public ImageFrameSuper, public nsIImageFrame { public: @@ -108,6 +108,10 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); + NS_IMETHOD ContentChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsISupports* aSubContent); + NS_IMETHOD CanContinueTextRun(PRBool& aContinueTextRun) const; @@ -220,7 +224,7 @@ private: nsresult LoadImage(const nsAReadableString& aSpec, nsIPresContext *aPresContext, imgIRequest *aRequest); nsresult RealLoadImage(const nsAReadableString& aSpec, nsIPresContext *aPresContext, imgIRequest *aRequest); inline int GetImageLoad(imgIRequest *aRequest); - + nscoord GetContinuationOffset(nscoord* aWidth = 0) const; nsImageMap* mImageMap; diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index 7e7c0806c12a..6b63a9e6df02 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -2079,9 +2079,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If we're supposed to update our maximum width, then we'll also need to // reflow this line if it's line wrapped and any of the continuing lines - // are dirty - if (!line->IsDirty() && - (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && + // are dirty. If we are printing (constrained height), always reflow the line + if ((NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight) || + (!line->IsDirty() && + aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line, line_end))) { line->MarkDirty(); } diff --git a/layout/html/base/src/nsImageFrame.cpp b/layout/html/base/src/nsImageFrame.cpp index c9c1350a73c3..6aae55d900ab 100644 --- a/layout/html/base/src/nsImageFrame.cpp +++ b/layout/html/base/src/nsImageFrame.cpp @@ -236,7 +236,7 @@ nsImageFrame::Destroy(nsIPresContext* aPresContext) mListener = nsnull; - return nsLeafFrame::Destroy(aPresContext); + return nsSplittableFrame::Destroy(aPresContext); } @@ -248,9 +248,8 @@ nsImageFrame::Init(nsIPresContext* aPresContext, nsIStyleContext* aContext, nsIFrame* aPrevInFlow) { - nsresult rv = nsLeafFrame::Init(aPresContext, aContent, aParent, - aContext, aPrevInFlow); - + nsresult rv = nsSplittableFrame::Init(aPresContext, aContent, aParent, + aContext, aPrevInFlow); // See if we have a SRC attribute nsAutoString src; nsresult ca; @@ -761,8 +760,43 @@ nsImageFrame::GetInnerArea(nsIPresContext* aPresContext, aInnerArea.y = mBorderPadding.top; aInnerArea.width = mRect.width - (mBorderPadding.left + mBorderPadding.right); - aInnerArea.height = mRect.height - - (mBorderPadding.top + mBorderPadding.bottom); + aInnerArea.height = (!mPrevInFlow && !mNextInFlow) + ? mRect.height - mBorderPadding.top - mBorderPadding.bottom : mComputedSize.height; +} + +NS_IMETHODIMP +nsImageFrame::ContentChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsISupports* aSubContent) +{ + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + mState |= NS_FRAME_IS_DIRTY; + return mParent->ReflowDirtyChild(shell, this); +} + +// get the offset into the content area of the image where aImg starts if it is a continuation. +nscoord +nsImageFrame::GetContinuationOffset(nscoord* aWidth) const +{ + nscoord offset = 0; + if (aWidth) { + *aWidth = 0; + } + + if (mPrevInFlow) { + for (nsIFrame* prevInFlow = mPrevInFlow ; prevInFlow; prevInFlow->GetPrevInFlow(&prevInFlow)) { + nsRect rect; + prevInFlow->GetRect(rect); + if (aWidth) { + *aWidth = rect.width; + } + offset += rect.height; + } + offset -= mBorderPadding.top; + offset = PR_MAX(0, offset); + } + return offset; } NS_IMETHODIMP @@ -779,14 +813,41 @@ nsImageFrame::Reflow(nsIPresContext* aPresContext, NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); + aStatus = NS_FRAME_COMPLETE; + // see if we have a frozen size (i.e. a fixed width and height) HaveFixedSize(aReflowState, mSizeConstrained); if (aReflowState.reason == eReflowReason_Initial) mGotInitialReflow = PR_TRUE; + // get the desired size of the complete image GetDesiredSize(aPresContext, aReflowState, aMetrics); - AddBordersAndPadding(aPresContext, aReflowState, aMetrics, mBorderPadding); + + // add borders and padding + mBorderPadding = aReflowState.mComputedBorderPadding; + aMetrics.width += mBorderPadding.left + mBorderPadding.right; + aMetrics.height += mBorderPadding.top + mBorderPadding.bottom; + + if (mPrevInFlow) { + nscoord y = GetContinuationOffset(&aMetrics.width); + aMetrics.height -= y + mBorderPadding.top; + aMetrics.height = PR_MAX(0, aMetrics.height); + } + + if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) && + (aMetrics.height > aReflowState.availableHeight)) { + nsCOMPtr fType; + GetFrameType(getter_AddRefs(fType)); + // split an image frame but not an image control frame + if (nsLayoutAtoms::imageFrame == fType.get()) { + aMetrics.height = aReflowState.availableHeight; + aStatus = NS_FRAME_NOT_COMPLETE; + } + } + aMetrics.ascent = aMetrics.height; + aMetrics.descent = 0; + if (nsnull != aMetrics.maxElementSize) { // If we have a percentage based width, then our MES width is 0 if (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit()) { @@ -799,7 +860,6 @@ nsImageFrame::Reflow(nsIPresContext* aPresContext, if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { aMetrics.mMaximumWidth = aMetrics.width; } - aStatus = NS_FRAME_COMPLETE; NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsImageFrame::Reflow: size=%d,%d", @@ -1038,8 +1098,27 @@ nsImageFrame::Paint(nsIPresContext* aPresContext, // First paint background and borders - nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, - aWhichLayer); + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { + const nsStyleVisibility* vis = + (const nsStyleVisibility*)mStyleContext->GetStyleData(eStyleStruct_Visibility); + if (vis->IsVisibleOrCollapsed()) { + const nsStyleBackground* myColor = (const nsStyleBackground*) + mStyleContext->GetStyleData(eStyleStruct_Background); + const nsStyleBorder* myBorder = (const nsStyleBorder*) + mStyleContext->GetStyleData(eStyleStruct_Border); + const nsStyleOutline* myOutline = (const nsStyleOutline*) + mStyleContext->GetStyleData(eStyleStruct_Outline); + nsRect rect(0, 0, mRect.width, mRect.height); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myColor, *myBorder, 0, 0); + + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myBorder, mStyleContext, 0); + + nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myBorder, *myOutline, mStyleContext, 0); + } + } nsCOMPtr imgCon; @@ -1078,23 +1157,51 @@ nsImageFrame::Paint(nsIPresContext* aPresContext, } if (imgCon) { - nsPoint p(inner.x, inner.y); + nscoord offsetY = 0; + nsSize size(inner.width, inner.height); + // if the image is split account for y-offset, border, padding + if (mPrevInFlow || mNextInFlow) { + if (mPrevInFlow) { + offsetY = GetContinuationOffset(); + } + size.height = mRect.height; + if (!mPrevInFlow) { + size.height -= mBorderPadding.top; + } + if (!mNextInFlow) { + size.height -= mBorderPadding.bottom; + } + } + if (mLoads[0].mIntrinsicSize == mComputedSize) { + nsPoint p(inner.x, inner.y); inner.IntersectRect(inner, aDirtyRect); nsRect r(inner.x, inner.y, inner.width, inner.height); r.x -= mBorderPadding.left; r.y -= mBorderPadding.top; + if (mPrevInFlow) { + r.y = offsetY; + p.y = 0; + } aRenderingContext.DrawImage(imgCon, &r, &p); } else { nsTransform2D trans; trans.SetToScale((float(mLoads[0].mIntrinsicSize.width) / float(inner.width)), (float(mLoads[0].mIntrinsicSize.height) / float(inner.height))); - nsRect r(0, 0, inner.width, inner.height); + nsRect r(0, offsetY, size.width, size.height); trans.TransformCoord(&r.x, &r.y, &r.width, &r.height); nsRect d(inner.x, inner.y, mComputedSize.width, mComputedSize.height); + // if the image is split account for y-offset, border, padding + if (mPrevInFlow || mNextInFlow) { + if (mPrevInFlow) { + d.y -= mBorderPadding.top; + } + d.height = size.height; + } + aRenderingContext.DrawScaledImage(imgCon, &r, &d); } } @@ -1421,7 +1528,7 @@ nsImageFrame::HandleEvent(nsIPresContext* aPresContext, break; } - return nsLeafFrame::HandleEvent(aPresContext, aEvent, aEventStatus); + return nsSplittableFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } //XXX This will need to be rewritten once we have content for areas @@ -1458,8 +1565,8 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext, PRInt32 aModType, PRInt32 aHint) { - nsresult rv = nsLeafFrame::AttributeChanged(aPresContext, aChild, - aNameSpaceID, aAttribute, aModType, aHint); + nsresult rv = nsSplittableFrame::AttributeChanged(aPresContext, aChild, + aNameSpaceID, aAttribute, aModType, aHint); if (NS_OK != rv) { return rv; } diff --git a/layout/html/base/src/nsImageFrame.h b/layout/html/base/src/nsImageFrame.h index 6a59a4cfb763..3758972cd734 100644 --- a/layout/html/base/src/nsImageFrame.h +++ b/layout/html/base/src/nsImageFrame.h @@ -37,7 +37,7 @@ #ifndef nsImageFrame_h___ #define nsImageFrame_h___ -#include "nsLeafFrame.h" +#include "nsSplittableFrame.h" #include "nsString.h" #include "nsAReadableString.h" #include "nsIPresContext.h" @@ -83,7 +83,7 @@ struct ImageLoad { nsTransform2D mTransform; }; -#define ImageFrameSuper nsLeafFrame +#define ImageFrameSuper nsSplittableFrame class nsImageFrame : public ImageFrameSuper, public nsIImageFrame { public: @@ -108,6 +108,10 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); + NS_IMETHOD ContentChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsISupports* aSubContent); + NS_IMETHOD CanContinueTextRun(PRBool& aContinueTextRun) const; @@ -220,7 +224,7 @@ private: nsresult LoadImage(const nsAReadableString& aSpec, nsIPresContext *aPresContext, imgIRequest *aRequest); nsresult RealLoadImage(const nsAReadableString& aSpec, nsIPresContext *aPresContext, imgIRequest *aRequest); inline int GetImageLoad(imgIRequest *aRequest); - + nscoord GetContinuationOffset(nscoord* aWidth = 0) const; nsImageMap* mImageMap; diff --git a/layout/html/forms/src/nsImageControlFrame.cpp b/layout/html/forms/src/nsImageControlFrame.cpp index bece11bc0c17..cd60491b0567 100644 --- a/layout/html/forms/src/nsImageControlFrame.cpp +++ b/layout/html/forms/src/nsImageControlFrame.cpp @@ -60,6 +60,7 @@ #include "nsFormFrame.h" #include "nsFormControlFrame.h" #include "nsGUIEvent.h" +#include "nsLayoutAtoms.h" #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif @@ -101,6 +102,8 @@ public: nsGUIEvent* aEvent, nsEventStatus* aEventStatus); + NS_IMETHOD GetFrameType(nsIAtom** aType) const; + #ifdef ACCESSIBILITY NS_IMETHOD GetAccessible(nsIAccessible** aAccessible); #endif @@ -252,6 +255,15 @@ nsrefcnt nsImageControlFrame::Release(void) return 1; } +NS_IMETHODIMP +nsImageControlFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::imageControlFrame; + NS_ADDREF(*aType); + return NS_OK; +} + NS_IMETHODIMP nsImageControlFrame::Init(nsIPresContext* aPresContext, nsIContent* aContent, diff --git a/layout/html/style/src/nsCSSFrameConstructor.cpp b/layout/html/style/src/nsCSSFrameConstructor.cpp index a015d1bb237f..5e7393b66c95 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -10923,6 +10923,12 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsIPresShell* aPresShell, styleContext, nsnull, PR_FALSE); } + } else if (nsLayoutAtoms::imageFrame == frameType) { + rv = NS_NewImageFrame(aPresShell, &newFrame); + if (NS_SUCCEEDED(rv)) { + newFrame->Init(aPresContext, content, aParentFrame, styleContext, aFrame); + } + } else { NS_ASSERTION(PR_FALSE, "unexpected frame type"); rv = NS_ERROR_UNEXPECTED; diff --git a/layout/html/table/src/nsTableCellFrame.cpp b/layout/html/table/src/nsTableCellFrame.cpp index 791132c0d659..1eec30abe4bb 100644 --- a/layout/html/table/src/nsTableCellFrame.cpp +++ b/layout/html/table/src/nsTableCellFrame.cpp @@ -684,6 +684,15 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); #endif + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + + // work around pixel rounding errors, round down to ensure we don't exceed the avail height in + nscoord availHeight = aReflowState.availableHeight; + if (NS_UNCONSTRAINEDSIZE != availHeight) { + availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown); + } + nsresult rv = NS_OK; // this should probably be cached somewhere nsCompatibility compatMode; @@ -696,7 +705,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } aStatus = NS_FRAME_COMPLETE; - nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight); + nsSize availSize(aReflowState.availableWidth, availHeight); nsSize maxElementSize; nsSize* pMaxElementSize = aDesiredSize.maxElementSize; if (NS_UNCONSTRAINEDSIZE==aReflowState.availableWidth) @@ -825,8 +834,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)pos)); // calculate the min cell width - float p2t; - aPresContext->GetScaledPixelsToTwips(&p2t); nscoord onePixel = NSIntPixelsToTwips(1, p2t); nscoord smallestMinWidth = 0; if (eCompatibility_NavQuirks == compatMode) { @@ -884,8 +891,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, if (NS_UNCONSTRAINEDSIZE != cellHeight) { cellHeight += topInset + bottomInset; + // work around block rounding errors, round down to ensure we don't exceed the avail height in + nsPixelRound roundMethod = (NS_UNCONSTRAINEDSIZE == availHeight) ? eAlwaysRoundUp : eAlwaysRoundDown; + cellHeight = nsTableFrame::RoundToPixel(cellHeight, p2t, roundMethod); } - cellHeight = nsTableFrame::RoundToPixel(cellHeight, p2t); // work around block rounding errors // if the table allocated extra vertical space to row groups, rows, cells in pagination mode // then use that height as the desired height unless the cell needs to split. diff --git a/layout/html/table/src/nsTableFrame.cpp b/layout/html/table/src/nsTableFrame.cpp index 785a22d985b7..610534819295 100644 --- a/layout/html/table/src/nsTableFrame.cpp +++ b/layout/html/table/src/nsTableFrame.cpp @@ -353,9 +353,9 @@ nsTableFrame::InterruptNotification(nsIPresContext* aPresContext, } nscoord -nsTableFrame::RoundToPixel(nscoord aValue, - float aPixelToTwips, - PRBool aRoundUp) +nsTableFrame::RoundToPixel(nscoord aValue, + float aPixelToTwips, + nsPixelRound aRound) { nscoord halfPixel = NSToCoordRound(aPixelToTwips / 2.0f); nscoord fullPixel = NSToCoordRound(aPixelToTwips); @@ -364,11 +364,15 @@ nsTableFrame::RoundToPixel(nscoord aValue, return aValue; } else { - if ((excess > halfPixel) || aRoundUp) { - return aValue + (fullPixel - excess); - } - else { + switch(aRound) { + case eRoundUpIfHalfOrMore: + if (excess >= halfPixel) { // eRoundUpIfHalfOrMore + return aValue + (fullPixel - excess); + } + case eAlwaysRoundDown: return aValue - excess; + default: // eAlwaysRoundUp + return aValue + (fullPixel - excess); } } } @@ -3301,7 +3305,7 @@ nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, nsRect rowRect; rowFrame->GetRect(rowRect); float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights; - nscoord excessForRow = RoundToPixel(NSToCoordRound((float)aExcess * percent), p2t, PR_TRUE); + nscoord excessForRow = RoundToPixel(NSToCoordRound((float)aExcess * percent), p2t); excessForRow = PR_MIN(excessForRow, aExcess - aExcessAllocated); nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height); diff --git a/layout/html/table/src/nsTableFrame.h b/layout/html/table/src/nsTableFrame.h index c3d63cacc3e7..7b462dc77ce8 100644 --- a/layout/html/table/src/nsTableFrame.h +++ b/layout/html/table/src/nsTableFrame.h @@ -60,6 +60,8 @@ class nsHTMLValue; struct nsTableReflowState; struct nsStylePosition; +enum nsPixelRound {eAlwaysRoundUp=0, eAlwaysRoundDown, eRoundUpIfHalfOrMore}; + #ifdef DEBUG_TABLE_REFLOW_TIMING #ifdef WIN32 #include @@ -201,9 +203,9 @@ public: nsIFrame* aPrevInFlow); - static nscoord RoundToPixel(nscoord aValue, - float aPixelToTwips, - PRBool aRoundUp = PR_FALSE); + static nscoord RoundToPixel(nscoord aValue, + float aPixelToTwips, + nsPixelRound aRound= eAlwaysRoundUp); NS_IMETHOD IsPercentageBase(PRBool& aBase) const; diff --git a/layout/html/table/src/nsTableOuterFrame.cpp b/layout/html/table/src/nsTableOuterFrame.cpp index 5f01b36c5c80..982973d298d2 100644 --- a/layout/html/table/src/nsTableOuterFrame.cpp +++ b/layout/html/table/src/nsTableOuterFrame.cpp @@ -1469,6 +1469,15 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS); #endif + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + + // work around pixel rounding errors, round down to ensure we don't exceed the avail height in + nscoord availHeight = aOuterRS.availableHeight; + if (NS_UNCONSTRAINEDSIZE != availHeight) { + availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown); + } + nsresult rv = NS_OK; PRUint8 captionSide = GetCaptionSide(); diff --git a/layout/html/table/src/nsTableRowGroupFrame.cpp b/layout/html/table/src/nsTableRowGroupFrame.cpp index 19ed469dd5f3..f863ef3047ae 100644 --- a/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -918,6 +918,31 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, return tallestCell; } +nsIFrame* GetNextRow(nsIFrame& aFrame) +{ + nsIFrame* rowFrame; + for (aFrame.GetNextSibling(&rowFrame); rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + nsCOMPtr fType; + rowFrame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableRowFrame == fType.get()) { + return rowFrame; + } + } + return nsnull; +} + +nsIFrame* GetFirstRow(nsTableRowGroupFrame& aRowGroupFrame) +{ + for (nsIFrame* rowFrame = aRowGroupFrame.GetFirstFrame(); rowFrame; rowFrame = GetNextRow(*rowFrame)) { + nsCOMPtr fType; + rowFrame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableRowFrame == fType.get()) { + return rowFrame; + } + } + return nsnull; +} + nsresult nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -946,7 +971,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, // Walk each of the row frames looking for the first row frame that // doesn't fit in the available space - for (nsIFrame* rowFrame = GetFirstFrame(); rowFrame; GetNextFrame(rowFrame, &rowFrame)) { + for (nsIFrame* rowFrame = GetFirstRow(*this); rowFrame; rowFrame = GetNextRow(*rowFrame)) { PRBool rowIsOnCurrentPage = PR_TRUE; PRBool degenerateRow = PR_FALSE; nsRect bounds; @@ -975,7 +1000,10 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // the row frame is incomplete and all of the cells' block frames have split CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); - aDesiredSize.height += aTableFrame->GetCellSpacingY() + desiredSize.height; + aDesiredSize.height += desiredSize.height; + if (prevRowFrame) { + aDesiredSize.height += aTableFrame->GetCellSpacingY(); + } } else if (0 == desiredSize.height) { // the row frame is complete because it had no cells originating in it. diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 791132c0d659..1eec30abe4bb 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -684,6 +684,15 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); #endif + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + + // work around pixel rounding errors, round down to ensure we don't exceed the avail height in + nscoord availHeight = aReflowState.availableHeight; + if (NS_UNCONSTRAINEDSIZE != availHeight) { + availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown); + } + nsresult rv = NS_OK; // this should probably be cached somewhere nsCompatibility compatMode; @@ -696,7 +705,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } aStatus = NS_FRAME_COMPLETE; - nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight); + nsSize availSize(aReflowState.availableWidth, availHeight); nsSize maxElementSize; nsSize* pMaxElementSize = aDesiredSize.maxElementSize; if (NS_UNCONSTRAINEDSIZE==aReflowState.availableWidth) @@ -825,8 +834,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)pos)); // calculate the min cell width - float p2t; - aPresContext->GetScaledPixelsToTwips(&p2t); nscoord onePixel = NSIntPixelsToTwips(1, p2t); nscoord smallestMinWidth = 0; if (eCompatibility_NavQuirks == compatMode) { @@ -884,8 +891,10 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, if (NS_UNCONSTRAINEDSIZE != cellHeight) { cellHeight += topInset + bottomInset; + // work around block rounding errors, round down to ensure we don't exceed the avail height in + nsPixelRound roundMethod = (NS_UNCONSTRAINEDSIZE == availHeight) ? eAlwaysRoundUp : eAlwaysRoundDown; + cellHeight = nsTableFrame::RoundToPixel(cellHeight, p2t, roundMethod); } - cellHeight = nsTableFrame::RoundToPixel(cellHeight, p2t); // work around block rounding errors // if the table allocated extra vertical space to row groups, rows, cells in pagination mode // then use that height as the desired height unless the cell needs to split. diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 785a22d985b7..610534819295 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -353,9 +353,9 @@ nsTableFrame::InterruptNotification(nsIPresContext* aPresContext, } nscoord -nsTableFrame::RoundToPixel(nscoord aValue, - float aPixelToTwips, - PRBool aRoundUp) +nsTableFrame::RoundToPixel(nscoord aValue, + float aPixelToTwips, + nsPixelRound aRound) { nscoord halfPixel = NSToCoordRound(aPixelToTwips / 2.0f); nscoord fullPixel = NSToCoordRound(aPixelToTwips); @@ -364,11 +364,15 @@ nsTableFrame::RoundToPixel(nscoord aValue, return aValue; } else { - if ((excess > halfPixel) || aRoundUp) { - return aValue + (fullPixel - excess); - } - else { + switch(aRound) { + case eRoundUpIfHalfOrMore: + if (excess >= halfPixel) { // eRoundUpIfHalfOrMore + return aValue + (fullPixel - excess); + } + case eAlwaysRoundDown: return aValue - excess; + default: // eAlwaysRoundUp + return aValue + (fullPixel - excess); } } } @@ -3301,7 +3305,7 @@ nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, nsRect rowRect; rowFrame->GetRect(rowRect); float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights; - nscoord excessForRow = RoundToPixel(NSToCoordRound((float)aExcess * percent), p2t, PR_TRUE); + nscoord excessForRow = RoundToPixel(NSToCoordRound((float)aExcess * percent), p2t); excessForRow = PR_MIN(excessForRow, aExcess - aExcessAllocated); nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height); diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index c3d63cacc3e7..7b462dc77ce8 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -60,6 +60,8 @@ class nsHTMLValue; struct nsTableReflowState; struct nsStylePosition; +enum nsPixelRound {eAlwaysRoundUp=0, eAlwaysRoundDown, eRoundUpIfHalfOrMore}; + #ifdef DEBUG_TABLE_REFLOW_TIMING #ifdef WIN32 #include @@ -201,9 +203,9 @@ public: nsIFrame* aPrevInFlow); - static nscoord RoundToPixel(nscoord aValue, - float aPixelToTwips, - PRBool aRoundUp = PR_FALSE); + static nscoord RoundToPixel(nscoord aValue, + float aPixelToTwips, + nsPixelRound aRound= eAlwaysRoundUp); NS_IMETHOD IsPercentageBase(PRBool& aBase) const; diff --git a/layout/tables/nsTableOuterFrame.cpp b/layout/tables/nsTableOuterFrame.cpp index 5f01b36c5c80..982973d298d2 100644 --- a/layout/tables/nsTableOuterFrame.cpp +++ b/layout/tables/nsTableOuterFrame.cpp @@ -1469,6 +1469,15 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aOuterRS); #endif + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + + // work around pixel rounding errors, round down to ensure we don't exceed the avail height in + nscoord availHeight = aOuterRS.availableHeight; + if (NS_UNCONSTRAINEDSIZE != availHeight) { + availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown); + } + nsresult rv = NS_OK; PRUint8 captionSide = GetCaptionSide(); diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 19ed469dd5f3..f863ef3047ae 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -918,6 +918,31 @@ nsTableRowGroupFrame::SplitSpanningCells(nsIPresContext& aPresContext, return tallestCell; } +nsIFrame* GetNextRow(nsIFrame& aFrame) +{ + nsIFrame* rowFrame; + for (aFrame.GetNextSibling(&rowFrame); rowFrame; rowFrame->GetNextSibling(&rowFrame)) { + nsCOMPtr fType; + rowFrame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableRowFrame == fType.get()) { + return rowFrame; + } + } + return nsnull; +} + +nsIFrame* GetFirstRow(nsTableRowGroupFrame& aRowGroupFrame) +{ + for (nsIFrame* rowFrame = aRowGroupFrame.GetFirstFrame(); rowFrame; rowFrame = GetNextRow(*rowFrame)) { + nsCOMPtr fType; + rowFrame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableRowFrame == fType.get()) { + return rowFrame; + } + } + return nsnull; +} + nsresult nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -946,7 +971,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, // Walk each of the row frames looking for the first row frame that // doesn't fit in the available space - for (nsIFrame* rowFrame = GetFirstFrame(); rowFrame; GetNextFrame(rowFrame, &rowFrame)) { + for (nsIFrame* rowFrame = GetFirstRow(*this); rowFrame; rowFrame = GetNextRow(*rowFrame)) { PRBool rowIsOnCurrentPage = PR_TRUE; PRBool degenerateRow = PR_FALSE; nsRect bounds; @@ -975,7 +1000,10 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext, if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // the row frame is incomplete and all of the cells' block frames have split CreateContinuingRowFrame(*aPresContext, *styleSet.get(), *rowFrame, &contRowFrame); - aDesiredSize.height += aTableFrame->GetCellSpacingY() + desiredSize.height; + aDesiredSize.height += desiredSize.height; + if (prevRowFrame) { + aDesiredSize.height += aTableFrame->GetCellSpacingY(); + } } else if (0 == desiredSize.height) { // the row frame is complete because it had no cells originating in it.