# HG changeset patch # User Benjamin Stover # Date 1308171829 25200 # Node ID 302c81d5c8ffea9c112015bbf741343f545ed31d # Parent a584e2e06d74fd23c0d9af78fed8cce314375eeb Bug 524925 Recompute overflow without reflowing for transforms diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -7978,6 +7978,30 @@ ApplyRenderingChangeToTree(presContext, frame, hint); didInvalidate = PR_TRUE; } + if (hint & nsChangeHint_UpdateOverflow) { + nsOverflowAreas overflowAreas; + nsOverflowAreas* pre = static_cast + (frame->Properties().Get(frame->PreTransformScrollableOverflowProperty())); + if (pre) { + // FinishAndStoreOverflow will change the overflow areas passed in, + // so make a copy. + overflowAreas = *pre; + } else { + // There is no transform yet on this frame, so we can just use its + // current overflow areas. + overflowAreas = frame->GetOverflowAreas(); + } + + frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize()); + + // Ancestors' oveflow areas may be affected. + for (nsIFrame* ancestor = frame->GetParent(); ancestor; + ancestor = ancestor->GetParent()) { + if (!ancestor->UpdateOverflow()) { + break; + } + } + } if (hint & nsChangeHint_UpdateCursor) { mPresShell->SynthesizeMouseMove(PR_FALSE); } diff --git a/layout/base/nsChangeHint.h b/layout/base/nsChangeHint.h --- a/layout/base/nsChangeHint.h +++ b/layout/base/nsChangeHint.h @@ -91,7 +91,9 @@ // change requires frame change (e.g., display:). // This subsumes all the above. - nsChangeHint_ReconstructFrame = 0x400 + nsChangeHint_ReconstructFrame = 0x400, + + nsChangeHint_UpdateOverflow = 0x800 }; // Redefine these operators to return nothing. This will catch any use diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -158,6 +158,34 @@ return s3DTransformsEnabled; } +void +nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame, + nsOverflowAreas& aOverflowAreas) +{ + // Iterate over all children except pop-ups + nsIFrame::ChildListID childLists[] = { nsIFrame::kPrincipalList, + nsIFrame::kAbsoluteList, + nsIFrame::kBulletList, + nsIFrame::kCaptionList, + nsIFrame::kColGroupList, + nsIFrame::kExcessOverflowContainersList, + nsIFrame::kFixedList, + nsIFrame::kFloatList, + nsIFrame::kOverflowContainersList, + nsIFrame::kOverflowOutOfFlowList, + nsIFrame::kPushedFloatsList, + nsIFrame::kNoReflowPrincipalList }; + for (int i = 0; i < NS_ARRAY_LENGTH(childLists); ++i) { + nsFrameList children(aFrame->GetChildList(childLists[i])); + for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { + nsIFrame* child = e.get(); + nsOverflowAreas childOverflow = + child->GetOverflowAreas() + child->GetPosition(); + aOverflowAreas.UnionWith(childOverflow); + } + } +} + static void DestroyViewID(void* aObject, nsIAtom* aPropertyName, void* aPropertyValue, void* aData) { diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1426,6 +1426,13 @@ */ static PRBool Are3DTransformsEnabled(); + /** + * Unions the overflow areas of all non-popup children of aFrame with + * aOverflowAreas. + */ + static void UnionChildOverflow(nsIFrame* aFrame, + nsOverflowAreas& aOverflowAreas); + static void Shutdown(); #ifdef DEBUG diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -938,9 +938,9 @@ } static inline PRBool IsClippingChildren(nsIFrame* aFrame, - const nsHTMLReflowState& aReflowState) + const nsStyleDisplay* display) { - return aReflowState.mStyleDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP || + return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP || nsFrame::ApplyPaginatedOverflowClipping(aFrame); } @@ -975,7 +975,7 @@ // make sure our kids fit too. if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE && aReflowState.ComputedHeight() != NS_AUTOHEIGHT && - IsClippingChildren(this, aReflowState)) { + IsClippingChildren(this, aReflowState.mStyleDisplay)) { nsMargin heightExtras = aReflowState.mComputedBorderPadding; if (GetSkipSides() & NS_SIDE_TOP) { heightExtras.top = 0; @@ -1138,7 +1138,8 @@ // Compute our final size ComputeFinalSize(*reflowState, state, aMetrics); - ComputeOverflowAreas(*reflowState, aMetrics); + nsRect areaBounds = nsRect(0, 0, aMetrics.width, aMetrics.height); + ComputeOverflowAreas(areaBounds, aReflowState.mStyleDisplay, aMetrics.mOverflowAreas); // Factor overflow container child bounds into the overflow area aMetrics.mOverflowAreas.UnionWith(ocBounds); // Factor pushed float child bounds into the overflow area @@ -1465,16 +1466,16 @@ } void -nsBlockFrame::ComputeOverflowAreas(const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeOverflowAreas(nsRect& aBounds, + const nsStyleDisplay* display, + nsOverflowAreas& aOverflowAreas) { // Compute the overflow areas of our children // XXX_perf: This can be done incrementally. It is currently one of // the things that makes incremental reflow O(N^2). - nsRect bounds(0, 0, aMetrics.width, aMetrics.height); - nsOverflowAreas areas(bounds, bounds); - - if (!IsClippingChildren(this, aReflowState)) { + nsOverflowAreas areas(aBounds, aBounds); + + if (!IsClippingChildren(this, display)) { for (line_iterator line = begin_lines(), line_end = end_lines(); line != line_end; ++line) { @@ -1495,7 +1496,21 @@ printf(": ca=%d,%d,%d,%d\n", area.x, area.y, area.width, area.height); #endif - aMetrics.mOverflowAreas = areas; + aOverflowAreas = areas; +} + +PRBool +nsBlockFrame::UpdateOverflow() +{ + const nsStyleDisplay* display = mContent->GetPrimaryFrame()->GetStyleDisplay(); + if (IsClippingChildren(this, display)) + return PR_FALSE; + + nsRect bounds = nsRect(nsPoint(0,0), GetSize()); + nsOverflowAreas overflowAreas(bounds, bounds); + ComputeOverflowAreas(bounds, display, overflowAreas); + + return FinishAndStoreOverflow(overflowAreas, GetSize()); } nsresult diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -385,8 +385,9 @@ nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); - void ComputeOverflowAreas(const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aMetrics); + void ComputeOverflowAreas(nsRect& aBounds, + const nsStyleDisplay* display, + nsOverflowAreas& aOverflowAreas); /** add the frames in aFrameList to this block after aPrevSibling * this block thinks in terms of lines, but the frame construction code @@ -435,6 +436,8 @@ nsBlockFrame* aOldParent, PRBool aFromOverflow, PRBool aReparentSiblings); + virtual PRBool UpdateOverflow(); + /** Load all of aFrame's floats into the float manager iff aFrame is not a * block formatting context. Handles all necessary float manager translations; * assumes float manager is in aFrame's parent's coord system. diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4495,6 +4495,19 @@ return GetVisualOverflowRect(); } +PRBool +nsIFrame::UpdateOverflow() +{ + nsRect rect(nsPoint(0, 0), GetSize()); + nsOverflowAreas overflowAreas(rect, rect); + + if (!IsCollapsed()) { + nsLayoutUtils::UnionChildOverflow(this, overflowAreas); + } + + return FinishAndStoreOverflow(overflowAreas, GetSize()); +} + void nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize) { @@ -6167,7 +6180,7 @@ type == nsGkAtoms::positionedInlineFrame; } -void +PRBool nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, nsSize aNewSize) { @@ -6182,6 +6195,14 @@ "Computed overflow area must contain frame bounds"); } + PRBool hasTransform = IsTransformed(); + if (hasTransform) { + Properties().Set(nsIFrame::PreTransformScrollableOverflowProperty(), + new nsOverflowAreas(aOverflowAreas)); + } else { + Properties().Delete(nsIFrame::PreTransformScrollableOverflowProperty()); + } + // If we clip our children, clear accumulated overflow area. The // children are actually clipped to the padding-box, but since the // overflow area should include the entire border-box, just set it to @@ -6249,7 +6270,6 @@ } /* If we're transformed, transform the overflow rect by the current transformation. */ - PRBool hasTransform = IsTransformed(); if (hasTransform) { Properties().Set(nsIFrame::PreTransformBBoxProperty(), new nsRect(aOverflowAreas.VisualOverflow())); @@ -6265,6 +6285,8 @@ } } + PRBool scrollableOverflowChanged = + !GetScrollableOverflowRect().IsEqualInterior(aOverflowAreas.ScrollableOverflow()); PRBool visualOverflowChanged = !GetVisualOverflowRect().IsEqualInterior(aOverflowAreas.VisualOverflow()); @@ -6316,6 +6338,8 @@ nsDisplayItem::TYPE_TRANSFORM); } } + + return visualOverflowChanged || scrollableOverflowChanged; } void @@ -6782,7 +6806,7 @@ return metrics->mPrefSize; } - if (IsCollapsed(aState)) + if (IsCollapsed()) return size; // get our size in CSS. @@ -6818,7 +6842,7 @@ return size; } - if (IsCollapsed(aState)) + if (IsCollapsed()) return size; // get our size in CSS. @@ -6853,7 +6877,7 @@ return size; } - if (IsCollapsed(aState)) + if (IsCollapsed()) return size; size = nsBox::GetMaxSize(aState); @@ -6881,7 +6905,7 @@ if (!DoesNeedRecalc(metrics->mAscent)) return metrics->mAscent; - if (IsCollapsed(aState)) { + if (IsCollapsed()) { metrics->mAscent = 0; } else { // Refresh our caches with new sizes. @@ -6907,7 +6931,7 @@ rv = BoxReflow(aState, presContext, desiredSize, rendContext, ourRect.x, ourRect.y, ourRect.width, ourRect.height); - if (IsCollapsed(aState)) { + if (IsCollapsed()) { SetSize(nsSize(0, 0)); } else { @@ -7147,7 +7171,7 @@ aDesiredSize, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME); // Save the ascent. (bug 103925) - if (IsCollapsed(aState)) { + if (IsCollapsed()) { metrics->mAscent = 0; } else { if (aDesiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) { diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -790,7 +790,7 @@ } PRBool -nsHTMLScrollFrame::IsCollapsed(nsBoxLayoutState& aBoxLayoutState) +nsHTMLScrollFrame::IsCollapsed() { // We're never collapsed in the box sense. return PR_FALSE; @@ -3256,6 +3256,32 @@ } } +PRBool +nsGfxScrollFrameInner::UpdateOverflow() +{ + PRBool changed = mOuter->nsFrame::UpdateOverflow(); + if (!changed) { + return changed; + } + + nsIScrollableFrame* sf = do_QueryFrame(mOuter); + ScrollbarStyles ss = sf->GetScrollbarStyles(); + if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN && + ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN && + GetScrollPosition() == nsPoint()) { + // No need to reflow in this special case. There are no scrollbars and we + // are at the top of the pane, so any child overflow changes will not remove + // width or height that could change the scroll position. + return PR_FALSE; + } + + nsPresContext* presContext = mOuter->PresContext(); + presContext->PresShell()->FrameNeedsReflow( + mOuter, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); + + return changed; +} + void nsGfxScrollFrameInner::AdjustScrollbarRectForResizer( nsIFrame* aFrame, nsPresContext* aPresContext, diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -239,6 +239,9 @@ PRBool IsLTR() const; PRBool IsScrollbarOnRight() const; PRBool IsScrollingActive() const { return mScrollingActive || ShouldBuildLayer(); } + + virtual PRBool UpdateOverflow(); + // adjust the scrollbar rectangle aRect to account for any visible resizer. // aHasResizer specifies if there is a content resizer, however this method // will also check if a widget resizer is present as well. @@ -380,7 +383,7 @@ virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext); virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext); NS_IMETHOD GetPadding(nsMargin& aPadding); - virtual PRBool IsCollapsed(nsBoxLayoutState& aBoxLayoutState); + virtual PRBool IsCollapsed(); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -492,6 +495,9 @@ virtual PRBool IsScrollingActive() { return mInner.IsScrollingActive(); } + virtual PRBool UpdateOverflow() { + return mInner.UpdateOverflow(); + } // nsIStatefulFrame NS_IMETHOD SaveState(SpecialStateID aStateID, nsPresState** aState) { @@ -727,6 +733,9 @@ virtual PRBool IsScrollingActive() { return mInner.IsScrollingActive(); } + virtual PRBool UpdateOverflow() { + return mInner.UpdateOverflow(); + } // nsIStatefulFrame NS_IMETHOD SaveState(SpecialStateID aStateID, nsPresState** aState) { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -891,6 +891,8 @@ NS_DECLARE_FRAME_PROPERTY(OutlineInnerRectProperty, DestroyRect) NS_DECLARE_FRAME_PROPERTY(PreEffectsBBoxProperty, DestroyRect) NS_DECLARE_FRAME_PROPERTY(PreTransformBBoxProperty, DestroyRect) + NS_DECLARE_FRAME_PROPERTY(PreTransformScrollableOverflowProperty, + DestroyOverflowAreas) NS_DECLARE_FRAME_PROPERTY(UsedMarginProperty, DestroyMargin) NS_DECLARE_FRAME_PROPERTY(UsedPaddingProperty, DestroyMargin) @@ -1744,6 +1746,13 @@ // XXX Maybe these three should be a separate interface? /** + * Updates the overflow areas of the frame. This can be called if an + * overflow area of the frame's children has changed without reflowing. + * @return PR_TRUE if either of the overflow areas for this frame have changed. + */ + virtual PRBool UpdateOverflow(); + + /** * Helper method used by block reflow to identify runs of text so * that proper word-breaking can be done. * @@ -2237,13 +2246,15 @@ * Store the overflow area in the frame's mOverflow.mVisualDeltas * fields or as a frame property in the frame manager so that it can * be retrieved later without reflowing the frame. + * + * @return true if either of the overflow areas have changed */ - void FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, - nsSize aNewSize); + PRBool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, + nsSize aNewSize); - void FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) { - FinishAndStoreOverflow(aMetrics->mOverflowAreas, - nsSize(aMetrics->width, aMetrics->height)); + PRBool FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) { + return FinishAndStoreOverflow(aMetrics->mOverflowAreas, + nsSize(aMetrics->width, aMetrics->height)); } /** @@ -2580,7 +2591,7 @@ virtual nscoord GetFlex(nsBoxLayoutState& aBoxLayoutState) = 0; virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) = 0; - virtual PRBool IsCollapsed(nsBoxLayoutState& aBoxLayoutState) = 0; + virtual PRBool IsCollapsed() = 0; // This does not alter the overflow area. If the caller is changing // the box size, the caller is responsible for updating the overflow // area. It's enough to just call Layout or SyncLayout on the @@ -2885,6 +2896,7 @@ mRect.height + mOverflow.mVisualDeltas.mBottom + mOverflow.mVisualDeltas.mTop); } + friend class nsCSSFrameConstructor; void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas); nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const; diff --git a/layout/mathml/nsMathMLContainerFrame.cpp b/layout/mathml/nsMathMLContainerFrame.cpp --- a/layout/mathml/nsMathMLContainerFrame.cpp +++ b/layout/mathml/nsMathMLContainerFrame.cpp @@ -874,6 +874,17 @@ FinishAndStoreOverflow(aMetrics); } +PRBool +nsMathMLContainerFrame::UpdateOverflow() +{ + // Our overflow areas may have changed, reflow the frame + PresContext()->PresShell()->FrameNeedsReflow( + this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); + + // As we're reflowing, there's no need to propagate this change + return PR_FALSE; +} + nsresult nsMathMLContainerFrame::ReflowChild(nsIFrame* aChildFrame, nsPresContext* aPresContext, diff --git a/layout/mathml/nsMathMLContainerFrame.h b/layout/mathml/nsMathMLContainerFrame.h --- a/layout/mathml/nsMathMLContainerFrame.h +++ b/layout/mathml/nsMathMLContainerFrame.h @@ -171,6 +171,8 @@ const nsRect& aDirtyRect, const nsDisplayListSet& aLists); + virtual PRBool UpdateOverflow(); + // Notification when an attribute is changed. The MathML module uses the // following paradigm: // diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -430,7 +430,8 @@ // FRAMECHANGE Structs: Display, XUL, Content, UserInterface, // Visibility, Outline, TableBorder, Table, Text, UIReset, Quotes nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE | - nsChangeHint_UpdateTransformLayer | nsChangeHint_UpdateOpacityLayer); + nsChangeHint_UpdateTransformLayer | nsChangeHint_UpdateOpacityLayer | + nsChangeHint_UpdateOverflow); DO_STRUCT_DIFFERENCE(Display); maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE | diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2213,16 +2213,17 @@ } else if (HasTransform()) { /* Otherwise, if we've kept the property lying around and we already had a - * transform, we need to see whether or not we've changed the transform. - * If so, we need to do a reflow and a repaint. The reflow is to recompute - * the overflow rect (which probably changed if the transform changed) - * and to redraw within the bounds of that new overflow rect. + * transform, we need to see whether or not we've changed the transform. If + * so, we need to recompute its overflow rect (which probably changed if + * the transform changed) and to redraw within the bounds of that new + * overflow rect. */ if (!mSpecifiedTransform != !aOther.mSpecifiedTransform || - (mSpecifiedTransform && *mSpecifiedTransform != *aOther.mSpecifiedTransform)) - NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, + (mSpecifiedTransform && *mSpecifiedTransform != *aOther.mSpecifiedTransform)) { + NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_UpdateTransformLayer)); - + } + for (PRUint8 index = 0; index < 3; ++index) if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) { NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, @@ -2268,7 +2269,7 @@ { // All the parts of FRAMECHANGE are present above in CalcDifference. return nsChangeHint(NS_STYLE_HINT_FRAMECHANGE | nsChangeHint_UpdateOpacityLayer | - nsChangeHint_UpdateTransformLayer); + nsChangeHint_UpdateTransformLayer | nsChangeHint_UpdateOverflow); } #endif diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -621,6 +621,17 @@ } } +PRBool +nsTableCellFrame::UpdateOverflow() +{ + nsRect bounds(nsPoint(0,0), GetSize()); + bounds.Inflate(GetBorderOverflow()); + nsOverflowAreas overflowAreas(bounds, bounds); + ConsiderChildOverflow(overflowAreas, mFrames.FirstChild()); + + return FinishAndStoreOverflow(overflowAreas, GetSize()); +} + // Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom', // length, percentage, and calc() values to 'baseline'. PRUint8 diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -242,6 +242,8 @@ void DecorateForSelection(nsRenderingContext& aRenderingContext, nsPoint aPt); + virtual PRBool UpdateOverflow(); + protected: /** implement abstract method on nsHTMLContainerFrame */ virtual PRIntn GetSkipSides() const; diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1871,6 +1871,26 @@ return rv; } +PRBool +nsTableFrame::UpdateOverflow() +{ + nsRect bounds(nsPoint(0, 0), GetSize()); + nsOverflowAreas overflowAreas(bounds, bounds); + + nsLayoutUtils::UnionChildOverflow(this, overflowAreas); + + // As above in Reflow, make sure the table overflow area includes the table + // rect, and check for collapsed borders leaking out + const nsStyleDisplay* display = mContent->GetPrimaryFrame()->GetStyleDisplay(); + if (display->IsTableClip()) { + nsMargin bcMargin = GetExcludedOuterBCBorder(); + bounds.Inflate(bcMargin); + } + overflowAreas.UnionAllWith(bounds); + + return FinishAndStoreOverflow(overflowAreas, GetSize()); +} + nsresult nsTableFrame::ReflowTable(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -508,6 +508,8 @@ const nsRect& aOrigVisualOverflow, PRBool aIsFirstReflow); + virtual PRBool UpdateOverflow(); + protected: /** protected constructor. diff --git a/layout/xul/base/src/grid/nsGrid.cpp b/layout/xul/base/src/grid/nsGrid.cpp --- a/layout/xul/base/src/grid/nsGrid.cpp +++ b/layout/xul/base/src/grid/nsGrid.cpp @@ -652,7 +652,7 @@ for (i=0; i < count; i++) { nsGridRow* row = GetRowAt(i,aIsHorizontal); - if (!row->IsCollapsed(aState)) { + if (!row->IsCollapsed()) { aFirstIndex = i; aFirstRow = row; break; @@ -663,7 +663,7 @@ for (i=count-1; i >= 0; i--) { nsGridRow* row = GetRowAt(i,aIsHorizontal); - if (!row->IsCollapsed(aState)) { + if (!row->IsCollapsed()) { aLastIndex = i; aLastRow = row; break; @@ -706,7 +706,7 @@ // borders padding into account if (box && !row->mIsBogus) { - if (!box->IsCollapsed(aState)) + if (!box->IsCollapsed()) { // get real border and padding. GetBorderAndPadding // is redefined on nsGridRowLeafFrame. If we called it here @@ -771,7 +771,7 @@ if (box) { // ignore collapsed children - if (!box->IsCollapsed(aState)) + if (!box->IsCollapsed()) { // include the margin of the columns. To the row // at this point border/padding and margins all added @@ -846,7 +846,7 @@ nsGridRow* row = GetRowAt(aIndex, aIsHorizontal); - if (row->IsCollapsed(aState)) + if (row->IsCollapsed()) return 0; if (row->IsPrefSet()) @@ -903,7 +903,7 @@ child = GetCellAt(aIndex,i); // ignore collapsed children - if (!child->IsCollapsed(aState)) + if (!child->IsCollapsed()) { nsSize childSize = child->GetPrefSize(aState); @@ -923,7 +923,7 @@ nsGridRow* row = GetRowAt(aIndex, aIsHorizontal); - if (row->IsCollapsed(aState)) + if (row->IsCollapsed()) return 0; if (row->IsMinSet()) @@ -978,7 +978,7 @@ child = GetCellAt(aIndex,i); // ignore collapsed children - if (!child->IsCollapsed(aState)) + if (!child->IsCollapsed()) { nsSize childSize = child->GetMinSize(aState); @@ -998,7 +998,7 @@ nsGridRow* row = GetRowAt(aIndex, aIsHorizontal); - if (row->IsCollapsed(aState)) + if (row->IsCollapsed()) return 0; if (row->IsMaxSet()) @@ -1053,7 +1053,7 @@ child = GetCellAt(aIndex,i); // ignore collapsed children - if (!child->IsCollapsed(aState)) + if (!child->IsCollapsed()) { nsSize min = child->GetMinSize(aState); nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState)); diff --git a/layout/xul/base/src/grid/nsGridCell.cpp b/layout/xul/base/src/grid/nsGridCell.cpp --- a/layout/xul/base/src/grid/nsGridCell.cpp +++ b/layout/xul/base/src/grid/nsGridCell.cpp @@ -150,10 +150,10 @@ PRBool -nsGridCell::IsCollapsed(nsBoxLayoutState& aState) +nsGridCell::IsCollapsed() { - return ((mBoxInColumn && mBoxInColumn->IsCollapsed(aState)) || - (mBoxInRow && mBoxInRow->IsCollapsed(aState))); + return ((mBoxInColumn && mBoxInColumn->IsCollapsed()) || + (mBoxInRow && mBoxInRow->IsCollapsed())); } diff --git a/layout/xul/base/src/grid/nsGridCell.h b/layout/xul/base/src/grid/nsGridCell.h --- a/layout/xul/base/src/grid/nsGridCell.h +++ b/layout/xul/base/src/grid/nsGridCell.h @@ -67,7 +67,7 @@ nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState); nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState); nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState); - PRBool IsCollapsed(nsBoxLayoutState& aBoxLayoutState); + PRBool IsCollapsed(); // accessors nsIBox* GetBoxInColumn() { return mBoxInColumn; } diff --git a/layout/xul/base/src/grid/nsGridRow.cpp b/layout/xul/base/src/grid/nsGridRow.cpp --- a/layout/xul/base/src/grid/nsGridRow.cpp +++ b/layout/xul/base/src/grid/nsGridRow.cpp @@ -82,8 +82,8 @@ } PRBool -nsGridRow::IsCollapsed(nsBoxLayoutState& aState) +nsGridRow::IsCollapsed() { - return mBox && mBox->IsCollapsed(aState); + return mBox && mBox->IsCollapsed(); } diff --git a/layout/xul/base/src/grid/nsGridRow.h b/layout/xul/base/src/grid/nsGridRow.h --- a/layout/xul/base/src/grid/nsGridRow.h +++ b/layout/xul/base/src/grid/nsGridRow.h @@ -68,7 +68,7 @@ PRBool IsMaxSet() { return (mMax != -1); } PRBool IsFlexSet() { return (mFlex != -1); } PRBool IsOffsetSet() { return (mTop != -1 && mBottom != -1); } - PRBool IsCollapsed(nsBoxLayoutState& aState); + PRBool IsCollapsed(); public: diff --git a/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp b/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp --- a/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp +++ b/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp @@ -170,7 +170,7 @@ nscoord bottomMargin = column->mBottomMargin; if (box) - collapsed = box->IsCollapsed(aState); + collapsed = box->IsCollapsed(); pref = pref - (left + right); if (pref < 0) diff --git a/layout/xul/base/src/nsBox.cpp b/layout/xul/base/src/nsBox.cpp --- a/layout/xul/base/src/nsBox.cpp +++ b/layout/xul/base/src/nsBox.cpp @@ -53,6 +53,7 @@ #include "nsIDocument.h" #include "nsITheme.h" #include "nsIServiceManager.h" +#include "nsIViewManager.h" #include "nsBoxLayout.h" #include "FrameLayerBuilder.h" @@ -435,7 +436,7 @@ nsSize pref(0,0); DISPLAY_PREF_SIZE(this, pref); - if (IsCollapsed(aState)) + if (IsCollapsed()) return pref; AddBorderAndPadding(pref); @@ -455,7 +456,7 @@ nsSize min(0,0); DISPLAY_MIN_SIZE(this, min); - if (IsCollapsed(aState)) + if (IsCollapsed()) return min; AddBorderAndPadding(min); @@ -478,7 +479,7 @@ nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE); DISPLAY_MAX_SIZE(this, maxSize); - if (IsCollapsed(aState)) + if (IsCollapsed()) return maxSize; AddBorderAndPadding(maxSize); @@ -520,14 +521,14 @@ nscoord nsBox::GetBoxAscent(nsBoxLayoutState& aState) { - if (IsCollapsed(aState)) + if (IsCollapsed()) return 0; return GetPrefSize(aState).height; } PRBool -nsBox::IsCollapsed(nsBoxLayoutState& aState) +nsBox::IsCollapsed() { return GetStyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE; } @@ -559,13 +560,21 @@ return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP; } +void +nsBox::UnionChildOverflow(nsOverflowAreas& aOverflowAreas) +{ + for (nsIFrame* kid = GetChildBox(); kid; kid = kid->GetNextBox()) { + nsOverflowAreas kidOverflow = + kid->GetOverflowAreas() + kid->GetPosition(); + aOverflowAreas.UnionWith(kidOverflow); + } +} + nsresult nsBox::SyncLayout(nsBoxLayoutState& aState) { /* - PRBool collapsed = PR_FALSE; - IsCollapsed(aState, collapsed); - if (collapsed) { + if (IsCollapsed()) { CollapseChild(aState, this, PR_TRUE); return NS_OK; } @@ -595,17 +604,13 @@ else { nsRect rect(nsPoint(0, 0), GetSize()); nsOverflowAreas overflowAreas(rect, rect); - if (!DoesClipChildren() && !IsCollapsed(aState)) { + if (!DoesClipChildren() && !IsCollapsed()) { // See if our child frames caused us to overflow after being laid // out. If so, store the overflow area. This normally can't happen // in XUL, but it can happen with the CSS 'outline' property and // possibly with other exotic stuff (e.g. relatively positioned // frames in HTML inside XUL). - for (nsIFrame* kid = GetChildBox(); kid; kid = kid->GetNextBox()) { - nsOverflowAreas kidOverflow = - kid->GetOverflowAreas() + kid->GetPosition(); - overflowAreas.UnionWith(kidOverflow); - } + UnionChildOverflow(overflowAreas); } FinishAndStoreOverflow(overflowAreas, GetSize()); @@ -627,6 +632,32 @@ return NS_OK; } +PRBool +nsBox::UpdateOverflow() +{ + nsRect bounds(nsPoint(0,0), GetSize()); + nsOverflowAreas overflowAreas(bounds, bounds); + + if (!DoesClipChildren() && !IsCollapsed()) { + UnionChildOverflow(overflowAreas); + } + + if (FinishAndStoreOverflow(overflowAreas, GetSize())) { + PRUint32 flags = 0; + GetLayoutFlags(flags); + + nsIView* view = GetView(); + if (view && (flags & NS_FRAME_NO_SIZE_VIEW) == 0) { + // Make sure the frame's view is properly sized. + nsIViewManager* vm = view->GetViewManager(); + vm->ResizeView(view, overflowAreas.VisualOverflow(), PR_TRUE); + } + return PR_TRUE; + } + + return PR_FALSE; +} + nsresult nsIFrame::Redraw(nsBoxLayoutState& aState, const nsRect* aDamageRect) diff --git a/layout/xul/base/src/nsBox.h b/layout/xul/base/src/nsBox.h --- a/layout/xul/base/src/nsBox.h +++ b/layout/xul/base/src/nsBox.h @@ -62,7 +62,7 @@ virtual nsSize GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState); - virtual PRBool IsCollapsed(nsBoxLayoutState& aBoxLayoutState); + virtual PRBool IsCollapsed(); virtual void SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect, PRBool aRemoveOverflowAreas = PR_FALSE); @@ -95,6 +95,9 @@ virtual PRBool DoesClipChildren(); virtual PRBool ComputesOwnOverflowArea() = 0; + void UnionChildOverflow(nsOverflowAreas& aOverflowAreas); + virtual PRBool UpdateOverflow(); + NS_HIDDEN_(nsresult) SyncLayout(nsBoxLayoutState& aBoxLayoutState); PRBool DoesNeedRecalc(const nsSize& aSize); diff --git a/layout/xul/base/src/nsBoxFrame.cpp b/layout/xul/base/src/nsBoxFrame.cpp --- a/layout/xul/base/src/nsBoxFrame.cpp +++ b/layout/xul/base/src/nsBoxFrame.cpp @@ -779,7 +779,7 @@ PropagateDebug(aBoxLayoutState); #endif - if (IsCollapsed(aBoxLayoutState)) + if (IsCollapsed()) return size; // if the size was not completely redefined in CSS then ask our children @@ -815,7 +815,7 @@ PropagateDebug(aBoxLayoutState); #endif - if (IsCollapsed(aBoxLayoutState)) + if (IsCollapsed()) return 0; if (mLayoutManager) @@ -842,7 +842,7 @@ PropagateDebug(aBoxLayoutState); #endif - if (IsCollapsed(aBoxLayoutState)) + if (IsCollapsed()) return size; // if the size was not completely redefined in CSS then ask our children @@ -882,7 +882,7 @@ PropagateDebug(aBoxLayoutState); #endif - if (IsCollapsed(aBoxLayoutState)) + if (IsCollapsed()) return size; // if the size was not completely redefined in CSS then ask our children @@ -1502,7 +1502,7 @@ nsBoxLayoutState state(GetPresContext()); nscoord flex = kid->GetFlex(state); - if (!kid->IsCollapsed(state)) { + if (!kid->IsCollapsed()) { aRenderingContext.SetColor(NS_RGB(255,255,255)); if (isHorizontal) diff --git a/layout/xul/base/src/nsMenuFrame.cpp b/layout/xul/base/src/nsMenuFrame.cpp --- a/layout/xul/base/src/nsMenuFrame.cpp +++ b/layout/xul/base/src/nsMenuFrame.cpp @@ -1330,7 +1330,7 @@ PRBool nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize) { - if (!IsCollapsed(aState)) { + if (!IsCollapsed()) { PRBool widthSet, heightSet; nsSize tmpSize(-1, 0); nsIBox::AddCSSPrefSize(this, tmpSize, widthSet, heightSet); diff --git a/layout/xul/base/src/nsSprocketLayout.cpp b/layout/xul/base/src/nsSprocketLayout.cpp --- a/layout/xul/base/src/nsSprocketLayout.cpp +++ b/layout/xul/base/src/nsSprocketLayout.cpp @@ -204,7 +204,7 @@ { // See if we are collapsed. If we are, then simply iterate over all our // children and give them a rect of 0 width and height. - if (aBox->IsCollapsed(aState)) { + if (aBox->IsCollapsed()) { nsIBox* child = aBox->GetChildBox(); while(child) { @@ -741,7 +741,7 @@ flex = child->GetFlex(aState); currentBox->flex = flex; - currentBox->collapsed = child->IsCollapsed(aState); + currentBox->collapsed = child->IsCollapsed(); } else { flex = start->flex; start = start->next; @@ -773,7 +773,7 @@ nsSize minSize(0,0); nsSize maxSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE); nscoord ascent = 0; - PRBool collapsed = child->IsCollapsed(aState); + PRBool collapsed = child->IsCollapsed(); if (!collapsed) { // only one flexible child? Cool we will just make its preferred size @@ -1361,7 +1361,7 @@ while (child) { // ignore collapsed children - if (!child->IsCollapsed(aState)) + if (!child->IsCollapsed()) { nsSize pref = child->GetPrefSize(aState); AddMargin(child, pref); @@ -1418,7 +1418,7 @@ while (child) { // ignore collapsed children - if (!child->IsCollapsed(aState)) + if (!child->IsCollapsed()) { nsSize min = child->GetMinSize(aState); nsSize pref(0,0); @@ -1487,7 +1487,7 @@ while (child) { // ignore collapsed children - if (!child->IsCollapsed(aState)) + if (!child->IsCollapsed()) { // if completely redefined don't even ask our child for its size. nsSize min = child->GetMinSize(aState); @@ -1548,7 +1548,7 @@ while (child) { // ignore collapsed children - //if (!child->IsCollapsed(aState)) + //if (!child->IsCollapsed()) //{ // if completely redefined don't even ask our child for its size. nscoord ascent = child->GetBoxAscent(aState);