Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 156705 Details for
Bug 251162
[patch]
patch representing current status
patch (text/plain), 143.89 KB, created by
Robert O'Callahan (:roc) (email my personal email if necessary)
(
hide
)
Description:
patch representing current status
Filename:
MIME Type:
Creator:
Robert O'Callahan (:roc) (email my personal email if necessary)
Size:
143.89 KB
patch
obsolete
>Index: content/shared/public/nsCSSAnonBoxList.h >=================================================================== >RCS file: /cvsroot/mozilla/content/shared/public/nsCSSAnonBoxList.h,v >retrieving revision 3.8 >diff -u -t -p -8 -r3.8 nsCSSAnonBoxList.h >--- content/shared/public/nsCSSAnonBoxList.h 15 May 2004 05:09:37 -0000 3.8 >+++ content/shared/public/nsCSSAnonBoxList.h 21 Aug 2004 22:50:55 -0000 >@@ -78,16 +78,17 @@ CSS_ANON_BOX(tableRowGroup, ":-moz-table > CSS_ANON_BOX(tableRow, ":-moz-table-row") > > CSS_ANON_BOX(canvas, ":-moz-canvas") > CSS_ANON_BOX(pageBreak, ":-moz-pagebreak") > CSS_ANON_BOX(page, ":-moz-page") > CSS_ANON_BOX(pageContent, ":-moz-pagecontent") > CSS_ANON_BOX(pageSequence, ":-moz-page-sequence") > CSS_ANON_BOX(scrolledContent, ":-moz-scrolled-content") >+CSS_ANON_BOX(columnContent, ":-moz-column-content") > CSS_ANON_BOX(viewport, ":-moz-viewport") > CSS_ANON_BOX(viewportScroll, ":-moz-viewport-scroll") > CSS_ANON_BOX(selectScrolledContent, ":-moz-select-scrolled-content") > > #ifdef MOZ_XUL > CSS_ANON_BOX(moztreecolumn, ":-moz-tree-column") > CSS_ANON_BOX(moztreerow, ":-moz-tree-row") > CSS_ANON_BOX(moztreeseparator, ":-moz-tree-separator") >Index: content/shared/public/nsLayoutAtomList.h >=================================================================== >RCS file: /cvsroot/mozilla/content/shared/public/nsLayoutAtomList.h,v >retrieving revision 1.86 >diff -u -t -p -8 -r1.86 nsLayoutAtomList.h >--- content/shared/public/nsLayoutAtomList.h 27 Jul 2004 23:31:08 -0000 1.86 >+++ content/shared/public/nsLayoutAtomList.h 21 Aug 2004 22:50:55 -0000 >@@ -92,16 +92,17 @@ LAYOUT_ATOM(documentFragmentNodeName, "# > > // Alphabetical list of frame types > LAYOUT_ATOM(areaFrame, "AreaFrame") > LAYOUT_ATOM(bcTableCellFrame, "BCTableCellFrame") // table cell in border collapsing model > LAYOUT_ATOM(blockFrame, "BlockFrame") > LAYOUT_ATOM(boxFrame, "BoxFrame") > LAYOUT_ATOM(brFrame, "BRFrame") > LAYOUT_ATOM(bulletFrame, "BulletFrame") >+LAYOUT_ATOM(columnFrame, "ColumnFrame") > LAYOUT_ATOM(fieldSetFrame, "FieldSetFrame") > LAYOUT_ATOM(gfxButtonControlFrame, "gfxButtonControlFrame") > LAYOUT_ATOM(subDocumentFrame, "subDocumentFrame") > LAYOUT_ATOM(imageBoxFrame, "ImageBoxFrame") > LAYOUT_ATOM(imageFrame, "ImageFrame") > LAYOUT_ATOM(imageControlFrame, "ImageControlFrame") > LAYOUT_ATOM(inlineFrame, "InlineFrame") > LAYOUT_ATOM(legendFrame, "LegendFrame") >Index: content/shared/src/nsStyleStruct.cpp >=================================================================== >RCS file: /cvsroot/mozilla/content/shared/src/nsStyleStruct.cpp,v >retrieving revision 3.98 >diff -u -t -p -8 -r3.98 nsStyleStruct.cpp >--- content/shared/src/nsStyleStruct.cpp 4 Aug 2004 03:23:35 -0000 3.98 >+++ content/shared/src/nsStyleStruct.cpp 21 Aug 2004 22:50:59 -0000 >@@ -745,22 +745,22 @@ nsStyleColumn::nsStyleColumn(const nsSty > { > memcpy((nsStyleColumn*)this, &aSource, sizeof(nsStyleColumn)); > } > > nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const > { > if ((mColumnWidth.GetUnit() == eStyleUnit_Auto) > != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) || >- (mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) >- != (aOther.mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO)) >+ mColumnCount != aOther.mColumnCount) >+ // We force column count changes to do a reframe, because it's tricky to handle >+ // some edge cases where the column count gets smaller and content overflows > return nsChangeHint_ReconstructFrame; > >- if (mColumnCount != aOther.mColumnCount || >- mColumnWidth != aOther.mColumnWidth || >+ if (mColumnWidth != aOther.mColumnWidth || > mColumnGap != aOther.mColumnGap) > return nsChangeHint_ReflowFrame; > > return NS_STYLE_HINT_NONE; > } > > #ifdef MOZ_SVG > // -------------------- >Index: layout/base/public/nsHTMLReflowState.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/public/nsHTMLReflowState.h,v >retrieving revision 3.40 >diff -u -t -p -8 -r3.40 nsHTMLReflowState.h >--- layout/base/public/nsHTMLReflowState.h 31 Jul 2004 23:15:09 -0000 3.40 >+++ layout/base/public/nsHTMLReflowState.h 21 Aug 2004 22:51:05 -0000 >@@ -239,16 +239,18 @@ struct nsHTMLReflowState { > > // This value keeps track of how deeply nested a given reflow state > // is from the top of the frame tree. > PRInt16 mReflowDepth; > > struct ReflowStateFlags { > PRUint16 mSpecialHeightReflow:1; // used by tables to communicate special reflow (in process) to handle > // percent height frames inside cells which may not have computed heights >+ PRUint16 mNextInFlowUntouched:1; // nothing in the frame's next-in-flow (or its descendants) >+ // is changing > PRUint16 mIsTopOfPage:1; // is the current context at the top of a page? > PRUint16 mBlinks:1; // Keep track of text-decoration: blink > PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages > PRUint16 mUnused:12; // for future use > } mFlags; > > #ifdef IBMBIDI > nscoord mRightEdge; >Index: layout/base/public/nsLayoutUtils.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/public/nsLayoutUtils.h,v >retrieving revision 3.13 >diff -u -t -p -8 -r3.13 nsLayoutUtils.h >--- layout/base/public/nsLayoutUtils.h 6 Aug 2004 15:55:17 -0000 3.13 >+++ layout/base/public/nsLayoutUtils.h 21 Aug 2004 22:51:05 -0000 >@@ -194,12 +194,17 @@ public: > > nsRefPtr<nsStyleContext> pseudoContext; > if (aContent) { > pseudoContext = aPresContext->StyleSet()-> > ProbePseudoStyleFor(aContent, aPseudoElement, aStyleContext); > } > return pseudoContext != nsnull; > } >- >+ >+ /** >+ * If this frame is a placeholder for a float, then return the float, >+ * otherwise return nsnull. >+ */ >+ static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPossiblePlaceholder); > }; > > #endif // nsLayoutUtils_h__ >Index: layout/base/src/nsLayoutUtils.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/src/nsLayoutUtils.cpp,v >retrieving revision 3.17 >diff -u -t -p -8 -r3.17 nsLayoutUtils.cpp >--- layout/base/src/nsLayoutUtils.cpp 6 Aug 2004 15:55:17 -0000 3.17 >+++ layout/base/src/nsLayoutUtils.cpp 21 Aug 2004 22:51:05 -0000 >@@ -40,16 +40,17 @@ > #include "nsPresContext.h" > #include "nsIContent.h" > #include "nsFrameList.h" > #include "nsLayoutAtoms.h" > #include "nsIAtom.h" > #include "nsCSSPseudoElements.h" > #include "nsIView.h" > #include "nsIScrollableView.h" >+#include "nsPlaceholderFrame.h" > > /** > * A namespace class for static layout utilities. > */ > > /** > * GetFirstChildFrame returns the first "real" child frame of a > * given frame. It will descend down into pseudo-frames (unless the >@@ -169,16 +170,33 @@ nsLayoutUtils::GetPageFrame(nsIFrame* aF > for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) { > if (frame->GetType() == nsLayoutAtoms::pageFrame) { > return frame; > } > } > return nsnull; > } > >+nsIFrame* >+nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) { >+ if (nsLayoutAtoms::placeholderFrame != aFrame->GetType()) { >+ return nsnull; >+ } >+ >+ nsIFrame *outOfFlowFrame = >+ NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame(); >+ // This is a hack. >+ if (outOfFlowFrame && >+ !outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) { >+ return outOfFlowFrame; >+ } >+ >+ return nsnull; >+} >+ > // static > PRBool > nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent, > nsIFrame* aFrame, > nsIAtom* aPseudoElement) > { > NS_PRECONDITION(aFrame, "Must have a frame"); > NS_PRECONDITION(aPseudoElement, "Must have a pseudo name"); >Index: layout/base/src/nsSpaceManager.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/src/nsSpaceManager.cpp,v >retrieving revision 3.58 >diff -u -t -p -8 -r3.58 nsSpaceManager.cpp >--- layout/base/src/nsSpaceManager.cpp 31 Jul 2004 23:15:09 -0000 3.58 >+++ layout/base/src/nsSpaceManager.cpp 21 Aug 2004 22:51:08 -0000 >@@ -41,16 +41,17 @@ > #include "nsSize.h" > #include <stdlib.h> > #include "nsVoidArray.h" > #include "nsIFrame.h" > #include "nsString.h" > #include "nsIPresShell.h" > #include "nsMemory.h" > #include "nsHTMLReflowState.h" >+#include "nsHashSets.h" > #ifdef DEBUG > #include "nsIFrameDebug.h" > #endif > > ///////////////////////////////////////////////////////////////////////////// > // BandList > > PRInt32 nsSpaceManager::sCachedSpaceManagerCount = 0; >@@ -839,16 +840,40 @@ nsSpaceManager::AddRectRegion(nsIFrame* > } > > // Insert the band rect > InsertBandRect(bandRect); > return NS_OK; > } > > nsresult >+nsSpaceManager::RemoveRegions(nsIFrame* aFrameList) { >+ nsVoidHashSet frameSet; >+ >+ frameSet.Init(1); >+ for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) { >+ frameSet.Put(f); >+ } >+ >+ // Pop frame regions off as long as they're in the set of frames to >+ // remove >+ while (mFrameInfoMap && frameSet.Contains(mFrameInfoMap->mFrame)) { >+ RemoveRegion(mFrameInfoMap->mFrame); >+ } >+ >+#ifdef DEBUG >+ for (FrameInfo* frameInfo = mFrameInfoMap; frameInfo; >+ frameInfo = frameInfo->mNext) { >+ NS_ASSERTION(!frameSet.Contains(frameInfo->mFrame), >+ "Frame region deletion was requested but we couldn't delete it"); >+ } >+#endif >+} >+ >+nsresult > nsSpaceManager::RemoveRegion(nsIFrame* aFrame) > { > // Get the frame info associated with aFrame > FrameInfo* frameInfo = GetFrameInfoFor(aFrame); > > if (nsnull == frameInfo) { > NS_WARNING("no region associated with aFrame"); > return NS_ERROR_INVALID_ARG; >Index: layout/base/src/nsSpaceManager.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/src/nsSpaceManager.h,v >retrieving revision 3.37 >diff -u -t -p -8 -r3.37 nsSpaceManager.h >--- layout/base/src/nsSpaceManager.h 31 Jul 2004 23:15:09 -0000 3.37 >+++ layout/base/src/nsSpaceManager.h 21 Aug 2004 22:51:09 -0000 >@@ -247,22 +247,34 @@ public: > * @param aUnavailableSpace the bounding rect of the unavailable space > * @return NS_OK if successful > * NS_ERROR_FAILURE if there is already a region tagged with aFrame > */ > nsresult AddRectRegion(nsIFrame* aFrame, > const nsRect& aUnavailableSpace); > > /** >+ * Remove the regions associated with this frame and its >+ * next-sibling list. Some of the frames may never have been added; >+ * we just skip those. This is not fully general; it only works as >+ * long as the N frames to be removed are the last N frames to have >+ * been added; if there's a frame in the middle of them that should >+ * not be removed, YOU LOSE. >+ */ >+ nsresult RemoveRegions(nsIFrame* aFrameList); >+ >+protected: >+ /** > * Remove the region associated with aFrane. > * >+ * doesn't work in the general case! >+ * > * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region > * tagged with aFrame > */ >-protected: /* doesn't work in the general case */ > nsresult RemoveRegion(nsIFrame* aFrame); > > public: > /** > * Clears the list of regions representing the unavailable space. > */ > void ClearRegions(); > >Index: layout/html/base/src/Makefile.in >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/Makefile.in,v >retrieving revision 1.97 >diff -u -t -p -8 -r1.97 Makefile.in >--- layout/html/base/src/Makefile.in 18 Apr 2004 14:30:23 -0000 1.97 >+++ layout/html/base/src/Makefile.in 21 Aug 2004 22:51:09 -0000 >@@ -85,16 +85,17 @@ CPPSRCS = \ > nsAbsoluteContainingBlock.cpp \ > nsAreaFrame.cpp \ > nsBRFrame.cpp \ > nsBlockBandData.cpp \ > nsBlockFrame.cpp \ > nsBlockReflowContext.cpp \ > nsBlockReflowState.cpp \ > nsBulletFrame.cpp \ >+ nsColumnFrame.cpp \ > nsContainerFrame.cpp \ > nsFirstLetterFrame.cpp \ > nsFrame.cpp \ > nsFrameManager.cpp \ > nsGfxScrollFrame.cpp \ > nsHTMLContainerFrame.cpp \ > nsHTMLFrame.cpp \ > nsHTMLReflowCommand.cpp \ >Index: layout/html/base/src/nsBlockFrame.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/nsBlockFrame.cpp,v >retrieving revision 3.641 >diff -u -t -p -8 -r3.641 nsBlockFrame.cpp >--- layout/html/base/src/nsBlockFrame.cpp 11 Aug 2004 00:17:54 -0000 3.641 >+++ layout/html/base/src/nsBlockFrame.cpp 21 Aug 2004 22:51:27 -0000 >@@ -74,16 +74,17 @@ > #include "plstr.h" > #include "nsGUIEvent.h" > #include "nsLayoutErrors.h" > #include "nsAutoPtr.h" > #include "nsIServiceManager.h" > #ifdef ACCESSIBILITY > #include "nsIAccessibilityService.h" > #endif >+#include "nsLayoutUtils.h" > > #ifdef IBMBIDI > #include "nsBidiPresUtils.h" > #endif // IBMBIDI > > #include "nsIDOMHTMLBodyElement.h" > #include "nsIDOMHTMLHtmlElement.h" > >@@ -654,16 +655,22 @@ nsBlockFrame::Reflow(nsPresContext* > // Factor the absolutely positioned child bounds into the overflow area > ComputeCombinedArea(aReflowState, aMetrics); > nsRect childBounds; > mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); > aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); > > FinishAndStoreOverflow(&aMetrics); > >+#ifdef DEBUG >+ if (gNoisy) { >+ gNoiseIndent--; >+ } >+#endif >+ > return NS_OK; > } > } > > // OK, some lines may be reflowed. Blow away any saved line cursor because > // we may invalidate the nondecreasing combinedArea.y/yMost invariant, > // and we may even delete the line with the line cursor. > ClearLineCursor(); >@@ -716,23 +723,27 @@ nsBlockFrame::Reflow(nsPresContext* > } > } > #endif // IBMBIDI > RenumberLists(aPresContext); > } > > nsresult rv = NS_OK; > >+ // ALWAYS drain overflow. We never want to leave the previnflow's >+ // overflow lines hanging around; block reflow depends on the >+ // overflow line lists being cleared out between reflow passes. >+ DrainOverflowLines(); >+ > switch (aReflowState.reason) { > case eReflowReason_Initial: > #ifdef NOISY_REFLOW_REASON > ListTag(stdout); > printf(": reflow=initial\n"); > #endif >- DrainOverflowLines(aPresContext); > rv = PrepareInitialReflow(state); > mState &= ~NS_FRAME_FIRST_REFLOW; > break; > > case eReflowReason_Dirty: > // Do nothing; the dirty lines will already have been marked. > break; > >@@ -791,39 +802,44 @@ nsBlockFrame::Reflow(nsPresContext* > #ifdef NOISY_REFLOW_REASON > printf("\n"); > #endif > > break; > } > > case eReflowReason_StyleChange: >- DrainOverflowLines(aPresContext); > rv = PrepareStyleChangedReflow(state); > break; > > case eReflowReason_Resize: > default: > #ifdef NOISY_REFLOW_REASON > ListTag(stdout); > printf(": reflow=resize (%d)\n", aReflowState.reason); > #endif >- DrainOverflowLines(aPresContext); > rv = PrepareResizeReflow(state); > break; > } > > NS_ASSERTION(NS_SUCCEEDED(rv), "setting up reflow failed"); > if (NS_FAILED(rv)) return rv; > > // Now reflow... > rv = ReflowDirtyLines(state); > NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); > if (NS_FAILED(rv)) return rv; > >+ if (NS_FRAME_IS_NOT_COMPLETE(state.mReflowStatus) >+ || NS_FRAME_IS_TRUNCATED(state.mReflowStatus)) { >+ if (GetOverflowLines() || GetOverflowPlaceholders()) { >+ state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; >+ } >+ } >+ > // If the block is complete, put continuted floats in the closest ancestor > // block that uses the same space manager and leave the block complete; this > // allows subsequent lines on the page to be impacted by floats. If the > // block is incomplete or there is no ancestor using the same space manager, > // put continued floats at the beginning of the first overflow line. > nsFrameList* overflowPlace = nsnull; > if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) && > (overflowPlace = RemoveOverflowPlaceholders())) { >@@ -889,17 +905,17 @@ nsBlockFrame::Reflow(nsPresContext* > // Create a line, put the floats in it, and then push. > nsLineBox* newLine = state.NewLineBox(overflowPlace->FirstChild(), numOverflowPlace, PR_FALSE); > if (!newLine) > return NS_ERROR_OUT_OF_MEMORY; > mLines.push_back(newLine); > nsLineList::iterator nextToLastLine = ----end_lines(); > PushLines(state, nextToLastLine); > } >- state.mReflowStatus = NS_FRAME_NOT_COMPLETE; >+ state.mReflowStatus |= NS_FRAME_NOT_COMPLETE; > } > delete overflowPlace; > } > > if (NS_FRAME_IS_NOT_COMPLETE(state.mReflowStatus)) { > if (NS_STYLE_OVERFLOW_CLIP == aReflowState.mStyleDisplay->mOverflow) { > state.mReflowStatus = NS_FRAME_COMPLETE; > } >@@ -907,18 +923,18 @@ nsBlockFrame::Reflow(nsPresContext* > #ifdef DEBUG_kipp > ListTag(stdout); printf(": block is not complete\n"); > #endif > } > } > > // XXX_perf get rid of this! This is one of the things that makes > // incremental reflow O(N^2). >- BuildFloatList(); >- >+ BuildFloatList(state); >+ > // Compute our final size > ComputeFinalSize(aReflowState, state, aMetrics); > FinishAndStoreOverflow(&aMetrics); > > // see if verifyReflow is enabled, and if so store off the space manager pointer > #ifdef DEBUG > PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); > if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) >@@ -932,19 +948,16 @@ nsBlockFrame::Reflow(nsPresContext* > reflowState.mSpaceManager, > nsnull /* should be nsSpaceManagerDestroyer*/); > > autoSpaceManager.DebugOrphanSpaceManager(); > } > } > #endif > >- // Determine if we need to repaint our border, background or outline >- CheckInvalidateSizeChange(aPresContext, aMetrics, aReflowState); >- > // Let the absolutely positioned container reflow any absolutely positioned > // child frames that need to be reflowed, e.g., elements with a percentage > // based width/height > // We want to do this under either of two conditions: > // 1. If we didn't do the incremental reflow above. > // 2. If our size changed. > // Even though it's the padding edge that's the containing block, we > // can use our rect (the border edge) since if the border style >@@ -969,16 +982,20 @@ nsBlockFrame::Reflow(nsPresContext* > mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); > } > > // Factor the absolutely positioned child bounds into the overflow area > aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); > > FinishAndStoreOverflow(&aMetrics); > } >+ >+ // Determine if we need to repaint our border, background or outline >+ CheckInvalidateSizeChange(aPresContext, aMetrics, aReflowState); >+ > // Clear the space manager pointer in the block reflow state so we > // don't waste time translating the coordinate system back on a dead > // space manager. > if (NS_BLOCK_SPACE_MGR & mState) > state.mSpaceManager = nsnull; > > aStatus = state.mReflowStatus; > >@@ -1367,68 +1384,39 @@ nsBlockFrame::ComputeFinalSize(const nsH > > void > nsBlockFrame::ComputeCombinedArea(const nsHTMLReflowState& aReflowState, > nsHTMLReflowMetrics& aMetrics) > { > // Compute the combined area of our children > // XXX_perf: This can be done incrementally. It is currently one of > // the things that makes incremental reflow O(N^2). >- nscoord xa = 0, ya = 0, xb = aMetrics.width, yb = aMetrics.height; >+ nsRect area(0, 0, aMetrics.width, aMetrics.height); > if (NS_STYLE_OVERFLOW_CLIP != aReflowState.mStyleDisplay->mOverflow) { > for (line_iterator line = begin_lines(), line_end = end_lines(); > line != line_end; >- ++line) >- { >- // Compute min and max x/y values for the reflowed frame's >- // combined areas >- nsRect lineCombinedArea(line->GetCombinedArea()); >- nscoord x = lineCombinedArea.x; >- nscoord y = lineCombinedArea.y; >- nscoord xmost = x + lineCombinedArea.width; >- nscoord ymost = y + lineCombinedArea.height; >- if (x < xa) { >- xa = x; >- } >- if (xmost > xb) { >- xb = xmost; >- } >- if (y < ya) { >- ya = y; >- } >- if (ymost > yb) { >- yb = ymost; >- } >+ ++line) { >+ area.UnionRect(area, line->GetCombinedArea()); > } > > // Factor the bullet in; normally the bullet will be factored into > // the line-box's combined area. However, if the line is a block > // line then it won't; if there are no lines, it won't. So just > // factor it in anyway (it can't hurt if it was already done). > // XXXldb Can we just fix GetCombinedArea instead? > if (mBullet) { >- nsRect r = mBullet->GetRect(); >- if (r.x < xa) xa = r.x; >- if (r.y < ya) ya = r.y; >- nscoord xmost = r.XMost(); >- if (xmost > xb) xb = xmost; >- nscoord ymost = r.YMost(); >- if (ymost > yb) yb = ymost; >+ area.UnionRect(area, mBullet->GetRect()); > } > } > #ifdef NOISY_COMBINED_AREA > ListTag(stdout); >- printf(": ca=%d,%d,%d,%d\n", xa, ya, xb-xa, yb-ya); >+ printf(": ca=%d,%d,%d,%d\n", area.x, area.y, area.width, area.height); > #endif > >- aMetrics.mOverflowArea.x = xa; >- aMetrics.mOverflowArea.y = ya; >- aMetrics.mOverflowArea.width = xb - xa; >- aMetrics.mOverflowArea.height = yb - ya; >- >+ aMetrics.mOverflowArea = area; > } > > nsresult > nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) > { > PrepareResizeReflow(aState); > return NS_OK; > } >@@ -1699,17 +1687,17 @@ nsBlockFrame::PrepareResizeReflow(nsBloc > { > // See if we can try and avoid marking all the lines as dirty > PRBool tryAndSkipLines = PR_FALSE; > > // we need to calculate if any part of then block itself > // is impacted by a float (bug 19579) > aState.GetAvailableSpace(); > >- // See if this is this a constrained resize reflow that is not impacted by floats >+ // See if this is a constrained resize reflow that is not impacted by floats > if ((! aState.IsImpactedByFloat()) && > (aState.mReflowState.reason == eReflowReason_Resize) && > (NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) { > > // If the text is left-aligned, then we try and avoid reflowing the lines > const nsStyleText* styleText = GetStyleText(); > > if ((NS_STYLE_TEXT_ALIGN_LEFT == styleText->mTextAlign) || >@@ -1839,17 +1827,17 @@ nsBlockFrame::FindLineFor(nsIFrame* aFra > // float's placeholder, then we've found our line. > if (line->HasFloats()) { > for (nsFloatCache *fc = line->GetFirstFloat(); > fc != nsnull; > fc = fc->Next()) { > if (aFrame == fc->mPlaceholder->GetOutOfFlowFrame()) > return line; > } >- } >+ } > } > > return line_end; > } > > /** > * Propagate reflow "damage" from from earlier lines to the current > * line. The reflow damage comes from the following sources: >@@ -1936,16 +1924,54 @@ WrappedLinesAreDirty(nsLineList::iterato > } > } > > return PR_FALSE; > } > > static void PlaceFrameView(nsPresContext* aPresContext, nsIFrame* aFrame); > >+static void ReparentFrame(nsIFrame* aFrame, nsIFrame* aNewParent, nsIFrame* aOldParent) { >+ aFrame->SetParent(aNewParent); >+ >+ // When pushing and pulling frames we need to check for whether any >+ // views need to be reparented >+ nsHTMLContainerFrame::ReparentFrameView(aFrame->GetPresContext(), aFrame, >+ aOldParent, aNewParent); >+} >+ >+static void CollectFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, >+ nsIFrame** aHead, nsIFrame** aTail); >+ >+void >+nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, >+ nsBlockFrame* aOldParent, PRBool aFromOverflow) { >+ nsIFrame* head = nsnull; >+ nsIFrame* tail = nsnull; >+ CollectFloats(aFirstFrame, aOldParent, &head, &tail); >+ if (head) { >+ if (aFromOverflow) { >+ nsFrameList* oofs = aOldParent->GetOverflowOutOfFlows(); >+ NS_ASSERTION(oofs && head == oofs->FirstChild(), "Floats out of order"); >+ if (tail->GetNextSibling()) { >+ oofs->SetFrames(tail->GetNextSibling()); >+ } else { >+ delete aOldParent->RemoveOverflowOutOfFlows(); >+ } >+ } else { >+ NS_ASSERTION(head == aOldParent->mFloats.FirstChild(), "Floats out of order"); >+ aOldParent->mFloats.SetFrames(tail->GetNextSibling()); >+ } >+ for (nsIFrame* f = head; f != tail->GetNextSibling(); >+ f = f->GetNextSibling()) { >+ ReparentFrame(f, this, aOldParent); >+ } >+ } >+} >+ > /** > * Reflow the dirty lines > */ > nsresult > nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) > { > nsresult rv = NS_OK; > PRBool keepGoing = PR_TRUE; >@@ -1985,16 +2011,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe > // dirty > nscoord deltaY = 0; > > // whether we did NOT reflow the previous line and thus we need to > // recompute the carried out margin before the line if we want to > // reflow it or if its previous margin is dirty > PRBool needToRecoverState = PR_FALSE; > >+ PRBool lastLineMovedUp = PR_FALSE; >+ > // Reflow the lines that are already ours > line_iterator line = begin_lines(), line_end = end_lines(); > for ( ; line != line_end; ++line, aState.AdvanceToNextLine()) { > #ifdef DEBUG > if (gNoisyReflow) { > nsRect lca(line->GetCombinedArea()); > IndentBy(stdout, gNoiseIndent); > printf("line=%p mY=%d dirty=%s oldBounds={%d,%d,%d,%d} oldCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n", >@@ -2005,22 +2033,20 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe > lca.x, lca.y, lca.width, lca.height, > deltaY, aState.mPrevBottomMargin.get()); > gNoiseIndent++; > } > #endif > > // If we're supposed to update our maximum width, then we'll also need to > // reflow this line if it's line wrapped and any of the continuing lines >- // are dirty. If we are printing (constrained height), always reflow >- // the line. >+ // are dirty. > // XXXperf XXXldb Check that the previous line was not wrapped > // before doing this check (it's O(N^2) as written now). >- if ((NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight) || >- (!line->IsDirty() && >+ if ((!line->IsDirty() && > aState.GetFlag(BRS_COMPUTEMAXWIDTH) && > ::WrappedLinesAreDirty(line, line_end))) { > line->MarkDirty(); > } > > // Make sure |aState.mPrevBottomMargin| is at the correct position > // before calling PropagateFloatDamage. > if (needToRecoverState && >@@ -2039,94 +2065,108 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe > ++line; > > // We need to reconstruct the bottom margin only if we didn't > // reflow the previous line and we do need to reflow (or repair > // the top position of) the next line. > aState.ReconstructMarginAbove(line); > } > >- if (line->IsPreviousMarginDirty() && !line->IsDirty()) { >- // If the previous margin is dirty and we're not going to reflow >- // the line we need to pull out the correct top margin and set >- // |deltaY| correctly. >- // If there's float damage we might end up doing this work twice, >- // but whatever... >- if (line->IsBlock()) { >- // We could actually make this faster by stealing code from the >- // top of nsBlockFrame::ReflowBlockFrame, but it's an edge case >- // that will generally happen at most once per reflow. >- line->MarkDirty(); >- } else { >- deltaY = aState.mY + aState.mPrevBottomMargin.get() - line->mBounds.y; >- } >- } >- line->ClearPreviousMarginDirty(); >- >- // See if there's any reflow damage that requires that we mark the >- // line dirty. >- if (!line->IsDirty()) { >+ if (line->IsPreviousMarginDirty()) { >+ line->MarkDirty(); >+ line->ClearPreviousMarginDirty(); >+ } else if (line->mBounds.YMost() + deltaY >+ > aState.mReflowState.availableHeight) { >+ // Lines that aren't dirty but get slid past our height constraint must >+ // be reflowed. >+ line->MarkDirty(); >+ } else if (!line->IsDirty()) { >+ // See if there's any reflow damage that requires that we mark the >+ // line dirty. > PropagateFloatDamage(aState, line, deltaY); > } > > if (needToRecoverState) { > needToRecoverState = PR_FALSE; > > // Update aState.mPrevChild as if we had reflowed all of the frames in > // this line. This is expensive in some cases, since it requires > // walking |GetNextSibling|. > if (line->IsDirty()) > aState.mPrevChild = line.prev()->LastChild(); > } > > // Now repair the line and update |aState.mY| by calling > // |ReflowLine| or |SlideLine|. > if (line->IsDirty()) { >+ lastLineMovedUp = PR_TRUE; >+ > // Compute the dirty lines "before" YMost, after factoring in > // the running deltaY value - the running value is implicit in > // aState.mY. > nscoord oldY = line->mBounds.y; > nscoord oldYMost = line->mBounds.YMost(); > > // Reflow the dirty line. If it's an incremental reflow, then force > // it to invalidate the dirty area if necessary > rv = ReflowLine(aState, line, &keepGoing, doInvalidate); > if (NS_FAILED(rv)) { > return rv; > } > if (!keepGoing) { >+#ifdef DEBUG >+ if (gNoisyReflow) { >+ gNoiseIndent--; >+ nsRect lca(line->GetCombinedArea()); >+ IndentBy(stdout, gNoiseIndent); >+ printf("line=%p mY=%d newBounds={%d,%d,%d,%d} newCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d childCount=%d\n", >+ NS_STATIC_CAST(void*, line.get()), aState.mY, >+ line->mBounds.x, line->mBounds.y, >+ line->mBounds.width, line->mBounds.height, >+ lca.x, lca.y, lca.width, lca.height, >+ deltaY, aState.mPrevBottomMargin.get(), >+ line->GetChildCount()); >+ } >+#endif > if (0 == line->GetChildCount()) { > DeleteLine(aState, line, line_end); > } > break; > } > if (oldY == 0 && deltaY != line->mBounds.y) { > // This means the current line was just reflowed for the first > // time. Thus we must mark the the previous margin of the next > // line dirty. > // XXXldb Move this into where we insert the line! (or will > // that mess up deltaY manipulation?) > if (line.next() != end_lines()) { > line.next()->MarkPreviousMarginDirty(); > // since it's marked dirty, nobody will care about |deltaY| > } >- } else { >- deltaY = line->mBounds.YMost() - oldYMost; > } >+ >+ deltaY = line->mBounds.YMost() - oldYMost; > } else { >+ lastLineMovedUp = deltaY < 0; >+ > if (deltaY != 0) > SlideLine(aState, line, deltaY); > else > repositionViews = PR_TRUE; > > // XXX EVIL O(N^2) EVIL > aState.RecoverStateFrom(line, deltaY); > >- // Keep mY up to date in case we're propagating reflow damage. >- aState.mY = line->mBounds.YMost(); >+ // Keep mY up to date in case we're propagating reflow damage >+ // and also because our final height may depend on it. Only >+ // update mY if the line is not empty, because that's what >+ // PlaceLine does. >+ if (!line->IsEmpty()) { >+ aState.mY = line->mBounds.YMost(); >+ } > needToRecoverState = PR_TRUE; > } > > #ifdef DEBUG > if (gNoisyReflow) { > gNoiseIndent--; > nsRect lca(line->GetCombinedArea()); > IndentBy(stdout, gNoiseIndent); >@@ -2149,99 +2189,144 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe > // walking |GetNextSibling|. > aState.mPrevChild = line.prev()->LastChild(); > } > > // Should we really have to do this? > if (repositionViews) > ::PlaceFrameView(aState.mPresContext, this); > >- // Pull data from a next-in-flow if there's still room for more >- // content here. >- while (keepGoing && (nsnull != aState.mNextInFlow)) { >- // Grab first line from our next-in-flow >- nsBlockFrame* nextInFlow = aState.mNextInFlow; >- line_iterator nifLine = nextInFlow->begin_lines(); >- if (nifLine == nextInFlow->end_lines()) { >- NS_WARNING("Drained the life from next-in-flow!\n"); >- aState.mNextInFlow = (nsBlockFrame*) aState.mNextInFlow->mNextInFlow; >- continue; >- } >- // XXX See if the line is not dirty; if it's not maybe we can >- // avoid the pullup if it can't fit? >- nsLineBox *toMove = nifLine; >- nextInFlow->mLines.erase(nifLine); >- if (0 == toMove->GetChildCount()) { >- // The line is empty. Try the next one. >- NS_ASSERTION(nsnull == toMove->mFirstChild, "bad empty line"); >- aState.FreeLineBox(toMove); >- continue; >- } >- >- // XXX move to a subroutine: run-in, overflow, pullframe and this do this >- // Make the children in the line ours. >- nsIFrame* frame = toMove->mFirstChild; >- nsIFrame* lastFrame = nsnull; >- PRInt32 n = toMove->GetChildCount(); >- while (--n >= 0) { >- frame->SetParent(this); >- // When pushing and pulling frames we need to check for whether any >- // views need to be reparented >- nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, mNextInFlow, this); >- lastFrame = frame; >- frame = frame->GetNextSibling(); >+ // We can skip trying to pull up the next line if there is no next in flow or >+ // if the next in flow is not changing and we cannot have added more space for its first >+ // line to be pulled up into. >+ PRBool canSkipPull = !aState.mNextInFlow >+ || (aState.mReflowState.mFlags.mNextInFlowUntouched && !lastLineMovedUp); >+ >+ if (canSkipPull) { >+ if (aState.mNextInFlow) { >+ aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE; > } >- lastFrame->SetNextSibling(nsnull); >- >- // Add line to our line list >- if (aState.mPrevChild) { >- aState.mPrevChild->SetNextSibling(toMove->mFirstChild); >- } >- >- line = mLines.before_insert(end_lines(), toMove); >- >- // If line contains floats, remove them from aState.mNextInFlow's >- // float list. They will be pushed onto this blockframe's float >- // list, via BuildFloatList(), when we are done reflowing dirty lines. >- // >- // XXX: If the call to BuildFloatList() is removed from >- // nsBlockFrame::Reflow(), we'll probably need to manually >- // append the floats to |this|'s float list. >- >- if (line->HasFloats()) { >- nsFloatCache* fc = line->GetFirstFloat(); >- while (fc) { >- if (fc->mPlaceholder) { >- nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame(); >- if (floatFrame) >- aState.mNextInFlow->mFloats.RemoveFrame(floatFrame); >+ } else { >+ // Pull data from a next-in-flow if there's still room for more >+ // content here. >+ while (keepGoing && (nsnull != aState.mNextInFlow)) { >+ // Grab first line from our next-in-flow >+ nsBlockFrame* nextInFlow = aState.mNextInFlow; >+ line_iterator nifLine = nextInFlow->begin_lines(); >+ nsLineBox *toMove; >+ PRBool collectOverflowFloats; >+ if (nifLine != nextInFlow->end_lines()) { >+ toMove = nifLine; >+ nextInFlow->mLines.erase(nifLine); >+ collectOverflowFloats = PR_FALSE; >+ } else { >+ // Grab an overflow line if there are any >+ nsLineList* overflowLines = nextInFlow->RemoveOverflowLines(); >+ if (!overflowLines) { >+ aState.mNextInFlow = (nsBlockFrame*)nextInFlow->mNextInFlow; >+ continue; >+ } >+ nifLine = overflowLines->begin(); >+ NS_ASSERTION(nifLine != overflowLines->end(), >+ "Stored overflow line list should not be empty"); >+ toMove = nifLine; >+ nifLine = overflowLines->erase(nifLine); >+ if (nifLine != overflowLines->end()) { >+ // We need to this remove-and-put-back dance because we want >+ // to avoid making the overflow line list empty while it's >+ // stored in the property (because the property has the >+ // invariant that the list is never empty). >+ nextInFlow->SetOverflowLines(overflowLines); > } >- fc = fc->Next(); >+ collectOverflowFloats = PR_TRUE; > } >- } >+ >+ if (0 == toMove->GetChildCount()) { >+ // The line is empty. Try the next one. >+ NS_ASSERTION(nsnull == toMove->mFirstChild, "bad empty line"); >+ aState.FreeLineBox(toMove); >+ continue; >+ } >+ >+ // XXX move to a subroutine: run-in, overflow, pullframe and this do this >+ // Make the children in the line ours. >+ nsIFrame* frame = toMove->mFirstChild; >+ nsIFrame* lastFrame = nsnull; >+ PRInt32 n = toMove->GetChildCount(); >+ while (--n >= 0) { >+ ReparentFrame(frame, this, nextInFlow); >+ lastFrame = frame; >+ frame = frame->GetNextSibling(); >+ } >+ lastFrame->SetNextSibling(nsnull); > >- // Now reflow it and any lines that it makes during it's reflow >- // (we have to loop here because reflowing the line may case a new >- // line to be created; see SplitLine's callers for examples of >- // when this happens). >- while (line != end_lines()) { >- rv = ReflowLine(aState, line, &keepGoing, doInvalidate); >- if (NS_FAILED(rv)) { >- return rv; >+ // Add line to our line list >+ if (aState.mPrevChild) { >+ aState.mPrevChild->SetNextSibling(toMove->mFirstChild); > } >- if (!keepGoing) { >- if (0 == line->GetChildCount()) { >- DeleteLine(aState, line, line_end); >+ >+ line = mLines.before_insert(end_lines(), toMove); >+ >+ // Reparent floats whose placeholders are in the line. We need >+ // to do this differently depending on whether the line is an >+ // overflow line or not. >+ if (collectOverflowFloats) { >+ ReparentFloats(line->mFirstChild, nextInFlow, PR_TRUE); >+ } else { >+ // If line contains floats, remove them from aState.mNextInFlow's >+ // float list. They will be pushed onto this blockframe's float >+ // list, via BuildFloatList(), when we are done reflowing dirty lines. >+ // >+ // XXX: If the call to BuildFloatList() is removed from >+ // nsBlockFrame::Reflow(), we'll probably need to manually >+ // append the floats to |this|'s float list. >+ // >+ // We don't need to fix the line's float cache because we're >+ // next going to reflow the line, which will wipe and >+ // rebuild the float cache. >+ if (line->HasFloats()) { >+ nsFloatCache* fc = line->GetFirstFloat(); >+ while (fc) { >+ if (fc->mPlaceholder) { >+ nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame(); >+ if (floatFrame) { >+ nextInFlow->mFloats.RemoveFrame(floatFrame); >+ ReparentFrame(floatFrame, this, nextInFlow); >+ } >+ } >+ fc = fc->Next(); >+ } > } >- break; > } >- >- // If this is an inline frame then its time to stop >- ++line; >- aState.AdvanceToNextLine(); >+ >+ // Now reflow it and any lines that it makes during it's reflow >+ // (we have to loop here because reflowing the line may case a new >+ // line to be created; see SplitLine's callers for examples of >+ // when this happens). >+ while (line != end_lines()) { >+ rv = ReflowLine(aState, line, &keepGoing, doInvalidate); >+ if (NS_FAILED(rv)) { >+ NS_WARNING("Line reflow failed"); >+ return rv; >+ } >+ if (!keepGoing) { >+ if (0 == line->GetChildCount()) { >+ DeleteLine(aState, line, line_end); >+ } >+ break; >+ } >+ >+ // If this is an inline frame then its time to stop >+ ++line; >+ aState.AdvanceToNextLine(); >+ } >+ } >+ >+ if (NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)) { >+ aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; > } > } > > // Handle an odd-ball case: a list-item with no lines > if (mBullet && HaveOutsideBullet() && mLines.empty()) { > nsHTMLReflowMetrics metrics(nsnull); > ReflowBullet(aState, metrics); > >@@ -2500,26 +2585,37 @@ nsBlockFrame::PullFrame(nsBlockReflowSta > line_iterator aLine, > PRBool aDamageDeletedLines, > nsIFrame*& aFrameResult) > { > aFrameResult = nsnull; > > // First check our remaining lines > if (end_lines() != aLine.next()) { >- return PullFrameFrom(aState, aLine, mLines, aLine.next(), PR_FALSE, >+ return PullFrameFrom(aState, aLine, this, PR_FALSE, aLine.next(), > aDamageDeletedLines, aFrameResult); > } > >- // Pull frames from the next-in-flow(s) until we can't >+ NS_ASSERTION(!GetOverflowLines(), >+ "Our overflow lines should have been removed at the start of reflow"); >+ >+ // Try each next in flows > nsBlockFrame* nextInFlow = aState.mNextInFlow; >- while (nsnull != nextInFlow) { >- if (! nextInFlow->mLines.empty()) { >- return PullFrameFrom(aState, aLine, nextInFlow->mLines, >- nextInFlow->mLines.begin(), PR_TRUE, >+ while (nextInFlow) { >+ // first normal lines, then overflow lines >+ if (!nextInFlow->mLines.empty()) { >+ return PullFrameFrom(aState, aLine, nextInFlow, PR_FALSE, >+ nextInFlow->mLines.begin(), >+ aDamageDeletedLines, aFrameResult); >+ } >+ >+ nsLineList* overflowLines = nextInFlow->GetOverflowLines(); >+ if (overflowLines) { >+ return PullFrameFrom(aState, aLine, nextInFlow, PR_TRUE, >+ overflowLines->begin(), > aDamageDeletedLines, aFrameResult); > } > > nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow; > aState.mNextInFlow = nextInFlow; > } > > return NS_OK; >@@ -2536,19 +2632,19 @@ nsBlockFrame::PullFrame(nsBlockReflowSta > * line's float array. This happens indirectly: either the line gets > * emptied (and destroyed) or the line gets reflowed (because we mark > * it dirty) and the code at the top of ReflowLine empties the > * array. So eventually, it will be removed, just not right away. > */ > nsresult > nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState, > nsLineBox* aLine, >- nsLineList& aFromContainer, >+ nsBlockFrame* aFromContainer, >+ PRBool aFromOverflowLine, > nsLineList::iterator aFromLine, >- PRBool aUpdateGeometricParent, > PRBool aDamageDeletedLines, > nsIFrame*& aFrameResult) > { > nsLineBox* fromLine = aFromLine; > NS_ABORT_IF_FALSE(fromLine, "bad line to pull from"); > NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line"); > NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line"); > >@@ -2573,42 +2669,51 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo > else { > // Free up the fromLine now that it's empty > // Its bounds might need to be redrawn, though. > // XXX WHY do we invalidate the bounds AND the combined area? doesn't > // the combined area always enclose the bounds? > if (aDamageDeletedLines) { > Invalidate(fromLine->mBounds); > } >- if (aFromLine.next() != aFromContainer.end()) >+ nsLineList* fromLineList = aFromOverflowLine >+ ? aFromContainer->RemoveOverflowLines() >+ : &aFromContainer->mLines; >+ if (aFromLine.next() != fromLineList->end()) > aFromLine.next()->MarkPreviousMarginDirty(); > > Invalidate(fromLine->GetCombinedArea()); >- aFromContainer.erase(aFromLine); >+ fromLineList->erase(aFromLine); > // Note that aFromLine just got incremented, so don't use it again here! > aState.FreeLineBox(fromLine); >+ >+ // Put any remaining overflow lines back. >+ if (aFromOverflowLine && !fromLineList->empty()) { >+ aFromContainer->SetOverflowLines(fromLineList); >+ } > } > > // Change geometric parents >- if (aUpdateGeometricParent) { >- // Before we set the new parent frame get the current parent >- nsIFrame* oldParentFrame = frame->GetParent(); >- frame->SetParent(this); >- >+ if (aFromContainer != this) { > // When pushing and pulling frames we need to check for whether any > // views need to be reparented >- NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); >- nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, oldParentFrame, this); >- >+ NS_ASSERTION(frame->GetParent() == aFromContainer, "unexpected parent frame"); >+ >+ ReparentFrame(frame, this, aFromContainer); >+ > // The frame is being pulled from a next-in-flow; therefore we > // need to add it to our sibling list. > frame->SetNextSibling(nsnull); > if (nsnull != aState.mPrevChild) { > aState.mPrevChild->SetNextSibling(frame); > } >+ >+ // The frame might have (or contain) floats that need to be >+ // brought over too. >+ ReparentFloats(frame, aFromContainer, aFromOverflowLine); > } > > // Stop pulling because we found a frame to pull > aFrameResult = frame; > #ifdef DEBUG > VerifyLines(PR_TRUE); > #endif > } >@@ -3059,30 +3164,33 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe > aState.IsAdjacentWithTop(), computedOffsets, > blockHtmlRS, frameReflowStatus); > > // Remove the frame from the reflow tree. > if (aState.mReflowState.path) > aState.mReflowState.path->RemoveChild(frame); > > if (NS_FAILED(rv)) { >+#ifdef DEBUG_roc >+ printf("Block reflow failed on frame %p\n", frame); >+#endif > return rv; > } > aState.mPrevChild = frame; > > #if defined(REFLOW_STATUS_COVERAGE) > RecordReflowStatus(PR_TRUE, frameReflowStatus); > #endif > > if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) { > // None of the child block fits. > UndoSplitPlaceholders(aState, lastPlaceholder); > PushLines(aState, aLine.prev()); > *aKeepReflowGoing = PR_FALSE; >- aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; >+ aState.mReflowStatus = NS_FRAME_NOT_COMPLETE | NS_FRAME_REFLOW_NEXTINFLOW; > } > else { > // Note: line-break-after a block is a nop > > // Try to place the child block > PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); > nsCollapsingMargin collapsedBottomMargin; > nsRect combinedArea(0,0,0,0); >@@ -3117,30 +3225,55 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe > // Continue the block frame now if it didn't completely fit in > // the available space. > if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) { > PRBool madeContinuation; > rv = CreateContinuationFor(aState, nsnull, frame, madeContinuation); > if (NS_FAILED(rv)) > return rv; > >+ nsIFrame* nextFrame; >+ frame->GetNextInFlow(&nextFrame); >+ > // Push continuation to a new line, but only if we actually made one. > if (madeContinuation) { >- frame = frame->GetNextSibling(); >- nsLineBox* line = aState.NewLineBox(frame, 1, PR_TRUE); >+ nsLineBox* line = aState.NewLineBox(nextFrame, 1, PR_TRUE); > if (nsnull == line) { > return NS_ERROR_OUT_OF_MEMORY; > } > mLines.after_insert(aLine, line); > } > > // Advance to next line since some of the block fit. That way > // only the following lines will be pushed. > PushLines(aState, aLine); > aState.mReflowStatus = NS_FRAME_NOT_COMPLETE; >+ // If we need to reflow the continuation of the block child, >+ // then we'd better reflow our continuation >+ if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) { >+ aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; >+ // We also need to make that continuation's line dirty so it >+ // gets reflowed when we reflow our next in flow. The >+ // nif's line must always be either the first line >+ // of the nif's parent block or else one of our own overflow >+ // lines. In the latter case the line is already marked dirty, >+ // so just detect and handle the first case. >+ nsBlockFrame* nifBlock = NS_STATIC_CAST(nsBlockFrame*, nextFrame->GetParent()); >+#ifdef DEBUG_roc >+ printf("*** BLOCK nested dirtying: this=%p, child=%p, child->next=%p, child->next->parent=%p\n", >+ (void*)this, (void*)frame, (void*)nextFrame, (void*)nextFrame->GetParent()); >+#endif >+ NS_ASSERTION(nifBlock->GetType() == nsLayoutAtoms::blockFrame >+ || nifBlock->GetType() == nsLayoutAtoms::areaFrame, >+ "A block's child's next in flow's parent must be a block!"); >+ line_iterator firstLine = nifBlock->begin_lines(); >+ if (firstLine != nifBlock->end_lines() && firstLine->Contains(nextFrame)) { >+ firstLine->MarkDirty(); >+ } >+ } > *aKeepReflowGoing = PR_FALSE; > > // The bottom margin for a block is only applied on the last > // flow block. Since we just continued the child block frame, > // we know that line->mFirstChild is not the last flow block > // therefore zero out the running margin value. > #ifdef NOISY_VERTICAL_MARGINS > ListTag(stdout); >@@ -3391,16 +3524,19 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo > nsIFrame* frame = aLine->mFirstChild; > aLine->SetHasPercentageChild(PR_FALSE); // To be set by ReflowInlineFrame below > // need to repeatedly call GetChildCount here, because the child > // count can change during the loop! > for (i = 0; i < aLine->GetChildCount(); i++) { > rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame, > &lineReflowStatus); > if (NS_FAILED(rv)) { >+#ifdef DEBUG_roc >+ printf("Inline reflow failed on frame %p\n", frame); >+#endif > return rv; > } > if (LINE_REFLOW_OK != lineReflowStatus) { > // It is possible that one or more of next lines are empty > // (because of DeleteNextInFlowChild). If so, delete them now > // in case we are finished. > ++aLine; > while ((aLine != end_lines()) && (0 == aLine->GetChildCount())) { >@@ -3409,38 +3545,47 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo > nsLineBox *toremove = aLine; > aLine = mLines.erase(aLine); > NS_ASSERTION(nsnull == toremove->mFirstChild, "bad empty line"); > aState.FreeLineBox(toremove); > } > --aLine; > > if (LINE_REFLOW_TRUNCATED == lineReflowStatus) { >- // Push the line with the truncated float >- PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); >+ // Don't push any lines if we just want to calculate the maximum width >+ if (!aUpdateMaximumWidth) { >+ // Push the line with the truncated float >+ PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); >+ } > } > break; > } > frame = frame->GetNextSibling(); > } > > // Pull frames and reflow them until we can't > while (LINE_REFLOW_OK == lineReflowStatus) { > rv = PullFrame(aState, aLine, aDamageDirtyArea, frame); > if (NS_FAILED(rv)) { >+#ifdef DEBUG_roc >+ printf("Inline reflow failed pull\n"); >+#endif > return rv; > } > if (nsnull == frame) { > break; > } > while (LINE_REFLOW_OK == lineReflowStatus) { > PRInt32 oldCount = aLine->GetChildCount(); > rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame, > &lineReflowStatus); > if (NS_FAILED(rv)) { >+#ifdef DEBUG_roc >+ printf("Inline reflow failed on frame %p\n", frame); >+#endif > return rv; > } > if (aLine->GetChildCount() != oldCount) { > // We just created a continuation for aFrame AND its going > // to end up on this line (e.g. :first-letter > // situation). Therefore we have to loop here before trying > // to pull another frame. > frame = frame->GetNextSibling(); >@@ -3472,17 +3617,17 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo > > // XXX: a small optimization can be done here when paginating: > // if the new Y coordinate is past the end of the block then > // push the line and return now instead of later on after we are > // past the float. > } > else if (LINE_REFLOW_TRUNCATED != lineReflowStatus) { > // If we are propagating out a break-before status then there is >- // no point in placing the line. >+ // no point in placing the line. Also, > if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { > if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) { > UndoSplitPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line > } > } > } > *aLineReflowStatus = lineReflowStatus; > >@@ -3996,17 +4141,23 @@ nsBlockFrame::PlaceLine(nsBlockReflowSta > // XXXldb If it's empty, shouldn't the next line control the ascent? > if (mLines.front() == aLine) { > mAscent += dy; > } > } > > // See if the line fit. If it doesn't we need to push it. Our first > // line will always fit. >- if ((mLines.front() != aLine) && (newY > aState.mBottomEdge)) { >+ >+ // If we're just updating the maximum width then we don't care if it >+ // fits; we'll assume it does, so that the maximum width will get >+ // updated below. The line will be reflowed again and pushed then >+ // if necessary. >+ if ((mLines.front() != aLine) && (newY > aState.mBottomEdge) >+ && !aUpdateMaximumWidth) { > // Push this line and all of it's children and anything else that > // follows to our next-in-flow > NS_ASSERTION((aState.mCurrentLine == aLine), "oops"); > PushLines(aState, aLine.prev()); > > // Stop reflow and whack the reflow status if reflow hasn't > // already been stopped. > if (*aKeepReflowGoing) { >@@ -4057,17 +4208,21 @@ nsBlockFrame::PlaceLine(nsBlockReflowSta > // lines float list if there aren't any truncated floats. > if (aState.PlaceBelowCurrentLineFloats(aState.mBelowCurrentLineFloats)) { > aLine->AppendFloats(aState.mBelowCurrentLineFloats); > } > else { > // At least one float is truncated, so fix up any placeholders that got split and > // push the line. XXX It may be better to put the float on the next line, but this > // is not common enough to justify the complexity. >- PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); >+ // If we just want to calculate the maximum width, then don't push the line. >+ // We'll reflow it again and then it will get pushed if necessary. >+ if (!aUpdateMaximumWidth) { >+ PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); >+ } > } > } > > // When a line has floats, factor them into the combined-area > // computations. > if (aLine->HasFloats()) { > // Combine the float combined area (stored in aState) and the > // value computed by the line layout code. >@@ -4179,16 +4334,21 @@ nsBlockFrame::PushLines(nsBlockReflowSta > > // XXXldb Can this get called O(N) times making the whole thing O(N^2)? > for (line_iterator line = overflowLines->begin(), > line_end = overflowLines->end(); > line != line_end; > ++line) > { > line->MarkDirty(); >+ line->MarkPreviousMarginDirty(); >+ line->mBounds.SetRect(0, 0, 0, 0); >+ if (line->HasFloats()) { >+ line->FreeFloats(aState.mFloatCacheFreeList); >+ } > } > } > > // Break frame sibling list > if (!firstLine) > aLineBefore->LastChild()->SetNextSibling(nsnull); > > #ifdef DEBUG >@@ -4196,17 +4356,17 @@ nsBlockFrame::PushLines(nsBlockReflowSta > #endif > } > > // The overflowLines property is stored as a pointer to a line list, > // which must be deleted. However, the following functions all maintain > // the invariant that the property is never set if the list is empty. > > PRBool >-nsBlockFrame::DrainOverflowLines(nsPresContext* aPresContext) >+nsBlockFrame::DrainOverflowLines() > { > #ifdef DEBUG > VerifyOverflowSituation(); > #endif > PRBool drained = PR_FALSE; > nsLineList* overflowLines; > > // First grab the prev-in-flows overflow lines >@@ -4217,50 +4377,46 @@ nsBlockFrame::DrainOverflowLines(nsPresC > NS_ASSERTION(! overflowLines->empty(), > "overflow lines should never be set and empty"); > drained = PR_TRUE; > > // Make all the frames on the overflow line list mine > nsIFrame* lastFrame = nsnull; > nsIFrame* frame = overflowLines->front()->mFirstChild; > while (nsnull != frame) { >- frame->SetParent(this); >- >- // When pushing and pulling frames we need to check for whether any >- // views need to be reparented >- // XXXldb Are float lists in sync with what floats are actually >- // present in the lines, so their views can be reparented? >- nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, prevBlock, this); >+ ReparentFrame(frame, this, prevBlock); > > // Get the next frame > lastFrame = frame; > frame = frame->GetNextSibling(); > } > >+ // The lines on the overflow list have already been marked dirty and their >+ // previous margins marked dirty also. >+ > // Join the line lists > NS_ASSERTION(lastFrame, "overflow list was created with no frames"); >- if (! mLines.empty()) { >+ if (! mLines.empty()) >+ { >+ // Remember to recompute the margins on the first line. This will >+ // also recompute the correct deltaY if necessary. >+ mLines.front()->MarkPreviousMarginDirty(); > // Join the sibling lists together > lastFrame->SetNextSibling(mLines.front()->mFirstChild); > } > // Place overflow lines at the front of our line list > mLines.splice(mLines.begin(), *overflowLines); > NS_ASSERTION(overflowLines->empty(), "splice should empty list"); > delete overflowLines; > >- // Out-of-flow floats need to be reparented too. > nsFrameList* overflowOutOfFlows = prevBlock->RemoveOverflowOutOfFlows(); > if (overflowOutOfFlows) { > for (nsIFrame* f = overflowOutOfFlows->FirstChild(); f; > f = f->GetNextSibling()) { >- f->SetParent(this); >- >- // When pushing and pulling frames we need to check for whether any >- // views need to be reparented >- nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, prevBlock, this); >+ ReparentFrame(f, this, prevBlock); > } > delete overflowOutOfFlows; > } > } > } > > // Now grab our own overflow lines > overflowLines = RemoveOverflowLines(); >@@ -4303,16 +4459,17 @@ nsBlockFrame::GetOverflowLines() const > > nsLineList* > nsBlockFrame::RemoveOverflowLines() const > { > nsLineList* lines = > NS_STATIC_CAST(nsLineList*, > RemoveProperty(nsLayoutAtoms::overflowLinesProperty)); > NS_ASSERTION(!lines || !lines->empty(), "value should never be stored as empty"); >+ > return lines; > } > > // Destructor function for the overflowLines frame property > static void > DestroyOverflowLines(nsPresContext* aPresContext, > nsIFrame* aFrame, > nsIAtom* aPropertyName, >@@ -4623,16 +4780,31 @@ nsBlockFrame::AddFrames(nsPresContext* a > } > > #ifdef DEBUG > VerifyLines(PR_TRUE); > #endif > return NS_OK; > } > >+nsBlockFrame::line_iterator >+nsBlockFrame::RemoveFloat(nsIFrame* aFloat) { >+ // Find which line contains the float >+ line_iterator line = begin_lines(), line_end = end_lines(); >+ for ( ; line != line_end; ++line) { >+ if (line->IsInline() && line->RemoveFloat(aFloat)) { >+ break; >+ } >+ } >+ >+ mFloats.DestroyFrame(GetPresContext(), aFloat); >+ >+ return line; >+} >+ > NS_IMETHODIMP > nsBlockFrame::RemoveFrame(nsPresContext* aPresContext, > nsIPresShell& aPresShell, > nsIAtom* aListName, > nsIFrame* aOldFrame) > { > nsresult rv = NS_OK; > >@@ -4646,25 +4818,18 @@ nsBlockFrame::RemoveFrame(nsPresContext* > if (nsnull == aListName) { > rv = DoRemoveFrame(aPresContext, aOldFrame); > } > else if (mAbsoluteContainer.GetChildListName() == aListName) { > return mAbsoluteContainer.RemoveFrame(this, aPresContext, aPresShell, > aListName, aOldFrame); > } > else if (nsLayoutAtoms::floatList == aListName) { >- // Find which line contains the float >- line_iterator line = begin_lines(), line_end = end_lines(); >- for ( ; line != line_end; ++line) { >- if (line->IsInline() && line->RemoveFloat(aOldFrame)) { >- break; >- } >- } >- >- mFloats.DestroyFrame(aPresContext, aOldFrame); >+ line_iterator line = RemoveFloat(aOldFrame); >+ line_iterator line_end = end_lines(); > > // Mark every line at and below the line where the float was dirty > // XXXldb This could be done more efficiently. > for ( ; line != line_end; ++line) { > line->MarkDirty(); > } > } > #ifdef IBMBIDI >@@ -4707,182 +4872,225 @@ nsBlockFrame::DoRemoveOutOfFlowFrame(nsP > } > > nsBlockFrame* block = (nsBlockFrame*)parent; > // Remove aFrame from the appropriate list. > if (display->IsAbsolutelyPositioned()) { > block->mAbsoluteContainer.RemoveFrame(block, aPresContext, > *(aPresContext->PresShell()), > block->mAbsoluteContainer.GetChildListName(), aFrame); >+ aFrame->Destroy(aPresContext); >+ } else { >+ // This also destroys the frame. >+ block->RemoveFloat(aFrame); > } >- else { >- block->mFloats.RemoveFrame(aFrame); >+} >+ >+// This helps us iterate over the list of all normal + overflow lines >+void >+nsBlockFrame::TryAllLines(nsLineList::iterator* aIterator, >+ nsLineList::iterator* aEndIterator, >+ PRBool* aInOverflowLines) { >+ if (*aIterator == *aEndIterator) { >+ if (!*aInOverflowLines) { >+ *aInOverflowLines = PR_TRUE; >+ // Try the overflow lines >+ nsLineList* overflowLines = GetOverflowLines(); >+ if (overflowLines) { >+ *aIterator = overflowLines->begin(); >+ *aEndIterator = overflowLines->end(); >+ } >+ } > } >- // Destroy aFrame >- aFrame->Destroy(aPresContext); > } > >+// This function removes aDeletedFrame and all its continuations. It >+// is optimized for deleting a whole series of frames. The easy >+// implementation would invoke itself recursively on >+// aDeletedFrame->GetNextInFlow, then locate the line containing >+// aDeletedFrame and remove aDeletedFrame from that line. But here we >+// start by locating aDeletedFrame and then scanning from that point >+// on looking for continuations. > nsresult > nsBlockFrame::DoRemoveFrame(nsPresContext* aPresContext, > nsIFrame* aDeletedFrame) > { > // Clear our line cursor, since our lines may change. > ClearLineCursor(); > > if (aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { > DoRemoveOutOfFlowFrame(aPresContext, aDeletedFrame); > return NS_OK; > } > > nsIPresShell *presShell = aPresContext->PresShell(); > > // Find the line and the previous sibling that contains > // deletedFrame; we also find the pointer to the line. >- nsBlockFrame* flow = this; >- nsLineList* lines = &flow->mLines; >- nsLineList::iterator line = lines->begin(), >- line_end = lines->end(); >+ nsLineList::iterator line = mLines.begin(), >+ line_end = mLines.end(); >+ PRBool searchingOverflowList = PR_FALSE; > nsIFrame* prevSibling = nsnull; >- for ( ; line != line_end; ++line) { >+ // Make sure we look in the overflow lines even if the normal line >+ // list is empty >+ TryAllLines(&line, &line_end, &searchingOverflowList); >+ while (line != line_end) { > nsIFrame* frame = line->mFirstChild; > PRInt32 n = line->GetChildCount(); > while (--n >= 0) { > if (frame == aDeletedFrame) { > goto found_frame; > } > prevSibling = frame; > frame = frame->GetNextSibling(); > } >+ ++line; >+ TryAllLines(&line, &line_end, &searchingOverflowList); > } > found_frame:; > if (line == line_end) { > NS_ERROR("can't find deleted frame in lines"); > return NS_ERROR_FAILURE; > } >- NS_ASSERTION(!prevSibling || prevSibling->GetNextSibling() == aDeletedFrame, "bad prevSibling"); > >- // Remove frame and all of its continuations >- while (nsnull != aDeletedFrame) { >- while ((line != line_end) && (nsnull != aDeletedFrame)) { >- NS_ASSERTION(flow == aDeletedFrame->GetParent(), "messed up delete code"); >- NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); >- >- // See if the frame being deleted is the last one on the line >- PRBool isLastFrameOnLine = PR_FALSE; >- if (1 == line->GetChildCount()) { >- isLastFrameOnLine = PR_TRUE; >- } >- else if (line->LastChild() == aDeletedFrame) { >- isLastFrameOnLine = PR_TRUE; >- } >- >- // Remove aDeletedFrame from the line >- nsIFrame* nextFrame = aDeletedFrame->GetNextSibling(); >- if (line->mFirstChild == aDeletedFrame) { >- line->mFirstChild = nextFrame; >- } >+ if (prevSibling && !prevSibling->GetNextSibling()) { >+ // We must have found the first frame in the overflow line list. So >+ // there is no prevSibling >+ prevSibling = nsnull; >+ } >+ NS_ASSERTION(!prevSibling || prevSibling->GetNextSibling() == aDeletedFrame, "bad prevSibling"); > >- --line; >- if (line != line_end && !line->IsBlock()) { >- // Since we just removed a frame that follows some inline >- // frames, we need to reflow the previous line. >- line->MarkDirty(); >- } >- ++line; >+ while ((line != line_end) && (nsnull != aDeletedFrame)) { >+ NS_ASSERTION(this == aDeletedFrame->GetParent(), "messed up delete code"); >+ NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); >+ >+ // See if the frame being deleted is the last one on the line >+ PRBool isLastFrameOnLine = PR_FALSE; >+ if (1 == line->GetChildCount()) { >+ isLastFrameOnLine = PR_TRUE; >+ } >+ else if (line->LastChild() == aDeletedFrame) { >+ isLastFrameOnLine = PR_TRUE; >+ } >+ >+ // Remove aDeletedFrame from the line >+ nsIFrame* nextFrame = aDeletedFrame->GetNextSibling(); >+ if (line->mFirstChild == aDeletedFrame) { >+ // We should be setting this to null if aDeletedFrame >+ // is the only frame on the line. HOWEVER in that case >+ // we will be removing the line anyway, see below. >+ line->mFirstChild = nextFrame; >+ } >+ >+ // Hmm, this won't do anything if we're removing a frame in the first >+ // overflow line... Hopefully doesn't matter >+ --line; >+ if (line != line_end && !line->IsBlock()) { >+ // Since we just removed a frame that follows some inline >+ // frames, we need to reflow the previous line. >+ line->MarkDirty(); >+ } >+ ++line; > >- // Take aDeletedFrame out of the sibling list. Note that >- // prevSibling will only be nsnull when we are deleting the very >- // first frame. >- if (prevSibling) { >- prevSibling->SetNextSibling(nextFrame); >- } >- >- // Update the child count of the line to be accurate >- PRInt32 lineChildCount = line->GetChildCount(); >- lineChildCount--; >- line->SetChildCount(lineChildCount); >- >- // Destroy frame; capture its next-in-flow first in case we need >- // to destroy that too. >- nsIFrame* nextInFlow; >- aDeletedFrame->GetNextInFlow(&nextInFlow); >+ // Take aDeletedFrame out of the sibling list. Note that >+ // prevSibling will only be nsnull when we are deleting the very >+ // first frame in the main or overflow list. >+ if (prevSibling) { >+ prevSibling->SetNextSibling(nextFrame); >+ } >+ >+ // Update the child count of the line to be accurate >+ PRInt32 lineChildCount = line->GetChildCount(); >+ lineChildCount--; >+ line->SetChildCount(lineChildCount); >+ >+ // Destroy frame; capture its next-in-flow first in case we need >+ // to destroy that too. >+ nsIFrame* nextInFlow; >+ aDeletedFrame->GetNextInFlow(&nextInFlow); > #ifdef NOISY_REMOVE_FRAME >- printf("DoRemoveFrame: line=%p frame=", line); >- nsFrame::ListTag(stdout, aDeletedFrame); >- printf(" prevSibling=%p nextInFlow=%p\n", prevSibling, nextInFlow); >-#endif >- aDeletedFrame->Destroy(aPresContext); >- aDeletedFrame = nextInFlow; >- >- // If line is empty, remove it now >- if (0 == lineChildCount) { >- nsLineBox *cur = line; >- line = lines->erase(line); >+ printf("DoRemoveFrame: line=%p frame=", line); >+ nsFrame::ListTag(stdout, aDeletedFrame); >+ printf(" prevSibling=%p nextInFlow=%p\n", prevSibling, nextInFlow); >+#endif >+ aDeletedFrame->Destroy(aPresContext); >+ aDeletedFrame = nextInFlow; >+ >+ // If line is empty, remove it now. >+ if (0 == lineChildCount) { >+ nsLineBox *cur = line; >+ if (!searchingOverflowList) { >+ line = mLines.erase(line); > // Invalidate the space taken up by the line. > // XXX We need to do this if we're removing a frame as a result of > // a call to RemoveFrame(), but we may not need to do this in all > // cases... > nsRect lineCombinedArea(cur->GetCombinedArea()); > #ifdef NOISY_BLOCK_INVALIDATE > printf("%p invalidate 10 (%d, %d, %d, %d)\n", > this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height); > #endif > Invalidate(lineCombinedArea); >- cur->Destroy(presShell); >- >- // If we're removing a line, ReflowDirtyLines isn't going to >- // know that it needs to slide lines unless something is marked >- // dirty. So mark the previous margin of the next line dirty if >- // there is one. >- if (line != line_end) >- line->MarkPreviousMarginDirty(); >- } >- else { >- // Make the line that just lost a frame dirty >- line->MarkDirty(); >- >- // If we just removed the last frame on the line then we need >- // to advance to the next line. >- if (isLastFrameOnLine) { >- ++line; >+ } else { >+ nsLineList* lineList = RemoveOverflowLines(); >+ line = lineList->erase(line); >+ if (line != lineList->end()) { >+ SetOverflowLines(lineList); > } > } >+ cur->Destroy(presShell); >+ >+ // If we're removing a line, ReflowDirtyLines isn't going to >+ // know that it needs to slide lines unless something is marked >+ // dirty. So mark the previous margin of the next line dirty if >+ // there is one. >+ if (line != line_end) >+ line->MarkPreviousMarginDirty(); >+ } >+ else { >+ // Make the line that just lost a frame dirty, and advance to >+ // next line. >+ line->MarkDirty(); >+ ++line; >+ } > >- // See if we should keep looking in the current flow's line list. >- if (nsnull != aDeletedFrame) { >- if (aDeletedFrame != nextFrame) { >- // The deceased frames continuation is not the next frame in >- // the current flow's frame list. Therefore we know that the >- // continuation is in a different parent. So break out of >- // the loop so that we advance to the next parent. >- NS_ASSERTION(aDeletedFrame->GetParent() != flow, "strange continuation"); >- break; >- } >+ // If we just removed the last frame on the line then we need >+ // to advance to the next line. >+ if (isLastFrameOnLine) { >+ TryAllLines(&line, &line_end, &searchingOverflowList); >+ // Detect the case when we've run off the end of the normal line >+ // list and we're starting the overflow line list >+ if (prevSibling && !prevSibling->GetNextSibling()) { >+ prevSibling = nsnull; > } > } > >- // Advance to next flow block if the frame has more continuations >- if (flow && aDeletedFrame) { >- flow = (nsBlockFrame*) flow->mNextInFlow; >- NS_ASSERTION(nsnull != flow, "whoops, continuation without a parent"); >- // add defensive pointer check for bug 56894 >- if (flow) { >- lines = &flow->mLines; >- line = lines->begin(); >- line_end = lines->end(); >- prevSibling = nsnull; >- } else { >- aDeletedFrame = nsnull; >+ // See if we should keep looking in the current flow's line list. >+ if (nsnull != aDeletedFrame) { >+ if (aDeletedFrame->GetParent() != this) { >+ // The deceased frames continuation is not a child of the >+ // current block. So break out of the loop so that we advance >+ // to the next parent. >+ break; > } > } > } > > #ifdef DEBUG > VerifyLines(PR_TRUE); > #endif >+ >+ // Advance to next flow block if the frame has more continuations >+ if (aDeletedFrame) { >+ nsBlockFrame* nextBlock = NS_STATIC_CAST(nsBlockFrame*, aDeletedFrame->GetParent()); >+ NS_ASSERTION(nextBlock->GetType() == nsLayoutAtoms::blockFrame, >+ "Our child's continuation's parent is not a block?"); >+ return nextBlock->DoRemoveFrame(aPresContext, aDeletedFrame); >+ } >+ > return NS_OK; > } > > void > nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext, > nsIFrame* aNextInFlow) > { > nsIFrame* prevInFlow; >@@ -4903,24 +5111,16 @@ nsBlockFrame::DeleteNextInFlowChild(nsPr > // Float support > > nsresult > nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, > nsPlaceholderFrame* aPlaceholder, > nsFloatCache* aFloatCache, > nsReflowStatus& aReflowStatus) > { >- // Delete the placeholder's next in flows, if any >- nsIFrame* nextInFlow; >- aPlaceholder->GetNextInFlow(&nextInFlow); >- if (nextInFlow) { >- // If aPlaceholder's parent is an inline, nextInFlow's will be a block. >- NS_STATIC_CAST(nsHTMLContainerFrame*, nextInFlow->GetParent()) >- ->DeleteNextInFlowChild(aState.mPresContext, nextInFlow); >- } > // Reflow the float. > nsIFrame* floatFrame = aPlaceholder->GetOutOfFlowFrame(); > aReflowStatus = NS_FRAME_COMPLETE; > > #ifdef NOISY_FLOAT > printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n", > aPlaceholder->GetOutOfFlowFrame(), this, > aState.mAvailSpaceRect.x, aState.mAvailSpaceRect.y, >@@ -4998,16 +5198,29 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS > nsresult rv = brc.ReflowBlock(availSpace, PR_TRUE, margin, isAdjacentWithTop, > aFloatCache->mOffsets, floatRS, > aReflowStatus); > // An incomplete reflow status means we should split the float > // if the height is constrained (bug 145305). > if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight)) > aReflowStatus = NS_FRAME_COMPLETE; > >+ if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { >+ // Float is now complete, so delete the placeholder's next in >+ // flows, if any; their floats (which are this float's continuations) >+ // have already been deleted. >+ nsIFrame* nextInFlow; >+ aPlaceholder->GetNextInFlow(&nextInFlow); >+ if (nextInFlow) { >+ // If aPlaceholder's parent is an inline, nextInFlow's will be a block. >+ NS_STATIC_CAST(nsHTMLContainerFrame*, nextInFlow->GetParent()) >+ ->DeleteNextInFlowChild(aState.mPresContext, nextInFlow); >+ } >+ } >+ > if (NS_SUCCEEDED(rv) && isAutoWidth) { > nscoord maxElementWidth = brc.GetMaxElementWidth(); > if (maxElementWidth > availSpace.width) { > // The float's maxElementWidth is larger than the available > // width. Reflow it again, this time pinning the width to the > // maxElementWidth. > availSpace.width = maxElementWidth; > nsCollapsingMargin marginMEW; >@@ -6413,57 +6626,49 @@ nsBlockFrame::ReflowBullet(nsBlockReflow > nscoord y = bp.top; > mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); > mBullet->DidReflow(aState.mPresContext, &aState.mReflowState, NS_FRAME_REFLOW_FINISHED); > } > > // This is used to scan overflow frames for any float placeholders, > // and add their floats to the list represented by aHead and aTail. We > // only search the inline descendants. >-static void CollectOverflowFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, >- nsIFrame** aHead, nsIFrame** aTail) { >+static void CollectFloats(nsIFrame* aFrame, nsIFrame* aBlockParent, >+ nsIFrame** aHead, nsIFrame** aTail) { > while (aFrame) { > // Don't descend into block children > if (!aFrame->GetStyleDisplay()->IsBlockLevel()) { >- if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) { >- nsIFrame *outOfFlowFrame = >- NS_STATIC_CAST(nsPlaceholderFrame*, aFrame)->GetOutOfFlowFrame(); >+ nsIFrame *outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); >+ if (outOfFlowFrame) { > // Make sure that its parent is the block we care > // about. Otherwise we don't want to mess around with it because > // it belongs to someone else. I think this could happen if the > // overflow lines contain a block descendant which owns its own > // floats. >- if (outOfFlowFrame && >- !outOfFlowFrame->GetStyleDisplay()->IsAbsolutelyPositioned()) { >- NS_ASSERTION(outOfFlowFrame->GetParent() == aBlockParent, >- "Out of flow frame doesn't have the expected parent"); >- // It's not an absolute or fixed positioned frame, so it must >- // be a float! >- // XXX This is a lame-o way of detecting a float, but it's the >- // only way apparently >- if (!*aHead) { >- *aHead = *aTail = outOfFlowFrame; >- } else { >- (*aTail)->SetNextSibling(outOfFlowFrame); >- *aTail = outOfFlowFrame; >- } >+ NS_ASSERTION(outOfFlowFrame->GetParent() == aBlockParent, >+ "Out of flow frame doesn't have the expected parent"); >+ if (!*aHead) { >+ *aHead = *aTail = outOfFlowFrame; >+ } else { >+ (*aTail)->SetNextSibling(outOfFlowFrame); >+ *aTail = outOfFlowFrame; > } > } > >- CollectOverflowFloats(aFrame->GetFirstChild(nsnull), aBlockParent, >- aHead, aTail); >+ CollectFloats(aFrame->GetFirstChild(nsnull), aBlockParent, >+ aHead, aTail); > } > > aFrame = aFrame->GetNextSibling(); > } > } > > //XXX get rid of this -- its slow > void >-nsBlockFrame::BuildFloatList() >+nsBlockFrame::BuildFloatList(nsBlockReflowState& aState) > { > // Accumulate float list into mFloats. > // Use the float cache to speed up searching the lines for floats. > nsIFrame* head = nsnull; > nsIFrame* current = nsnull; > for (line_iterator line = begin_lines(), line_end = end_lines(); > line != line_end; > ++line) { >@@ -6492,21 +6697,31 @@ nsBlockFrame::BuildFloatList() > // and not dropped from the frame tree! > // Note that overflow lines do not have any float cache set up for them, > // because the float cache contains only laid-out floats > nsLineList* overflowLines = GetOverflowLines(); > if (overflowLines) { > head = nsnull; > current = nsnull; > >- CollectOverflowFloats(overflowLines->front()->mFirstChild, >- this, &head, ¤t); >+ CollectFloats(overflowLines->front()->mFirstChild, >+ this, &head, ¤t); > > if (current) { > current->SetNextSibling(nsnull); >+ >+ // Floats that were pushed should be removed from our space >+ // manager. Otherwise the space manager's YMost might be larger >+ // than necessary, causing this block to get an incorrect >+ // desired height. Some of these floats may not actually have >+ // been added to the space manager because they weren't reflowed >+ // before being pushed; that's OK, RemoveRegions will ignore >+ // them. >+ aState.mSpaceManager->RemoveRegions(head); >+ > nsFrameList* frameList = new nsFrameList(head); > if (frameList) { > SetOverflowOutOfFlows(frameList); > } > } > } > } > >Index: layout/html/base/src/nsBlockFrame.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/nsBlockFrame.h,v >retrieving revision 3.185 >diff -u -t -p -8 -r3.185 nsBlockFrame.h >--- layout/html/base/src/nsBlockFrame.h 31 Jul 2004 23:15:10 -0000 3.185 >+++ layout/html/base/src/nsBlockFrame.h 21 Aug 2004 22:51:29 -0000 >@@ -274,16 +274,20 @@ protected: > * aPoint is the point to search for. > * aClosestLine is the result. > */ > nsresult GetClosestLine(nsILineIterator *aLI, > const nsPoint &aOrigin, > const nsPoint &aPoint, > PRInt32 &aClosestLine); > >+ void TryAllLines(nsLineList::iterator* aIterator, >+ nsLineList::iterator* aEndIterator, >+ PRBool* aInOverflowLines); >+ > void SetFlags(PRUint32 aFlags) { > mState &= ~NS_BLOCK_FLAGS_MASK; > mState |= aFlags; > } > > PRBool HaveOutsideBullet() const { > #if defined(DEBUG) && !defined(DEBUG_rods) > if(mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET) { >@@ -294,22 +298,16 @@ protected: > } > > /** move the frames contained by aLine by aDY > * if aLine is a block, it's child floats are added to the state manager > */ > void SlideLine(nsBlockReflowState& aState, > nsLineBox* aLine, nscoord aDY); > >- /** grab overflow lines from this block's prevInFlow, and make them >- * part of this block's mLines list. >- * @return PR_TRUE if any lines were drained. >- */ >- PRBool DrainOverflowLines(nsPresContext* aPresContext); >- > virtual PRIntn GetSkipSides() const; > > virtual void ComputeFinalSize(const nsHTMLReflowState& aReflowState, > nsBlockReflowState& aState, > nsHTMLReflowMetrics& aMetrics); > > void ComputeCombinedArea(const nsHTMLReflowState& aReflowState, > nsHTMLReflowMetrics& aMetrics); >@@ -327,16 +325,28 @@ protected: > /** does all the real work for removing aDeletedFrame from this > * finds the line containing aFrame. > * handled continued frames > * marks lines dirty as needed > */ > nsresult DoRemoveFrame(nsPresContext* aPresContext, > nsIFrame* aDeletedFrame); > >+ /** grab overflow lines from this block's prevInFlow, and make them >+ * part of this block's mLines list. >+ * @return PR_TRUE if any lines were drained. >+ */ >+ PRBool DrainOverflowLines(); >+ >+ /** >+ * Remove a float from our float list and also the float cache >+ * for the line its placeholder is on. >+ */ >+ line_iterator RemoveFloat(nsIFrame* aFloat); >+ > // Remove a float, abs, rel positioned frame from the appropriate block's list > static void DoRemoveOutOfFlowFrame(nsPresContext* aPresContext, > nsIFrame* aFrame); > > /** set up the conditions necessary for an initial reflow */ > nsresult PrepareInitialReflow(nsBlockReflowState& aState); > > /** set up the conditions necessary for an styleChanged reflow */ >@@ -477,43 +487,47 @@ protected: > nsIFrame* aFrame); > > nsresult PullFrame(nsBlockReflowState& aState, > line_iterator aLine, > PRBool aDamageDeletedLine, > nsIFrame*& aFrameResult); > > nsresult PullFrameFrom(nsBlockReflowState& aState, >- nsLineBox* aToLine, >- nsLineList& aFromContainer, >+ nsLineBox* aLine, >+ nsBlockFrame* aFromContainer, >+ PRBool aFromOverflowLine, > nsLineList::iterator aFromLine, >- PRBool aUpdateGeometricParent, > PRBool aDamageDeletedLines, > nsIFrame*& aFrameResult); > > void PushLines(nsBlockReflowState& aState, > nsLineList::iterator aLineBefore); > >+ >+ void ReparentFloats(nsIFrame* aFirstFrame, >+ nsBlockFrame* aOldParent, PRBool aFromOverflow); >+ > //---------------------------------------- > //XXX > virtual void PaintChildren(nsPresContext* aPresContext, > nsIRenderingContext& aRenderingContext, > const nsRect& aDirtyRect, > nsFramePaintLayer aWhichLayer, > PRUint32 aFlags = 0); > > void PaintFloats(nsPresContext* aPresContext, > nsIRenderingContext& aRenderingContext, > const nsRect& aDirtyRect); > > void PropagateFloatDamage(nsBlockReflowState& aState, > nsLineBox* aLine, > nscoord aDeltaY); > >- void BuildFloatList(); >+ void BuildFloatList(nsBlockReflowState& aState); > > //---------------------------------------- > // List handling kludge > > void RenumberLists(nsPresContext* aPresContext); > > PRBool RenumberListsInBlock(nsPresContext* aPresContext, > nsBlockFrame* aContainerFrame, >Index: layout/html/base/src/nsBlockReflowState.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/nsBlockReflowState.cpp,v >retrieving revision 3.484 >diff -u -t -p -8 -r3.484 nsBlockReflowState.cpp >--- layout/html/base/src/nsBlockReflowState.cpp 31 Jul 2004 23:15:10 -0000 3.484 >+++ layout/html/base/src/nsBlockReflowState.cpp 21 Aug 2004 22:51:32 -0000 >@@ -813,17 +813,17 @@ nsBlockReflowState::CanPlaceFloat(const > GetAvailableSpace(); > } > } > } > return result; > } > > void >-nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, >+nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, > PRBool* aIsLeftFloat, > nsReflowStatus& aReflowStatus) > { > aReflowStatus = NS_FRAME_COMPLETE; > // Save away the Y coordinate before placing the float. We will > // restore mY at the end after placing the float. This is > // necessary because any adjustments to mY during the float > // placement are for the float only, not for any non-floating >@@ -853,16 +853,19 @@ nsBlockReflowState::FlowAndPlaceFloat(ns > // XXXldb Does this handle vertical margins correctly? > ClearFloats(mY, floatDisplay->mBreakType); > } > else { > // Get the band of available space > GetAvailableSpace(); > } > >+ NS_ASSERTION(floatFrame->GetParent() == mBlock, >+ "Float frame has wrong parent"); >+ > // Reflow the float > mBlock->ReflowFloat(*this, placeholder, aFloatCache, aReflowStatus); > > // Get the floats bounding box and margin information > region = floatFrame->GetRect(); > > #ifdef DEBUG > if (nsBlockFrame::gNoisyReflow) { >Index: layout/html/base/src/nsHTMLParts.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/nsHTMLParts.h,v >retrieving revision 3.120 >diff -u -t -p -8 -r3.120 nsHTMLParts.h >--- layout/html/base/src/nsHTMLParts.h 31 Jul 2004 23:15:10 -0000 3.120 >+++ layout/html/base/src/nsHTMLParts.h 21 Aug 2004 22:51:48 -0000 >@@ -171,16 +171,20 @@ NS_NewTextFrame(nsIPresShell* aPresShell > nsresult > NS_NewContinuingTextFrame(nsIPresShell* aPresShell, nsIFrame** aResult); > nsresult > NS_NewEmptyFrame(nsIPresShell* aPresShell, nsIFrame** aResult); > inline nsresult > NS_NewWBRFrame(nsIPresShell* aPresShell, nsIFrame** aResult) { > return NS_NewEmptyFrame(aPresShell, aResult); > } >+ >+nsresult >+NS_NewColumnFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aStateFlags ); >+ > nsresult > NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsIFrame** aResult); > nsresult > NS_NewPageFrame(nsIPresShell* aPresShell, nsIFrame** aResult); > nsresult > NS_NewPageContentFrame(nsIPresShell* aPresShell, nsIFrame** aResult); > nsresult > NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsIFrame** aResult); >Index: layout/html/base/src/nsHTMLReflowState.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/nsHTMLReflowState.cpp,v >retrieving revision 1.204 >diff -u -t -p -8 -r1.204 nsHTMLReflowState.cpp >--- layout/html/base/src/nsHTMLReflowState.cpp 31 Jul 2004 23:15:10 -0000 1.204 >+++ layout/html/base/src/nsHTMLReflowState.cpp 21 Aug 2004 22:51:55 -0000 >@@ -105,16 +105,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP > path = nsnull; > availableWidth = aAvailableSpace.width; > availableHeight = aAvailableSpace.height; > rendContext = aRenderingContext; > mSpaceManager = nsnull; > mLineLayout = nsnull; > mFlags.mSpecialHeightReflow = PR_FALSE; > mFlags.mIsTopOfPage = PR_FALSE; >+ mFlags.mNextInFlowUntouched = PR_FALSE; > mFlags.mUnused = 0; > mPercentHeightObserver = nsnull; > mPercentHeightReflowInitiator = nsnull; > Init(aPresContext); > #ifdef IBMBIDI > mFlags.mVisualBidiFormControl = IsBidiFormControl(aPresContext); > mRightEdge = NS_UNCONSTRAINEDSIZE; > #endif >@@ -137,26 +138,36 @@ nsHTMLReflowState::nsHTMLReflowState(nsP > frame = aFrame; > availableWidth = aAvailableSpace.width; > availableHeight = aAvailableSpace.height; > rendContext = aRenderingContext; > mSpaceManager = nsnull; > mLineLayout = nsnull; > mFlags.mSpecialHeightReflow = PR_FALSE; > mFlags.mIsTopOfPage = PR_FALSE; >+ mFlags.mNextInFlowUntouched = PR_FALSE; > mFlags.mUnused = 0; > mPercentHeightObserver = nsnull; > mPercentHeightReflowInitiator = nsnull; > Init(aPresContext); > #ifdef IBMBIDI > mFlags.mVisualBidiFormControl = IsBidiFormControl(aPresContext); > mRightEdge = NS_UNCONSTRAINEDSIZE; > #endif // IBMBIDI > } > >+static PRBool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent) >+{ >+ nsIFrame* frameNext; >+ aFrame->GetNextInFlow(&frameNext); >+ nsIFrame* parentNext; >+ aParent->GetNextInFlow(&parentNext); >+ return frameNext && parentNext && frameNext->GetParent() == parentNext; >+} >+ > // Initialize a reflow state for a child frames reflow. Some state > // is copied from the parent reflow state; the remaining state is > // computed. > nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, > const nsHTMLReflowState& aParentReflowState, > nsIFrame* aFrame, > const nsSize& aAvailableSpace, > nsReflowReason aReason, >@@ -179,16 +190,18 @@ nsHTMLReflowState::nsHTMLReflowState(nsP > > availableWidth = aAvailableSpace.width; > availableHeight = aAvailableSpace.height; > > rendContext = aParentReflowState.rendContext; > mSpaceManager = aParentReflowState.mSpaceManager; > mLineLayout = aParentReflowState.mLineLayout; > mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; >+ mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched && >+ CheckNextInFlowParenthood(aFrame, aParentReflowState.frame); > mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && > aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) > ? aParentReflowState.mPercentHeightObserver : nsnull; > mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; > > if (aInit) { > Init(aPresContext); > } >@@ -224,16 +237,18 @@ nsHTMLReflowState::nsHTMLReflowState(nsP > > availableWidth = aAvailableSpace.width; > availableHeight = aAvailableSpace.height; > > rendContext = aParentReflowState.rendContext; > mSpaceManager = aParentReflowState.mSpaceManager; > mLineLayout = aParentReflowState.mLineLayout; > mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; >+ mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched && >+ CheckNextInFlowParenthood(aFrame, aParentReflowState.frame); > mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && > aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) > ? aParentReflowState.mPercentHeightObserver : nsnull; > mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; > > Init(aPresContext); > > #ifdef IBMBIDI >@@ -269,16 +284,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP > > availableWidth = aAvailableSpace.width; > availableHeight = aAvailableSpace.height; > > rendContext = aParentReflowState.rendContext; > mSpaceManager = aParentReflowState.mSpaceManager; > mLineLayout = aParentReflowState.mLineLayout; > mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; >+ mFlags.mNextInFlowUntouched = PR_FALSE; > mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && > aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) > ? aParentReflowState.mPercentHeightObserver : nsnull; > mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; > > Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); > > #ifdef IBMBIDI >Index: layout/html/base/src/nsLineLayout.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/base/src/nsLineLayout.cpp,v >retrieving revision 3.201 >diff -u -t -p -8 -r3.201 nsLineLayout.cpp >--- layout/html/base/src/nsLineLayout.cpp 31 Jul 2004 23:15:10 -0000 3.201 >+++ layout/html/base/src/nsLineLayout.cpp 21 Aug 2004 22:52:03 -0000 >@@ -60,16 +60,17 @@ > #include "nsIHTMLDocument.h" > #include "nsIContent.h" > #include "nsITextContent.h" > #include "nsIView.h" > #include "nsIViewManager.h" > #include "nsHTMLAtoms.h" > #include "nsTextFragment.h" > #include "nsBidiUtils.h" >+#include "nsLayoutUtils.h" > > #ifdef DEBUG > #undef NOISY_HORIZONTAL_ALIGN > #undef NOISY_VERTICAL_ALIGN > #undef REALLY_NOISY_VERTICAL_ALIGN > #undef NOISY_REFLOW > #undef REALLY_NOISY_REFLOW > #undef NOISY_PUSHING >@@ -998,35 +999,32 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra > pfd->mJustificationNumSpaces = mTextJustificationNumSpaces; > pfd->mJustificationNumLetters = mTextJustificationNumLetters; > > // XXX See if the frame is a placeholderFrame and if it is process > // the float. > if (frameType) { > if (nsLayoutAtoms::placeholderFrame == frameType) { > pfd->SetFlag(PFD_ISPLACEHOLDERFRAME, PR_TRUE); >- nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame(); >+ nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame); > if (outOfFlowFrame) { >- // Make sure it's floated and not absolutely positioned >- const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay(); >- if (!display->IsAbsolutelyPositioned()) { >- if (eReflowReason_Incremental == reason) { >- InitFloat((nsPlaceholderFrame*)aFrame, aReflowStatus); >- } >- else { >- AddFloat((nsPlaceholderFrame*)aFrame, aReflowStatus); >- } >- if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { >- SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); >- // An incomplete reflow status means we should split the >- // float if the height is constrained (bug 145305). We >- // never split floating first letters. >- if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) >- aReflowStatus = NS_FRAME_COMPLETE; >- } >+ nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame); >+ if (eReflowReason_Incremental == reason) { >+ InitFloat(placeholder, aReflowStatus); >+ } >+ else { >+ AddFloat(placeholder, aReflowStatus); >+ } >+ if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) { >+ SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE); >+ // An incomplete reflow status means we should split the >+ // float if the height is constrained (bug 145305). We >+ // never split floating first letters. >+ if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) >+ aReflowStatus = NS_FRAME_COMPLETE; > } > } > } > else if (nsLayoutAtoms::textFrame == frameType) { > // Note non-empty text-frames for inline frame compatability hackery > pfd->SetFlag(PFD_ISTEXTFRAME, PR_TRUE); > // XXX An empty text frame at the end of the line seems not > // to have zero width. >Index: layout/html/document/src/ua.css >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/document/src/ua.css,v >retrieving revision 3.212 >diff -u -t -p -8 -r3.212 ua.css >--- layout/html/document/src/ua.css 20 Jun 2004 09:51:10 -0000 3.212 >+++ layout/html/document/src/ua.css 21 Aug 2004 22:52:03 -0000 >@@ -142,16 +142,20 @@ > *|*::-moz-scrolled-content { > /* e.g., text inputs, select boxes */ > padding: inherit; > display: inherit; > -moz-box-orient: inherit; > -moz-counter-reset: inherit; > } > >+*|*::-moz-column-content { >+ /* the column boxes inside a column-flowed block */ >+} >+ > *|*::-moz-page, *|*::-moz-page-sequence { > display: block !important; > background: transparent; > } > > *|*::-moz-pagecontent { > display: block !important; > } >Index: layout/html/style/src/nsCSSFrameConstructor.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp,v >retrieving revision 1.965 >diff -u -t -p -8 -r1.965 nsCSSFrameConstructor.cpp >--- layout/html/style/src/nsCSSFrameConstructor.cpp 20 Aug 2004 20:34:35 -0000 1.965 >+++ layout/html/style/src/nsCSSFrameConstructor.cpp 21 Aug 2004 22:52:43 -0000 >@@ -6302,17 +6288,17 @@ nsCSSFrameConstructor::ConstructFrameByD > if (!pseudoParent && !aState.mPseudoFrames.IsEmpty()) { // process pending pseudo frames > ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aFrameItems); > } > // Create an area frame > NS_NewFloatingItemWrapperFrame(aPresShell, &newFrame); > > ConstructBlock(aPresShell, aPresContext, aState, aDisplay, aContent, > aState.mFloatedItems.containingBlock, adjParentFrame, >- aStyleContext, newFrame, >+ aStyleContext, &newFrame, > aDisplay->mPosition == NS_STYLE_POSITION_RELATIVE); > } > // See if it's relatively positioned > else if ((NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) && > ((NS_STYLE_DISPLAY_BLOCK == aDisplay->mDisplay) || > (NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay) || > (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay))) { > if (!pseudoParent && !aState.mPseudoFrames.IsEmpty()) { // process pending pseudo frames >@@ -6320,17 +6306,17 @@ nsCSSFrameConstructor::ConstructFrameByD > } > // Is it block-level or inline-level? > if ((NS_STYLE_DISPLAY_BLOCK == aDisplay->mDisplay) || > (NS_STYLE_DISPLAY_LIST_ITEM == aDisplay->mDisplay)) { > // Create a wrapper frame. No space manager, though > NS_NewRelativeItemWrapperFrame(aPresShell, &newFrame); > // XXXbz should we be passing in a non-null aContentParentFrame? > ConstructBlock(aPresShell, aPresContext, aState, aDisplay, aContent, >- adjParentFrame, nsnull, aStyleContext, newFrame, PR_TRUE); >+ adjParentFrame, nsnull, aStyleContext, &newFrame, PR_TRUE); > } else { > // Create a positioned inline frame > NS_NewPositionedInlineFrame(aPresShell, &newFrame); > ConstructInline(aPresShell, aPresContext, aState, aDisplay, aContent, > adjParentFrame, aStyleContext, PR_TRUE, newFrame, > &newBlock, &nextInline); > } > } >@@ -6345,17 +6331,17 @@ nsCSSFrameConstructor::ConstructFrameByD > } > // Create the block frame > rv = NS_NewBlockFrame(aPresShell, &newFrame); > if (NS_SUCCEEDED(rv)) { // That worked so construct the block and its children > nsPseudoFrames savePseudo; > aState.mPseudoFrames.Reset(&savePseudo); > // XXXbz should we be passing in a non-null aContentParentFrame? > rv = ConstructBlock(aPresShell, aPresContext, aState, aDisplay, aContent, >- adjParentFrame, nsnull, aStyleContext, newFrame, >+ adjParentFrame, nsnull, aStyleContext, &newFrame, > PR_FALSE); > if (!aState.mPseudoFrames.IsEmpty()) { // process pending pseudo frames > ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aFrameItems); > } > aState.mPseudoFrames = savePseudo; > } > } > // See if it's an inline frame of some sort >@@ -6974,17 +6960,17 @@ nsCSSFrameConstructor::ConstructSVGFrame > // Claim to be relatively positioned so that we end up being the > // absolute containing block. Also, push "null" as the floater > // containing block so that we get the SPACE_MGR bit set. > nsFrameConstructorSaveState saveState; > aState.PushFloatContainingBlock(nsnull, saveState, PR_FALSE, PR_FALSE); > const nsStyleDisplay* disp = aStyleContext->GetStyleDisplay(); > rv = ConstructBlock(aPresShell, aPresContext, aState, disp, aContent, > geometricParent, aParentFrame, aStyleContext, >- newFrame, PR_TRUE); >+ &newFrame, PR_TRUE); > } else { > InitAndRestoreFrame(aPresContext, aState, aContent, > geometricParent, aStyleContext, nsnull, newFrame); > > nsHTMLContainerFrame::CreateViewForFrame(newFrame, aParentFrame, forceView); > > // Process the child content if requested > nsFrameItems childItems; >@@ -9907,17 +9893,17 @@ nsCSSFrameConstructor::RestyleElement(ns > nsIContent *aContent, > nsIFrame *aPrimaryFrame, > nsChangeHint aMinHint) > { > if (aMinHint & nsChangeHint_ReconstructFrame) { > RecreateFramesForContent(aPresContext, aContent); > } else if (aPrimaryFrame) { > nsStyleChangeList changeList; >- if (aMinHint != NS_STYLE_HINT_NONE) { >+ if (aMinHint) { > changeList.AppendChange(aPrimaryFrame, aContent, aMinHint); > } > nsChangeHint frameChange = aPresContext->GetPresShell()->FrameManager()-> > ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint); > > if (frameChange & nsChangeHint_ReconstructFrame) { > RecreateFramesForContent(aPresContext, aContent); > changeList.Clear(); >@@ -10681,16 +10667,25 @@ nsCSSFrameConstructor::CreateContinuingF > rv = NS_NewAreaFrame(shell, &newFrame, 0); > if (NS_SUCCEEDED(rv)) { > newFrame->Init(aPresContext, content, aParentFrame, styleContext, > aFrame); > // XXXbz should we be passing in a non-null aContentParentFrame? > nsHTMLContainerFrame::CreateViewForFrame(newFrame, nsnull, PR_FALSE); > } > >+ } else if (nsLayoutAtoms::columnFrame == frameType) { >+ rv = NS_NewColumnFrame(shell, &newFrame, 0); >+ if (NS_SUCCEEDED(rv)) { >+ newFrame->Init(aPresContext, content, aParentFrame, styleContext, >+ aFrame); >+ // XXXbz should we be passing in a non-null aContentParentFrame? >+ nsHTMLContainerFrame::CreateViewForFrame(newFrame, nsnull, PR_FALSE); >+ } >+ > } else if (nsLayoutAtoms::positionedInlineFrame == frameType) { > rv = NS_NewPositionedInlineFrame(shell, &newFrame); > if (NS_SUCCEEDED(rv)) { > newFrame->Init(aPresContext, content, aParentFrame, styleContext, aFrame); > // XXXbz should we be passing in a non-null aContentParentFrame? > nsHTMLContainerFrame::CreateViewForFrame(newFrame, nsnull, PR_FALSE); > } > >@@ -12465,70 +12460,104 @@ nsresult > nsCSSFrameConstructor::ConstructBlock(nsIPresShell* aPresShell, > nsPresContext* aPresContext, > nsFrameConstructorState& aState, > const nsStyleDisplay* aDisplay, > nsIContent* aContent, > nsIFrame* aParentFrame, > nsIFrame* aContentParentFrame, > nsStyleContext* aStyleContext, >- nsIFrame* aNewFrame, >+ nsIFrame** aNewFrame, > PRBool aRelPos) > { >- InitAndRestoreFrame(aPresContext, aState, aContent, >- aParentFrame, aStyleContext, nsnull, aNewFrame); >+ // Create column wrapper if necessary >+ nsIFrame* blockFrame = *aNewFrame; >+ nsIFrame* parent = aParentFrame; >+ nsIFrame* contentParent = aContentParentFrame; >+ nsRefPtr<nsStyleContext> blockStyle = aStyleContext; >+ const nsStyleColumn* columns = aStyleContext->GetStyleColumn(); >+ >+ if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO >+ || columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) { >+ nsIFrame* columnFrame = nsnull; >+ NS_NewColumnFrame(aPresShell, &columnFrame, 0); >+ if (!columnFrame) { >+ return NS_ERROR_OUT_OF_MEMORY; >+ } >+ >+ InitAndRestoreFrame(aPresContext, aState, aContent, >+ aParentFrame, aStyleContext, nsnull, columnFrame); >+ // See if we need to create a view, e.g. the frame is absolutely positioned >+ nsHTMLContainerFrame::CreateViewForFrame(columnFrame, aContentParentFrame, >+ PR_FALSE); >+ blockStyle = aPresContext->StyleSet()-> >+ ResolvePseudoStyleFor(aContent, nsCSSAnonBoxes::columnContent, >+ aStyleContext); >+ contentParent = columnFrame; >+ parent = columnFrame; >+ *aNewFrame = columnFrame; >+ >+ columnFrame->SetInitialChildList(aPresContext, nsnull, blockFrame); >+ >+ blockFrame->AddStateBits(NS_BLOCK_SPACE_MGR); >+ } >+ >+ InitAndRestoreFrame(aPresContext, aState, aContent, >+ parent, blockStyle, nsnull, blockFrame); > > // See if we need to create a view, e.g. the frame is absolutely positioned >- nsHTMLContainerFrame::CreateViewForFrame(aNewFrame, aContentParentFrame, >- PR_FALSE); >+ nsHTMLContainerFrame::CreateViewForFrame(blockFrame, contentParent, PR_FALSE); > > // If we're the first block to be created (e.g., because we're > // contained inside a XUL document), then make sure that we've got a > // space manager so we can handle floats... > if (! aState.mFloatedItems.containingBlock) { >- aNewFrame->AddStateBits(NS_BLOCK_SPACE_MGR | NS_BLOCK_MARGIN_ROOT); >+ blockFrame->AddStateBits(NS_BLOCK_SPACE_MGR | NS_BLOCK_MARGIN_ROOT); > } > > // ...and that we're the absolute containing block. >+ // This makes absolute children of a block in columns be positioned >+ // relative to the container, not flowed into columns. I don't know if this >+ // is right... > nsFrameConstructorSaveState absoluteSaveState; > if (aRelPos || !aState.mAbsoluteItems.containingBlock) { > // NS_ASSERTION(aRelPos, "should have made area frame for this"); >- aState.PushAbsoluteContainingBlock(aPresContext, aNewFrame, absoluteSaveState); >+ aState.PushAbsoluteContainingBlock(aPresContext, *aNewFrame, absoluteSaveState); > } > > // See if the block has first-letter style applied to it... > PRBool haveFirstLetterStyle, haveFirstLineStyle; > HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, > &haveFirstLetterStyle, &haveFirstLineStyle); > > // Process the child content > nsFrameItems childItems; > nsFrameConstructorSaveState floatSaveState; >- aState.PushFloatContainingBlock(aNewFrame, floatSaveState, >+ aState.PushFloatContainingBlock(blockFrame, floatSaveState, > haveFirstLetterStyle, > haveFirstLineStyle); > nsresult rv = ProcessChildren(aPresShell, aPresContext, aState, aContent, >- aNewFrame, PR_TRUE, childItems, PR_TRUE); >+ blockFrame, PR_TRUE, childItems, PR_TRUE); > > CreateAnonymousFrames(aPresShell, aPresContext, aContent->Tag(), aState, >- aContent, aNewFrame, PR_FALSE, childItems); >+ aContent, blockFrame, PR_FALSE, childItems); > > // Set the frame's initial child list >- aNewFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList); >+ blockFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList); > > // Set the frame's float list if there were any floated children > if (aState.mFloatedItems.childList) { >- aNewFrame->SetInitialChildList(aPresContext, >- nsLayoutAtoms::floatList, >- aState.mFloatedItems.childList); >+ blockFrame->SetInitialChildList(aPresContext, >+ nsLayoutAtoms::floatList, >+ aState.mFloatedItems.childList); > } > // and the same for absolutely positioned children. > if (aRelPos && aState.mAbsoluteItems.childList) { >- aNewFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::absoluteList, >- aState.mAbsoluteItems.childList); >+ blockFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::absoluteList, >+ aState.mAbsoluteItems.childList); > } > > return rv; > } > > PRBool > nsCSSFrameConstructor::AreAllKidsInline(nsIFrame* aFrameList) > { >@@ -13329,17 +13358,17 @@ ProcessRestyle(nsISupports* aContent, > > nsIPresShell* shell = context->PresShell(); > > nsIFrame* primaryFrame = nsnull; > shell->GetPrimaryFrameFor(content, &primaryFrame); > if (aData.mRestyleHint & eReStyle_Self) { > shell->FrameConstructor()->RestyleElement(context, content, primaryFrame, > aData.mChangeHint); >- } else if (aData.mChangeHint != NS_STYLE_HINT_NONE && >+ } else if (aData.mChangeHint && > (primaryFrame || > (aData.mChangeHint & nsChangeHint_ReconstructFrame))) { > // Don't need to recompute style; just apply the hint > nsStyleChangeList changeList; > changeList.AppendChange(primaryFrame, content, aData.mChangeHint); > shell->FrameConstructor()->ProcessRestyledFrames(changeList, context); > } > >@@ -13361,17 +13390,17 @@ nsCSSFrameConstructor::ProcessPendingRes > mPendingRestyles.Clear(); > } > > void > nsCSSFrameConstructor::PostRestyleEvent(nsIContent* aContent, > nsReStyleHint aRestyleHint, > nsChangeHint aMinChangeHint) > { >- if (aRestyleHint == 0 && aMinChangeHint == NS_STYLE_HINT_NONE) { >+ if (aRestyleHint == 0 && !aMinChangeHint) { > // Nothing to do here > return; > } > > RestyleData existingData; > existingData.mRestyleHint = nsReStyleHint(0); > existingData.mChangeHint = NS_STYLE_HINT_NONE; > >Index: layout/html/style/src/nsCSSFrameConstructor.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/html/style/src/nsCSSFrameConstructor.h,v >retrieving revision 1.155 >diff -u -t -p -8 -r1.155 nsCSSFrameConstructor.h >--- layout/html/style/src/nsCSSFrameConstructor.h 10 Aug 2004 03:24:40 -0000 1.155 >+++ layout/html/style/src/nsCSSFrameConstructor.h 21 Aug 2004 22:52:47 -0000 >@@ -825,17 +825,17 @@ private: > nsresult ConstructBlock(nsIPresShell* aPresShell, > nsPresContext* aPresContext, > nsFrameConstructorState& aState, > const nsStyleDisplay* aDisplay, > nsIContent* aContent, > nsIFrame* aParentFrame, > nsIFrame* aContentParentFrame, > nsStyleContext* aStyleContext, >- nsIFrame* aNewFrame, >+ nsIFrame** aNewFrame, > PRBool aRelPos); > > nsresult ConstructInline(nsIPresShell* aPresShell, > nsPresContext* aPresContext, > nsFrameConstructorState& aState, > const nsStyleDisplay* aDisplay, > nsIContent* aContent, > nsIFrame* aParentFrame, >Index: layout/html/base/src/nsColumnFrame.cpp >=================================================================== >RCS file: layout/html/base/src/nsColumnFrame.cpp >diff -N layout/html/base/src/nsColumnFrame.cpp >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ layout/html/base/src/nsColumnFrame.cpp 21 Aug 2004 22:59:53 -0000 >@@ -0,0 +1,865 @@ >+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ >+/* ***** BEGIN LICENSE BLOCK ***** >+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 >+ * >+ * The contents of this file are subject to the Mozilla Public License Version >+ * 1.1 (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * http://www.mozilla.org/MPL/ >+ * >+ * Software distributed under the License is distributed on an "AS IS" basis, >+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License >+ * for the specific language governing rights and limitations under the >+ * License. >+ * >+ * The Original Code is mozilla.org code. >+ * >+ * The Initial Developer of the Original Code is >+ * Netscape Communications Corporation. >+ * Portions created by the Initial Developer are Copyright (C) 1998 >+ * the Initial Developer. All Rights Reserved. >+ * >+ * Contributor(s): >+ * roc@ocallahan.org >+ * >+ * Alternatively, the contents of this file may be used under the terms of >+ * either of the GNU General Public License Version 2 or later (the "GPL"), >+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), >+ * in which case the provisions of the GPL or the LGPL are applicable instead >+ * of those above. If you wish to allow use of your version of this file only >+ * under the terms of either the GPL or the LGPL, and not to allow others to >+ * use your version of this file under the terms of the MPL, indicate your >+ * decision by deleting the provisions above and replace them with the notice >+ * and other provisions required by the GPL or the LGPL. If you do not delete >+ * the provisions above, a recipient may use your version of this file under >+ * the terms of any one of the MPL, the GPL or the LGPL. >+ * >+ * ***** END LICENSE BLOCK ***** */ >+ >+#include "nsHTMLContainerFrame.h" >+#include "nsCSSRendering.h" >+#include "nsIContent.h" >+#include "nsIFrame.h" >+#include "nsISupports.h" >+#include "nsIAtom.h" >+#include "nsPresContext.h" >+#include "nsHTMLParts.h" >+#include "nsHTMLAtoms.h" >+#include "nsLayoutAtoms.h" >+#include "nsStyleConsts.h" >+#include "nsCOMPtr.h" >+#include "nsIServiceManager.h" >+#include "nsReflowPath.h" >+#include "nsCSSFrameConstructor.h" >+ >+class nsColumnFrame : public nsHTMLContainerFrame { >+public: >+ nsColumnFrame(); >+ >+ NS_IMETHOD SetInitialChildList(nsPresContext* aPresContext, >+ nsIAtom* aListName, >+ nsIFrame* aChildList); >+ >+ NS_IMETHOD Reflow(nsPresContext* aPresContext, >+ nsHTMLReflowMetrics& aDesiredSize, >+ const nsHTMLReflowState& aReflowState, >+ nsReflowStatus& aStatus); >+ >+ NS_IMETHOD AppendFrames(nsPresContext* aPresContext, >+ nsIPresShell& aPresShell, >+ nsIAtom* aListName, >+ nsIFrame* aFrameList); >+ NS_IMETHOD InsertFrames(nsPresContext* aPresContext, >+ nsIPresShell& aPresShell, >+ nsIAtom* aListName, >+ nsIFrame* aPrevFrame, >+ nsIFrame* aFrameList); >+ NS_IMETHOD RemoveFrame(nsPresContext* aPresContext, >+ nsIPresShell& aPresShell, >+ nsIAtom* aListName, >+ nsIFrame* aOldFrame); >+ >+ virtual nsIFrame* GetContentInsertionFrame() { >+ return GetFirstChild(nsnull)->GetContentInsertionFrame(); >+ } >+ >+ virtual nsIAtom* GetType() const; >+ >+#ifdef DEBUG >+ NS_IMETHOD GetFrameName(nsAString& aResult) const { >+ return MakeFrameName(NS_LITERAL_STRING("Column"), aResult); >+ } >+#endif >+ >+protected: >+ nscoord mLastBalanceHeight; >+ nsReflowStatus mLastFrameStatus; >+ >+ virtual PRIntn GetSkipSides() const; >+ >+ /** >+ * These are the parameters that control the layout of columns. >+ */ >+ struct ReflowConfig { >+ PRInt32 mBalanceColCount; >+ nscoord mColWidth; >+ nscoord mExpectedWidthLeftOver; >+ nscoord mColGap; >+ nscoord mColMaxHeight; >+ }; >+ >+ /** >+ * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not >+ * handled by our prev-in-flow, and any columns sitting on our own >+ * overflow list, and put them in our primary child list for reflowing. >+ */ >+ void DrainOverflowColumns(); >+ >+ /** >+ * The basic reflow strategy is to call this function repeatedly to >+ * obtain specific parameters that determine the layout of the >+ * columns. This function will compute those parameters from the CSS >+ * style. This function will also be responsible for implementing >+ * the state machine that controls column balancing. >+ */ >+ ReflowConfig ChooseColumnStrategy(const nsHTMLReflowState& aReflowState); >+ >+ /** >+ * Reflow column children. Returns PR_TRUE iff the content that was reflowed >+ * fit into the mColMaxHeight. >+ */ >+ PRBool ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, >+ const nsHTMLReflowState& aReflowState, >+ nsReflowReason aReason, >+ nsReflowStatus& aStatus, >+ const ReflowConfig& aConfig, >+ PRBool aLastColumnUnbounded); >+}; >+ >+/** >+ * Tracking issues: >+ * >+ * XXX cursor movement around the top and bottom of colums seems to make the editor >+ * lose the caret. >+ * >+ * XXX should we support CSS columns applied to table elements? >+ */ >+nsresult >+NS_NewColumnFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aStateFlags ) >+{ >+ NS_PRECONDITION(aNewFrame, "null OUT ptr"); >+ if (nsnull == aNewFrame) { >+ return NS_ERROR_NULL_POINTER; >+ } >+ nsColumnFrame* it = new (aPresShell) nsColumnFrame; >+ if (!it) { >+ return NS_ERROR_OUT_OF_MEMORY; >+ } >+ >+ // set the state flags (if any are provided) >+ it->AddStateBits(aStateFlags); >+ >+ *aNewFrame = it; >+ return NS_OK; >+} >+ >+nsColumnFrame::nsColumnFrame() >+ : nsHTMLContainerFrame(), mLastBalanceHeight(NS_INTRINSICSIZE), >+ mLastFrameStatus(NS_FRAME_COMPLETE) >+{ >+} >+ >+nsIAtom* >+nsColumnFrame::GetType() const >+{ >+ return nsLayoutAtoms::columnFrame; >+} >+ >+NS_IMETHODIMP >+nsColumnFrame::SetInitialChildList(nsPresContext* aPresContext, >+ nsIAtom* aListName, >+ nsIFrame* aChildList) >+{ >+ NS_ASSERTION(!aListName, "Only normal children supported"); >+ NS_ASSERTION(aChildList && !aChildList->GetNextSibling(), >+ "must set to a singleton initial child list"); >+ // Queue up the frames for the content frame >+ return nsHTMLContainerFrame::SetInitialChildList(aPresContext, nsnull, aChildList); >+} >+ >+static nscoord GetAvailableContentHeight(const nsHTMLReflowState& aReflowState) { >+ if (aReflowState.availableHeight == NS_INTRINSICSIZE) { >+ return NS_INTRINSICSIZE; >+ } >+ nscoord borderPaddingHeight = >+ aReflowState.mComputedBorderPadding.top + >+ aReflowState.mComputedBorderPadding.bottom; >+ return PR_MAX(0, aReflowState.availableHeight - borderPaddingHeight); >+} >+ >+nsColumnFrame::ReflowConfig >+nsColumnFrame::ChooseColumnStrategy(const nsHTMLReflowState& aReflowState) >+{ >+ const nsStyleColumn* colStyle = GetStyleColumn(); >+ nscoord availWidth = aReflowState.availableWidth; >+ if (aReflowState.mComputedWidth != NS_INTRINSICSIZE) { >+ availWidth = aReflowState.mComputedWidth; >+ } >+ nscoord colHeight = GetAvailableContentHeight(aReflowState); >+ if (aReflowState.mComputedHeight != NS_INTRINSICSIZE) { >+ colHeight = aReflowState.mComputedHeight; >+ } >+ >+ nscoord colGap = 0; >+ switch (colStyle->mColumnGap.GetUnit()) { >+ case eStyleUnit_Coord: >+ colGap = colStyle->mColumnGap.GetCoordValue(); >+ break; >+ case eStyleUnit_Percent: >+ if (availWidth != NS_INTRINSICSIZE) { >+ colGap = NSToCoordRound(colStyle->mColumnGap.GetPercentValue()*availWidth); >+ } >+ break; >+ default: >+ NS_NOTREACHED("Unknown gap type"); >+ break; >+ } >+ >+ nscoord colWidth = NS_INTRINSICSIZE; >+ if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) { >+ colWidth = colStyle->mColumnWidth.GetCoordValue(); >+ } else if (colStyle->mColumnCount > 0 && availWidth != NS_INTRINSICSIZE) { >+ nscoord widthMinusGaps = availWidth - colGap*(colStyle->mColumnCount - 1); >+ colWidth = widthMinusGaps/colStyle->mColumnCount; >+ } >+ >+ if (colWidth < 1) { >+ colWidth = 1; >+ } >+ >+ PRInt32 numColumns = colStyle->mColumnCount; >+ nscoord expectedWidthLeftOver = 0; >+ >+ if (colWidth != NS_INTRINSICSIZE && availWidth != NS_INTRINSICSIZE) { >+ // distribute leftover space >+ >+ // First, determine how many columns will be showing >+ if (numColumns <= 0) { >+ // choose so that colGap*(nominalColumnCount - 1) + >+ // colWidth*nominalColumnCount is nearly availWidth >+ // make sure to round down >+ numColumns = (availWidth + colGap)/(colGap + colWidth); >+ } >+ >+ // Compute extra space and divide it among the columns >+ nscoord extraSpace = availWidth - (colWidth*numColumns + colGap*(numColumns - 1)); >+ nscoord extraToColumns = extraSpace/numColumns; >+ colWidth += extraToColumns; >+ expectedWidthLeftOver = extraSpace - (extraToColumns*numColumns); >+ } >+ >+ if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) { >+ // Balancing! >+ if (numColumns <= 0) { >+ // Hmm, auto column count, column width or available width is unknown, >+ // and balancing is required. Let's just use one column then. >+ numColumns = 1; >+ } >+ colHeight = PR_MIN(mLastBalanceHeight, GetAvailableContentHeight(aReflowState)); >+ } else { >+ // No balancing, so don't limit the column count >+ numColumns = PR_INT32_MAX; >+ } >+ >+#ifdef DEBUG_roc >+ printf("*** nsColumnFrame::ChooseColumnStrategy: numColumns=%d, colWidth=%d, expectedWidthLeftOver=%d, colHeight=%d, colGap=%d\n", >+ numColumns, colWidth, expectedWidthLeftOver, colHeight, colGap); >+#endif >+ ReflowConfig config = { numColumns, colWidth, expectedWidthLeftOver, colGap, colHeight }; >+ return config; >+} >+ >+// XXX copied from nsBlockFrame, should this be moved to nsContainerFrame? >+static void >+PlaceFrameView(nsIFrame* aFrame) >+{ >+ if (aFrame->HasView()) >+ nsContainerFrame::PositionFrameView(aFrame->GetPresContext(), aFrame); >+ else >+ nsContainerFrame::PositionChildViews(aFrame->GetPresContext(), aFrame); >+} >+ >+static void MoveChildTo(nsIFrame* aParent, nsIFrame* aChild, nsPoint aOrigin) { >+ if (aChild->GetPosition() == aOrigin) { >+ return; >+ } >+ >+ nsRect* overflowArea = aChild->GetOverflowAreaProperty(PR_FALSE); >+ nsRect r = overflowArea ? *overflowArea : nsRect(nsPoint(0, 0), aChild->GetSize()); >+ r += aChild->GetPosition(); >+ aParent->Invalidate(r); >+ r -= aChild->GetPosition(); >+ aChild->SetPosition(aOrigin); >+ r += aOrigin; >+ aParent->Invalidate(r); >+ PlaceFrameView(aChild); >+} >+ >+PRBool >+nsColumnFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, >+ const nsHTMLReflowState& aReflowState, >+ nsReflowReason aKidReason, >+ nsReflowStatus& aStatus, >+ const ReflowConfig& aConfig, >+ PRBool aUnboundedLastColumn) { >+ PRBool allFit = PR_TRUE; >+ PRBool RTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; >+ PRBool shrinkingHeightOnly = aKidReason == eReflowReason_Resize && >+ mLastBalanceHeight > aConfig.mColMaxHeight; >+ >+#ifdef DEBUG_roc >+ printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n", >+ mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount, >+ aConfig.mColWidth, aConfig.mColGap); >+#endif >+ >+ DrainOverflowColumns(); >+ >+ if (mLastBalanceHeight != aConfig.mColMaxHeight) { >+ mLastBalanceHeight = aConfig.mColMaxHeight; >+ // XXX Seems like this could fire if incremental reflow pushed the column set >+ // down so we reflow incrementally with a different available height. >+ // We need a way to do an incremental reflow and be sure availableHeight >+ // changes are taken account of! Right now I think block frames with absolute >+ // children might exit early. >+ NS_ASSERTION(aKidReason != eReflowReason_Incremental, >+ "incremental reflow should not have changed the balance height"); >+ } >+ >+ // get our border and padding >+ const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; >+ >+ nsRect contentRect(0, 0, 0, 0); >+ aDesiredSize.mMaxElementWidth = 0; >+ nsRect overflowRect(0, 0, 0, 0); >+ >+ nsIFrame* child = mFrames.FirstChild(); >+ nsPoint childOrigin = nsPoint(borderPadding.left, borderPadding.top); >+ // For RTL, figure out where the last column's left edge should be. Since the >+ // columns might not fill the frame exactly, we need to account for the >+ // slop. Otherwise we'll waste time moving the columns by some tiny >+ // amount unnecessarily. >+ nscoord targetX = borderPadding.left; >+ if (RTL) { >+ nscoord availWidth = aReflowState.availableWidth; >+ if (aReflowState.mComputedWidth != NS_INTRINSICSIZE) { >+ availWidth = aReflowState.mComputedWidth; >+ } >+ if (availWidth != NS_INTRINSICSIZE) { >+ childOrigin.x += availWidth - aConfig.mColWidth; >+ targetX += aConfig.mExpectedWidthLeftOver; >+#ifdef DEBUG_roc >+ printf("*** childOrigin.x = %d\n", childOrigin.x); >+#endif >+ } >+ } >+ int columnCount = 0; >+ PRBool reflowNext = PR_FALSE; >+ >+ while (child) { >+ // Try to skip reflowing the child. We can't skip if the child is dirty. We also can't >+ // skip if the next column is dirty, because the next column's first line(s) >+ // might be pullable back to this column. >+ PRBool skipIncremental = aKidReason == eReflowReason_Incremental >+ && !(child->GetStateBits() & NS_FRAME_IS_DIRTY) >+ && (!child->GetNextSibling() >+ || !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) >+ && !aDesiredSize.mComputeMEW; >+ PRBool skipResizeHeightShrink = shrinkingHeightOnly >+ && child->GetSize().height <= aConfig.mColMaxHeight; >+ if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) { >+ // This child does not need to be reflowed, but we may need to move it >+ MoveChildTo(this, child, childOrigin); >+ >+ // If this is the last frame then make sure we get the right status >+ if (child->GetNextSibling()) { >+ aStatus = NS_FRAME_NOT_COMPLETE; >+ } else { >+ aStatus = mLastFrameStatus; >+ } >+#ifdef DEBUG_roc >+ printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n", >+ columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus); >+#endif >+ } else { >+ nsSize availSize(aConfig.mColWidth, aConfig.mColMaxHeight); >+ >+ if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) { >+ availSize.height = GetAvailableContentHeight(aReflowState); >+ } >+ >+ nsReflowReason tmpReason = aKidReason; >+ if (reflowNext && aKidReason == eReflowReason_Incremental >+ && !(child->GetStateBits() & NS_FRAME_IS_DIRTY)) { >+ // If this frame was not being incrementally reflowed but was >+ // just reflowed because the previous frame wants us to >+ // reflow, then force this child to reflow its dirty lines! >+ // XXX what we should really do here is add the child block to >+ // the incremental reflow path! Currently I think if there's an >+ // incremental reflow targeted only at the absolute frames of a >+ // column, then the column will be dirty BUT reflowing it will >+ // not reflow any lines affected by the prev-in-flow! >+ tmpReason = eReflowReason_Dirty; >+ } >+ >+ nsHTMLReflowState kidReflowState(GetPresContext(), aReflowState, child, >+ availSize, tmpReason); >+ >+#ifdef DEBUG_roc >+ printf("*** Reflowing child #%d %p: reason = %d, availHeight=%d\n", >+ columnCount, (void*)child, tmpReason, availSize.height); >+#endif >+ >+ // Note if the column's next in flow is not being changed by this incremental reflow. >+ // This may allow the current column to avoid trying to pull lines from the next column. >+ if (child->GetNextSibling() && aKidReason == eReflowReason_Incremental && >+ !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) { >+ kidReflowState.mFlags.mNextInFlowUntouched = PR_TRUE; >+ } >+ >+ nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); >+ >+ // XXX it would be cool to consult the space manager for the >+ // previous block to figure out the region of floats from the >+ // previous column that extend into this column, and subtract >+ // that region from the new space manager. So you could stick a >+ // really big float in the first column and text in following >+ // columns would flow around it. >+ >+ // Reflow the frame >+ ReflowChild(child, GetPresContext(), kidDesiredSize, kidReflowState, >+ childOrigin.x + kidReflowState.mComputedMargin.left, >+ childOrigin.y + kidReflowState.mComputedMargin.top, >+ 0, aStatus); >+ >+ // If the frame returned "truncated" status then we can assume >+ // it will fit once we reflow the next-in-flow. >+ if (kidDesiredSize.height > aConfig.mColMaxHeight >+ && !NS_FRAME_IS_TRUNCATED(aStatus)) { >+ allFit = PR_FALSE; >+ } >+ >+ reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0; >+ >+#ifdef DEBUG_roc >+ printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d\n", >+ columnCount, (void*)child, aStatus, kidDesiredSize.width, kidDesiredSize.height); >+#endif >+ >+ /** XXX print preview just doesn't work at all >+ */ >+ >+ NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus); >+ >+ FinishReflowChild(child, GetPresContext(), &kidReflowState, >+ kidDesiredSize, childOrigin.x, childOrigin.y, 0); >+ >+ if (aDesiredSize.mComputeMEW) { >+ aDesiredSize.mMaxElementWidth = PR_MAX(aDesiredSize.mMaxElementWidth, >+ kidDesiredSize.mMaxElementWidth); >+ } >+ } >+ >+ contentRect.UnionRect(contentRect, child->GetRect()); >+ >+ ConsiderChildOverflow(GetPresContext(), overflowRect, child); >+ >+ // Build a continuation column if necessary >+ nsIFrame* kidNextInFlow; >+ child->GetNextInFlow(&kidNextInFlow); >+ >+ if (NS_FRAME_IS_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) { >+ NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted"); >+ break; >+ } else { >+ ++columnCount; >+ // Make sure that the column has a next-in-flow. If not, we must >+ // create one to hold the overflowing stuff, even if we're just >+ // going to put it on our overflow list and let *our* >+ // next in flow handle it. >+ if (!kidNextInFlow) { >+ NS_ASSERTION(aStatus & NS_FRAME_REFLOW_NEXTINFLOW, >+ "We have to create a continuation, but the block doesn't want us to reflow it?"); >+ >+ // We need to create a continuing column >+ nsIFrame* continuation; >+ nsresult rv = CreateNextInFlow(GetPresContext(), this, child, continuation); >+ >+ if (NS_FAILED(rv)) { >+ NS_NOTREACHED("Couldn't create continuation"); >+ break; >+ } >+ >+ continuation->AddStateBits(NS_BLOCK_SPACE_MGR); >+ >+ // Do an initial reflow if we're going to reflow this thing. >+ aKidReason = eReflowReason_Initial; >+ } >+ >+ if (columnCount >= aConfig.mBalanceColCount) { >+ // No more columns allowed here. Stop. >+ aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; >+ >+ // Move any of our leftover columns to our overflow list. Our >+ // next-in-flow will eventually pick them up. >+ nsIFrame* continuationColumns = child->GetNextSibling(); >+ if (continuationColumns) { >+ SetOverflowFrames(GetPresContext(), continuationColumns); >+ child->SetNextSibling(nsnull); >+ } >+ break; >+ } >+ } >+ >+ // Advance to the next column >+ child = child->GetNextSibling(); >+ >+ if (child) { >+ if (!RTL) { >+ childOrigin.x += aConfig.mColWidth + aConfig.mColGap; >+ } else { >+ childOrigin.x -= aConfig.mColWidth + aConfig.mColGap; >+ } >+ >+#ifdef DEBUG_roc >+ printf("*** NEXT CHILD ORIGIN.x = %d\n", childOrigin.x); >+#endif >+ } >+ } >+ >+ // If we're doing RTL, we need to make sure our last column is at the left-hand side of the frame. >+ if (RTL && childOrigin.x != targetX) { >+ overflowRect = nsRect(0, 0, 0, 0); >+ contentRect = nsRect(0, 0, 0, 0); >+ PRInt32 deltaX = targetX - childOrigin.x; >+#ifdef DEBUG_roc >+ printf("*** CHILDORIGIN.x = %d, targetX = %d, DELTAX = %d\n", childOrigin.x, targetX, deltaX); >+#endif >+ for (child = mFrames.FirstChild(); child; child = child->GetNextSibling()) { >+ MoveChildTo(this, child, child->GetPosition() + nsPoint(deltaX, 0)); >+ ConsiderChildOverflow(GetPresContext(), overflowRect, child); >+ contentRect.UnionRect(contentRect, child->GetRect()); >+ } >+ } >+ >+ mLastFrameStatus = aStatus; >+ >+ // contentRect included the borderPadding.left,borderPadding.top of the child rects >+ contentRect -= nsPoint(borderPadding.left, borderPadding.top); >+ >+ nsSize contentSize = nsSize(contentRect.XMost(), contentRect.YMost()); >+ >+ // Apply computed and min/max values >+ if (aReflowState.mComputedHeight != NS_INTRINSICSIZE) { >+ contentSize.height = aReflowState.mComputedHeight; >+ } else { >+ if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) { >+ contentSize.height = PR_MIN(aReflowState.mComputedMaxHeight, contentSize.height); >+ } >+ if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) { >+ contentSize.height = PR_MAX(aReflowState.mComputedMinHeight, contentSize.height); >+ } >+ } >+ if (aReflowState.mComputedWidth != NS_INTRINSICSIZE) { >+ contentSize.width = aReflowState.mComputedWidth; >+ } else { >+ if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) { >+ contentSize.width = PR_MIN(aReflowState.mComputedMaxWidth, contentSize.width); >+ } >+ if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) { >+ contentSize.width = PR_MAX(aReflowState.mComputedMinWidth, contentSize.width); >+ } >+ } >+ >+ aDesiredSize.height = borderPadding.top + contentSize.height + >+ borderPadding.bottom; >+ aDesiredSize.width = contentSize.width + borderPadding.left + borderPadding.right; >+ aDesiredSize.ascent = aDesiredSize.height; >+ aDesiredSize.descent = 0; >+ aDesiredSize.mMaximumWidth = aDesiredSize.width; >+ if (aDesiredSize.mComputeMEW) { >+ // add in padding. >+ aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right; >+ } >+ overflowRect.UnionRect(overflowRect, nsRect(0, 0, aDesiredSize.width, aDesiredSize.height)); >+ aDesiredSize.mOverflowArea = overflowRect; >+ >+#ifdef DEBUG_roc >+ printf("*** DONE PASS feasible=%d\n", allFit && NS_FRAME_IS_COMPLETE(aStatus) >+ && !NS_FRAME_IS_TRUNCATED(aStatus)); >+#endif >+ return allFit && NS_FRAME_IS_COMPLETE(aStatus) >+ && !NS_FRAME_IS_TRUNCATED(aStatus); >+} >+ >+static nscoord ComputeSumOfChildHeights(nsIFrame* aFrame) { >+ nscoord totalHeight = 0; >+ for (nsIFrame* f = aFrame->GetFirstChild(nsnull); f; f = f->GetNextSibling()) { >+ // individual columns don't have borders or padding so this is a >+ // reasonable way to get their content height >+ totalHeight += f->GetSize().height; >+ } >+ return totalHeight; >+} >+ >+void >+nsColumnFrame::DrainOverflowColumns() >+{ >+ // First grab the prev-in-flows overflows and reparent them to this >+ // frame. >+ nsColumnFrame* prev = NS_STATIC_CAST(nsColumnFrame*, mPrevInFlow); >+ if (prev) { >+ nsIFrame* overflows = prev->GetOverflowFrames(GetPresContext(), PR_TRUE); >+ if (overflows) { >+ // Make all the frames on the overflow list mine >+ nsIFrame* lastFrame = nsnull; >+ for (nsIFrame* f = overflows; f; f = f->GetNextSibling()) { >+ f->SetParent(this); >+ >+ // When pushing and pulling frames we need to check for whether any >+ // views need to be reparented >+ nsHTMLContainerFrame::ReparentFrameView(GetPresContext(), f, prev, this); >+ >+ // Get the next frame >+ lastFrame = f; >+ } >+ >+ NS_ASSERTION(lastFrame, "overflow list was created with no frames"); >+ lastFrame->SetNextSibling(mFrames.FirstChild()); >+ >+ mFrames.SetFrames(overflows); >+ } >+ } >+ >+ // Now pull back our own overflows and append them to our children. >+ // We don't need to reparent them since we're already their parent. >+ nsIFrame* overflows = GetOverflowFrames(GetPresContext(), PR_TRUE); >+ if (overflows) { >+ mFrames.AppendFrames(this, overflows); >+ } >+} >+ >+ >+NS_IMETHODIMP >+nsColumnFrame::Reflow(nsPresContext* aPresContext, >+ nsHTMLReflowMetrics& aDesiredSize, >+ const nsHTMLReflowState& aReflowState, >+ nsReflowStatus& aStatus) >+{ >+ DO_GLOBAL_REFLOW_COUNT("nsColumnFrame", aReflowState.reason); >+ DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); >+ >+ // Initialize OUT parameter >+ aStatus = NS_FRAME_COMPLETE; >+ >+ //------------ Handle Incremental Reflow ----------------- >+ nsReflowReason kidReason = aReflowState.reason; >+ >+ if ( aReflowState.reason == eReflowReason_Incremental ) { >+ nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; >+ >+ // Dirty any frames on the incremental reflow path >+ nsReflowPath *path = aReflowState.path; >+ nsReflowPath::iterator iter = path->FirstChild(); >+ nsReflowPath::iterator end = path->EndChildren(); >+ for ( ; iter != end; ++iter) { >+ (*iter)->AddStateBits(NS_FRAME_IS_DIRTY); >+ } >+ >+ // See if it's targeted at us >+ if (command) { >+ nsReflowType reflowType; >+ command->GetType(reflowType); >+ >+ switch (reflowType) { >+ >+ case eReflowType_StyleChanged: >+ kidReason = eReflowReason_StyleChange; >+ break; >+ >+ // if its a dirty type then reflow us with a dirty reflow >+ case eReflowType_ReflowDirty: >+ kidReason = eReflowReason_Dirty; >+ break; >+ >+ default: >+ NS_ERROR("Unexpected Reflow Type"); >+ } >+ } >+ } >+ >+ ReflowConfig config = ChooseColumnStrategy(aReflowState); >+ PRBool isBalancing = config.mBalanceColCount < PR_INT32_MAX; >+ >+ // If balancing, then we allow the last column to grow to unbounded >+ // height during the first reflow. This gives us a way to estimate >+ // what the average column height should be, because we can measure >+ // the heights of all the columns and sum them up. But don't do this >+ // if we have a next in flow because we don't want to suck all its >+ // content back here and then have to push it out again! >+ nsIFrame* nextInFlow; >+ GetNextInFlow(&nextInFlow); >+ PRBool unboundedLastColumn = isBalancing && nextInFlow; >+ PRBool feasible = ReflowChildren(aDesiredSize, aReflowState, kidReason, >+ aStatus, config, unboundedLastColumn); >+ >+ if (isBalancing) { >+ nscoord availableContentHeight = GetAvailableContentHeight(aReflowState); >+ >+ // Termination of the algorithm below is guaranteed because >+ // knownFeasibleHeight - knownInfeasibleHeight decreases in every >+ // iteration. >+ nscoord knownFeasibleHeight = NS_INTRINSICSIZE; >+ nscoord knownInfeasibleHeight = 0; >+ >+ while (1) { >+ nscoord maxHeight = 0; >+ for (nsIFrame* f = mFrames.FirstChild(); f; f = f->GetNextSibling()) { >+ maxHeight = PR_MAX(maxHeight, f->GetSize().height); >+ } >+ >+ // Record what we learned from the last reflow >+ if (feasible) { >+ // maxHeight is feasible (and always maxHeight <= >+ // mLastBalanceHeight) >+ knownFeasibleHeight = PR_MIN(knownFeasibleHeight, maxHeight); >+ >+ // Furthermore, no height less than the height of the last >+ // column can ever be feasible. >+ if (mFrames.GetLength() == config.mBalanceColCount) { >+ knownInfeasibleHeight = PR_MAX(knownInfeasibleHeight, >+ mFrames.LastChild()->GetSize().height - 1); >+ } >+ } else { >+ knownInfeasibleHeight = PR_MAX(knownInfeasibleHeight, mLastBalanceHeight); >+ >+ if (unboundedLastColumn) { >+ // The last column is unbounded, so all content got reflowed, so the >+ // maxHeight is feasible. >+ knownFeasibleHeight = PR_MIN(knownFeasibleHeight, maxHeight); >+ } >+ } >+ >+#ifdef DEBUG_roc >+ printf("*** nsColumnFrame::Reflow balancing knownInfeasible=%d knownFeasible=%d\n", >+ knownInfeasibleHeight, knownFeasibleHeight); >+#endif >+ >+ if (knownInfeasibleHeight >= knownFeasibleHeight - 1) { >+ // knownFeasibleHeight is where we want to be >+ break; >+ } >+ >+ if (knownInfeasibleHeight >= availableContentHeight) { >+ break; >+ } >+ >+ nscoord nextGuess = (knownFeasibleHeight + knownInfeasibleHeight)/2; >+ // The constant of 600 twips is arbitrary. It's about two line-heights. >+ if (knownFeasibleHeight - nextGuess < 600) { >+ // We're close to our target, so just try shrinking just the >+ // minimum amount that will cause one of our columns to break >+ // differently. >+ nextGuess = knownFeasibleHeight - 1; >+ } else if (unboundedLastColumn) { >+ // Make a guess by dividing that into N columns. Add some slop >+ // to try to make it on the feasible side. The constant of >+ // 600 twips is arbitrary. It's about two line-heights. >+ nextGuess = ComputeSumOfChildHeights(this)/config.mBalanceColCount + 600; >+ // Sanitize it >+ nextGuess = PR_MIN(PR_MAX(nextGuess, knownInfeasibleHeight + 1), >+ knownFeasibleHeight - 1); >+ } else if (knownFeasibleHeight == NS_INTRINSICSIZE) { >+ // This can happen when we had a next-in-flow so we didn't >+ // want to do an unbounded height measuring step. Let's just increase >+ // from the infeasible height by some reasonable amount. >+ nextGuess = knownInfeasibleHeight*2 + 600; >+ } >+ // Don't bother guessing more than our height constraint. >+ nextGuess = PR_MIN(availableContentHeight, nextGuess); >+ >+#ifdef DEBUG_roc >+ printf("*** nsColumnFrame::Reflow balancing choosing next guess=%d\n", nextGuess); >+#endif >+ >+ config.mColMaxHeight = nextGuess; >+ >+ unboundedLastColumn = PR_FALSE; >+ feasible = ReflowChildren(aDesiredSize, aReflowState, >+ eReflowReason_Resize, aStatus, config, PR_FALSE); >+ } >+ >+ if (!feasible) { >+ // We may need to reflow one more time at the feasible height to >+ // get a valid layout. >+ PRBool skip = PR_FALSE; >+ if (knownInfeasibleHeight >= availableContentHeight) { >+ config.mColMaxHeight = availableContentHeight; >+ if (mLastBalanceHeight == availableContentHeight) { >+ skip = PR_TRUE; >+ } >+ } else { >+ config.mColMaxHeight = knownFeasibleHeight; >+ } >+ if (!skip) { >+ ReflowChildren(aDesiredSize, aReflowState, >+ eReflowReason_Resize, aStatus, config, PR_FALSE); >+ } >+ } >+ } >+ >+ CheckInvalidateSizeChange(GetPresContext(), aDesiredSize, aReflowState); >+ >+ FinishAndStoreOverflow(&aDesiredSize); >+ >+ NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); >+ >+ return NS_OK; >+} >+ >+PRIntn >+nsColumnFrame::GetSkipSides() const >+{ >+ return 0; >+} >+ >+NS_IMETHODIMP >+nsColumnFrame::AppendFrames(nsPresContext* aPresContext, >+ nsIPresShell& aPresShell, >+ nsIAtom* aListName, >+ nsIFrame* aFrameList) >+{ >+ NS_NOTREACHED("AppendFrames not supported"); >+ return NS_ERROR_NOT_IMPLEMENTED; >+} >+ >+NS_IMETHODIMP >+nsColumnFrame::InsertFrames(nsPresContext* aPresContext, >+ nsIPresShell& aPresShell, >+ nsIAtom* aListName, >+ nsIFrame* aPrevFrame, >+ nsIFrame* aFrameList) >+{ >+ NS_NOTREACHED("InsertFrames not supported"); >+ return NS_ERROR_NOT_IMPLEMENTED; >+} >+ >+NS_IMETHODIMP >+nsColumnFrame::RemoveFrame(nsPresContext* aPresContext, >+ nsIPresShell& aPresShell, >+ nsIAtom* aListName, >+ nsIFrame* aOldFrame) >+{ >+ NS_NOTREACHED("RemoveFrame not supported"); >+ return NS_ERROR_NOT_IMPLEMENTED; >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
|
Review
Attachments on
bug 251162
:
153017
|
153019
|
153165
|
153257
|
154541
|
156700
|
156704
|
156705
|
157237
|
159052
|
161444
|
161483
|
161484
|
161485
|
9183667
|
9183668