LCOV - app.info - layout/generic/nsColumnSetFrame.cpp

LCOV - code coverage report
| Current view: | directory - layout/generic - nsColumnSetFrame.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 433 | 0 | 0.0 %
| Date: | 2012-06-02 | Functions: | 31 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Robert O'Callahan <roc@ocallahan.org>
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : /* rendering object for css3 multi-column layout */
          40                 :
          41                 : #include "nsContainerFrame.h"
          42                 : #include "nsIContent.h"
          43                 : #include "nsIFrame.h"
          44                 : #include "nsISupports.h"
          45                 : #include "nsIAtom.h"
          46                 : #include "nsPresContext.h"
          47                 : #include "nsHTMLParts.h"
          48                 : #include "nsGkAtoms.h"
          49                 : #include "nsStyleConsts.h"
          50                 : #include "nsCOMPtr.h"
          51                 : #include "nsLayoutUtils.h"
          52                 : #include "nsDisplayList.h"
          53                 : #include "nsCSSRendering.h"
          54                 :
          55                 : using namespace mozilla;
          56                 :
          57               0 : class nsColumnSetFrame : public nsContainerFrame {
          58                 : public:
          59                 :   NS_DECL_FRAMEARENA_HELPERS
          60                 :
          61                 :   nsColumnSetFrame(nsStyleContext* aContext);
          62                 :
          63                 :   NS_IMETHOD SetInitialChildList(ChildListID     aListID,
          64                 :                                  nsFrameList&    aChildList);
          65                 :
          66                 :   NS_IMETHOD Reflow(nsPresContext* aPresContext,
          67                 :                     nsHTMLReflowMetrics& aDesiredSize,
          68                 :                     const nsHTMLReflowState& aReflowState,
          69                 :                     nsReflowStatus& aStatus);
          70                 :
          71                 :   NS_IMETHOD  AppendFrames(ChildListID     aListID,
          72                 :                            nsFrameList&    aFrameList);
          73                 :   NS_IMETHOD  InsertFrames(ChildListID     aListID,
          74                 :                            nsIFrame*       aPrevFrame,
          75                 :                            nsFrameList&    aFrameList);
          76                 :   NS_IMETHOD  RemoveFrame(ChildListID     aListID,
          77                 :                           nsIFrame*       aOldFrame);
          78                 :
          79                 :   virtual void DestroyFrom(nsIFrame* aDestructRoot);
          80                 :   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
          81                 :   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
          82                 :
          83               0 :   virtual nsIFrame* GetContentInsertionFrame() {
          84               0 :     nsIFrame* frame = GetFirstPrincipalChild();
          85                 :
          86                 :     // if no children return nsnull
          87               0 :     if (!frame)
          88               0 :       return nsnull;
          89                 :
          90               0 :     return frame->GetContentInsertionFrame();
          91                 :   }
          92                 :
          93               0 :   virtual nsresult StealFrame(nsPresContext* aPresContext,
          94                 :                               nsIFrame*      aChild,
          95                 :                               bool           aForceNormal)
          96                 :   { // nsColumnSetFrame keeps overflow containers in main child list
          97               0 :     return nsContainerFrame::StealFrame(aPresContext, aChild, true);
          98                 :   }
          99                 :
         100                 :   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
         101                 :                               const nsRect&           aDirtyRect,
         102                 :                               const nsDisplayListSet& aLists);
         103                 :
         104                 :   virtual nsIAtom* GetType() const;
         105                 :
         106                 :   virtual void PaintColumnRule(nsRenderingContext* aCtx,
         107                 :                                const nsRect&        aDirtyRect,
         108                 :                                const nsPoint&       aPt);
         109                 :
         110                 : #ifdef DEBUG
         111               0 :   NS_IMETHOD GetFrameName(nsAString& aResult) const {
         112               0 :     return MakeFrameName(NS_LITERAL_STRING("ColumnSet"), aResult);
         113                 :   }
         114                 : #endif
         115                 :
         116                 : protected:
         117                 :   nscoord        mLastBalanceHeight;
         118                 :   nsReflowStatus mLastFrameStatus;
         119                 :
         120                 :   virtual PRIntn GetSkipSides() const;
         121                 :
         122                 :   /**
         123                 :    * These are the parameters that control the layout of columns.
         124                 :    */
         125                 :   struct ReflowConfig {
         126                 :     PRInt32 mBalanceColCount;
         127                 :     nscoord mColWidth;
         128                 :     nscoord mExpectedWidthLeftOver;
         129                 :     nscoord mColGap;
         130                 :     nscoord mColMaxHeight;
         131                 :   };
         132                 :
         133                 :   /**
         134                 :    * Some data that is better calculated during reflow
         135                 :    */
         136                 :   struct ColumnBalanceData {
         137                 :     // The maximum "content height" of any column
         138                 :     nscoord mMaxHeight;
         139                 :     // The sum of the "content heights" for all columns
         140                 :     nscoord mSumHeight;
         141                 :     // The "content height" of the last column
         142                 :     nscoord mLastHeight;
         143                 :     // The maximum "content height" of all columns that overflowed
         144                 :     // their available height
         145                 :     nscoord mMaxOverflowingHeight;
         146               0 :     void Reset() {
         147               0 :       mMaxHeight = mSumHeight = mLastHeight = mMaxOverflowingHeight = 0;
         148               0 :     }
         149                 :   };
         150                 :
         151                 :   /**
         152                 :    * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not
         153                 :    * handled by our prev-in-flow, and any columns sitting on our own
         154                 :    * overflow list, and put them in our primary child list for reflowing.
         155                 :    */
         156                 :   void DrainOverflowColumns();
         157                 :
         158                 :   /**
         159                 :    * The basic reflow strategy is to call this function repeatedly to
         160                 :    * obtain specific parameters that determine the layout of the
         161                 :    * columns. This function will compute those parameters from the CSS
         162                 :    * style. This function will also be responsible for implementing
         163                 :    * the state machine that controls column balancing.
         164                 :    */
         165                 :   ReflowConfig ChooseColumnStrategy(const nsHTMLReflowState& aReflowState);
         166                 :
         167                 :   /**
         168                 :    * Reflow column children. Returns true iff the content that was reflowed
         169                 :    * fit into the mColMaxHeight.
         170                 :    */
         171                 :   bool ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
         172                 :                         const nsHTMLReflowState& aReflowState,
         173                 :                         nsReflowStatus& aStatus,
         174                 :                         const ReflowConfig& aConfig,
         175                 :                         bool aLastColumnUnbounded,
         176                 :                         nsCollapsingMargin* aCarriedOutBottomMargin,
         177                 :                         ColumnBalanceData& aColData);
         178                 : };
         179                 :
         180                 : /**
         181                 :  * Tracking issues:
         182                 :  *
         183                 :  * XXX cursor movement around the top and bottom of colums seems to make the editor
         184                 :  * lose the caret.
         185                 :  *
         186                 :  * XXX should we support CSS columns applied to table elements?
         187                 :  */
         188                 : nsIFrame*
         189               0 : NS_NewColumnSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aStateFlags)
         190                 : {
         191               0 :   nsColumnSetFrame* it = new (aPresShell) nsColumnSetFrame(aContext);
         192               0 :   if (it) {
         193                 :     // set the state flags (if any are provided)
         194               0 :     it->AddStateBits(aStateFlags);
         195                 :   }
         196                 :
         197               0 :   return it;
         198                 : }
         199                 :
         200               0 : NS_IMPL_FRAMEARENA_HELPERS(nsColumnSetFrame)
         201                 :
         202               0 : nsColumnSetFrame::nsColumnSetFrame(nsStyleContext* aContext)
         203                 :   : nsContainerFrame(aContext), mLastBalanceHeight(NS_INTRINSICSIZE),
         204               0 :     mLastFrameStatus(NS_FRAME_COMPLETE)
         205                 : {
         206               0 : }
         207                 :
         208                 : void
         209               0 : nsColumnSetFrame::DestroyFrom(nsIFrame* aDestructRoot)
         210                 : {
         211               0 :   DestroyAbsoluteFrames(aDestructRoot);
         212               0 :   nsContainerFrame::DestroyFrom(aDestructRoot);
         213               0 : }
         214                 :
         215                 : nsIAtom*
         216               0 : nsColumnSetFrame::GetType() const
         217                 : {
         218               0 :   return nsGkAtoms::columnSetFrame;
         219                 : }
         220                 :
         221                 : static void
         222               0 : PaintColumnRule(nsIFrame* aFrame, nsRenderingContext* aCtx,
         223                 :                 const nsRect& aDirtyRect, nsPoint aPt)
         224                 : {
         225               0 :   static_cast<nsColumnSetFrame*>(aFrame)->PaintColumnRule(aCtx, aDirtyRect, aPt);
         226               0 : }
         227                 :
         228                 : void
         229               0 : nsColumnSetFrame::PaintColumnRule(nsRenderingContext* aCtx,
         230                 :                                   const nsRect& aDirtyRect,
         231                 :                                   const nsPoint& aPt)
         232                 : {
         233               0 :   nsIFrame* child = mFrames.FirstChild();
         234               0 :   if (!child)
         235               0 :     return;  // no columns
         236                 :
         237               0 :   nsIFrame* nextSibling = child->GetNextSibling();
         238               0 :   if (!nextSibling)
         239               0 :     return;  // 1 column only - this means no gap to draw on
         240                 :
         241               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
         242               0 :   const nsStyleColumn* colStyle = GetStyleColumn();
         243                 :
         244                 :   PRUint8 ruleStyle;
         245                 :   // Per spec, inset => ridge and outset => groove
         246               0 :   if (colStyle->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_INSET)
         247               0 :     ruleStyle = NS_STYLE_BORDER_STYLE_RIDGE;
         248               0 :   else if (colStyle->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_OUTSET)
         249               0 :     ruleStyle = NS_STYLE_BORDER_STYLE_GROOVE;
         250                 :   else
         251               0 :     ruleStyle = colStyle->mColumnRuleStyle;
         252                 :
         253               0 :   nsPresContext* presContext = PresContext();
         254               0 :   nscoord ruleWidth = colStyle->GetComputedColumnRuleWidth();
         255               0 :   if (!ruleWidth)
         256               0 :     return;
         257                 :
         258                 :   nscolor ruleColor =
         259               0 :     GetVisitedDependentColor(eCSSProperty__moz_column_rule_color);
         260                 :
         261                 :   // In order to re-use a large amount of code, we treat the column rule as a border.
         262                 :   // We create a new border style object and fill in all the details of the column rule as
         263                 :   // the left border. PaintBorder() does all the rendering for us, so we not
         264                 :   // only save an enormous amount of code but we'll support all the line styles that
         265                 :   // we support on borders!
         266               0 :   nsStyleBorder border(presContext);
         267               0 :   border.SetBorderWidth(NS_SIDE_LEFT, ruleWidth);
         268               0 :   border.SetBorderStyle(NS_SIDE_LEFT, ruleStyle);
         269               0 :   border.SetBorderColor(NS_SIDE_LEFT, ruleColor);
         270                 :
         271                 :   // Get our content rect as an absolute coordinate, not relative to
         272                 :   // our parent (which is what the X and Y normally is)
         273               0 :   nsRect contentRect = GetContentRect() - GetRect().TopLeft() + aPt;
         274               0 :   nsSize ruleSize(ruleWidth, contentRect.height);
         275                 :
         276               0 :   while (nextSibling) {
         277                 :     // The frame tree goes RTL in RTL
         278               0 :     nsIFrame* leftSibling = isRTL ? nextSibling : child;
         279               0 :     nsIFrame* rightSibling = isRTL ? child : nextSibling;
         280                 :
         281                 :     // Each child frame's position coordinates is actually relative to this nsColumnSetFrame.
         282                 :     // linePt will be at the top-left edge to paint the line.
         283               0 :     nsPoint edgeOfLeftSibling = leftSibling->GetRect().TopRight() + aPt;
         284               0 :     nsPoint edgeOfRightSibling = rightSibling->GetRect().TopLeft() + aPt;
         285                 :     nsPoint linePt((edgeOfLeftSibling.x + edgeOfRightSibling.x - ruleWidth) / 2,
         286               0 :                    contentRect.y);
         287                 :
         288               0 :     nsRect lineRect(linePt, ruleSize);
         289                 :     nsCSSRendering::PaintBorderWithStyleBorder(presContext, *aCtx, this,
         290                 :         aDirtyRect, lineRect, border, GetStyleContext(),
         291                 :         // Remember, we only have the "left" "border". Skip everything else
         292               0 :         (1 << NS_SIDE_TOP | 1 << NS_SIDE_RIGHT | 1 << NS_SIDE_BOTTOM));
         293                 :
         294               0 :     child = nextSibling;
         295               0 :     nextSibling = nextSibling->GetNextSibling();
         296                 :   }
         297                 : }
         298                 :
         299                 : NS_IMETHODIMP
         300               0 : nsColumnSetFrame::SetInitialChildList(ChildListID     aListID,
         301                 :                                       nsFrameList&    aChildList)
         302                 : {
         303               0 :   if (aListID == kAbsoluteList) {
         304               0 :     return nsContainerFrame::SetInitialChildList(aListID, aChildList);
         305                 :   }
         306                 :
         307               0 :   NS_ASSERTION(aListID == kPrincipalList,
         308                 :                "Only default child list supported");
         309               0 :   NS_ASSERTION(aChildList.OnlyChild(),
         310                 :                "initial child list must have exactly one child");
         311                 :   // Queue up the frames for the content frame
         312               0 :   return nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
         313                 : }
         314                 :
         315                 : static nscoord
         316               0 : GetAvailableContentWidth(const nsHTMLReflowState& aReflowState)
         317                 : {
         318               0 :   if (aReflowState.availableWidth == NS_INTRINSICSIZE) {
         319               0 :     return NS_INTRINSICSIZE;
         320                 :   }
         321                 :   nscoord borderPaddingWidth =
         322                 :     aReflowState.mComputedBorderPadding.left +
         323               0 :     aReflowState.mComputedBorderPadding.right;
         324               0 :   return NS_MAX(0, aReflowState.availableWidth - borderPaddingWidth);
         325                 : }
         326                 :
         327                 : static nscoord
         328               0 : GetAvailableContentHeight(const nsHTMLReflowState& aReflowState)
         329                 : {
         330               0 :   if (aReflowState.availableHeight == NS_INTRINSICSIZE) {
         331               0 :     return NS_INTRINSICSIZE;
         332                 :   }
         333                 :   nscoord borderPaddingHeight =
         334                 :     aReflowState.mComputedBorderPadding.top +
         335               0 :     aReflowState.mComputedBorderPadding.bottom;
         336               0 :   return NS_MAX(0, aReflowState.availableHeight - borderPaddingHeight);
         337                 : }
         338                 :
         339                 : static nscoord
         340               0 : GetColumnGap(nsColumnSetFrame*    aFrame,
         341                 :              const nsStyleColumn* aColStyle)
         342                 : {
         343               0 :   if (eStyleUnit_Normal == aColStyle->mColumnGap.GetUnit())
         344               0 :     return aFrame->GetStyleFont()->mFont.size;
         345               0 :   if (eStyleUnit_Coord == aColStyle->mColumnGap.GetUnit()) {
         346               0 :     nscoord colGap = aColStyle->mColumnGap.GetCoordValue();
         347               0 :     NS_ASSERTION(colGap >= 0, "negative column gap");
         348               0 :     return colGap;
         349                 :   }
         350                 :
         351               0 :   NS_NOTREACHED("Unknown gap type");
         352               0 :   return 0;
         353                 : }
         354                 :
         355                 : nsColumnSetFrame::ReflowConfig
         356               0 : nsColumnSetFrame::ChooseColumnStrategy(const nsHTMLReflowState& aReflowState)
         357                 : {
         358               0 :   const nsStyleColumn* colStyle = GetStyleColumn();
         359               0 :   nscoord availContentWidth = GetAvailableContentWidth(aReflowState);
         360               0 :   if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) {
         361               0 :     availContentWidth = aReflowState.ComputedWidth();
         362                 :   }
         363               0 :   nscoord colHeight = GetAvailableContentHeight(aReflowState);
         364               0 :   if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) {
         365               0 :     colHeight = aReflowState.ComputedHeight();
         366                 :   }
         367                 :
         368               0 :   nscoord colGap = GetColumnGap(this, colStyle);
         369               0 :   PRInt32 numColumns = colStyle->mColumnCount;
         370                 :
         371               0 :   bool isBalancing = colStyle->mColumnFill == NS_STYLE_COLUMN_FILL_BALANCE;
         372               0 :   if (isBalancing) {
         373               0 :     const PRUint32 MAX_NESTED_COLUMN_BALANCING = 2;
         374               0 :     PRUint32 cnt = 1;
         375               0 :     for (const nsHTMLReflowState* rs = aReflowState.parentReflowState;
         376                 :          rs && cnt < MAX_NESTED_COLUMN_BALANCING;
         377                 :          rs = rs->parentReflowState) {
         378               0 :       if (rs->mFlags.mIsColumnBalancing) {
         379               0 :         ++cnt;
         380                 :       }
         381                 :     }
         382               0 :     if (cnt == MAX_NESTED_COLUMN_BALANCING) {
         383               0 :       numColumns = 1;
         384                 :     }
         385                 :   }
         386                 :
         387                 :   nscoord colWidth;
         388               0 :   if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) {
         389               0 :     colWidth = colStyle->mColumnWidth.GetCoordValue();
         390               0 :     NS_ASSERTION(colWidth >= 0, "negative column width");
         391                 :     // Reduce column count if necessary to make columns fit in the
         392                 :     // available width. Compute max number of columns that fit in
         393                 :     // availContentWidth, satisfying colGap*(maxColumns - 1) +
         394                 :     // colWidth*maxColumns <= availContentWidth
         395               0 :     if (availContentWidth != NS_INTRINSICSIZE && colGap + colWidth > 0
         396                 :         && numColumns > 0) {
         397                 :       // This expression uses truncated rounding, which is what we
         398                 :       // want
         399               0 :       PRInt32 maxColumns = (availContentWidth + colGap)/(colGap + colWidth);
         400               0 :       numColumns = NS_MAX(1, NS_MIN(numColumns, maxColumns));
         401                 :     }
         402               0 :   } else if (numColumns > 0 && availContentWidth != NS_INTRINSICSIZE) {
         403               0 :     nscoord widthMinusGaps = availContentWidth - colGap*(numColumns - 1);
         404               0 :     colWidth = widthMinusGaps/numColumns;
         405                 :   } else {
         406               0 :     colWidth = NS_INTRINSICSIZE;
         407                 :   }
         408                 :   // Take care of the situation where there's only one column but it's
         409                 :   // still too wide
         410               0 :   colWidth = NS_MAX(1, NS_MIN(colWidth, availContentWidth));
         411                 :
         412               0 :   nscoord expectedWidthLeftOver = 0;
         413                 :
         414               0 :   if (colWidth != NS_INTRINSICSIZE && availContentWidth != NS_INTRINSICSIZE) {
         415                 :     // distribute leftover space
         416                 :
         417                 :     // First, determine how many columns will be showing if the column
         418                 :     // count is auto
         419               0 :     if (numColumns <= 0) {
         420                 :       // choose so that colGap*(nominalColumnCount - 1) +
         421                 :       // colWidth*nominalColumnCount is nearly availContentWidth
         422                 :       // make sure to round down
         423               0 :       if (colGap + colWidth > 0) {
         424               0 :         numColumns = (availContentWidth + colGap)/(colGap + colWidth);
         425                 :       }
         426               0 :       if (numColumns <= 0) {
         427               0 :         numColumns = 1;
         428                 :       }
         429                 :     }
         430                 :
         431                 :     // Compute extra space and divide it among the columns
         432                 :     nscoord extraSpace =
         433               0 :       NS_MAX(0, availContentWidth - (colWidth*numColumns + colGap*(numColumns - 1)));
         434               0 :     nscoord extraToColumns = extraSpace/numColumns;
         435               0 :     colWidth += extraToColumns;
         436               0 :     expectedWidthLeftOver = extraSpace - (extraToColumns*numColumns);
         437                 :   }
         438                 :
         439                 :   // If column-fill is set to 'balance', then we want to balance the columns.
         440               0 :   if (isBalancing) {
         441                 :     // Balancing!
         442                 :
         443               0 :     if (numColumns <= 0) {
         444                 :       // Hmm, auto column count, column width or available width is unknown,
         445                 :       // and balancing is required. Let's just use one column then.
         446               0 :       numColumns = 1;
         447                 :     }
         448                 :
         449                 :     colHeight = NS_MIN(mLastBalanceHeight,
         450               0 :                        GetAvailableContentHeight(aReflowState));
         451                 :   } else {
         452                 :     // This is the case when the column-fill property is set to 'auto'.
         453                 :     // No balancing, so don't limit the column count
         454                 :
         455               0 :     numColumns = PR_INT32_MAX;
         456                 :   }
         457                 :
         458                 : #ifdef DEBUG_roc
         459                 :   printf("*** nsColumnSetFrame::ChooseColumnStrategy: numColumns=%d, colWidth=%d, expectedWidthLeftOver=%d, colHeight=%d, colGap=%d\n",
         460                 :          numColumns, colWidth, expectedWidthLeftOver, colHeight, colGap);
         461                 : #endif
         462               0 :   ReflowConfig config = { numColumns, colWidth, expectedWidthLeftOver, colGap, colHeight };
         463                 :   return config;
         464                 : }
         465                 :
         466                 : // XXX copied from nsBlockFrame, should this be moved to nsContainerFrame?
         467                 : static void
         468               0 : PlaceFrameView(nsIFrame* aFrame)
         469                 : {
         470               0 :   if (aFrame->HasView())
         471               0 :     nsContainerFrame::PositionFrameView(aFrame);
         472                 :   else
         473               0 :     nsContainerFrame::PositionChildViews(aFrame);
         474               0 : }
         475                 :
         476               0 : static void MoveChildTo(nsIFrame* aParent, nsIFrame* aChild, nsPoint aOrigin) {
         477               0 :   if (aChild->GetPosition() == aOrigin) {
         478               0 :     return;
         479                 :   }
         480                 :
         481               0 :   nsRect r = aChild->GetVisualOverflowRect();
         482               0 :   r += aChild->GetPosition();
         483               0 :   aParent->Invalidate(r);
         484               0 :   r -= aChild->GetPosition();
         485               0 :   aChild->SetPosition(aOrigin);
         486               0 :   r += aOrigin;
         487               0 :   aParent->Invalidate(r);
         488               0 :   PlaceFrameView(aChild);
         489                 : }
         490                 :
         491                 : nscoord
         492               0 : nsColumnSetFrame::GetMinWidth(nsRenderingContext *aRenderingContext) {
         493               0 :   nscoord width = 0;
         494               0 :   DISPLAY_MIN_WIDTH(this, width);
         495               0 :   if (mFrames.FirstChild()) {
         496               0 :     width = mFrames.FirstChild()->GetMinWidth(aRenderingContext);
         497                 :   }
         498               0 :   const nsStyleColumn* colStyle = GetStyleColumn();
         499                 :   nscoord colWidth;
         500               0 :   if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) {
         501               0 :     colWidth = colStyle->mColumnWidth.GetCoordValue();
         502                 :     // As available width reduces to zero, we reduce our number of columns
         503                 :     // to one, and don't enforce the column width, so just return the min
         504                 :     // of the child's min-width with any specified column width.
         505               0 :     width = NS_MIN(width, colWidth);
         506                 :   } else {
         507               0 :     NS_ASSERTION(colStyle->mColumnCount > 0,
         508                 :                  "column-count and column-width can't both be auto");
         509                 :     // As available width reduces to zero, we still have mColumnCount columns,
         510                 :     // so multiply the child's min-width by the number of columns.
         511               0 :     colWidth = width;
         512               0 :     width *= colStyle->mColumnCount;
         513                 :     // The multiplication above can make 'width' negative (integer overflow),
         514                 :     // so use NS_MAX to protect against that.
         515               0 :     width = NS_MAX(width, colWidth);
         516                 :   }
         517                 :   // XXX count forced column breaks here? Maybe we should return the child's
         518                 :   // min-width times the minimum number of columns.
         519               0 :   return width;
         520                 : }
         521                 :
         522                 : nscoord
         523               0 : nsColumnSetFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) {
         524                 :   // Our preferred width is our desired column width, if specified, otherwise
         525                 :   // the child's preferred width, times the number of columns, plus the width
         526                 :   // of any required column gaps
         527                 :   // XXX what about forced column breaks here?
         528               0 :   nscoord result = 0;
         529               0 :   DISPLAY_PREF_WIDTH(this, result);
         530               0 :   const nsStyleColumn* colStyle = GetStyleColumn();
         531               0 :   nscoord colGap = GetColumnGap(this, colStyle);
         532                 :
         533                 :   nscoord colWidth;
         534               0 :   if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) {
         535               0 :     colWidth = colStyle->mColumnWidth.GetCoordValue();
         536               0 :   } else if (mFrames.FirstChild()) {
         537               0 :     colWidth = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
         538                 :   } else {
         539               0 :     colWidth = 0;
         540                 :   }
         541                 :
         542               0 :   PRInt32 numColumns = colStyle->mColumnCount;
         543               0 :   if (numColumns <= 0) {
         544                 :     // if column-count is auto, assume one column
         545               0 :     numColumns = 1;
         546                 :   }
         547                 :
         548               0 :   nscoord width = colWidth*numColumns + colGap*(numColumns - 1);
         549                 :   // The multiplication above can make 'width' negative (integer overflow),
         550                 :   // so use NS_MAX to protect against that.
         551               0 :   result = NS_MAX(width, colWidth);
         552               0 :   return result;
         553                 : }
         554                 :
         555                 : bool
         556               0 : nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics&     aDesiredSize,
         557                 :                                  const nsHTMLReflowState& aReflowState,
         558                 :                                  nsReflowStatus&          aStatus,
         559                 :                                  const ReflowConfig&      aConfig,
         560                 :                                  bool                     aUnboundedLastColumn,
         561                 :                                  nsCollapsingMargin*      aBottomMarginCarriedOut,
         562                 :                                  ColumnBalanceData&       aColData)
         563                 : {
         564               0 :   aColData.Reset();
         565               0 :   bool allFit = true;
         566               0 :   bool RTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
         567               0 :   bool shrinkingHeightOnly = !NS_SUBTREE_DIRTY(this) &&
         568               0 :     mLastBalanceHeight > aConfig.mColMaxHeight;
         569                 :
         570                 : #ifdef DEBUG_roc
         571                 :   printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n",
         572                 :          mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount,
         573                 :          aConfig.mColWidth, aConfig.mColGap);
         574                 : #endif
         575                 :
         576               0 :   DrainOverflowColumns();
         577                 :
         578               0 :   if (mLastBalanceHeight != aConfig.mColMaxHeight) {
         579               0 :     mLastBalanceHeight = aConfig.mColMaxHeight;
         580                 :     // XXX Seems like this could fire if incremental reflow pushed the column set
         581                 :     // down so we reflow incrementally with a different available height.
         582                 :     // We need a way to do an incremental reflow and be sure availableHeight
         583                 :     // changes are taken account of! Right now I think block frames with absolute
         584                 :     // children might exit early.
         585                 :     //NS_ASSERTION(aKidReason != eReflowReason_Incremental,
         586                 :     //             "incremental reflow should not have changed the balance height");
         587                 :   }
         588                 :
         589                 :   // get our border and padding
         590               0 :   const nsMargin &borderPadding = aReflowState.mComputedBorderPadding;
         591                 :
         592               0 :   nsRect contentRect(0, 0, 0, 0);
         593               0 :   nsOverflowAreas overflowRects;
         594                 :
         595               0 :   nsIFrame* child = mFrames.FirstChild();
         596               0 :   nsPoint childOrigin = nsPoint(borderPadding.left, borderPadding.top);
         597                 :   // For RTL, figure out where the last column's left edge should be. Since the
         598                 :   // columns might not fill the frame exactly, we need to account for the
         599                 :   // slop. Otherwise we'll waste time moving the columns by some tiny
         600                 :   // amount unnecessarily.
         601               0 :   nscoord targetX = borderPadding.left;
         602               0 :   if (RTL) {
         603               0 :     nscoord availWidth = aReflowState.availableWidth;
         604               0 :     if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) {
         605               0 :       availWidth = aReflowState.ComputedWidth();
         606                 :     }
         607               0 :     if (availWidth != NS_INTRINSICSIZE) {
         608               0 :       childOrigin.x += availWidth - aConfig.mColWidth;
         609               0 :       targetX += aConfig.mExpectedWidthLeftOver;
         610                 : #ifdef DEBUG_roc
         611                 :       printf("*** childOrigin.x = %d\n", childOrigin.x);
         612                 : #endif
         613                 :     }
         614                 :   }
         615               0 :   int columnCount = 0;
         616               0 :   int contentBottom = 0;
         617               0 :   bool reflowNext = false;
         618                 :
         619               0 :   while (child) {
         620                 :     // Try to skip reflowing the child. We can't skip if the child is dirty. We also can't
         621                 :     // skip if the next column is dirty, because the next column's first line(s)
         622                 :     // might be pullable back to this column. We can't skip if it's the last child
         623                 :     // because we need to obtain the bottom margin. We can't skip
         624                 :     // if this is the last column and we're supposed to assign unbounded
         625                 :     // height to it, because that could change the available height from
         626                 :     // the last time we reflowed it and we should try to pull all the
         627                 :     // content from its next sibling. (Note that it might be the last
         628                 :     // column, but not be the last child because the desired number of columns
         629                 :     // has changed.)
         630               0 :     bool skipIncremental = !aReflowState.ShouldReflowAllKids()
         631               0 :       && !NS_SUBTREE_DIRTY(child)
         632               0 :       && child->GetNextSibling()
         633               0 :       && !(aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1)
         634               0 :       && !NS_SUBTREE_DIRTY(child->GetNextSibling());
         635                 :     // If we need to pull up content from the prev-in-flow then this is not just
         636                 :     // a height shrink. The prev in flow will have set the dirty bit.
         637                 :     // Check the overflow rect YMost instead of just the child's content height. The child
         638                 :     // may have overflowing content that cares about the available height boundary.
         639                 :     // (It may also have overflowing content that doesn't care about the available height
         640                 :     // boundary, but if so, too bad, this optimization is defeated.)
         641                 :     // We want scrollable overflow here since this is a calculation that
         642                 :     // affects layout.
         643                 :     bool skipResizeHeightShrink = shrinkingHeightOnly
         644               0 :       && child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxHeight;
         645                 :
         646               0 :     nscoord childContentBottom = 0;
         647               0 :     if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) {
         648                 :       // This child does not need to be reflowed, but we may need to move it
         649               0 :       MoveChildTo(this, child, childOrigin);
         650                 :
         651                 :       // If this is the last frame then make sure we get the right status
         652               0 :       nsIFrame* kidNext = child->GetNextSibling();
         653               0 :       if (kidNext) {
         654               0 :         aStatus = (kidNext->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
         655                 :                   ? NS_FRAME_OVERFLOW_INCOMPLETE
         656               0 :                   : NS_FRAME_NOT_COMPLETE;
         657                 :       } else {
         658               0 :         aStatus = mLastFrameStatus;
         659                 :       }
         660               0 :       childContentBottom = nsLayoutUtils::CalculateContentBottom(child);
         661                 : #ifdef DEBUG_roc
         662                 :       printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n",
         663                 :              columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus);
         664                 : #endif
         665                 :     } else {
         666               0 :       nsSize availSize(aConfig.mColWidth, aConfig.mColMaxHeight);
         667                 :
         668               0 :       if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) {
         669               0 :         availSize.height = GetAvailableContentHeight(aReflowState);
         670                 :       }
         671                 :
         672               0 :       if (reflowNext)
         673               0 :         child->AddStateBits(NS_FRAME_IS_DIRTY);
         674                 :
         675                 :       nsHTMLReflowState kidReflowState(PresContext(), aReflowState, child,
         676                 :                                        availSize, availSize.width,
         677               0 :                                        aReflowState.ComputedHeight());
         678               0 :       kidReflowState.mFlags.mIsTopOfPage = true;
         679               0 :       kidReflowState.mFlags.mTableIsSplittable = false;
         680               0 :       kidReflowState.mFlags.mIsColumnBalancing = aConfig.mBalanceColCount < PR_INT32_MAX;
         681                 :
         682                 : #ifdef DEBUG_roc
         683                 :       printf("*** Reflowing child #%d %p: availHeight=%d\n",
         684                 :              columnCount, (void*)child,availSize.height);
         685                 : #endif
         686                 :
         687                 :       // Note if the column's next in flow is not being changed by this incremental reflow.
         688                 :       // This may allow the current column to avoid trying to pull lines from the next column.
         689               0 :       if (child->GetNextSibling() &&
         690               0 :           !(GetStateBits() & NS_FRAME_IS_DIRTY) &&
         691               0 :         !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) {
         692               0 :         kidReflowState.mFlags.mNextInFlowUntouched = true;
         693                 :       }
         694                 :
         695               0 :       nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags);
         696                 :
         697                 :       // XXX it would be cool to consult the float manager for the
         698                 :       // previous block to figure out the region of floats from the
         699                 :       // previous column that extend into this column, and subtract
         700                 :       // that region from the new float manager.  So you could stick a
         701                 :       // really big float in the first column and text in following
         702                 :       // columns would flow around it.
         703                 :
         704                 :       // Reflow the frame
         705                 :       ReflowChild(child, PresContext(), kidDesiredSize, kidReflowState,
         706                 :                   childOrigin.x + kidReflowState.mComputedMargin.left,
         707                 :                   childOrigin.y + kidReflowState.mComputedMargin.top,
         708               0 :                   0, aStatus);
         709                 :
         710               0 :       reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0;
         711                 :
         712                 : #ifdef DEBUG_roc
         713                 :       printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d\n",
         714                 :              columnCount, (void*)child, aStatus, kidDesiredSize.width, kidDesiredSize.height);
         715                 : #endif
         716                 :
         717               0 :       NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus);
         718                 :
         719               0 :       *aBottomMarginCarriedOut = kidDesiredSize.mCarriedOutBottomMargin;
         720                 :
         721                 :       FinishReflowChild(child, PresContext(), &kidReflowState,
         722               0 :                         kidDesiredSize, childOrigin.x, childOrigin.y, 0);
         723                 :
         724               0 :       childContentBottom = nsLayoutUtils::CalculateContentBottom(child);
         725               0 :       if (childContentBottom > aConfig.mColMaxHeight) {
         726               0 :         allFit = false;
         727                 :       }
         728               0 :       if (childContentBottom > availSize.height) {
         729                 :         aColData.mMaxOverflowingHeight = NS_MAX(childContentBottom,
         730               0 :             aColData.mMaxOverflowingHeight);
         731                 :       }
         732                 :     }
         733                 :
         734               0 :     contentRect.UnionRect(contentRect, child->GetRect());
         735                 :
         736               0 :     ConsiderChildOverflow(overflowRects, child);
         737               0 :     contentBottom = NS_MAX(contentBottom, childContentBottom);
         738               0 :     aColData.mLastHeight = childContentBottom;
         739               0 :     aColData.mSumHeight += childContentBottom;
         740                 :
         741                 :     // Build a continuation column if necessary
         742               0 :     nsIFrame* kidNextInFlow = child->GetNextInFlow();
         743                 :
         744               0 :     if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) {
         745               0 :       NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted");
         746               0 :       child = nsnull;
         747               0 :       break;
         748                 :     } else {
         749               0 :       ++columnCount;
         750                 :       // Make sure that the column has a next-in-flow. If not, we must
         751                 :       // create one to hold the overflowing stuff, even if we're just
         752                 :       // going to put it on our overflow list and let *our*
         753                 :       // next in flow handle it.
         754               0 :       if (!kidNextInFlow) {
         755               0 :         NS_ASSERTION(aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
         756                 :                      "We have to create a continuation, but the block doesn't want us to reflow it?");
         757                 :
         758                 :         // We need to create a continuing column
         759               0 :         nsresult rv = CreateNextInFlow(PresContext(), child, kidNextInFlow);
         760                 :
         761               0 :         if (NS_FAILED(rv)) {
         762               0 :           NS_NOTREACHED("Couldn't create continuation");
         763               0 :           child = nsnull;
         764               0 :           break;
         765                 :         }
         766                 :       }
         767                 :
         768                 :       // Make sure we reflow a next-in-flow when it switches between being
         769                 :       // normal or overflow container
         770               0 :       if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
         771               0 :         if (!(kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
         772               0 :           aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
         773               0 :           reflowNext = true;
         774               0 :           kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
         775                 :         }
         776                 :       }
         777               0 :       else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
         778               0 :         aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
         779               0 :         reflowNext = true;
         780               0 :         kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
         781                 :       }
         782                 :
         783               0 :       if (columnCount >= aConfig.mBalanceColCount) {
         784                 :         // No more columns allowed here. Stop.
         785               0 :         aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
         786               0 :         kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY);
         787                 :
         788                 :         // Move any of our leftover columns to our overflow list. Our
         789                 :         // next-in-flow will eventually pick them up.
         790               0 :         const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child);
         791               0 :         if (continuationColumns.NotEmpty()) {
         792               0 :           SetOverflowFrames(PresContext(), continuationColumns);
         793                 :         }
         794               0 :         child = nsnull;
         795                 :         break;
         796                 :       }
         797                 :     }
         798                 :
         799               0 :     if (PresContext()->HasPendingInterrupt()) {
         800                 :       // Stop the loop now while |child| still points to the frame that bailed
         801                 :       // out.  We could keep going here and condition a bunch of the code in
         802                 :       // this loop on whether there's an interrupt, or even just keep going and
         803                 :       // trying to reflow the blocks (even though we know they'll interrupt
         804                 :       // right after their first line), but stopping now is conceptually the
         805                 :       // simplest (and probably fastest) thing.
         806               0 :       break;
         807                 :     }
         808                 :
         809                 :     // Advance to the next column
         810               0 :     child = child->GetNextSibling();
         811                 :
         812               0 :     if (child) {
         813               0 :       if (!RTL) {
         814               0 :         childOrigin.x += aConfig.mColWidth + aConfig.mColGap;
         815                 :       } else {
         816               0 :         childOrigin.x -= aConfig.mColWidth + aConfig.mColGap;
         817                 :       }
         818                 :
         819                 : #ifdef DEBUG_roc
         820                 :       printf("*** NEXT CHILD ORIGIN.x = %d\n", childOrigin.x);
         821                 : #endif
         822                 :     }
         823                 :   }
         824                 :
         825               0 :   if (PresContext()->CheckForInterrupt(this) &&
         826               0 :       (GetStateBits() & NS_FRAME_IS_DIRTY)) {
         827                 :     // Mark all our kids starting with |child| dirty
         828                 :
         829                 :     // Note that this is a CheckForInterrupt call, not a HasPendingInterrupt,
         830                 :     // because we might have interrupted while reflowing |child|, and since
         831                 :     // we're about to add a dirty bit to |child| we need to make sure that
         832                 :     // |this| is scheduled to have dirty bits marked on it and its ancestors.
         833                 :     // Otherwise, when we go to mark dirty bits on |child|'s ancestors we'll
         834                 :     // bail out immediately, since it'll already have a dirty bit.
         835               0 :     for (; child; child = child->GetNextSibling()) {
         836               0 :       child->AddStateBits(NS_FRAME_IS_DIRTY);
         837                 :     }
         838                 :   }
         839                 :
         840                 :   // If we're doing RTL, we need to make sure our last column is at the left-hand side of the frame.
         841               0 :   if (RTL && childOrigin.x != targetX) {
         842               0 :     overflowRects.Clear();
         843               0 :     contentRect = nsRect(0, 0, 0, 0);
         844               0 :     PRInt32 deltaX = targetX - childOrigin.x;
         845                 : #ifdef DEBUG_roc
         846                 :     printf("*** CHILDORIGIN.x = %d, targetX = %d, DELTAX = %d\n", childOrigin.x, targetX, deltaX);
         847                 : #endif
         848               0 :     for (child = mFrames.FirstChild(); child; child = child->GetNextSibling()) {
         849               0 :       MoveChildTo(this, child, child->GetPosition() + nsPoint(deltaX, 0));
         850               0 :       ConsiderChildOverflow(overflowRects, child);
         851               0 :       contentRect.UnionRect(contentRect, child->GetRect());
         852                 :     }
         853                 :   }
         854               0 :   aColData.mMaxHeight = contentBottom;
         855               0 :   contentRect.height = NS_MAX(contentRect.height, contentBottom);
         856               0 :   mLastFrameStatus = aStatus;
         857                 :
         858                 :   // contentRect included the borderPadding.left,borderPadding.top of the child rects
         859               0 :   contentRect -= nsPoint(borderPadding.left, borderPadding.top);
         860                 :
         861               0 :   nsSize contentSize = nsSize(contentRect.XMost(), contentRect.YMost());
         862                 :
         863                 :   // Apply computed and min/max values
         864               0 :   if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) {
         865               0 :     contentSize.height = aReflowState.ComputedHeight();
         866                 :   } else {
         867               0 :     if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) {
         868               0 :       contentSize.height = NS_MIN(aReflowState.mComputedMaxHeight, contentSize.height);
         869                 :     }
         870               0 :     if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) {
         871               0 :       contentSize.height = NS_MAX(aReflowState.mComputedMinHeight, contentSize.height);
         872                 :     }
         873                 :   }
         874               0 :   if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) {
         875               0 :     contentSize.width = aReflowState.ComputedWidth();
         876                 :   } else {
         877               0 :     if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
         878               0 :       contentSize.width = NS_MIN(aReflowState.mComputedMaxWidth, contentSize.width);
         879                 :     }
         880               0 :     if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
         881               0 :       contentSize.width = NS_MAX(aReflowState.mComputedMinWidth, contentSize.width);
         882                 :     }
         883                 :   }
         884                 :
         885                 :   aDesiredSize.height = borderPadding.top + contentSize.height +
         886               0 :     borderPadding.bottom;
         887               0 :   aDesiredSize.width = contentSize.width + borderPadding.left + borderPadding.right;
         888               0 :   aDesiredSize.mOverflowAreas = overflowRects;
         889               0 :   aDesiredSize.UnionOverflowAreasWithDesiredBounds();
         890                 :
         891                 : #ifdef DEBUG_roc
         892                 :   printf("*** DONE PASS feasible=%d\n", allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus)
         893                 :          && !NS_FRAME_IS_TRUNCATED(aStatus));
         894                 : #endif
         895               0 :   return allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus)
         896               0 :     && !NS_FRAME_IS_TRUNCATED(aStatus);
         897                 : }
         898                 :
         899                 : void
         900               0 : nsColumnSetFrame::DrainOverflowColumns()
         901                 : {
         902                 :   // First grab the prev-in-flows overflows and reparent them to this
         903                 :   // frame.
         904               0 :   nsColumnSetFrame* prev = static_cast<nsColumnSetFrame*>(GetPrevInFlow());
         905               0 :   if (prev) {
         906               0 :     nsAutoPtr<nsFrameList> overflows(prev->StealOverflowFrames());
         907               0 :     if (overflows) {
         908               0 :       nsContainerFrame::ReparentFrameViewList(PresContext(), *overflows,
         909               0 :                                               prev, this);
         910                 :
         911               0 :       mFrames.InsertFrames(this, nsnull, *overflows);
         912                 :     }
         913                 :   }
         914                 :
         915                 :   // Now pull back our own overflows and append them to our children.
         916                 :   // We don't need to reparent them since we're already their parent.
         917               0 :   nsAutoPtr<nsFrameList> overflows(StealOverflowFrames());
         918               0 :   if (overflows) {
         919                 :     // We're already the parent for these frames, so no need to set
         920                 :     // their parent again.
         921               0 :     mFrames.AppendFrames(nsnull, *overflows);
         922                 :   }
         923               0 : }
         924                 :
         925                 : NS_IMETHODIMP
         926               0 : nsColumnSetFrame::Reflow(nsPresContext*           aPresContext,
         927                 :                          nsHTMLReflowMetrics&     aDesiredSize,
         928                 :                          const nsHTMLReflowState& aReflowState,
         929                 :                          nsReflowStatus&          aStatus)
         930                 : {
         931                 :   // Don't support interruption in columns
         932               0 :   nsPresContext::InterruptPreventer noInterrupts(aPresContext);
         933                 :
         934               0 :   DO_GLOBAL_REFLOW_COUNT("nsColumnSetFrame");
         935               0 :   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
         936                 :
         937                 :   // Initialize OUT parameter
         938               0 :   aStatus = NS_FRAME_COMPLETE;
         939                 :
         940                 :   // Our children depend on our height if we have a fixed height.
         941               0 :   if (aReflowState.ComputedHeight() != NS_AUTOHEIGHT) {
         942               0 :     NS_ASSERTION(aReflowState.ComputedHeight() != NS_INTRINSICSIZE,
         943                 :                  "Unexpected mComputedHeight");
         944               0 :     AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
         945                 :   }
         946                 :   else {
         947               0 :     RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
         948                 :   }
         949                 :
         950                 :   //------------ Handle Incremental Reflow -----------------
         951                 :
         952               0 :   ReflowConfig config = ChooseColumnStrategy(aReflowState);
         953               0 :   bool isBalancing = config.mBalanceColCount < PR_INT32_MAX;
         954                 :
         955                 :   // If balancing, then we allow the last column to grow to unbounded
         956                 :   // height during the first reflow. This gives us a way to estimate
         957                 :   // what the average column height should be, because we can measure
         958                 :   // the heights of all the columns and sum them up. But don't do this
         959                 :   // if we have a next in flow because we don't want to suck all its
         960                 :   // content back here and then have to push it out again!
         961               0 :   nsIFrame* nextInFlow = GetNextInFlow();
         962               0 :   bool unboundedLastColumn = isBalancing && !nextInFlow;
         963               0 :   nsCollapsingMargin carriedOutBottomMargin;
         964                 :   ColumnBalanceData colData;
         965                 :   bool feasible = ReflowChildren(aDesiredSize, aReflowState,
         966               0 :     aStatus, config, unboundedLastColumn, &carriedOutBottomMargin, colData);
         967                 :
         968               0 :   if (isBalancing && !aPresContext->HasPendingInterrupt()) {
         969               0 :     nscoord availableContentHeight = GetAvailableContentHeight(aReflowState);
         970                 :
         971                 :     // Termination of the algorithm below is guaranteed because
         972                 :     // knownFeasibleHeight - knownInfeasibleHeight decreases in every
         973                 :     // iteration.
         974               0 :     nscoord knownFeasibleHeight = NS_INTRINSICSIZE;
         975               0 :     nscoord knownInfeasibleHeight = 0;
         976                 :     // We set this flag when we detect that we may contain a frame
         977                 :     // that can break anywhere (thus foiling the linear decrease-by-one
         978                 :     // search)
         979               0 :     bool maybeContinuousBreakingDetected = false;
         980                 :
         981               0 :     while (!aPresContext->HasPendingInterrupt()) {
         982               0 :       nscoord lastKnownFeasibleHeight = knownFeasibleHeight;
         983                 :
         984                 :       // Record what we learned from the last reflow
         985               0 :       if (feasible) {
         986                 :         // maxHeight is feasible. Also, mLastBalanceHeight is feasible.
         987               0 :         knownFeasibleHeight = NS_MIN(knownFeasibleHeight, colData.mMaxHeight);
         988               0 :         knownFeasibleHeight = NS_MIN(knownFeasibleHeight, mLastBalanceHeight);
         989                 :
         990                 :         // Furthermore, no height less than the height of the last
         991                 :         // column can ever be feasible. (We might be able to reduce the
         992                 :         // height of a non-last column by moving content to a later column,
         993                 :         // but we can't do that with the last column.)
         994               0 :         if (mFrames.GetLength() == config.mBalanceColCount) {
         995                 :           knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight,
         996               0 :                                          colData.mLastHeight - 1);
         997                 :         }
         998                 :       } else {
         999               0 :         knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight, mLastBalanceHeight);
        1000                 :         // If a column didn't fit in its available height, then its current
        1001                 :         // height must be the minimum height for unbreakable content in
        1002                 :         // the column, and therefore no smaller height can be feasible.
        1003                 :         knownInfeasibleHeight = NS_MAX(knownInfeasibleHeight,
        1004               0 :                                        colData.mMaxOverflowingHeight - 1);
        1005                 :
        1006               0 :         if (unboundedLastColumn) {
        1007                 :           // The last column is unbounded, so all content got reflowed, so the
        1008                 :           // mColMaxHeight is feasible.
        1009                 :           knownFeasibleHeight = NS_MIN(knownFeasibleHeight,
        1010               0 :                                        colData.mMaxHeight);
        1011                 :         }
        1012                 :       }
        1013                 :
        1014                 : #ifdef DEBUG_roc
        1015                 :       printf("*** nsColumnSetFrame::Reflow balancing knownInfeasible=%d knownFeasible=%d\n",
        1016                 :              knownInfeasibleHeight, knownFeasibleHeight);
        1017                 : #endif
        1018                 :
        1019               0 :       if (knownInfeasibleHeight >= knownFeasibleHeight - 1) {
        1020                 :         // knownFeasibleHeight is where we want to be
        1021               0 :         break;
        1022                 :       }
        1023                 :
        1024               0 :       if (knownInfeasibleHeight >= availableContentHeight) {
        1025               0 :         break;
        1026                 :       }
        1027                 :
        1028               0 :       if (lastKnownFeasibleHeight - knownFeasibleHeight == 1) {
        1029                 :         // We decreased the feasible height by one twip only. This could
        1030                 :         // indicate that there is a continuously breakable child frame
        1031                 :         // that we are crawling through.
        1032               0 :         maybeContinuousBreakingDetected = true;
        1033                 :       }
        1034                 :
        1035               0 :       nscoord nextGuess = (knownFeasibleHeight + knownInfeasibleHeight)/2;
        1036                 :       // The constant of 600 twips is arbitrary. It's about two line-heights.
        1037               0 :       if (knownFeasibleHeight - nextGuess < 600 &&
        1038               0 :           !maybeContinuousBreakingDetected) {
        1039                 :         // We're close to our target, so just try shrinking just the
        1040                 :         // minimum amount that will cause one of our columns to break
        1041                 :         // differently.
        1042               0 :         nextGuess = knownFeasibleHeight - 1;
        1043               0 :       } else if (unboundedLastColumn) {
        1044                 :         // Make a guess by dividing that into N columns. Add some slop
        1045                 :         // to try to make it on the feasible side.  The constant of
        1046                 :         // 600 twips is arbitrary. It's about two line-heights.
        1047               0 :         nextGuess = colData.mSumHeight/config.mBalanceColCount + 600;
        1048                 :         // Sanitize it
        1049                 :         nextGuess = clamped(nextGuess, knownInfeasibleHeight + 1,
        1050               0 :                                        knownFeasibleHeight - 1);
        1051               0 :       } else if (knownFeasibleHeight == NS_INTRINSICSIZE) {
        1052                 :         // This can happen when we had a next-in-flow so we didn't
        1053                 :         // want to do an unbounded height measuring step. Let's just increase
        1054                 :         // from the infeasible height by some reasonable amount.
        1055               0 :         nextGuess = knownInfeasibleHeight*2 + 600;
        1056                 :       }
        1057                 :       // Don't bother guessing more than our height constraint.
        1058               0 :       nextGuess = NS_MIN(availableContentHeight, nextGuess);
        1059                 :
        1060                 : #ifdef DEBUG_roc
        1061                 :       printf("*** nsColumnSetFrame::Reflow balancing choosing next guess=%d\n", nextGuess);
        1062                 : #endif
        1063                 :
        1064               0 :       config.mColMaxHeight = nextGuess;
        1065                 :
        1066               0 :       unboundedLastColumn = false;
        1067               0 :       AddStateBits(NS_FRAME_IS_DIRTY);
        1068                 :       feasible = ReflowChildren(aDesiredSize, aReflowState,
        1069                 :                                 aStatus, config, false,
        1070               0 :                                 &carriedOutBottomMargin, colData);
        1071                 :     }
        1072                 :
        1073               0 :     if (!feasible && !aPresContext->HasPendingInterrupt()) {
        1074                 :       // We may need to reflow one more time at the feasible height to
        1075                 :       // get a valid layout.
        1076               0 :       bool skip = false;
        1077               0 :       if (knownInfeasibleHeight >= availableContentHeight) {
        1078               0 :         config.mColMaxHeight = availableContentHeight;
        1079               0 :         if (mLastBalanceHeight == availableContentHeight) {
        1080               0 :           skip = true;
        1081                 :         }
        1082                 :       } else {
        1083               0 :         config.mColMaxHeight = knownFeasibleHeight;
        1084                 :       }
        1085               0 :       if (!skip) {
        1086                 :         // If our height is unconstrained, make sure that the last column is
        1087                 :         // allowed to have arbitrary height here, even though we were balancing.
        1088                 :         // Otherwise we'd have to split, and it's not clear what we'd do with
        1089                 :         // that.
        1090               0 :         AddStateBits(NS_FRAME_IS_DIRTY);
        1091                 :         ReflowChildren(aDesiredSize, aReflowState, aStatus, config,
        1092                 :                        availableContentHeight == NS_UNCONSTRAINEDSIZE,
        1093               0 :                        &carriedOutBottomMargin, colData);
        1094                 :       }
        1095                 :     }
        1096                 :   }
        1097                 :
        1098               0 :   if (aPresContext->HasPendingInterrupt() &&
        1099                 :       aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
        1100                 :     // In this situation, we might be lying about our reflow status, because
        1101                 :     // our last kid (the one that got interrupted) was incomplete.  Fix that.
        1102               0 :     aStatus = NS_FRAME_COMPLETE;
        1103                 :   }
        1104                 :
        1105               0 :   CheckInvalidateSizeChange(aDesiredSize);
        1106                 :
        1107               0 :   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, false);
        1108                 :
        1109               0 :   aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin;
        1110                 :
        1111               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
        1112                 :
        1113               0 :   NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
        1114                 :                aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE,
        1115                 :                "Column set should be complete if the available height is unconstrained");
        1116                 :
        1117               0 :   return NS_OK;
        1118                 : }
        1119                 :
        1120                 : NS_IMETHODIMP
        1121               0 : nsColumnSetFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
        1122                 :                                    const nsRect&           aDirtyRect,
        1123                 :                                    const nsDisplayListSet& aLists) {
        1124               0 :   nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
        1125               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1126                 :
        1127                 :   aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
        1128                 :       nsDisplayGeneric(aBuilder, this, ::PaintColumnRule, "ColumnRule",
        1129               0 :                        nsDisplayItem::TYPE_COLUMN_RULE));
        1130                 :
        1131               0 :   nsIFrame* kid = mFrames.FirstChild();
        1132                 :   // Our children won't have backgrounds so it doesn't matter where we put them.
        1133               0 :   while (kid) {
        1134               0 :     nsresult rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
        1135               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1136               0 :     kid = kid->GetNextSibling();
        1137                 :   }
        1138               0 :   return NS_OK;
        1139                 : }
        1140                 :
        1141                 : PRIntn
        1142               0 : nsColumnSetFrame::GetSkipSides() const
        1143                 : {
        1144               0 :   return 0;
        1145                 : }
        1146                 :
        1147                 : NS_IMETHODIMP
        1148               0 : nsColumnSetFrame::AppendFrames(ChildListID     aListID,
        1149                 :                                nsFrameList&    aFrameList)
        1150                 : {
        1151               0 :   if (aListID == kAbsoluteList) {
        1152               0 :     return nsContainerFrame::AppendFrames(aListID, aFrameList);
        1153                 :   }
        1154                 :
        1155               0 :   NS_ERROR("unexpected child list");
        1156               0 :   return NS_ERROR_INVALID_ARG;
        1157                 : }
        1158                 :
        1159                 : NS_IMETHODIMP
        1160               0 : nsColumnSetFrame::InsertFrames(ChildListID     aListID,
        1161                 :                                nsIFrame*       aPrevFrame,
        1162                 :                                nsFrameList&    aFrameList)
        1163                 : {
        1164               0 :   if (aListID == kAbsoluteList) {
        1165               0 :     return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
        1166                 :   }
        1167                 :
        1168               0 :   NS_ERROR("unexpected child list");
        1169               0 :   return NS_ERROR_INVALID_ARG;
        1170                 : }
        1171                 :
        1172                 : NS_IMETHODIMP
        1173               0 : nsColumnSetFrame::RemoveFrame(ChildListID     aListID,
        1174                 :                               nsIFrame*       aOldFrame)
        1175                 : {
        1176               0 :   if (aListID == kAbsoluteList) {
        1177               0 :     return nsContainerFrame::RemoveFrame(aListID, aOldFrame);
        1178                 :   }
        1179                 :
        1180               0 :   NS_ERROR("unexpected child list");
        1181               0 :   return NS_ERROR_INVALID_ARG;
        1182                 : }

Generated by: LCOV version 1.7