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