Bug 475968. Eliminate NS_FRAME_OUTSIDE_CHILDREN flag, store small overflow areas cheaply within the frame. r+sr=roc

This commit is contained in:
Jonathan Kew
2009-04-06 12:31:50 +12:00
parent ad75464e5e
commit ccbd2d2564
19 changed files with 181 additions and 59 deletions

View File

@@ -148,7 +148,7 @@ The table cell requires its children to compute the MES. It is reported back fro
The block has been required to compute the max. element size only once and it reports now: The block has been required to compute the max. element size only once and it reports now:
<p> <code class="log">block 02D7BCF8 d=1410,300</code></p> <p> <code class="log">block 02D7BCF8 d=1410,300</code></p>
<p>The block shows the same address as the previous one. <p>The block shows the same address as the previous one.
<p>Frames with children that overflow the parent have the <code>NS_FRAME_OUTSIDE_CHILDREN</code> flag set. For these frames <p>Frames with children that overflow the parent will return <code>PR_TRUE</code> from <code>HasOverflowRect()</code>. For these frames
the overflow area is displayed as <code class="log">block 025ED8F0 d=8940,1020 o=(0,0) 9180 x 1020</code>. The overflow area is specified as (x,y) origin and width x height. the overflow area is displayed as <code class="log">block 025ED8F0 d=8940,1020 o=(0,0) 9180 x 1020</code>. The overflow area is specified as (x,y) origin and width x height.
<p> The reflow finishes at the same level where it started. <p> The reflow finishes at the same level where it started.

View File

@@ -368,7 +368,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const
fprintf(out, " [state=%08x]", mState); fprintf(out, " [state=%08x]", mState);
} }
nsBlockFrame* f = const_cast<nsBlockFrame*>(this); nsBlockFrame* f = const_cast<nsBlockFrame*>(this);
if (f->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (f->HasOverflowRect()) {
nsRect overflowArea = f->GetOverflowRect(); nsRect overflowArea = f->GetOverflowRect();
fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y, fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
overflowArea.width, overflowArea.height); overflowArea.width, overflowArea.height);
@@ -1186,7 +1186,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ", aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ",
aMetrics.width, aMetrics.height, aMetrics.width, aMetrics.height,
aMetrics.mCarriedOutBottomMargin.get()); aMetrics.mCarriedOutBottomMargin.get());
if (mState & NS_FRAME_OUTSIDE_CHILDREN) { if (HasOverflowRect()) {
printf(" combinedArea={%d,%d,%d,%d}", printf(" combinedArea={%d,%d,%d,%d}",
aMetrics.mOverflowArea.x, aMetrics.mOverflowArea.x,
aMetrics.mOverflowArea.y, aMetrics.mOverflowArea.y,

View File

@@ -326,7 +326,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
} }
#endif #endif
if (!(NS_FRAME_OUTSIDE_CHILDREN & mFrame->GetStateBits())) { if (!mFrame->HasOverflowRect()) {
// Provide overflow area for child that doesn't have any // Provide overflow area for child that doesn't have any
mMetrics.mOverflowArea.x = 0; mMetrics.mOverflowArea.x = 0;
mMetrics.mOverflowArea.y = 0; mMetrics.mOverflowArea.y = 0;

View File

@@ -564,8 +564,8 @@ nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
vm->ResizeView(aView, *aCombinedArea, PR_TRUE); vm->ResizeView(aView, *aCombinedArea, PR_TRUE);
// Even if the size hasn't changed, we need to sync up the // Even if the size hasn't changed, we need to sync up the
// geometry dependent properties, because (kidState & // geometry dependent properties, because overflow areas of
// NS_FRAME_OUTSIDE_CHILDREN) might have changed, and we can't // children might have changed, and we can't
// detect whether it has or not. Likewise, whether the view size // detect whether it has or not. Likewise, whether the view size
// has changed or not, we may need to change the transparency // has changed or not, we may need to change the transparency
// state even if there is no clip. // state even if there is no clip.
@@ -1608,7 +1608,7 @@ nsContainerFrame::List(FILE* out, PRInt32 aIndent) const
} }
fprintf(out, " [content=%p]", static_cast<void*>(mContent)); fprintf(out, " [content=%p]", static_cast<void*>(mContent));
nsContainerFrame* f = const_cast<nsContainerFrame*>(this); nsContainerFrame* f = const_cast<nsContainerFrame*>(this);
if (f->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (f->HasOverflowRect()) {
nsRect overflowArea = f->GetOverflowRect(); nsRect overflowArea = f->GetOverflowRect();
fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y, fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
overflowArea.width, overflowArea.height); overflowArea.width, overflowArea.height);

View File

@@ -3975,11 +3975,22 @@ nsIFrame::GetOverflowRect() const
// areas will invalidate the appropriate area, so any (mis)uses of // areas will invalidate the appropriate area, so any (mis)uses of
// this method will be fixed up. // this method will be fixed up.
if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
// there is an overflow rect, and it's not stored as deltas but as
// a separately-allocated rect
return *const_cast<nsIFrame*>(this)->GetOverflowAreaProperty(PR_FALSE); return *const_cast<nsIFrame*>(this)->GetOverflowAreaProperty(PR_FALSE);
// NOTE this won't return accurate info if the overflow rect was updated }
// but the mRect hasn't been set yet!
return nsRect(nsPoint(0, 0), GetSize()); // Calculate the rect using deltas from the frame's border rect.
// Note that the mOverflow.mDeltas fields are unsigned, but we will often
// need to return negative values for the left and top, so take care
// to cast away the unsigned-ness.
return nsRect(-(PRInt32)mOverflow.mDeltas.mLeft,
-(PRInt32)mOverflow.mDeltas.mTop,
mRect.width + mOverflow.mDeltas.mRight +
mOverflow.mDeltas.mLeft,
mRect.height + mOverflow.mDeltas.mBottom +
mOverflow.mDeltas.mTop);
} }
nsRect nsRect
@@ -4068,7 +4079,7 @@ nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
{ {
if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) { if (aReflowState.mReflowDepth > MAX_FRAME_DEPTH) {
mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE; mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
mState &= ~NS_FRAME_OUTSIDE_CHILDREN; ClearOverflowRect();
aMetrics.width = 0; aMetrics.width = 0;
aMetrics.height = 0; aMetrics.height = 0;
aMetrics.ascent = 0; aMetrics.ascent = 0;
@@ -4148,7 +4159,7 @@ nsFrame::List(FILE* out, PRInt32 aIndent) const
} }
fprintf(out, " [content=%p]", static_cast<void*>(mContent)); fprintf(out, " [content=%p]", static_cast<void*>(mContent));
nsFrame* f = const_cast<nsFrame*>(this); nsFrame* f = const_cast<nsFrame*>(this);
if (f->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (f->HasOverflowRect()) {
nsRect overflowArea = f->GetOverflowRect(); nsRect overflowArea = f->GetOverflowRect();
fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y, fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
overflowArea.width, overflowArea.height); overflowArea.width, overflowArea.height);
@@ -5569,7 +5580,8 @@ nsFrame::GetAccessible(nsIAccessible** aAccessible)
nsRect* nsRect*
nsIFrame::GetOverflowAreaProperty(PRBool aCreateIfNecessary) nsIFrame::GetOverflowAreaProperty(PRBool aCreateIfNecessary)
{ {
if (!((GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) || aCreateIfNecessary)) { if (!((mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) ||
aCreateIfNecessary)) {
return nsnull; return nsnull;
} }
@@ -5588,10 +5600,44 @@ nsIFrame::GetOverflowAreaProperty(PRBool aCreateIfNecessary)
return overflow; return overflow;
} }
NS_NOTREACHED("Frame abuses NS_FRAME_OUTSIDE_CHILDREN flag"); NS_NOTREACHED("Frame abuses GetOverflowAreaProperty()");
return nsnull; return nsnull;
} }
/** Set the overflowArea rect, storing it as deltas or a separate rect
* depending on its size in relation to the primary frame rect.
*/
void
nsIFrame::SetOverflowRect(const nsRect& aRect)
{
PRUint32 l = -aRect.x, // left edge: positive delta is leftwards
t = -aRect.y, // top: positive is upwards
r = aRect.XMost() - mRect.width, // right: positive is rightwards
b = aRect.YMost() - mRect.height; // bottom: positive is downwards
if (l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
(l | t | r | b) != 0) {
// It's a "small" overflow area so we store the deltas for each edge
// directly in the frame, rather than allocating a separate rect.
// Note that we do NOT store in this way if *all* the deltas are zero,
// as that would be indistinguishable from the complete absence of
// an overflow rect.
DeleteProperty(nsGkAtoms::overflowAreaProperty);
mOverflow.mDeltas.mLeft = l;
mOverflow.mDeltas.mTop = t;
mOverflow.mDeltas.mRight = r;
mOverflow.mDeltas.mBottom = b;
} else {
// it's a large overflow area that we need to store as a property
mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE);
NS_ASSERTION(overflowArea, "should have created rect");
*overflowArea = aRect;
}
}
inline PRBool inline PRBool
IsInlineFrame(nsIFrame *aFrame) IsInlineFrame(nsIFrame *aFrame)
{ {
@@ -5682,18 +5728,14 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
PRBool overflowChanged; PRBool overflowChanged;
if (*aOverflowArea != nsRect(nsPoint(0, 0), aNewSize)) { if (*aOverflowArea != nsRect(nsPoint(0, 0), aNewSize)) {
mState |= NS_FRAME_OUTSIDE_CHILDREN; overflowChanged = *aOverflowArea != GetOverflowRect();
nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE); SetOverflowRect(*aOverflowArea);
NS_ASSERTION(overflowArea, "should have created rect");
overflowChanged = *overflowArea != *aOverflowArea;
*overflowArea = *aOverflowArea;
} }
else { else {
if (mState & NS_FRAME_OUTSIDE_CHILDREN) { if (HasOverflowRect()) {
// remove the previously stored overflow area // remove the previously stored overflow area
DeleteProperty(nsGkAtoms::overflowAreaProperty); ClearOverflowRect();
overflowChanged = PR_TRUE; overflowChanged = PR_TRUE;
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
} else { } else {
overflowChanged = PR_FALSE; overflowChanged = PR_FALSE;
} }
@@ -6624,7 +6666,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
// see if the overflow option is set. If it is then if our child's bounds overflow then // see if the overflow option is set. If it is then if our child's bounds overflow then
// we will set the child's rect to include the overflow size. // we will set the child's rect to include the overflow size.
if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (HasOverflowRect()) {
// This kinda sucks. We should be able to handle the case // This kinda sucks. We should be able to handle the case
// where there's overflow above or to the left of the // where there's overflow above or to the left of the
// origin. But for now just chop that stuff off. // origin. But for now just chop that stuff off.
@@ -6661,7 +6703,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
AddStateBits(NS_FRAME_IS_DIRTY); AddStateBits(NS_FRAME_IS_DIRTY);
WillReflow(aPresContext); WillReflow(aPresContext);
Reflow(aPresContext, aDesiredSize, reflowState, status); Reflow(aPresContext, aDesiredSize, reflowState, status);
if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) if (HasOverflowRect())
aDesiredSize.height = aDesiredSize.mOverflowArea.YMost(); aDesiredSize.height = aDesiredSize.mOverflowArea.YMost();
} }
} }
@@ -7694,13 +7736,13 @@ void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
printf(" status=0x%x", aStatus); printf(" status=0x%x", aStatus);
} }
if (aFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (aFrame->HasOverflowRect()) {
DR_state->PrettyUC(aMetrics.mOverflowArea.x, x); DR_state->PrettyUC(aMetrics.mOverflowArea.x, x);
DR_state->PrettyUC(aMetrics.mOverflowArea.y, y); DR_state->PrettyUC(aMetrics.mOverflowArea.y, y);
DR_state->PrettyUC(aMetrics.mOverflowArea.width, width); DR_state->PrettyUC(aMetrics.mOverflowArea.width, width);
DR_state->PrettyUC(aMetrics.mOverflowArea.height, height); DR_state->PrettyUC(aMetrics.mOverflowArea.height, height);
printf(" o=(%s,%s) %s x %s", x, y, width, height); printf(" o=(%s,%s) %s x %s", x, y, width, height);
if (aFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (aFrame->HasOverflowRect()) {
nsRect storedOverflow = aFrame->GetOverflowRect(); nsRect storedOverflow = aFrame->GetOverflowRect();
DR_state->PrettyUC(storedOverflow.x, x); DR_state->PrettyUC(storedOverflow.x, x);
DR_state->PrettyUC(storedOverflow.y, y); DR_state->PrettyUC(storedOverflow.y, y);

View File

@@ -540,7 +540,7 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
// always set mOverflowArea. In fact nsObjectFrame and nsFrameFrame don't // always set mOverflowArea. In fact nsObjectFrame and nsFrameFrame don't
// support the 'outline' property because of this. Rather than fix the world // support the 'outline' property because of this. Rather than fix the world
// right now, just fix up the overflow area if necessary. Note that we don't // right now, just fix up the overflow area if necessary. Note that we don't
// check NS_FRAME_OUTSIDE_CHILDREN because it could be set even though the // check HasOverflowRect() because it could be set even though the
// overflow area doesn't include the frame bounds. // overflow area doesn't include the frame bounds.
aMetrics->mOverflowArea.UnionRect(aMetrics->mOverflowArea, aMetrics->mOverflowArea.UnionRect(aMetrics->mOverflowArea,
nsRect(0, 0, aMetrics->width, aMetrics->height)); nsRect(0, 0, aMetrics->width, aMetrics->height));
@@ -712,12 +712,12 @@ nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState)
// Store the new overflow area. Note that this changes where an outline // Store the new overflow area. Note that this changes where an outline
// of the scrolled frame would be painted, but scrolled frames can't have // of the scrolled frame would be painted, but scrolled frames can't have
// outlines (the outline would go on this scrollframe instead). // outlines (the outline would go on this scrollframe instead).
// Using FinishAndStoreOverflow is needed so NS_FRAME_OUTSIDE_CHILDREN // Using FinishAndStoreOverflow is needed so the overflow rect
// gets set correctly. It also messes with the overflow rect in the // gets set correctly. It also messes with the overflow rect in the
// -moz-hidden-unscrollable case, but scrolled frames can't have // -moz-hidden-unscrollable case, but scrolled frames can't have
// 'overflow' either. // 'overflow' either.
// This needs to happen before SyncFrameViewAfterReflow so // This needs to happen before SyncFrameViewAfterReflow so
// NS_FRAME_OUTSIDE_CHILDREN is set. // HasOverflowRect() will return the correct value.
scrolledFrame->FinishAndStoreOverflow(&scrolledArea, scrolledFrame->FinishAndStoreOverflow(&scrolledArea,
scrolledFrame->GetSize()); scrolledFrame->GetSize());
@@ -2083,9 +2083,7 @@ nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState, const nsRect& aRect
// remove overflow area when we update the bounds, // remove overflow area when we update the bounds,
// because we've already accounted for it // because we've already accounted for it
mInner.mScrolledFrame->SetBounds(aState, childRect); mInner.mScrolledFrame->SetBounds(aState, childRect);
PresContext()->PropertyTable()-> mInner.mScrolledFrame->ClearOverflowRect();
DeleteProperty(mInner.mScrolledFrame, nsGkAtoms::overflowAreaProperty);
mInner.mScrolledFrame->RemoveStateBits(NS_FRAME_OUTSIDE_CHILDREN);
} }
aState.SetLayoutFlags(oldflags); aState.SetLayoutFlags(oldflags);

View File

@@ -159,7 +159,7 @@ struct nsHTMLReflowMetrics {
nsCollapsingMargin mCarriedOutBottomMargin; nsCollapsingMargin mCarriedOutBottomMargin;
// For frames that have content that overflow their content area // For frames that have content that overflow their content area
// (NS_FRAME_OUTSIDE_CHILDREN) this rectangle represents the total area // (HasOverflowRect() is true) this rectangle represents the total area
// of the frame including visible overflow, i.e., don't include overflowing // of the frame including visible overflow, i.e., don't include overflowing
// content that is hidden. // content that is hidden.
// The rect is in the local coordinate space of the frame, and should be at // The rect is in the local coordinate space of the frame, and should be at

View File

@@ -162,9 +162,14 @@ enum {
// continuation, e.g. a bidi continuation. // continuation, e.g. a bidi continuation.
NS_FRAME_IS_FLUID_CONTINUATION = 0x00000004, NS_FRAME_IS_FLUID_CONTINUATION = 0x00000004,
// This bit is set when the frame's overflow rect is /*
// different from its border rect (i.e. GetOverflowRect() != GetRect()) * This bit is obsolete, replaced by HasOverflowRect().
NS_FRAME_OUTSIDE_CHILDREN = 0x00000008, * The definition is left here as a placeholder for now, to remind us
* that this bit is now free to allocate for other purposes.
* // This bit is set when the frame's overflow rect is
* // different from its border rect (i.e. GetOverflowRect() != GetRect())
* NS_FRAME_OUTSIDE_CHILDREN = 0x00000008,
*/
// If this bit is set, then a reference to the frame is being held // If this bit is set, then a reference to the frame is being held
// elsewhere. The frame may want to send a notification when it is // elsewhere. The frame may want to send a notification when it is
@@ -441,6 +446,24 @@ typedef PRBool nsDidReflowStatus;
#define NS_FRAME_REFLOW_NOT_FINISHED PR_FALSE #define NS_FRAME_REFLOW_NOT_FINISHED PR_FALSE
#define NS_FRAME_REFLOW_FINISHED PR_TRUE #define NS_FRAME_REFLOW_FINISHED PR_TRUE
/**
* The overflow rect may be stored as four 1-byte deltas each strictly
* LESS THAN 0xff, for the four edges of the rectangle, or the four bytes
* may be read as a single 32-bit "overflow-rect type" value including
* at least one 0xff byte as an indicator that the value does NOT
* represent four deltas.
* If all four deltas are zero, this means that no overflow rect has
* actually been set (this is the initial state of newly-created frames).
*/
#define NS_FRAME_OVERFLOW_DELTA_MAX 0xfe // max delta we can store
#define NS_FRAME_OVERFLOW_NONE 0x00000000 // there is no overflow rect;
// code relies on this being
// the all-zero value
#define NS_FRAME_OVERFLOW_LARGE 0x000000ff // overflow is stored as a
// separate rect property
//---------------------------------------------------------------------- //----------------------------------------------------------------------
/** /**
@@ -710,9 +733,32 @@ public:
nsRect GetRect() const { return mRect; } nsRect GetRect() const { return mRect; }
nsPoint GetPosition() const { return nsPoint(mRect.x, mRect.y); } nsPoint GetPosition() const { return nsPoint(mRect.x, mRect.y); }
nsSize GetSize() const { return nsSize(mRect.width, mRect.height); } nsSize GetSize() const { return nsSize(mRect.width, mRect.height); }
void SetRect(const nsRect& aRect) { mRect = aRect; }
/**
* When we change the size of the frame's border-box rect, we may need to
* reset the overflow rect if it was previously stored as deltas.
* (If it is currently a "large" overflow and could be re-packed as deltas,
* we don't bother as the cost of the allocation has already been paid.)
*/
void SetRect(const nsRect& aRect) {
if (HasOverflowRect() && mOverflow.mType != NS_FRAME_OVERFLOW_LARGE) {
nsRect r = GetOverflowRect();
mRect = aRect;
SetOverflowRect(r);
} else {
mRect = aRect;
}
}
void SetSize(const nsSize& aSize) {
if (HasOverflowRect() && mOverflow.mType != NS_FRAME_OVERFLOW_LARGE) {
nsRect r = GetOverflowRect();
mRect.SizeTo(aSize);
SetOverflowRect(r);
} else {
mRect.SizeTo(aSize);
}
}
void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); } void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); }
void SetSize(const nsSize& aSize) { mRect.SizeTo(aSize); }
/** /**
* Return frame's computed offset due to relative positioning * Return frame's computed offset due to relative positioning
@@ -1756,8 +1802,8 @@ public:
* frame's outline, and descentant frames' outline, but does not include * frame's outline, and descentant frames' outline, but does not include
* areas clipped out by the CSS "overflow" and "clip" properties. * areas clipped out by the CSS "overflow" and "clip" properties.
* *
* The NS_FRAME_OUTSIDE_CHILDREN state bit is set when this overflow rect * HasOverflowRect() (below) will return PR_TRUE when this overflow rect
* is different from nsRect(0, 0, GetRect().width, GetRect().height). * has been explicitly set, even if it matches mRect.
* XXX Note: because of a space optimization using the formula above, * XXX Note: because of a space optimization using the formula above,
* during reflow this function does not give accurate data if * during reflow this function does not give accurate data if
* FinishAndStoreOverflow has been called but mRect hasn't yet been * FinishAndStoreOverflow has been called but mRect hasn't yet been
@@ -1776,7 +1822,7 @@ public:
* frame's outline, and descentant frames' outline, but does not include * frame's outline, and descentant frames' outline, but does not include
* areas clipped out by the CSS "overflow" and "clip" properties. * areas clipped out by the CSS "overflow" and "clip" properties.
* *
* The NS_FRAME_OUTSIDE_CHILDREN state bit is set when this overflow rect * HasOverflowRect() (below) will return PR_TRUE when this overflow rect
* is different from nsRect(0, 0, GetRect().width, GetRect().height). * is different from nsRect(0, 0, GetRect().width, GetRect().height).
* XXX Note: because of a space optimization using the formula above, * XXX Note: because of a space optimization using the formula above,
* during reflow this function does not give accurate data if * during reflow this function does not give accurate data if
@@ -1800,7 +1846,7 @@ public:
nsRect GetOverflowRectRelativeToSelf() const; nsRect GetOverflowRectRelativeToSelf() const;
/** /**
* Set/unset the NS_FRAME_OUTSIDE_CHILDREN flag and store the overflow area * Store the overflow area in the frame's mOverflow.mDeltas fields or
* as a frame property in the frame manager so that it can be retrieved * as a frame property in the frame manager so that it can be retrieved
* later without reflowing the frame. * later without reflowing the frame.
*/ */
@@ -1810,6 +1856,22 @@ public:
FinishAndStoreOverflow(&aMetrics->mOverflowArea, nsSize(aMetrics->width, aMetrics->height)); FinishAndStoreOverflow(&aMetrics->mOverflowArea, nsSize(aMetrics->width, aMetrics->height));
} }
/**
* Returns whether the frame has an overflow rect that is different from
* its border-box.
*/
PRBool HasOverflowRect() const {
return mOverflow.mType != NS_FRAME_OVERFLOW_NONE;
}
/**
* Removes any stored overflow rect from the frame.
*/
void ClearOverflowRect() {
DeleteProperty(nsGkAtoms::overflowAreaProperty);
mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
}
/** /**
* Determine whether borders should not be painted on certain sides of the * Determine whether borders should not be painted on certain sides of the
* frame. * frame.
@@ -2256,6 +2318,25 @@ protected:
nsIFrame* mNextSibling; // singly-linked list of frames nsIFrame* mNextSibling; // singly-linked list of frames
nsFrameState mState; nsFrameState mState;
// When there is an overflow area only slightly larger than mRect,
// we store a set of four 1-byte deltas from the edges of mRect
// rather than allocating a whole separate rectangle property.
// Note that these are unsigned values, all measured "outwards"
// from the edges of mRect, so /mLeft/ and /mTop/ are reversed from
// our normal coordinate system.
// If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the
// delta values are not meaningful and the overflow area is stored
// as a separate rect property.
union {
PRUint32 mType;
struct {
PRUint8 mLeft;
PRUint8 mTop;
PRUint8 mRight;
PRUint8 mBottom;
} mDeltas;
} mOverflow;
// Helpers // Helpers
/** /**
* For frames that have top-level windows (top-level viewports, * For frames that have top-level windows (top-level viewports,
@@ -2357,6 +2438,7 @@ protected:
private: private:
nsRect* GetOverflowAreaProperty(PRBool aCreateIfNecessary = PR_FALSE); nsRect* GetOverflowAreaProperty(PRBool aCreateIfNecessary = PR_FALSE);
void SetOverflowRect(const nsRect& aRect);
}; };
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@@ -384,7 +384,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext,
rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus); rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
// Note: the line layout code will properly compute our // Note: the line layout code will properly compute our
// NS_FRAME_OUTSIDE_CHILDREN state for us. // overflow-rect state for us.
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
return rv; return rv;

View File

@@ -2635,8 +2635,8 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
nsContainerFrame::PositionChildViews(frame); nsContainerFrame::PositionChildViews(frame);
} }
// Do this here (rather than along with NS_FRAME_OUTSIDE_CHILDREN // Do this here (rather than along with setting the overflow rect
// handling below) so we get leaf frames as well. No need to worry // below) so we get leaf frames as well. No need to worry
// about the root span, since it doesn't have a frame. // about the root span, since it doesn't have a frame.
if (frame->HasView()) if (frame->HasView())
nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame, nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
@@ -2647,7 +2647,7 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
} }
// If we just computed a spans combined area, we need to update its // If we just computed a spans combined area, we need to update its
// NS_FRAME_OUTSIDE_CHILDREN bit.. // overflow rect...
if (psd->mFrame) { if (psd->mFrame) {
PerFrameData* spanPFD = psd->mFrame; PerFrameData* spanPFD = psd->mFrame;
nsIFrame* frame = spanPFD->mFrame; nsIFrame* frame = spanPFD->mFrame;

View File

@@ -140,7 +140,7 @@ public:
/** /**
* Handle all the relative positioning in the line, compute the * Handle all the relative positioning in the line, compute the
* combined area (== overflow area) for the line, and handle view * combined area (== overflow area) for the line, and handle view
* sizing/positioning and the setting of NS_FRAME_OUTSIDE_CHILDREN. * sizing/positioning and the setting of the overflow rect.
*/ */
void RelativePositionFrames(nsRect& aCombinedArea); void RelativePositionFrames(nsRect& aCombinedArea);

View File

@@ -111,7 +111,7 @@ nsPageContentFrame::Reflow(nsPresContext* aPresContext,
kidReflowState.mStylePadding->GetPadding(padding); kidReflowState.mStylePadding->GetPadding(padding);
// First check the combined area // First check the combined area
if (NS_FRAME_OUTSIDE_CHILDREN & frame->GetStateBits()) { if (frame->HasOverflowRect()) {
// The background covers the content area and padding area, so check // The background covers the content area and padding area, so check
// for children sticking outside the child frame's padding edge // for children sticking outside the child frame's padding edge
if (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) { if (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) {

View File

@@ -6625,7 +6625,7 @@ nsTextFrame::List(FILE* out, PRInt32 aIndent) const
} }
} }
fprintf(out, " [content=%p]", static_cast<void*>(mContent)); fprintf(out, " [content=%p]", static_cast<void*>(mContent));
if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (HasOverflowRect()) {
nsRect overflowArea = GetOverflowRect(); nsRect overflowArea = GetOverflowRect();
fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y, fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
overflowArea.width, overflowArea.height); overflowArea.width, overflowArea.height);

View File

@@ -6423,6 +6423,8 @@ nsTableFrame::PaintBCBorders(nsIRenderingContext& aRenderingContext,
rowY += rowSize.height; rowY += rowSize.height;
} }
} }
// XXX comment refers to the obsolete NS_FRAME_OUTSIDE_CHILDREN flag
// XXX but I don't understand it, so not changing it for now
// outer table borders overflow the table, so the table might be // outer table borders overflow the table, so the table might be
// target to other areas as the NS_FRAME_OUTSIDE_CHILDREN is set // target to other areas as the NS_FRAME_OUTSIDE_CHILDREN is set
// on the table // on the table

View File

@@ -923,7 +923,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
desiredSize.width = cellDesiredSize.width; desiredSize.width = cellDesiredSize.width;
desiredSize.height = cellDesiredSize.height; desiredSize.height = cellDesiredSize.height;
if (cellFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) if (cellFrame->HasOverflowRect())
desiredSize.mOverflowArea = cellFrame->GetOverflowRect(); desiredSize.mOverflowArea = cellFrame->GetOverflowRect();
else else
desiredSize.mOverflowArea.SetRect(0, 0, cellDesiredSize.width, desiredSize.mOverflowArea.SetRect(0, 0, cellDesiredSize.width,

View File

@@ -280,11 +280,9 @@ nsBox::SetBounds(nsBoxLayoutState& aState, const nsRect& aRect, PRBool aRemoveOv
// Nuke the overflow area. The caller is responsible for restoring // Nuke the overflow area. The caller is responsible for restoring
// it if necessary. // it if necessary.
if (aRemoveOverflowArea && (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN)) { if (aRemoveOverflowArea && HasOverflowRect()) {
// remove the previously stored overflow area // remove the previously stored overflow area
PresContext()->PropertyTable()-> ClearOverflowRect();
DeleteProperty(this, nsGkAtoms::overflowAreaProperty);
RemoveStateBits(NS_FRAME_OUTSIDE_CHILDREN);
} }
if (!(flags & NS_FRAME_NO_MOVE_VIEW)) if (!(flags & NS_FRAME_NO_MOVE_VIEW))

View File

@@ -351,7 +351,7 @@ nsLeafBoxFrame::Reflow(nsPresContext* aPresContext,
aDesiredSize.height = mRect.height; aDesiredSize.height = mRect.height;
aDesiredSize.ascent = GetBoxAscent(state); aDesiredSize.ascent = GetBoxAscent(state);
// NS_FRAME_OUTSIDE_CHILDREN is set in SetBounds() above // the overflow rect is set in SetBounds() above
aDesiredSize.mOverflowArea = GetOverflowRect(); aDesiredSize.mOverflowArea = GetOverflowRect();
#ifdef DO_NOISY_REFLOW #ifdef DO_NOISY_REFLOW

View File

@@ -329,7 +329,7 @@ nsPopupSetFrame::List(FILE* out, PRInt32 aIndent) const
} }
fprintf(out, " [content=%p]", static_cast<void*>(mContent)); fprintf(out, " [content=%p]", static_cast<void*>(mContent));
nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this); nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this);
if (f->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { if (f->HasOverflowRect()) {
nsRect overflowArea = f->GetOverflowRect(); nsRect overflowArea = f->GetOverflowRect();
fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y, fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
overflowArea.width, overflowArea.height); overflowArea.width, overflowArea.height);

View File

@@ -105,7 +105,7 @@ public:
/** /**
* Treat scrollbars as clipping their children; overflowing children * Treat scrollbars as clipping their children; overflowing children
* will not be allowed to make NS_FRAME_OUTSIDE_CHILDREN on this * will not be allowed to set an overflow rect on this
* frame. This means that when the scroll code decides to hide a * frame. This means that when the scroll code decides to hide a
* scrollframe by setting its height or width to zero, that will * scrollframe by setting its height or width to zero, that will
* hide the children too. * hide the children too.