bug 28811

r=karnaze
The problem was we were over-eager in optimizing away a resize reflow for lines
that contain %-aware children.  We were only looking at the first-level children
of a line, not all the children.  Now, we compute a bit for each inline container
based on it's children, true if any of them are %-aware wrt any width measurement.
We propogate this bit upwards to a bit on the line itself, and check this bit during reflow.
This commit is contained in:
buster%netscape.com 2000-09-11 20:46:44 +00:00
parent a7d77f33f2
commit 37e900a62c
16 changed files with 374 additions and 104 deletions

View File

@ -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)) {

View File

@ -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)) {

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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);
};
//----------------------------------------------------------------------

View File

@ -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___ */

View File

@ -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<nsIAtom> 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;
}

View File

@ -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;

View File

@ -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)) {

View File

@ -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)) {

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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);
};
//----------------------------------------------------------------------

View File

@ -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___ */

View File

@ -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<nsIAtom> 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;
}

View File

@ -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;