diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 3d04a7c8cad3..b53a64df932a 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -157,7 +157,8 @@ InitDebugFlags() #undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested #undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" #undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef REALLY_NOISY_REFLOW // some extra debug info #endif @@ -781,7 +782,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, const nsMargin& borderPadding = BorderPadding(); - if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) { + if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) + { if (mBand.GetFloaterCount()) { // Use the float-edge property to determine how the child block // will interact with the floater. @@ -2006,15 +2008,6 @@ HaveAutoWidth(const nsHTMLReflowState& aReflowState) } -static PRBool -IsPercentageUnitSides(const nsStyleSides* aSides) -{ - return eStyleUnit_Percent == aSides->GetLeftUnit() - || eStyleUnit_Percent == aSides->GetRightUnit() - || eStyleUnit_Percent == aSides->GetTopUnit() - || eStyleUnit_Percent == aSides->GetBottomUnit(); -} - static PRBool IsPercentageAwareChild(const nsIFrame* aFrame) { @@ -2024,9 +2017,9 @@ IsPercentageAwareChild(const nsIFrame* aFrame) return PR_TRUE; // just to be on the safe side } - if (IsPercentageUnitSides(&space->mMargin) - || IsPercentageUnitSides(&space->mPadding) - || IsPercentageUnitSides(&space->mBorderRadius)) { + if (nsLineLayout::IsPercentageUnitSides(&space->mMargin) + || nsLineLayout::IsPercentageUnitSides(&space->mPadding) + || nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) { return PR_TRUE; } @@ -2042,7 +2035,7 @@ IsPercentageAwareChild(const nsIFrame* aFrame) || eStyleUnit_Percent == pos->mHeight.GetUnit() || eStyleUnit_Percent == pos->mMinHeight.GetUnit() || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() - || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! return PR_TRUE; } @@ -2600,6 +2593,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // newlines. Therefore, we don't need to reflow the line. } else if ((line->mNext && !line->HasBreak()) || + line->ResizeReflowOptimizationDisabled() || line->HasFloaters() || line->IsImpactedByFloater() || line->HasPercentageChild() || (line->mBounds.XMost() > newAvailWidth)) { diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 3d04a7c8cad3..b53a64df932a 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -157,7 +157,8 @@ InitDebugFlags() #undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested #undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" #undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef REALLY_NOISY_REFLOW // some extra debug info #endif @@ -781,7 +782,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, const nsMargin& borderPadding = BorderPadding(); - if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) { + if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) + { if (mBand.GetFloaterCount()) { // Use the float-edge property to determine how the child block // will interact with the floater. @@ -2006,15 +2008,6 @@ HaveAutoWidth(const nsHTMLReflowState& aReflowState) } -static PRBool -IsPercentageUnitSides(const nsStyleSides* aSides) -{ - return eStyleUnit_Percent == aSides->GetLeftUnit() - || eStyleUnit_Percent == aSides->GetRightUnit() - || eStyleUnit_Percent == aSides->GetTopUnit() - || eStyleUnit_Percent == aSides->GetBottomUnit(); -} - static PRBool IsPercentageAwareChild(const nsIFrame* aFrame) { @@ -2024,9 +2017,9 @@ IsPercentageAwareChild(const nsIFrame* aFrame) return PR_TRUE; // just to be on the safe side } - if (IsPercentageUnitSides(&space->mMargin) - || IsPercentageUnitSides(&space->mPadding) - || IsPercentageUnitSides(&space->mBorderRadius)) { + if (nsLineLayout::IsPercentageUnitSides(&space->mMargin) + || nsLineLayout::IsPercentageUnitSides(&space->mPadding) + || nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) { return PR_TRUE; } @@ -2042,7 +2035,7 @@ IsPercentageAwareChild(const nsIFrame* aFrame) || eStyleUnit_Percent == pos->mHeight.GetUnit() || eStyleUnit_Percent == pos->mMinHeight.GetUnit() || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() - || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! return PR_TRUE; } @@ -2600,6 +2593,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // newlines. Therefore, we don't need to reflow the line. } else if ((line->mNext && !line->HasBreak()) || + line->ResizeReflowOptimizationDisabled() || line->HasFloaters() || line->IsImpactedByFloater() || line->HasPercentageChild() || (line->mBounds.XMost() > newAvailWidth)) { diff --git a/layout/generic/nsBlockReflowState.h b/layout/generic/nsBlockReflowState.h index 3d04a7c8cad3..b53a64df932a 100644 --- a/layout/generic/nsBlockReflowState.h +++ b/layout/generic/nsBlockReflowState.h @@ -157,7 +157,8 @@ InitDebugFlags() #undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested #undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" #undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef REALLY_NOISY_REFLOW // some extra debug info #endif @@ -781,7 +782,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, const nsMargin& borderPadding = BorderPadding(); - if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) { + if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) + { if (mBand.GetFloaterCount()) { // Use the float-edge property to determine how the child block // will interact with the floater. @@ -2006,15 +2008,6 @@ HaveAutoWidth(const nsHTMLReflowState& aReflowState) } -static PRBool -IsPercentageUnitSides(const nsStyleSides* aSides) -{ - return eStyleUnit_Percent == aSides->GetLeftUnit() - || eStyleUnit_Percent == aSides->GetRightUnit() - || eStyleUnit_Percent == aSides->GetTopUnit() - || eStyleUnit_Percent == aSides->GetBottomUnit(); -} - static PRBool IsPercentageAwareChild(const nsIFrame* aFrame) { @@ -2024,9 +2017,9 @@ IsPercentageAwareChild(const nsIFrame* aFrame) return PR_TRUE; // just to be on the safe side } - if (IsPercentageUnitSides(&space->mMargin) - || IsPercentageUnitSides(&space->mPadding) - || IsPercentageUnitSides(&space->mBorderRadius)) { + if (nsLineLayout::IsPercentageUnitSides(&space->mMargin) + || nsLineLayout::IsPercentageUnitSides(&space->mPadding) + || nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) { return PR_TRUE; } @@ -2042,7 +2035,7 @@ IsPercentageAwareChild(const nsIFrame* aFrame) || eStyleUnit_Percent == pos->mHeight.GetUnit() || eStyleUnit_Percent == pos->mMinHeight.GetUnit() || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() - || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! return PR_TRUE; } @@ -2600,6 +2593,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // newlines. Therefore, we don't need to reflow the line. } else if ((line->mNext && !line->HasBreak()) || + line->ResizeReflowOptimizationDisabled() || line->HasFloaters() || line->IsImpactedByFloater() || line->HasPercentageChild() || (line->mBounds.XMost() > newAvailWidth)) { diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index e0e1fe972111..4b624ed1cc30 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -549,6 +549,41 @@ nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext, return rv; } +static +void SetContainsPercentAwareChild(nsIFrame *aFrame) +{ + nsFrameState myFrameState; + aFrame->GetFrameState(&myFrameState); + aFrame->SetFrameState(myFrameState | NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD); +} + +static +void MarkPercentAwareFrame(nsIPresContext *aPresContext, + nsInlineFrame *aInline, + nsIFrame *aFrame) +{ + nsFrameState childFrameState; + aFrame->GetFrameState(&childFrameState); + if (childFrameState & NS_FRAME_REPLACED_ELEMENT) + { // aFrame is a replaced element, check it's style + if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) { + SetContainsPercentAwareChild(aInline); + } + } + else + { + nsIFrame *child; + aFrame->FirstChild(aPresContext, nsnull, &child); + if (child) + { // aFrame is an inline container frame, check my frame state + if (childFrameState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) { + SetContainsPercentAwareChild(aInline); // if a child container is effected, so am I + } + } + // else frame is a leaf that we don't care about + } +} + nsresult nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, @@ -561,6 +596,15 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, PRBool pushedFrame; nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus, nsnull, pushedFrame); + /* This next block is for bug 28811 + Test the child frame for %-awareness, + and mark this frame with a bit if it is %-aware. + Don't bother if this frame is already marked + */ + if (!(mState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD)) { + MarkPercentAwareFrame(aPresContext, this, aFrame); + } + if (NS_FAILED(rv)) { return rv; } diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 93a9245d68e0..29c6e6e69bc1 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -33,6 +33,8 @@ class nsAnonymousBlockFrame; #define nsInlineFrameSuper nsHTMLContainerFrame +#define NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD 0X00010000 + /** * Inline frame class. * @@ -95,8 +97,8 @@ protected: nsIFrame* mNextRCFrame; nsIFrame* mPrevFrame; nsInlineFrame* mNextInFlow; - PRBool mSetParentPointer; // when reflowing child frame first set its - // parent frame pointer + PRPackedBool mSetParentPointer; // when reflowing child frame first set its + // parent frame pointer InlineReflowState() { mNextRCFrame = nsnull; @@ -129,6 +131,7 @@ protected: virtual void PushFrames(nsIPresContext* aPresContext, nsIFrame* aFromChild, nsIFrame* aPrevSibling); + }; //---------------------------------------------------------------------- diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h index a89a45661083..e809724f6e83 100644 --- a/layout/generic/nsLineBox.h +++ b/layout/generic/nsLineBox.h @@ -136,7 +136,7 @@ protected: //---------------------------------------------------------------------- #define LINE_MAX_BREAK_TYPE ((1 << 4) - 1) -#define LINE_MAX_CHILD_COUNT ((1 << 21) - 1) +#define LINE_MAX_CHILD_COUNT ((1 << 20) - 1) #if NS_STYLE_CLEAR_LAST_VALUE > 15 need to rearrange the mBits bitfield; @@ -231,6 +231,17 @@ public: PRBool IsForceInvalidate() const { return mFlags.mForceInvalidate; } + + // mResizeReflowOptimizationDisabled bit + void DisableResizeReflowOptimization() { + mFlags.mResizeReflowOptimizationDisabled = PR_TRUE; + } + void EnableResizeReflowOptimization() { + mFlags.mResizeReflowOptimizationDisabled = PR_FALSE; + } + PRBool ResizeReflowOptimizationDisabled() const { + return mFlags.mResizeReflowOptimizationDisabled; + } // mChildCount value PRInt32 GetChildCount() const { @@ -337,11 +348,11 @@ public: PRUint32 mTrimmed : 1; PRUint32 mHasPercentageChild : 1; PRUint32 mLineWrapped: 1; - PRUint32 mForceInvalidate: 1; - + PRUint32 mForceInvalidate: 1; // default 0 = means this line handles it's own invalidation. 1 = always invalidate this entire line + PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow PRUint32 mBreakType : 4; - PRUint32 mChildCount : 21; + PRUint32 mChildCount : 20; }; struct ExtraData { @@ -442,7 +453,7 @@ protected: nsLineBox** mLines; PRInt32 mIndex; PRInt32 mNumLines; - PRBool mRightToLeft; + PRPackedBool mRightToLeft; }; #endif /* nsLineBox_h___ */ diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 02e9740eba9a..e55f87e4015e 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -26,6 +26,7 @@ #include "nsCOMPtr.h" #include "nsLineLayout.h" #include "nsBlockFrame.h" +#include "nsInlineFrame.h" #include "nsStyleConsts.h" #include "nsHTMLContainerFrame.h" #include "nsHTMLIIDs.h" @@ -1548,6 +1549,86 @@ nsLineLayout::DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent) #define VALIGN_TOP 1 #define VALIGN_BOTTOM 2 +PRBool +nsLineLayout::IsPercentageUnitSides(const nsStyleSides* aSides) +{ + return eStyleUnit_Percent == aSides->GetLeftUnit() + || eStyleUnit_Percent == aSides->GetRightUnit() + || eStyleUnit_Percent == aSides->GetTopUnit() + || eStyleUnit_Percent == aSides->GetBottomUnit(); +} + +PRBool +nsLineLayout::IsPercentageAwareReplacedElement(nsIPresContext *aPresContext, + nsIFrame* aFrame) +{ + nsFrameState frameState; + aFrame->GetFrameState(&frameState); + if (frameState & NS_FRAME_REPLACED_ELEMENT) + { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::brFrame != frameType && + nsLayoutAtoms::textFrame != frameType) + { + const nsStyleSpacing* space; + nsresult rv = aFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct*&) space); + if (NS_FAILED(rv)) { + return PR_TRUE; // just to be on the safe side + } + + if (IsPercentageUnitSides(&space->mMargin) + || IsPercentageUnitSides(&space->mPadding) + || IsPercentageUnitSides(&space->mBorderRadius)) { + return PR_TRUE; + } + + const nsStylePosition* pos; + rv = aFrame->GetStyleData(eStyleStruct_Position,(const nsStyleStruct*&) pos); + if (NS_FAILED(rv)) { + return PR_TRUE; // just to be on the safe side + } + + if (eStyleUnit_Percent == pos->mWidth.GetUnit() + || eStyleUnit_Percent == pos->mMaxWidth.GetUnit() + || eStyleUnit_Percent == pos->mMinWidth.GetUnit() + || eStyleUnit_Percent == pos->mHeight.GetUnit() + || eStyleUnit_Percent == pos->mMinHeight.GetUnit() + || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() + || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + return PR_TRUE; + } + } + } + + return PR_FALSE; +} + +PRBool IsPercentageAwareFrame(nsIPresContext *aPresContext, nsIFrame *aFrame) +{ + nsFrameState childFrameState; + aFrame->GetFrameState(&childFrameState); + if (childFrameState & NS_FRAME_REPLACED_ELEMENT) { + if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) { + return PR_TRUE; + } + } + else + { + nsIFrame *child; + aFrame->FirstChild(aPresContext, nsnull, &child); + if (child) + { // aFrame is an inline container frame, check my frame state + if (childFrameState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) { + return PR_TRUE; + } + } + // else it's a frame we just don't care about + } + return PR_FALSE; +} + + void nsLineLayout::VerticalAlignFrames(nsLineBox* aLineBox, nsSize& aMaxElementSizeResult, @@ -1684,6 +1765,14 @@ nsLineLayout::VerticalAlignFrames(nsLineBox* aLineBox, nscoord distanceFromTop = pfd->mBounds.y - mTopEdge; PlaceTopBottomFrames(span, distanceFromTop, lineHeight); } + // check to see if the frame is an inline replace element + // and if it is percent-aware. If so, mark the line. + if ((PR_FALSE==aLineBox->ResizeReflowOptimizationDisabled()) && + pfd->mFrameType & NS_CSS_FRAME_TYPE_INLINE) + { + if (IsPercentageAwareFrame(mPresContext, pfd->mFrame)) + aLineBox->DisableResizeReflowOptimization(); + } pfd = pfd->mNext; } diff --git a/layout/generic/nsLineLayout.h b/layout/generic/nsLineLayout.h index 38914d0bdd28..d62ee935b315 100644 --- a/layout/generic/nsLineLayout.h +++ b/layout/generic/nsLineLayout.h @@ -251,6 +251,12 @@ public: static PRBool TreatFrameAsBlock(nsIFrame* aFrame); + static PRBool IsPercentageUnitSides(const nsStyleSides* aSides); + + static PRBool IsPercentageAwareReplacedElement(nsIPresContext *aPresContext, + nsIFrame *aFrame); + + //---------------------------------------- nsIPresContext* mPresContext; diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index 3d04a7c8cad3..b53a64df932a 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -157,7 +157,8 @@ InitDebugFlags() #undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested #undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" #undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef REALLY_NOISY_REFLOW // some extra debug info #endif @@ -781,7 +782,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, const nsMargin& borderPadding = BorderPadding(); - if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) { + if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) + { if (mBand.GetFloaterCount()) { // Use the float-edge property to determine how the child block // will interact with the floater. @@ -2006,15 +2008,6 @@ HaveAutoWidth(const nsHTMLReflowState& aReflowState) } -static PRBool -IsPercentageUnitSides(const nsStyleSides* aSides) -{ - return eStyleUnit_Percent == aSides->GetLeftUnit() - || eStyleUnit_Percent == aSides->GetRightUnit() - || eStyleUnit_Percent == aSides->GetTopUnit() - || eStyleUnit_Percent == aSides->GetBottomUnit(); -} - static PRBool IsPercentageAwareChild(const nsIFrame* aFrame) { @@ -2024,9 +2017,9 @@ IsPercentageAwareChild(const nsIFrame* aFrame) return PR_TRUE; // just to be on the safe side } - if (IsPercentageUnitSides(&space->mMargin) - || IsPercentageUnitSides(&space->mPadding) - || IsPercentageUnitSides(&space->mBorderRadius)) { + if (nsLineLayout::IsPercentageUnitSides(&space->mMargin) + || nsLineLayout::IsPercentageUnitSides(&space->mPadding) + || nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) { return PR_TRUE; } @@ -2042,7 +2035,7 @@ IsPercentageAwareChild(const nsIFrame* aFrame) || eStyleUnit_Percent == pos->mHeight.GetUnit() || eStyleUnit_Percent == pos->mMinHeight.GetUnit() || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() - || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! return PR_TRUE; } @@ -2600,6 +2593,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // newlines. Therefore, we don't need to reflow the line. } else if ((line->mNext && !line->HasBreak()) || + line->ResizeReflowOptimizationDisabled() || line->HasFloaters() || line->IsImpactedByFloater() || line->HasPercentageChild() || (line->mBounds.XMost() > newAvailWidth)) { diff --git a/layout/html/base/src/nsBlockReflowState.cpp b/layout/html/base/src/nsBlockReflowState.cpp index 3d04a7c8cad3..b53a64df932a 100644 --- a/layout/html/base/src/nsBlockReflowState.cpp +++ b/layout/html/base/src/nsBlockReflowState.cpp @@ -157,7 +157,8 @@ InitDebugFlags() #undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested #undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" #undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef REALLY_NOISY_REFLOW // some extra debug info #endif @@ -781,7 +782,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, const nsMargin& borderPadding = BorderPadding(); - if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) { + if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) + { if (mBand.GetFloaterCount()) { // Use the float-edge property to determine how the child block // will interact with the floater. @@ -2006,15 +2008,6 @@ HaveAutoWidth(const nsHTMLReflowState& aReflowState) } -static PRBool -IsPercentageUnitSides(const nsStyleSides* aSides) -{ - return eStyleUnit_Percent == aSides->GetLeftUnit() - || eStyleUnit_Percent == aSides->GetRightUnit() - || eStyleUnit_Percent == aSides->GetTopUnit() - || eStyleUnit_Percent == aSides->GetBottomUnit(); -} - static PRBool IsPercentageAwareChild(const nsIFrame* aFrame) { @@ -2024,9 +2017,9 @@ IsPercentageAwareChild(const nsIFrame* aFrame) return PR_TRUE; // just to be on the safe side } - if (IsPercentageUnitSides(&space->mMargin) - || IsPercentageUnitSides(&space->mPadding) - || IsPercentageUnitSides(&space->mBorderRadius)) { + if (nsLineLayout::IsPercentageUnitSides(&space->mMargin) + || nsLineLayout::IsPercentageUnitSides(&space->mPadding) + || nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) { return PR_TRUE; } @@ -2042,7 +2035,7 @@ IsPercentageAwareChild(const nsIFrame* aFrame) || eStyleUnit_Percent == pos->mHeight.GetUnit() || eStyleUnit_Percent == pos->mMinHeight.GetUnit() || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() - || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! return PR_TRUE; } @@ -2600,6 +2593,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // newlines. Therefore, we don't need to reflow the line. } else if ((line->mNext && !line->HasBreak()) || + line->ResizeReflowOptimizationDisabled() || line->HasFloaters() || line->IsImpactedByFloater() || line->HasPercentageChild() || (line->mBounds.XMost() > newAvailWidth)) { diff --git a/layout/html/base/src/nsBlockReflowState.h b/layout/html/base/src/nsBlockReflowState.h index 3d04a7c8cad3..b53a64df932a 100644 --- a/layout/html/base/src/nsBlockReflowState.h +++ b/layout/html/base/src/nsBlockReflowState.h @@ -157,7 +157,8 @@ InitDebugFlags() #undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested #undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete" #undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements -#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate +#undef REALLY_NOISY_REFLOW // some extra debug info #endif @@ -781,7 +782,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, const nsMargin& borderPadding = BorderPadding(); - if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) { + if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType) + { if (mBand.GetFloaterCount()) { // Use the float-edge property to determine how the child block // will interact with the floater. @@ -2006,15 +2008,6 @@ HaveAutoWidth(const nsHTMLReflowState& aReflowState) } -static PRBool -IsPercentageUnitSides(const nsStyleSides* aSides) -{ - return eStyleUnit_Percent == aSides->GetLeftUnit() - || eStyleUnit_Percent == aSides->GetRightUnit() - || eStyleUnit_Percent == aSides->GetTopUnit() - || eStyleUnit_Percent == aSides->GetBottomUnit(); -} - static PRBool IsPercentageAwareChild(const nsIFrame* aFrame) { @@ -2024,9 +2017,9 @@ IsPercentageAwareChild(const nsIFrame* aFrame) return PR_TRUE; // just to be on the safe side } - if (IsPercentageUnitSides(&space->mMargin) - || IsPercentageUnitSides(&space->mPadding) - || IsPercentageUnitSides(&space->mBorderRadius)) { + if (nsLineLayout::IsPercentageUnitSides(&space->mMargin) + || nsLineLayout::IsPercentageUnitSides(&space->mPadding) + || nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) { return PR_TRUE; } @@ -2042,7 +2035,7 @@ IsPercentageAwareChild(const nsIFrame* aFrame) || eStyleUnit_Percent == pos->mHeight.GetUnit() || eStyleUnit_Percent == pos->mMinHeight.GetUnit() || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() - || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! return PR_TRUE; } @@ -2600,6 +2593,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // newlines. Therefore, we don't need to reflow the line. } else if ((line->mNext && !line->HasBreak()) || + line->ResizeReflowOptimizationDisabled() || line->HasFloaters() || line->IsImpactedByFloater() || line->HasPercentageChild() || (line->mBounds.XMost() > newAvailWidth)) { diff --git a/layout/html/base/src/nsInlineFrame.cpp b/layout/html/base/src/nsInlineFrame.cpp index e0e1fe972111..4b624ed1cc30 100644 --- a/layout/html/base/src/nsInlineFrame.cpp +++ b/layout/html/base/src/nsInlineFrame.cpp @@ -549,6 +549,41 @@ nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext, return rv; } +static +void SetContainsPercentAwareChild(nsIFrame *aFrame) +{ + nsFrameState myFrameState; + aFrame->GetFrameState(&myFrameState); + aFrame->SetFrameState(myFrameState | NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD); +} + +static +void MarkPercentAwareFrame(nsIPresContext *aPresContext, + nsInlineFrame *aInline, + nsIFrame *aFrame) +{ + nsFrameState childFrameState; + aFrame->GetFrameState(&childFrameState); + if (childFrameState & NS_FRAME_REPLACED_ELEMENT) + { // aFrame is a replaced element, check it's style + if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) { + SetContainsPercentAwareChild(aInline); + } + } + else + { + nsIFrame *child; + aFrame->FirstChild(aPresContext, nsnull, &child); + if (child) + { // aFrame is an inline container frame, check my frame state + if (childFrameState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) { + SetContainsPercentAwareChild(aInline); // if a child container is effected, so am I + } + } + // else frame is a leaf that we don't care about + } +} + nsresult nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, @@ -561,6 +596,15 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, PRBool pushedFrame; nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus, nsnull, pushedFrame); + /* This next block is for bug 28811 + Test the child frame for %-awareness, + and mark this frame with a bit if it is %-aware. + Don't bother if this frame is already marked + */ + if (!(mState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD)) { + MarkPercentAwareFrame(aPresContext, this, aFrame); + } + if (NS_FAILED(rv)) { return rv; } diff --git a/layout/html/base/src/nsInlineFrame.h b/layout/html/base/src/nsInlineFrame.h index 93a9245d68e0..29c6e6e69bc1 100644 --- a/layout/html/base/src/nsInlineFrame.h +++ b/layout/html/base/src/nsInlineFrame.h @@ -33,6 +33,8 @@ class nsAnonymousBlockFrame; #define nsInlineFrameSuper nsHTMLContainerFrame +#define NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD 0X00010000 + /** * Inline frame class. * @@ -95,8 +97,8 @@ protected: nsIFrame* mNextRCFrame; nsIFrame* mPrevFrame; nsInlineFrame* mNextInFlow; - PRBool mSetParentPointer; // when reflowing child frame first set its - // parent frame pointer + PRPackedBool mSetParentPointer; // when reflowing child frame first set its + // parent frame pointer InlineReflowState() { mNextRCFrame = nsnull; @@ -129,6 +131,7 @@ protected: virtual void PushFrames(nsIPresContext* aPresContext, nsIFrame* aFromChild, nsIFrame* aPrevSibling); + }; //---------------------------------------------------------------------- diff --git a/layout/html/base/src/nsLineBox.h b/layout/html/base/src/nsLineBox.h index a89a45661083..e809724f6e83 100644 --- a/layout/html/base/src/nsLineBox.h +++ b/layout/html/base/src/nsLineBox.h @@ -136,7 +136,7 @@ protected: //---------------------------------------------------------------------- #define LINE_MAX_BREAK_TYPE ((1 << 4) - 1) -#define LINE_MAX_CHILD_COUNT ((1 << 21) - 1) +#define LINE_MAX_CHILD_COUNT ((1 << 20) - 1) #if NS_STYLE_CLEAR_LAST_VALUE > 15 need to rearrange the mBits bitfield; @@ -231,6 +231,17 @@ public: PRBool IsForceInvalidate() const { return mFlags.mForceInvalidate; } + + // mResizeReflowOptimizationDisabled bit + void DisableResizeReflowOptimization() { + mFlags.mResizeReflowOptimizationDisabled = PR_TRUE; + } + void EnableResizeReflowOptimization() { + mFlags.mResizeReflowOptimizationDisabled = PR_FALSE; + } + PRBool ResizeReflowOptimizationDisabled() const { + return mFlags.mResizeReflowOptimizationDisabled; + } // mChildCount value PRInt32 GetChildCount() const { @@ -337,11 +348,11 @@ public: PRUint32 mTrimmed : 1; PRUint32 mHasPercentageChild : 1; PRUint32 mLineWrapped: 1; - PRUint32 mForceInvalidate: 1; - + PRUint32 mForceInvalidate: 1; // default 0 = means this line handles it's own invalidation. 1 = always invalidate this entire line + PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow PRUint32 mBreakType : 4; - PRUint32 mChildCount : 21; + PRUint32 mChildCount : 20; }; struct ExtraData { @@ -442,7 +453,7 @@ protected: nsLineBox** mLines; PRInt32 mIndex; PRInt32 mNumLines; - PRBool mRightToLeft; + PRPackedBool mRightToLeft; }; #endif /* nsLineBox_h___ */ diff --git a/layout/html/base/src/nsLineLayout.cpp b/layout/html/base/src/nsLineLayout.cpp index 02e9740eba9a..e55f87e4015e 100644 --- a/layout/html/base/src/nsLineLayout.cpp +++ b/layout/html/base/src/nsLineLayout.cpp @@ -26,6 +26,7 @@ #include "nsCOMPtr.h" #include "nsLineLayout.h" #include "nsBlockFrame.h" +#include "nsInlineFrame.h" #include "nsStyleConsts.h" #include "nsHTMLContainerFrame.h" #include "nsHTMLIIDs.h" @@ -1548,6 +1549,86 @@ nsLineLayout::DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent) #define VALIGN_TOP 1 #define VALIGN_BOTTOM 2 +PRBool +nsLineLayout::IsPercentageUnitSides(const nsStyleSides* aSides) +{ + return eStyleUnit_Percent == aSides->GetLeftUnit() + || eStyleUnit_Percent == aSides->GetRightUnit() + || eStyleUnit_Percent == aSides->GetTopUnit() + || eStyleUnit_Percent == aSides->GetBottomUnit(); +} + +PRBool +nsLineLayout::IsPercentageAwareReplacedElement(nsIPresContext *aPresContext, + nsIFrame* aFrame) +{ + nsFrameState frameState; + aFrame->GetFrameState(&frameState); + if (frameState & NS_FRAME_REPLACED_ELEMENT) + { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::brFrame != frameType && + nsLayoutAtoms::textFrame != frameType) + { + const nsStyleSpacing* space; + nsresult rv = aFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct*&) space); + if (NS_FAILED(rv)) { + return PR_TRUE; // just to be on the safe side + } + + if (IsPercentageUnitSides(&space->mMargin) + || IsPercentageUnitSides(&space->mPadding) + || IsPercentageUnitSides(&space->mBorderRadius)) { + return PR_TRUE; + } + + const nsStylePosition* pos; + rv = aFrame->GetStyleData(eStyleStruct_Position,(const nsStyleStruct*&) pos); + if (NS_FAILED(rv)) { + return PR_TRUE; // just to be on the safe side + } + + if (eStyleUnit_Percent == pos->mWidth.GetUnit() + || eStyleUnit_Percent == pos->mMaxWidth.GetUnit() + || eStyleUnit_Percent == pos->mMinWidth.GetUnit() + || eStyleUnit_Percent == pos->mHeight.GetUnit() + || eStyleUnit_Percent == pos->mMinHeight.GetUnit() + || eStyleUnit_Percent == pos->mMaxHeight.GetUnit() + || IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!! + return PR_TRUE; + } + } + } + + return PR_FALSE; +} + +PRBool IsPercentageAwareFrame(nsIPresContext *aPresContext, nsIFrame *aFrame) +{ + nsFrameState childFrameState; + aFrame->GetFrameState(&childFrameState); + if (childFrameState & NS_FRAME_REPLACED_ELEMENT) { + if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) { + return PR_TRUE; + } + } + else + { + nsIFrame *child; + aFrame->FirstChild(aPresContext, nsnull, &child); + if (child) + { // aFrame is an inline container frame, check my frame state + if (childFrameState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) { + return PR_TRUE; + } + } + // else it's a frame we just don't care about + } + return PR_FALSE; +} + + void nsLineLayout::VerticalAlignFrames(nsLineBox* aLineBox, nsSize& aMaxElementSizeResult, @@ -1684,6 +1765,14 @@ nsLineLayout::VerticalAlignFrames(nsLineBox* aLineBox, nscoord distanceFromTop = pfd->mBounds.y - mTopEdge; PlaceTopBottomFrames(span, distanceFromTop, lineHeight); } + // check to see if the frame is an inline replace element + // and if it is percent-aware. If so, mark the line. + if ((PR_FALSE==aLineBox->ResizeReflowOptimizationDisabled()) && + pfd->mFrameType & NS_CSS_FRAME_TYPE_INLINE) + { + if (IsPercentageAwareFrame(mPresContext, pfd->mFrame)) + aLineBox->DisableResizeReflowOptimization(); + } pfd = pfd->mNext; } diff --git a/layout/html/base/src/nsLineLayout.h b/layout/html/base/src/nsLineLayout.h index 38914d0bdd28..d62ee935b315 100644 --- a/layout/html/base/src/nsLineLayout.h +++ b/layout/html/base/src/nsLineLayout.h @@ -251,6 +251,12 @@ public: static PRBool TreatFrameAsBlock(nsIFrame* aFrame); + static PRBool IsPercentageUnitSides(const nsStyleSides* aSides); + + static PRBool IsPercentageAwareReplacedElement(nsIPresContext *aPresContext, + nsIFrame *aFrame); + + //---------------------------------------- nsIPresContext* mPresContext;