LCOV - code coverage report
Current view: directory - layout/tables - nsTableFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 3230 0 0.0 %
Date: 2012-06-02 Functions: 256 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=80: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *   Mats Palmgren <matspal@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : #include "nsCOMPtr.h"
      41                 : #include "nsTableFrame.h"
      42                 : #include "nsRenderingContext.h"
      43                 : #include "nsStyleContext.h"
      44                 : #include "nsStyleConsts.h"
      45                 : #include "nsIContent.h"
      46                 : #include "nsCellMap.h"
      47                 : #include "nsTableCellFrame.h"
      48                 : #include "nsHTMLParts.h"
      49                 : #include "nsTableColFrame.h"
      50                 : #include "nsTableColGroupFrame.h"
      51                 : #include "nsTableRowFrame.h"
      52                 : #include "nsTableRowGroupFrame.h"
      53                 : #include "nsTableOuterFrame.h"
      54                 : #include "nsTablePainter.h"
      55                 : 
      56                 : #include "BasicTableLayoutStrategy.h"
      57                 : #include "FixedTableLayoutStrategy.h"
      58                 : 
      59                 : #include "nsPresContext.h"
      60                 : #include "nsCSSRendering.h"
      61                 : #include "nsGkAtoms.h"
      62                 : #include "nsCSSAnonBoxes.h"
      63                 : #include "nsIPresShell.h"
      64                 : #include "nsIDOMElement.h"
      65                 : #include "nsIDOMHTMLElement.h"
      66                 : #include "nsIDOMHTMLBodyElement.h"
      67                 : #include "nsFrameManager.h"
      68                 : #include "nsLayoutErrors.h"
      69                 : #include "nsAutoPtr.h"
      70                 : #include "nsCSSFrameConstructor.h"
      71                 : #include "nsStyleSet.h"
      72                 : #include "nsDisplayList.h"
      73                 : #include "nsIScrollableFrame.h"
      74                 : #include "nsCSSProps.h"
      75                 : 
      76                 : using namespace mozilla;
      77                 : using namespace mozilla::layout;
      78                 : 
      79                 : /********************************************************************************
      80                 :  ** nsTableReflowState                                                         **
      81                 :  ********************************************************************************/
      82                 : 
      83                 : struct nsTableReflowState {
      84                 : 
      85                 :   // the real reflow state
      86                 :   const nsHTMLReflowState& reflowState;
      87                 : 
      88                 :   // The table's available size
      89                 :   nsSize availSize;
      90                 : 
      91                 :   // Stationary x-offset
      92                 :   nscoord x;
      93                 : 
      94                 :   // Running y-offset
      95                 :   nscoord y;
      96                 : 
      97               0 :   nsTableReflowState(nsPresContext&           aPresContext,
      98                 :                      const nsHTMLReflowState& aReflowState,
      99                 :                      nsTableFrame&            aTableFrame,
     100                 :                      nscoord                  aAvailWidth,
     101                 :                      nscoord                  aAvailHeight)
     102               0 :     : reflowState(aReflowState)
     103                 :   {
     104               0 :     Init(aPresContext, aTableFrame, aAvailWidth, aAvailHeight);
     105               0 :   }
     106                 : 
     107               0 :   void Init(nsPresContext&  aPresContext,
     108                 :             nsTableFrame&   aTableFrame,
     109                 :             nscoord         aAvailWidth,
     110                 :             nscoord         aAvailHeight)
     111                 :   {
     112               0 :     nsTableFrame* table = (nsTableFrame*)aTableFrame.GetFirstInFlow();
     113               0 :     nsMargin borderPadding = table->GetChildAreaOffset(&reflowState);
     114               0 :     nscoord cellSpacingX = table->GetCellSpacingX();
     115                 : 
     116               0 :     x = borderPadding.left + cellSpacingX;
     117               0 :     y = borderPadding.top; //cellspacing added during reflow
     118                 : 
     119               0 :     availSize.width  = aAvailWidth;
     120               0 :     if (NS_UNCONSTRAINEDSIZE != availSize.width) {
     121                 :       availSize.width -= borderPadding.left + borderPadding.right
     122               0 :                          + (2 * cellSpacingX);
     123               0 :       availSize.width = NS_MAX(0, availSize.width);
     124                 :     }
     125                 : 
     126               0 :     availSize.height = aAvailHeight;
     127               0 :     if (NS_UNCONSTRAINEDSIZE != availSize.height) {
     128                 :       availSize.height -= borderPadding.top + borderPadding.bottom
     129               0 :                           + (2 * table->GetCellSpacingY());
     130               0 :       availSize.height = NS_MAX(0, availSize.height);
     131                 :     }
     132               0 :   }
     133                 : 
     134                 :   nsTableReflowState(nsPresContext&           aPresContext,
     135                 :                      const nsHTMLReflowState& aReflowState,
     136                 :                      nsTableFrame&            aTableFrame)
     137                 :     : reflowState(aReflowState)
     138                 :   {
     139                 :     Init(aPresContext, aTableFrame, aReflowState.availableWidth, aReflowState.availableHeight);
     140                 :   }
     141                 : 
     142                 : };
     143                 : 
     144                 : /********************************************************************************
     145                 :  ** nsTableFrame                                                               **
     146                 :  ********************************************************************************/
     147                 : 
     148                 : struct BCPropertyData
     149                 : {
     150               0 :   BCPropertyData() : mTopBorderWidth(0), mRightBorderWidth(0),
     151                 :                      mBottomBorderWidth(0), mLeftBorderWidth(0),
     152               0 :                      mLeftCellBorderWidth(0), mRightCellBorderWidth(0) {}
     153                 :   nsIntRect mDamageArea;
     154                 :   BCPixelSize mTopBorderWidth;
     155                 :   BCPixelSize mRightBorderWidth;
     156                 :   BCPixelSize mBottomBorderWidth;
     157                 :   BCPixelSize mLeftBorderWidth;
     158                 :   BCPixelSize mLeftCellBorderWidth;
     159                 :   BCPixelSize mRightCellBorderWidth;
     160                 : };
     161                 : 
     162                 : nsIFrame*
     163               0 : nsTableFrame::GetParentStyleContextFrame() const
     164                 : {
     165                 :   // Since our parent, the table outer frame, returned this frame, we
     166                 :   // must return whatever our parent would normally have returned.
     167                 : 
     168               0 :   NS_PRECONDITION(mParent, "table constructed without outer table");
     169               0 :   if (!mContent->GetParent() && !GetStyleContext()->GetPseudo()) {
     170                 :     // We're the root.  We have no style context parent.
     171               0 :     return nsnull;
     172                 :   }
     173                 : 
     174               0 :   return static_cast<nsFrame*>(GetParent())->DoGetParentStyleContextFrame();
     175                 : }
     176                 : 
     177                 : 
     178                 : nsIAtom*
     179               0 : nsTableFrame::GetType() const
     180                 : {
     181               0 :   return nsGkAtoms::tableFrame;
     182                 : }
     183                 : 
     184                 : 
     185               0 : nsTableFrame::nsTableFrame(nsStyleContext* aContext)
     186                 :   : nsContainerFrame(aContext),
     187                 :     mCellMap(nsnull),
     188               0 :     mTableLayoutStrategy(nsnull)
     189                 : {
     190               0 :   memset(&mBits, 0, sizeof(mBits));
     191               0 : }
     192                 : 
     193               0 : NS_QUERYFRAME_HEAD(nsTableFrame)
     194               0 :   NS_QUERYFRAME_ENTRY(nsITableLayout)
     195               0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
     196                 : 
     197                 : NS_IMETHODIMP
     198               0 : nsTableFrame::Init(nsIContent*      aContent,
     199                 :                    nsIFrame*        aParent,
     200                 :                    nsIFrame*        aPrevInFlow)
     201                 : {
     202               0 :   NS_PRECONDITION(!mCellMap, "Init called twice");
     203               0 :   NS_PRECONDITION(!aPrevInFlow ||
     204                 :                   aPrevInFlow->GetType() == nsGkAtoms::tableFrame,
     205                 :                   "prev-in-flow must be of same type");
     206                 : 
     207                 :   // Let the base class do its processing
     208               0 :   nsresult rv = nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
     209                 : 
     210                 :   // see if border collapse is on, if so set it
     211               0 :   const nsStyleTableBorder* tableStyle = GetStyleTableBorder();
     212               0 :   bool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse);
     213               0 :   SetBorderCollapse(borderCollapse);
     214                 : 
     215                 :   // Transforms need to affect the outer frame, not the inner frame (bug 722777)
     216               0 :   mState &= ~NS_FRAME_MAY_BE_TRANSFORMED;
     217                 : 
     218                 :   // Create the cell map if this frame is the first-in-flow.
     219               0 :   if (!aPrevInFlow) {
     220               0 :     mCellMap = new nsTableCellMap(*this, borderCollapse);
     221               0 :     if (!mCellMap)
     222               0 :       return NS_ERROR_OUT_OF_MEMORY;
     223                 :   }
     224                 : 
     225               0 :   if (aPrevInFlow) {
     226                 :     // set my width, because all frames in a table flow are the same width and
     227                 :     // code in nsTableOuterFrame depends on this being set
     228               0 :     mRect.width = aPrevInFlow->GetSize().width;
     229                 :   }
     230                 :   else {
     231               0 :     NS_ASSERTION(!mTableLayoutStrategy, "strategy was created before Init was called");
     232                 :     // create the strategy
     233               0 :     if (IsAutoLayout())
     234               0 :       mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
     235                 :     else
     236               0 :       mTableLayoutStrategy = new FixedTableLayoutStrategy(this);
     237               0 :     if (!mTableLayoutStrategy)
     238               0 :       return NS_ERROR_OUT_OF_MEMORY;
     239                 :   }
     240                 : 
     241               0 :   return rv;
     242                 : }
     243                 : 
     244               0 : nsTableFrame::~nsTableFrame()
     245                 : {
     246               0 :   delete mCellMap;
     247               0 :   delete mTableLayoutStrategy;
     248               0 : }
     249                 : 
     250                 : void
     251               0 : nsTableFrame::DestroyFrom(nsIFrame* aDestructRoot)
     252                 : {
     253               0 :   mColGroups.DestroyFramesFrom(aDestructRoot);
     254               0 :   nsContainerFrame::DestroyFrom(aDestructRoot);
     255               0 : }
     256                 : 
     257                 : // Make sure any views are positioned properly
     258                 : void
     259               0 : nsTableFrame::RePositionViews(nsIFrame* aFrame)
     260                 : {
     261               0 :   nsContainerFrame::PositionFrameView(aFrame);
     262               0 :   nsContainerFrame::PositionChildViews(aFrame);
     263               0 : }
     264                 : 
     265                 : static bool
     266               0 : IsRepeatedFrame(nsIFrame* kidFrame)
     267                 : {
     268               0 :   return (kidFrame->GetType() == nsGkAtoms::tableRowFrame ||
     269               0 :           kidFrame->GetType() == nsGkAtoms::tableRowGroupFrame) &&
     270               0 :          (kidFrame->GetStateBits() & NS_REPEATED_ROW_OR_ROWGROUP);
     271                 : }
     272                 : 
     273                 : bool
     274               0 : nsTableFrame::PageBreakAfter(nsIFrame* aSourceFrame,
     275                 :                              nsIFrame* aNextFrame)
     276                 : {
     277               0 :   const nsStyleDisplay* display = aSourceFrame->GetStyleDisplay();
     278               0 :   nsTableRowGroupFrame* prevRg = do_QueryFrame(aSourceFrame);
     279                 :   // don't allow a page break after a repeated element ...
     280               0 :   if ((display->mBreakAfter || (prevRg && prevRg->HasInternalBreakAfter())) &&
     281               0 :       !IsRepeatedFrame(aSourceFrame)) {
     282               0 :     return !(aNextFrame && IsRepeatedFrame(aNextFrame)); // or before
     283                 :   }
     284                 : 
     285               0 :   if (aNextFrame) {
     286               0 :     display = aNextFrame->GetStyleDisplay();
     287                 :     // don't allow a page break before a repeated element ...
     288               0 :      nsTableRowGroupFrame* nextRg = do_QueryFrame(aNextFrame);
     289               0 :     if ((display->mBreakBefore ||
     290               0 :         (nextRg && nextRg->HasInternalBreakBefore())) &&
     291               0 :         !IsRepeatedFrame(aNextFrame)) {
     292               0 :       return !IsRepeatedFrame(aSourceFrame); // or after
     293                 :     }
     294                 :   }
     295               0 :   return false;
     296                 : }
     297                 : 
     298                 : // XXX this needs to be cleaned up so that the frame constructor breaks out col group
     299                 : // frames into a separate child list, bug 343048.
     300                 : NS_IMETHODIMP
     301               0 : nsTableFrame::SetInitialChildList(ChildListID     aListID,
     302                 :                                   nsFrameList&    aChildList)
     303                 : {
     304                 : 
     305               0 :   if (!mFrames.IsEmpty() || !mColGroups.IsEmpty()) {
     306                 :     // We already have child frames which means we've already been
     307                 :     // initialized
     308               0 :     NS_NOTREACHED("unexpected second call to SetInitialChildList");
     309               0 :     return NS_ERROR_UNEXPECTED;
     310                 :   }
     311               0 :   if (aListID != kPrincipalList) {
     312                 :     // All we know about is the principal child list.
     313               0 :     NS_NOTREACHED("unknown frame list");
     314               0 :     return NS_ERROR_INVALID_ARG;
     315                 :   }
     316                 : 
     317                 :   // XXXbz the below code is an icky cesspit that's only needed in its current
     318                 :   // form for two reasons:
     319                 :   // 1) Both rowgroups and column groups come in on the principal child list.
     320               0 :   while (aChildList.NotEmpty()) {
     321               0 :     nsIFrame* childFrame = aChildList.FirstChild();
     322               0 :     aChildList.RemoveFirstChild();
     323               0 :     const nsStyleDisplay* childDisplay = childFrame->GetStyleDisplay();
     324                 : 
     325               0 :     if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == childDisplay->mDisplay) {
     326               0 :       NS_ASSERTION(nsGkAtoms::tableColGroupFrame == childFrame->GetType(),
     327                 :                    "This is not a colgroup");
     328               0 :       mColGroups.AppendFrame(nsnull, childFrame);
     329                 :     }
     330                 :     else { // row groups and unknown frames go on the main list for now
     331               0 :       mFrames.AppendFrame(nsnull, childFrame);
     332                 :     }
     333                 :   }
     334                 : 
     335                 :   // If we have a prev-in-flow, then we're a table that has been split and
     336                 :   // so don't treat this like an append
     337               0 :   if (!GetPrevInFlow()) {
     338                 :     // process col groups first so that real cols get constructed before
     339                 :     // anonymous ones due to cells in rows.
     340               0 :     InsertColGroups(0, mColGroups);
     341               0 :     InsertRowGroups(mFrames);
     342                 :     // calc collapsing borders
     343               0 :     if (IsBorderCollapse()) {
     344               0 :       SetFullBCDamageArea();
     345                 :     }
     346                 :   }
     347                 : 
     348               0 :   return NS_OK;
     349                 : }
     350                 : 
     351               0 : void nsTableFrame::AttributeChangedFor(nsIFrame*       aFrame,
     352                 :                                        nsIContent*     aContent,
     353                 :                                        nsIAtom*        aAttribute)
     354                 : {
     355               0 :   nsTableCellFrame *cellFrame = do_QueryFrame(aFrame);
     356               0 :   if (cellFrame) {
     357               0 :     if ((nsGkAtoms::rowspan == aAttribute) ||
     358                 :         (nsGkAtoms::colspan == aAttribute)) {
     359               0 :       nsTableCellMap* cellMap = GetCellMap();
     360               0 :       if (cellMap) {
     361                 :         // for now just remove the cell from the map and reinsert it
     362                 :         PRInt32 rowIndex, colIndex;
     363               0 :         cellFrame->GetRowIndex(rowIndex);
     364               0 :         cellFrame->GetColIndex(colIndex);
     365               0 :         RemoveCell(cellFrame, rowIndex);
     366               0 :         nsAutoTArray<nsTableCellFrame*, 1> cells;
     367               0 :         cells.AppendElement(cellFrame);
     368               0 :         InsertCells(cells, rowIndex, colIndex - 1);
     369                 : 
     370                 :         // XXX Should this use eStyleChange?  It currently doesn't need
     371                 :         // to, but it might given more optimization.
     372               0 :         PresContext()->PresShell()->
     373               0 :           FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     374                 :       }
     375                 :     }
     376                 :   }
     377               0 : }
     378                 : 
     379                 : 
     380                 : /* ****** CellMap methods ******* */
     381                 : 
     382                 : /* return the effective col count */
     383               0 : PRInt32 nsTableFrame::GetEffectiveColCount() const
     384                 : {
     385               0 :   PRInt32 colCount = GetColCount();
     386               0 :   if (LayoutStrategy()->GetType() == nsITableLayoutStrategy::Auto) {
     387               0 :     nsTableCellMap* cellMap = GetCellMap();
     388               0 :     if (!cellMap) {
     389               0 :       return 0;
     390                 :     }
     391                 :     // don't count cols at the end that don't have originating cells
     392               0 :     for (PRInt32 colX = colCount - 1; colX >= 0; colX--) {
     393               0 :       if (cellMap->GetNumCellsOriginatingInCol(colX) > 0) {
     394               0 :         break;
     395                 :       }
     396               0 :       colCount--;
     397                 :     }
     398                 :   }
     399               0 :   return colCount;
     400                 : }
     401                 : 
     402               0 : PRInt32 nsTableFrame::GetIndexOfLastRealCol()
     403                 : {
     404               0 :   PRInt32 numCols = mColFrames.Length();
     405               0 :   if (numCols > 0) {
     406               0 :     for (PRInt32 colX = numCols - 1; colX >= 0; colX--) {
     407               0 :       nsTableColFrame* colFrame = GetColFrame(colX);
     408               0 :       if (colFrame) {
     409               0 :         if (eColAnonymousCell != colFrame->GetColType()) {
     410               0 :           return colX;
     411                 :         }
     412                 :       }
     413                 :     }
     414                 :   }
     415               0 :   return -1;
     416                 : }
     417                 : 
     418                 : nsTableColFrame*
     419               0 : nsTableFrame::GetColFrame(PRInt32 aColIndex) const
     420                 : {
     421               0 :   NS_ASSERTION(!GetPrevInFlow(), "GetColFrame called on next in flow");
     422               0 :   PRInt32 numCols = mColFrames.Length();
     423               0 :   if ((aColIndex >= 0) && (aColIndex < numCols)) {
     424               0 :     return mColFrames.ElementAt(aColIndex);
     425                 :   }
     426                 :   else {
     427               0 :     NS_ERROR("invalid col index");
     428               0 :     return nsnull;
     429                 :   }
     430                 : }
     431                 : 
     432               0 : PRInt32 nsTableFrame::GetEffectiveRowSpan(PRInt32                 aRowIndex,
     433                 :                                           const nsTableCellFrame& aCell) const
     434                 : {
     435               0 :   nsTableCellMap* cellMap = GetCellMap();
     436               0 :   NS_PRECONDITION (nsnull != cellMap, "bad call, cellMap not yet allocated.");
     437                 : 
     438                 :   PRInt32 colIndex;
     439               0 :   aCell.GetColIndex(colIndex);
     440               0 :   return cellMap->GetEffectiveRowSpan(aRowIndex, colIndex);
     441                 : }
     442                 : 
     443               0 : PRInt32 nsTableFrame::GetEffectiveRowSpan(const nsTableCellFrame& aCell,
     444                 :                                           nsCellMap*              aCellMap)
     445                 : {
     446               0 :   nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1);
     447                 : 
     448                 :   PRInt32 colIndex, rowIndex;
     449               0 :   aCell.GetColIndex(colIndex);
     450               0 :   aCell.GetRowIndex(rowIndex);
     451                 : 
     452               0 :   if (aCellMap)
     453               0 :     return aCellMap->GetRowSpan(rowIndex, colIndex, true);
     454                 :   else
     455               0 :     return tableCellMap->GetEffectiveRowSpan(rowIndex, colIndex);
     456                 : }
     457                 : 
     458               0 : PRInt32 nsTableFrame::GetEffectiveColSpan(const nsTableCellFrame& aCell,
     459                 :                                           nsCellMap*              aCellMap) const
     460                 : {
     461               0 :   nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1);
     462                 : 
     463                 :   PRInt32 colIndex, rowIndex;
     464               0 :   aCell.GetColIndex(colIndex);
     465               0 :   aCell.GetRowIndex(rowIndex);
     466                 :   bool ignore;
     467                 : 
     468               0 :   if (aCellMap)
     469               0 :     return aCellMap->GetEffectiveColSpan(*tableCellMap, rowIndex, colIndex, ignore);
     470                 :   else
     471               0 :     return tableCellMap->GetEffectiveColSpan(rowIndex, colIndex);
     472                 : }
     473                 : 
     474               0 : bool nsTableFrame::HasMoreThanOneCell(PRInt32 aRowIndex) const
     475                 : {
     476               0 :   nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1);
     477               0 :   return tableCellMap->HasMoreThanOneCell(aRowIndex);
     478                 : }
     479                 : 
     480               0 : void nsTableFrame::AdjustRowIndices(PRInt32         aRowIndex,
     481                 :                                     PRInt32         aAdjustment)
     482                 : {
     483                 :   // Iterate over the row groups and adjust the row indices of all rows
     484                 :   // whose index is >= aRowIndex.
     485               0 :   RowGroupArray rowGroups;
     486               0 :   OrderRowGroups(rowGroups);
     487                 : 
     488               0 :   for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
     489               0 :     rowGroups[rgX]->AdjustRowIndices(aRowIndex, aAdjustment);
     490                 :   }
     491               0 : }
     492                 : 
     493                 : 
     494               0 : void nsTableFrame::ResetRowIndices(const nsFrameList::Slice& aRowGroupsToExclude)
     495                 : {
     496                 :   // Iterate over the row groups and adjust the row indices of all rows
     497                 :   // omit the rowgroups that will be inserted later
     498               0 :   RowGroupArray rowGroups;
     499               0 :   OrderRowGroups(rowGroups);
     500                 : 
     501               0 :   PRInt32 rowIndex = 0;
     502               0 :   nsTHashtable<nsPtrHashKey<nsTableRowGroupFrame> > excludeRowGroups;
     503               0 :   if (!excludeRowGroups.Init()) {
     504               0 :     NS_ERROR("Failed to initialize excludeRowGroups hash.");
     505                 :     return;
     506                 :   }
     507               0 :   nsFrameList::Enumerator excludeRowGroupsEnumerator(aRowGroupsToExclude);
     508               0 :   while (!excludeRowGroupsEnumerator.AtEnd()) {
     509               0 :     excludeRowGroups.PutEntry(static_cast<nsTableRowGroupFrame*>(excludeRowGroupsEnumerator.get()));
     510               0 :     excludeRowGroupsEnumerator.Next();
     511                 :   }
     512                 : 
     513               0 :   for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
     514               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
     515               0 :     if (!excludeRowGroups.GetEntry(rgFrame)) {
     516               0 :       const nsFrameList& rowFrames = rgFrame->PrincipalChildList();
     517               0 :       for (nsFrameList::Enumerator rows(rowFrames); !rows.AtEnd(); rows.Next()) {
     518               0 :         if (NS_STYLE_DISPLAY_TABLE_ROW==rows.get()->GetStyleDisplay()->mDisplay) {
     519               0 :           ((nsTableRowFrame *)rows.get())->SetRowIndex(rowIndex);
     520               0 :           rowIndex++;
     521                 :         }
     522                 :       }
     523                 :     }
     524                 :   }
     525                 : }
     526               0 : void nsTableFrame::InsertColGroups(PRInt32                   aStartColIndex,
     527                 :                                    const nsFrameList::Slice& aColGroups)
     528                 : {
     529               0 :   PRInt32 colIndex = aStartColIndex;
     530               0 :   nsFrameList::Enumerator colGroups(aColGroups);
     531               0 :   for (; !colGroups.AtEnd(); colGroups.Next()) {
     532                 :     nsTableColGroupFrame* cgFrame =
     533               0 :       static_cast<nsTableColGroupFrame*>(colGroups.get());
     534               0 :     cgFrame->SetStartColumnIndex(colIndex);
     535                 :     // XXXbz this sucks.  AddColsToTable will actually remove colgroups from
     536                 :     // the list we're traversing!  Need to fix things here.  :( I guess this is
     537                 :     // why the old code used pointer-to-last-frame as opposed to
     538                 :     // pointer-to-frame-after-last....
     539                 : 
     540                 :     // How about dealing with this by storing a const reference to the
     541                 :     // mNextSibling of the framelist's last frame, instead of storing a pointer
     542                 :     // to the first-after-next frame?  Will involve making nsFrameList friend
     543                 :     // of nsIFrame, but it's time for that anyway.
     544                 :     cgFrame->AddColsToTable(colIndex, false,
     545               0 :                               colGroups.get()->PrincipalChildList());
     546               0 :     PRInt32 numCols = cgFrame->GetColCount();
     547               0 :     colIndex += numCols;
     548                 :   }
     549                 : 
     550               0 :   nsFrameList::Enumerator remainingColgroups = colGroups.GetUnlimitedEnumerator();
     551               0 :   if (!remainingColgroups.AtEnd()) {
     552                 :     nsTableColGroupFrame::ResetColIndices(
     553               0 :       static_cast<nsTableColGroupFrame*>(remainingColgroups.get()), colIndex);
     554                 :   }
     555               0 : }
     556                 : 
     557               0 : void nsTableFrame::InsertCol(nsTableColFrame& aColFrame,
     558                 :                              PRInt32          aColIndex)
     559                 : {
     560               0 :   mColFrames.InsertElementAt(aColIndex, &aColFrame);
     561               0 :   nsTableColType insertedColType = aColFrame.GetColType();
     562               0 :   PRInt32 numCacheCols = mColFrames.Length();
     563               0 :   nsTableCellMap* cellMap = GetCellMap();
     564               0 :   if (cellMap) {
     565               0 :     PRInt32 numMapCols = cellMap->GetColCount();
     566               0 :     if (numCacheCols > numMapCols) {
     567               0 :       bool removedFromCache = false;
     568               0 :       if (eColAnonymousCell != insertedColType) {
     569               0 :         nsTableColFrame* lastCol = mColFrames.ElementAt(numCacheCols - 1);
     570               0 :         if (lastCol) {
     571               0 :           nsTableColType lastColType = lastCol->GetColType();
     572               0 :           if (eColAnonymousCell == lastColType) {
     573                 :             // remove the col from the cache
     574               0 :             mColFrames.RemoveElementAt(numCacheCols - 1);
     575                 :             // remove the col from the eColGroupAnonymousCell col group
     576               0 :             nsTableColGroupFrame* lastColGroup = (nsTableColGroupFrame *)mColGroups.LastChild();
     577               0 :             if (lastColGroup) {
     578               0 :               lastColGroup->RemoveChild(*lastCol, false);
     579                 : 
     580                 :               // remove the col group if it is empty
     581               0 :               if (lastColGroup->GetColCount() <= 0) {
     582               0 :                 mColGroups.DestroyFrame((nsIFrame*)lastColGroup);
     583                 :               }
     584                 :             }
     585               0 :             removedFromCache = true;
     586                 :           }
     587                 :         }
     588                 :       }
     589               0 :       if (!removedFromCache) {
     590               0 :         cellMap->AddColsAtEnd(1);
     591                 :       }
     592                 :     }
     593                 :   }
     594                 :   // for now, just bail and recalc all of the collapsing borders
     595               0 :   if (IsBorderCollapse()) {
     596               0 :     nsIntRect damageArea(aColIndex, 0, 1, GetRowCount());
     597               0 :     AddBCDamageArea(damageArea);
     598                 :   }
     599               0 : }
     600                 : 
     601               0 : void nsTableFrame::RemoveCol(nsTableColGroupFrame* aColGroupFrame,
     602                 :                              PRInt32               aColIndex,
     603                 :                              bool                  aRemoveFromCache,
     604                 :                              bool                  aRemoveFromCellMap)
     605                 : {
     606               0 :   if (aRemoveFromCache) {
     607               0 :     mColFrames.RemoveElementAt(aColIndex);
     608                 :   }
     609               0 :   if (aRemoveFromCellMap) {
     610               0 :     nsTableCellMap* cellMap = GetCellMap();
     611               0 :     if (cellMap) {
     612               0 :       AppendAnonymousColFrames(1);
     613                 :     }
     614                 :   }
     615                 :   // for now, just bail and recalc all of the collapsing borders
     616               0 :   if (IsBorderCollapse()) {
     617               0 :     nsIntRect damageArea(0, 0, GetColCount(), GetRowCount());
     618               0 :     AddBCDamageArea(damageArea);
     619                 :   }
     620               0 : }
     621                 : 
     622                 : /** Get the cell map for this table frame.  It is not always mCellMap.
     623                 :   * Only the firstInFlow has a legit cell map
     624                 :   */
     625               0 : nsTableCellMap* nsTableFrame::GetCellMap() const
     626                 : {
     627               0 :   nsTableFrame* firstInFlow = (nsTableFrame *)GetFirstInFlow();
     628               0 :   return firstInFlow->mCellMap;
     629                 : }
     630                 : 
     631                 : // XXX this needs to be moved to nsCSSFrameConstructor
     632                 : nsTableColGroupFrame*
     633               0 : nsTableFrame::CreateAnonymousColGroupFrame(nsTableColGroupType aColGroupType)
     634                 : {
     635               0 :   nsIContent* colGroupContent = GetContent();
     636               0 :   nsPresContext* presContext = PresContext();
     637               0 :   nsIPresShell *shell = presContext->PresShell();
     638                 : 
     639               0 :   nsRefPtr<nsStyleContext> colGroupStyle;
     640                 :   colGroupStyle = shell->StyleSet()->
     641               0 :     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableColGroup, mStyleContext);
     642                 :   // Create a col group frame
     643               0 :   nsIFrame* newFrame = NS_NewTableColGroupFrame(shell, colGroupStyle);
     644               0 :   if (newFrame) {
     645               0 :     ((nsTableColGroupFrame *)newFrame)->SetColType(aColGroupType);
     646               0 :     newFrame->Init(colGroupContent, this, nsnull);
     647                 :   }
     648               0 :   return (nsTableColGroupFrame *)newFrame;
     649                 : }
     650                 : 
     651                 : void
     652               0 : nsTableFrame::AppendAnonymousColFrames(PRInt32 aNumColsToAdd)
     653                 : {
     654                 :   // get the last col group frame
     655                 :   nsTableColGroupFrame* colGroupFrame =
     656               0 :     static_cast<nsTableColGroupFrame*>(mColGroups.LastChild());
     657                 : 
     658               0 :   if (!colGroupFrame ||
     659               0 :       (colGroupFrame->GetColType() != eColGroupAnonymousCell)) {
     660                 :     PRInt32 colIndex = (colGroupFrame) ?
     661               0 :                         colGroupFrame->GetStartColumnIndex() +
     662               0 :                         colGroupFrame->GetColCount() : 0;
     663               0 :     colGroupFrame = CreateAnonymousColGroupFrame(eColGroupAnonymousCell);
     664               0 :     if (!colGroupFrame) {
     665               0 :       return;
     666                 :     }
     667                 :     // add the new frame to the child list
     668               0 :     mColGroups.AppendFrame(this, colGroupFrame);
     669               0 :     colGroupFrame->SetStartColumnIndex(colIndex);
     670                 :   }
     671                 :   AppendAnonymousColFrames(colGroupFrame, aNumColsToAdd, eColAnonymousCell,
     672               0 :                            true);
     673                 : 
     674                 : }
     675                 : 
     676                 : // XXX this needs to be moved to nsCSSFrameConstructor
     677                 : // Right now it only creates the col frames at the end
     678                 : void
     679               0 : nsTableFrame::AppendAnonymousColFrames(nsTableColGroupFrame* aColGroupFrame,
     680                 :                                        PRInt32               aNumColsToAdd,
     681                 :                                        nsTableColType        aColType,
     682                 :                                        bool                  aAddToTable)
     683                 : {
     684               0 :   NS_PRECONDITION(aColGroupFrame, "null frame");
     685               0 :   NS_PRECONDITION(aColType != eColAnonymousCol, "Shouldn't happen");
     686                 : 
     687               0 :   nsIPresShell *shell = PresContext()->PresShell();
     688                 : 
     689                 :   // Get the last col frame
     690               0 :   nsFrameList newColFrames;
     691                 : 
     692               0 :   PRInt32 startIndex = mColFrames.Length();
     693               0 :   PRInt32 lastIndex  = startIndex + aNumColsToAdd - 1;
     694                 : 
     695               0 :   for (PRInt32 childX = startIndex; childX <= lastIndex; childX++) {
     696                 :     nsIContent* iContent;
     697               0 :     nsRefPtr<nsStyleContext> styleContext;
     698                 :     nsStyleContext* parentStyleContext;
     699                 : 
     700                 :     // all anonymous cols that we create here use a pseudo style context of the
     701                 :     // col group
     702               0 :     iContent = aColGroupFrame->GetContent();
     703               0 :     parentStyleContext = aColGroupFrame->GetStyleContext();
     704                 :     styleContext = shell->StyleSet()->
     705               0 :       ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableCol, parentStyleContext);
     706                 :     // ASSERTION to check for bug 54454 sneaking back in...
     707               0 :     NS_ASSERTION(iContent, "null content in CreateAnonymousColFrames");
     708                 : 
     709                 :     // create the new col frame
     710               0 :     nsIFrame* colFrame = NS_NewTableColFrame(shell, styleContext);
     711               0 :     ((nsTableColFrame *) colFrame)->SetColType(aColType);
     712               0 :     colFrame->Init(iContent, aColGroupFrame, nsnull);
     713                 : 
     714               0 :     newColFrames.AppendFrame(nsnull, colFrame);
     715                 :   }
     716               0 :   nsFrameList& cols = aColGroupFrame->GetWritableChildList();
     717               0 :   nsIFrame* oldLastCol = cols.LastChild();
     718                 :   const nsFrameList::Slice& newCols =
     719               0 :     cols.InsertFrames(nsnull, oldLastCol, newColFrames);
     720               0 :   if (aAddToTable) {
     721                 :     // get the starting col index in the cache
     722                 :     PRInt32 startColIndex;
     723               0 :     if (oldLastCol) {
     724                 :       startColIndex =
     725               0 :         static_cast<nsTableColFrame*>(oldLastCol)->GetColIndex() + 1;
     726                 :     } else {
     727               0 :       startColIndex = aColGroupFrame->GetStartColumnIndex();
     728                 :     }
     729                 : 
     730               0 :     aColGroupFrame->AddColsToTable(startColIndex, true, newCols);
     731                 :   }
     732               0 : }
     733                 : 
     734                 : void
     735               0 : nsTableFrame::MatchCellMapToColCache(nsTableCellMap* aCellMap)
     736                 : {
     737               0 :   PRInt32 numColsInMap   = GetColCount();
     738               0 :   PRInt32 numColsInCache = mColFrames.Length();
     739               0 :   PRInt32 numColsToAdd = numColsInMap - numColsInCache;
     740               0 :   if (numColsToAdd > 0) {
     741                 :     // this sets the child list, updates the col cache and cell map
     742               0 :     AppendAnonymousColFrames(numColsToAdd);
     743                 :   }
     744               0 :   if (numColsToAdd < 0) {
     745               0 :     PRInt32 numColsNotRemoved = DestroyAnonymousColFrames(-numColsToAdd);
     746                 :     // if the cell map has fewer cols than the cache, correct it
     747               0 :     if (numColsNotRemoved > 0) {
     748               0 :       aCellMap->AddColsAtEnd(numColsNotRemoved);
     749                 :     }
     750                 :   }
     751               0 :   if (numColsToAdd && HasZeroColSpans()) {
     752               0 :     SetNeedColSpanExpansion(true);
     753                 :   }
     754               0 :   if (NeedColSpanExpansion()) {
     755                 :     // This flag can be set in two ways -- either by changing
     756                 :     // the number of columns (that happens in the block above),
     757                 :     // or by adding a cell with colspan="0" to the cellmap.  To
     758                 :     // handle the latter case we need to explicitly check the
     759                 :     // flag here -- it may be set even if the number of columns
     760                 :     // did not change.
     761                 :     //
     762                 :     // @see nsCellMap::AppendCell
     763                 : 
     764               0 :     aCellMap->ExpandZeroColSpans();
     765                 :   }
     766               0 : }
     767                 : 
     768                 : void
     769               0 : nsTableFrame::DidResizeColumns()
     770                 : {
     771               0 :   NS_PRECONDITION(!GetPrevInFlow(),
     772                 :                   "should only be called on first-in-flow");
     773               0 :   if (mBits.mResizedColumns)
     774               0 :     return; // already marked
     775                 : 
     776               0 :   for (nsTableFrame *f = this; f;
     777               0 :        f = static_cast<nsTableFrame*>(f->GetNextInFlow()))
     778               0 :     f->mBits.mResizedColumns = true;
     779                 : }
     780                 : 
     781                 : void
     782               0 : nsTableFrame::AppendCell(nsTableCellFrame& aCellFrame,
     783                 :                          PRInt32           aRowIndex)
     784                 : {
     785               0 :   nsTableCellMap* cellMap = GetCellMap();
     786               0 :   if (cellMap) {
     787               0 :     nsIntRect damageArea(0,0,0,0);
     788               0 :     cellMap->AppendCell(aCellFrame, aRowIndex, true, damageArea);
     789               0 :     MatchCellMapToColCache(cellMap);
     790               0 :     if (IsBorderCollapse()) {
     791               0 :       AddBCDamageArea(damageArea);
     792                 :     }
     793                 :   }
     794               0 : }
     795                 : 
     796               0 : void nsTableFrame::InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames,
     797                 :                                PRInt32                      aRowIndex,
     798                 :                                PRInt32                      aColIndexBefore)
     799                 : {
     800               0 :   nsTableCellMap* cellMap = GetCellMap();
     801               0 :   if (cellMap) {
     802               0 :     nsIntRect damageArea(0,0,0,0);
     803               0 :     cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore, damageArea);
     804               0 :     MatchCellMapToColCache(cellMap);
     805               0 :     if (IsBorderCollapse()) {
     806               0 :       AddBCDamageArea(damageArea);
     807                 :     }
     808                 :   }
     809               0 : }
     810                 : 
     811                 : // this removes the frames from the col group and table, but not the cell map
     812                 : PRInt32
     813               0 : nsTableFrame::DestroyAnonymousColFrames(PRInt32 aNumFrames)
     814                 : {
     815                 :   // only remove cols that are of type eTypeAnonymous cell (they are at the end)
     816               0 :   PRInt32 endIndex   = mColFrames.Length() - 1;
     817               0 :   PRInt32 startIndex = (endIndex - aNumFrames) + 1;
     818               0 :   PRInt32 numColsRemoved = 0;
     819               0 :   for (PRInt32 colX = endIndex; colX >= startIndex; colX--) {
     820               0 :     nsTableColFrame* colFrame = GetColFrame(colX);
     821               0 :     if (colFrame && (eColAnonymousCell == colFrame->GetColType())) {
     822                 :       nsTableColGroupFrame* cgFrame =
     823               0 :         static_cast<nsTableColGroupFrame*>(colFrame->GetParent());
     824                 :       // remove the frame from the colgroup
     825               0 :       cgFrame->RemoveChild(*colFrame, false);
     826                 :       // remove the frame from the cache, but not the cell map
     827               0 :       RemoveCol(nsnull, colX, true, false);
     828               0 :       numColsRemoved++;
     829                 :     }
     830                 :     else {
     831               0 :       break;
     832                 :     }
     833                 :   }
     834               0 :   return (aNumFrames - numColsRemoved);
     835                 : }
     836                 : 
     837               0 : void nsTableFrame::RemoveCell(nsTableCellFrame* aCellFrame,
     838                 :                               PRInt32           aRowIndex)
     839                 : {
     840               0 :   nsTableCellMap* cellMap = GetCellMap();
     841               0 :   if (cellMap) {
     842               0 :     nsIntRect damageArea(0,0,0,0);
     843               0 :     cellMap->RemoveCell(aCellFrame, aRowIndex, damageArea);
     844               0 :     MatchCellMapToColCache(cellMap);
     845               0 :     if (IsBorderCollapse()) {
     846               0 :       AddBCDamageArea(damageArea);
     847                 :     }
     848                 :   }
     849               0 : }
     850                 : 
     851                 : PRInt32
     852               0 : nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame* aRowGroupFrame)
     853                 : {
     854               0 :   RowGroupArray orderedRowGroups;
     855               0 :   OrderRowGroups(orderedRowGroups);
     856                 : 
     857               0 :   PRInt32 rowIndex = 0;
     858               0 :   for (PRUint32 rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
     859               0 :     nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex];
     860               0 :     if (rgFrame == aRowGroupFrame) {
     861               0 :       break;
     862                 :     }
     863               0 :     PRInt32 numRows = rgFrame->GetRowCount();
     864               0 :     rowIndex += numRows;
     865                 :   }
     866               0 :   return rowIndex;
     867                 : }
     868                 : 
     869                 : // this cannot extend beyond a single row group
     870               0 : void nsTableFrame::AppendRows(nsTableRowGroupFrame*       aRowGroupFrame,
     871                 :                               PRInt32                     aRowIndex,
     872                 :                               nsTArray<nsTableRowFrame*>& aRowFrames)
     873                 : {
     874               0 :   nsTableCellMap* cellMap = GetCellMap();
     875               0 :   if (cellMap) {
     876               0 :     PRInt32 absRowIndex = GetStartRowIndex(aRowGroupFrame) + aRowIndex;
     877               0 :     InsertRows(aRowGroupFrame, aRowFrames, absRowIndex, true);
     878                 :   }
     879               0 : }
     880                 : 
     881                 : // this cannot extend beyond a single row group
     882                 : PRInt32
     883               0 : nsTableFrame::InsertRows(nsTableRowGroupFrame*       aRowGroupFrame,
     884                 :                          nsTArray<nsTableRowFrame*>& aRowFrames,
     885                 :                          PRInt32                     aRowIndex,
     886                 :                          bool                        aConsiderSpans)
     887                 : {
     888                 : #ifdef DEBUG_TABLE_CELLMAP
     889                 :   printf("=== insertRowsBefore firstRow=%d \n", aRowIndex);
     890                 :   Dump(true, false, true);
     891                 : #endif
     892                 : 
     893               0 :   PRInt32 numColsToAdd = 0;
     894               0 :   nsTableCellMap* cellMap = GetCellMap();
     895               0 :   if (cellMap) {
     896               0 :     nsIntRect damageArea(0,0,0,0);
     897               0 :     PRInt32 origNumRows = cellMap->GetRowCount();
     898               0 :     PRInt32 numNewRows = aRowFrames.Length();
     899               0 :     cellMap->InsertRows(aRowGroupFrame, aRowFrames, aRowIndex, aConsiderSpans, damageArea);
     900               0 :     MatchCellMapToColCache(cellMap);
     901               0 :     if (aRowIndex < origNumRows) {
     902               0 :       AdjustRowIndices(aRowIndex, numNewRows);
     903                 :     }
     904                 :     // assign the correct row indices to the new rows. If they were adjusted above
     905                 :     // it may not have been done correctly because each row is constructed with index 0
     906               0 :     for (PRInt32 rowY = 0; rowY < numNewRows; rowY++) {
     907               0 :       nsTableRowFrame* rowFrame = aRowFrames.ElementAt(rowY);
     908               0 :       rowFrame->SetRowIndex(aRowIndex + rowY);
     909                 :     }
     910               0 :     if (IsBorderCollapse()) {
     911               0 :       AddBCDamageArea(damageArea);
     912                 :     }
     913                 :   }
     914                 : #ifdef DEBUG_TABLE_CELLMAP
     915                 :   printf("=== insertRowsAfter \n");
     916                 :   Dump(true, false, true);
     917                 : #endif
     918                 : 
     919               0 :   return numColsToAdd;
     920                 : }
     921                 : 
     922                 : // this cannot extend beyond a single row group
     923               0 : void nsTableFrame::RemoveRows(nsTableRowFrame& aFirstRowFrame,
     924                 :                               PRInt32          aNumRowsToRemove,
     925                 :                               bool             aConsiderSpans)
     926                 : {
     927                 : #ifdef TBD_OPTIMIZATION
     928                 :   // decide if we need to rebalance. we have to do this here because the row group
     929                 :   // cannot do it when it gets the dirty reflow corresponding to the frame being destroyed
     930                 :   bool stopTelling = false;
     931                 :   for (nsIFrame* kidFrame = aFirstFrame.FirstChild(); (kidFrame && !stopAsking);
     932                 :        kidFrame = kidFrame->GetNextSibling()) {
     933                 :     nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
     934                 :     if (cellFrame) {
     935                 :       stopTelling = tableFrame->CellChangedWidth(*cellFrame, cellFrame->GetPass1MaxElementWidth(),
     936                 :                                                  cellFrame->GetMaximumWidth(), true);
     937                 :     }
     938                 :   }
     939                 :   // XXX need to consider what happens if there are cells that have rowspans
     940                 :   // into the deleted row. Need to consider moving rows if a rebalance doesn't happen
     941                 : #endif
     942                 : 
     943               0 :   PRInt32 firstRowIndex = aFirstRowFrame.GetRowIndex();
     944                 : #ifdef DEBUG_TABLE_CELLMAP
     945                 :   printf("=== removeRowsBefore firstRow=%d numRows=%d\n", firstRowIndex, aNumRowsToRemove);
     946                 :   Dump(true, false, true);
     947                 : #endif
     948               0 :   nsTableCellMap* cellMap = GetCellMap();
     949               0 :   if (cellMap) {
     950               0 :     nsIntRect damageArea(0,0,0,0);
     951               0 :     cellMap->RemoveRows(firstRowIndex, aNumRowsToRemove, aConsiderSpans, damageArea);
     952               0 :     MatchCellMapToColCache(cellMap);
     953               0 :     if (IsBorderCollapse()) {
     954               0 :       AddBCDamageArea(damageArea);
     955                 :     }
     956                 :   }
     957               0 :   AdjustRowIndices(firstRowIndex, -aNumRowsToRemove);
     958                 : #ifdef DEBUG_TABLE_CELLMAP
     959                 :   printf("=== removeRowsAfter\n");
     960                 :   Dump(true, true, true);
     961                 : #endif
     962               0 : }
     963                 : 
     964                 : // collect the rows ancestors of aFrame
     965                 : PRInt32
     966               0 : nsTableFrame::CollectRows(nsIFrame*                   aFrame,
     967                 :                           nsTArray<nsTableRowFrame*>& aCollection)
     968                 : {
     969               0 :   NS_PRECONDITION(aFrame, "null frame");
     970               0 :   PRInt32 numRows = 0;
     971               0 :   nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
     972               0 :   while (childFrame) {
     973               0 :     aCollection.AppendElement(static_cast<nsTableRowFrame*>(childFrame));
     974               0 :     numRows++;
     975               0 :     childFrame = childFrame->GetNextSibling();
     976                 :   }
     977               0 :   return numRows;
     978                 : }
     979                 : 
     980                 : void
     981               0 : nsTableFrame::InsertRowGroups(const nsFrameList::Slice& aRowGroups)
     982                 : {
     983                 : #ifdef DEBUG_TABLE_CELLMAP
     984                 :   printf("=== insertRowGroupsBefore\n");
     985                 :   Dump(true, false, true);
     986                 : #endif
     987               0 :   nsTableCellMap* cellMap = GetCellMap();
     988               0 :   if (cellMap) {
     989               0 :     RowGroupArray orderedRowGroups;
     990               0 :     OrderRowGroups(orderedRowGroups);
     991                 : 
     992               0 :     nsAutoTArray<nsTableRowFrame*, 8> rows;
     993                 :     // Loop over the rowgroups and check if some of them are new, if they are
     994                 :     // insert cellmaps in the order that is predefined by OrderRowGroups,
     995                 :     // XXXbz this code is O(N*M) where N is number of new rowgroups
     996                 :     // and M is number of rowgroups we have!
     997                 :     PRUint32 rgIndex;
     998               0 :     for (rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
     999               0 :       for (nsFrameList::Enumerator rowgroups(aRowGroups); !rowgroups.AtEnd();
    1000               0 :            rowgroups.Next()) {
    1001               0 :         if (orderedRowGroups[rgIndex] == rowgroups.get()) {
    1002                 :           nsTableRowGroupFrame* priorRG =
    1003               0 :             (0 == rgIndex) ? nsnull : orderedRowGroups[rgIndex - 1];
    1004                 :           // create and add the cell map for the row group
    1005               0 :           cellMap->InsertGroupCellMap(orderedRowGroups[rgIndex], priorRG);
    1006                 : 
    1007               0 :           break;
    1008                 :         }
    1009                 :       }
    1010                 :     }
    1011               0 :     cellMap->Synchronize(this);
    1012               0 :     ResetRowIndices(aRowGroups);
    1013                 : 
    1014                 :     //now that the cellmaps are reordered too insert the rows
    1015               0 :     for (rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
    1016               0 :       for (nsFrameList::Enumerator rowgroups(aRowGroups); !rowgroups.AtEnd();
    1017               0 :            rowgroups.Next()) {
    1018               0 :         if (orderedRowGroups[rgIndex] == rowgroups.get()) {
    1019                 :           nsTableRowGroupFrame* priorRG =
    1020               0 :             (0 == rgIndex) ? nsnull : orderedRowGroups[rgIndex - 1];
    1021                 :           // collect the new row frames in an array and add them to the table
    1022               0 :           PRInt32 numRows = CollectRows(rowgroups.get(), rows);
    1023               0 :           if (numRows > 0) {
    1024               0 :             PRInt32 rowIndex = 0;
    1025               0 :             if (priorRG) {
    1026               0 :               PRInt32 priorNumRows = priorRG->GetRowCount();
    1027               0 :               rowIndex = priorRG->GetStartRowIndex() + priorNumRows;
    1028                 :             }
    1029               0 :             InsertRows(orderedRowGroups[rgIndex], rows, rowIndex, true);
    1030               0 :             rows.Clear();
    1031                 :           }
    1032               0 :           break;
    1033                 :         }
    1034                 :       }
    1035                 :     }
    1036                 : 
    1037                 :   }
    1038                 : #ifdef DEBUG_TABLE_CELLMAP
    1039                 :   printf("=== insertRowGroupsAfter\n");
    1040                 :   Dump(true, true, true);
    1041                 : #endif
    1042               0 : }
    1043                 : 
    1044                 : 
    1045                 : /////////////////////////////////////////////////////////////////////////////
    1046                 : // Child frame enumeration
    1047                 : 
    1048                 : const nsFrameList&
    1049               0 : nsTableFrame::GetChildList(ChildListID aListID) const
    1050                 : {
    1051               0 :   if (aListID == kColGroupList) {
    1052               0 :     return mColGroups;
    1053                 :   }
    1054               0 :   return nsContainerFrame::GetChildList(aListID);
    1055                 : }
    1056                 : 
    1057                 : void
    1058               0 : nsTableFrame::GetChildLists(nsTArray<ChildList>* aLists) const
    1059                 : {
    1060               0 :   nsContainerFrame::GetChildLists(aLists);
    1061               0 :   mColGroups.AppendIfNonempty(aLists, kColGroupList);
    1062               0 : }
    1063                 : 
    1064                 : nsRect
    1065               0 : nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder) {
    1066               0 :   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
    1067                 : }
    1068                 : 
    1069                 : bool
    1070               0 : nsDisplayTableItem::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
    1071                 :                                                    nsIFrame* aFrame)
    1072                 : {
    1073               0 :   if (!mPartHasFixedBackground)
    1074               0 :     return false;
    1075                 : 
    1076                 :   // If aFrame is mFrame or an ancestor in this document, and aFrame is
    1077                 :   // not the viewport frame, then moving aFrame will move mFrame
    1078                 :   // relative to the viewport, so our fixed-pos background will change.
    1079                 :   return mFrame == aFrame ||
    1080               0 :     nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame);
    1081                 : }
    1082                 : 
    1083                 : /* static */ void
    1084               0 : nsDisplayTableItem::UpdateForFrameBackground(nsIFrame* aFrame)
    1085                 : {
    1086                 :   nsStyleContext *bgSC;
    1087               0 :   if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC))
    1088               0 :     return;
    1089               0 :   if (!bgSC->GetStyleBackground()->HasFixedBackground())
    1090               0 :     return;
    1091                 : 
    1092               0 :   mPartHasFixedBackground = true;
    1093                 : }
    1094                 : 
    1095                 : class nsDisplayTableBorderBackground : public nsDisplayTableItem {
    1096                 : public:
    1097               0 :   nsDisplayTableBorderBackground(nsDisplayListBuilder* aBuilder,
    1098                 :                                  nsTableFrame* aFrame) :
    1099               0 :     nsDisplayTableItem(aBuilder, aFrame) {
    1100               0 :     MOZ_COUNT_CTOR(nsDisplayTableBorderBackground);
    1101               0 :   }
    1102                 : #ifdef NS_BUILD_REFCNT_LOGGING
    1103               0 :   virtual ~nsDisplayTableBorderBackground() {
    1104               0 :     MOZ_COUNT_DTOR(nsDisplayTableBorderBackground);
    1105               0 :   }
    1106                 : #endif
    1107                 : 
    1108                 :   virtual void Paint(nsDisplayListBuilder* aBuilder,
    1109                 :                      nsRenderingContext* aCtx);
    1110               0 :   NS_DISPLAY_DECL_NAME("TableBorderBackground", TYPE_TABLE_BORDER_BACKGROUND)
    1111                 : };
    1112                 : 
    1113                 : void
    1114               0 : nsDisplayTableBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
    1115                 :                                       nsRenderingContext* aCtx)
    1116                 : {
    1117                 :   static_cast<nsTableFrame*>(mFrame)->
    1118                 :     PaintTableBorderBackground(*aCtx, mVisibleRect,
    1119               0 :                                ToReferenceFrame(),
    1120               0 :                                aBuilder->GetBackgroundPaintFlags());
    1121               0 : }
    1122                 : 
    1123               0 : static PRInt32 GetTablePartRank(nsDisplayItem* aItem)
    1124                 : {
    1125               0 :   nsIAtom* type = aItem->GetUnderlyingFrame()->GetType();
    1126               0 :   if (type == nsGkAtoms::tableFrame)
    1127               0 :     return 0;
    1128               0 :   if (type == nsGkAtoms::tableRowGroupFrame)
    1129               0 :     return 1;
    1130               0 :   if (type == nsGkAtoms::tableRowFrame)
    1131               0 :     return 2;
    1132               0 :   return 3;
    1133                 : }
    1134                 : 
    1135               0 : static bool CompareByTablePartRank(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
    1136                 :                                      void* aClosure)
    1137                 : {
    1138               0 :   return GetTablePartRank(aItem1) <= GetTablePartRank(aItem2);
    1139                 : }
    1140                 : 
    1141                 : /* static */ nsresult
    1142               0 : nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
    1143                 :                                const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
    1144                 : {
    1145                 :   // This is similar to what nsContainerFrame::BuildDisplayListForNonBlockChildren
    1146                 :   // does, except that we allow the children's background and borders to go
    1147                 :   // in our BorderBackground list. This doesn't really affect background
    1148                 :   // painting --- the children won't actually draw their own backgrounds
    1149                 :   // because the nsTableFrame already drew them, unless a child has its own
    1150                 :   // stacking context, in which case the child won't use its passed-in
    1151                 :   // BorderBackground list anyway. It does affect cell borders though; this
    1152                 :   // lets us get cell borders into the nsTableFrame's BorderBackground list.
    1153               0 :   nsIFrame* kid = aFrame->GetFirstPrincipalChild();
    1154               0 :   while (kid) {
    1155               0 :     nsresult rv = aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
    1156               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1157               0 :     kid = kid->GetNextSibling();
    1158                 :   }
    1159               0 :   return NS_OK;
    1160                 : }
    1161                 : 
    1162                 : /* static */ nsresult
    1163               0 : nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
    1164                 :                                       nsFrame* aFrame,
    1165                 :                                       const nsRect& aDirtyRect,
    1166                 :                                       const nsDisplayListSet& aLists,
    1167                 :                                       nsDisplayTableItem* aDisplayItem,
    1168                 :                                       DisplayGenericTablePartTraversal aTraversal)
    1169                 : {
    1170               0 :   nsDisplayList eventsBorderBackground;
    1171                 :   // If we need to sort the event backgrounds, then we'll put descendants'
    1172                 :   // display items into their own set of lists.
    1173               0 :   bool sortEventBackgrounds = aDisplayItem && aBuilder->IsForEventDelivery();
    1174               0 :   nsDisplayListCollection separatedCollection;
    1175               0 :   const nsDisplayListSet* lists = sortEventBackgrounds ? &separatedCollection : &aLists;
    1176                 : 
    1177               0 :   nsAutoPushCurrentTableItem pushTableItem;
    1178               0 :   if (aDisplayItem) {
    1179               0 :     pushTableItem.Push(aBuilder, aDisplayItem);
    1180                 :   }
    1181                 : 
    1182               0 :   if (aFrame->IsVisibleForPainting(aBuilder)) {
    1183               0 :     nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
    1184                 :     // currentItem may be null, when none of the table parts have a
    1185                 :     // background or border
    1186               0 :     if (currentItem) {
    1187               0 :       currentItem->UpdateForFrameBackground(aFrame);
    1188                 :     }
    1189                 : 
    1190                 :     // Paint the outset box-shadows for the table frames
    1191               0 :     bool hasBoxShadow = aFrame->GetStyleBorder()->mBoxShadow != nsnull;
    1192               0 :     if (hasBoxShadow) {
    1193                 :       nsresult rv = lists->BorderBackground()->AppendNewToTop(
    1194               0 :           new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame));
    1195               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1196                 :     }
    1197                 : 
    1198                 :     // Create dedicated background display items per-frame when we're
    1199                 :     // handling events.
    1200                 :     // XXX how to handle collapsed borders?
    1201               0 :     if (aBuilder->IsForEventDelivery()) {
    1202                 :       nsresult rv = lists->BorderBackground()->AppendNewToTop(
    1203               0 :           new (aBuilder) nsDisplayBackground(aBuilder, aFrame));
    1204               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1205                 :     }
    1206                 : 
    1207                 :     // Paint the inset box-shadows for the table frames
    1208               0 :     if (hasBoxShadow) {
    1209                 :       nsresult rv = lists->BorderBackground()->AppendNewToTop(
    1210               0 :           new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame));
    1211               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1212                 :     }
    1213                 :   }
    1214                 : 
    1215               0 :   nsresult rv = aTraversal(aBuilder, aFrame, aDirtyRect, *lists);
    1216               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1217                 : 
    1218               0 :   if (sortEventBackgrounds) {
    1219                 :     // Ensure that the table frame event background goes before the
    1220                 :     // table rowgroups event backgrounds, before the table row event backgrounds,
    1221                 :     // before everything else (cells and their blocks)
    1222               0 :     separatedCollection.BorderBackground()->Sort(aBuilder, CompareByTablePartRank, nsnull);
    1223               0 :     separatedCollection.MoveTo(aLists);
    1224                 :   }
    1225                 : 
    1226               0 :   return aFrame->DisplayOutline(aBuilder, aLists);
    1227                 : }
    1228                 : 
    1229                 : #ifdef DEBUG
    1230                 : static bool
    1231               0 : IsFrameAllowedInTable(nsIAtom* aType)
    1232                 : {
    1233               0 :   return IS_TABLE_CELL(aType) ||
    1234                 :          nsGkAtoms::tableRowFrame == aType ||
    1235                 :          nsGkAtoms::tableRowGroupFrame == aType ||
    1236                 :          nsGkAtoms::scrollFrame == aType ||
    1237                 :          nsGkAtoms::tableFrame == aType ||
    1238                 :          nsGkAtoms::tableColFrame == aType ||
    1239               0 :          nsGkAtoms::tableColGroupFrame == aType;
    1240                 : }
    1241                 : #endif
    1242                 : 
    1243                 : static bool
    1244               0 : AnyTablePartHasBorderOrBackground(nsIFrame* aStart, nsIFrame* aEnd)
    1245                 : {
    1246               0 :   for (nsIFrame* f = aStart; f != aEnd; f = f->GetNextSibling()) {
    1247               0 :     NS_ASSERTION(IsFrameAllowedInTable(f->GetType()), "unexpected frame type");
    1248                 : 
    1249               0 :     if (f->GetStyleVisibility()->IsVisible() &&
    1250               0 :         (!f->GetStyleBackground()->IsTransparent() ||
    1251               0 :          f->GetStyleDisplay()->mAppearance ||
    1252               0 :          f->HasBorder()))
    1253               0 :       return true;
    1254                 : 
    1255               0 :     nsTableCellFrame *cellFrame = do_QueryFrame(f);
    1256               0 :     if (cellFrame)
    1257               0 :       continue;
    1258                 : 
    1259               0 :     if (AnyTablePartHasBorderOrBackground(f->PrincipalChildList().FirstChild(), nsnull))
    1260               0 :       return true;
    1261                 :   }
    1262                 : 
    1263               0 :   return false;
    1264                 : }
    1265                 : 
    1266                 : // table paint code is concerned primarily with borders and bg color
    1267                 : // SEC: TODO: adjust the rect for captions
    1268                 : NS_IMETHODIMP
    1269               0 : nsTableFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1270                 :                                const nsRect&           aDirtyRect,
    1271                 :                                const nsDisplayListSet& aLists)
    1272                 : {
    1273               0 :   DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255));
    1274                 : 
    1275               0 :   nsDisplayTableItem* item = nsnull;
    1276               0 :   if (IsVisibleInSelection(aBuilder)) {
    1277               0 :     if (GetStyleVisibility()->IsVisible()) {
    1278               0 :       nsMargin deflate = GetDeflationForBackground(PresContext());
    1279                 :       // If 'deflate' is (0,0,0,0) then we can paint the table background
    1280                 :       // in its own display item, so do that to take advantage of
    1281                 :       // opacity and visibility optimizations
    1282               0 :       if (deflate == nsMargin(0, 0, 0, 0)) {
    1283               0 :         nsresult rv = DisplayBackgroundUnconditional(aBuilder, aLists, false);
    1284               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1285                 :       }
    1286                 :     }
    1287                 :     
    1288                 :     // This background is created if any of the table parts are visible,
    1289                 :     // or if we're doing event handling (since DisplayGenericTablePart
    1290                 :     // needs the item for the |sortEventBackgrounds|-dependent code).
    1291                 :     // Specific visibility decisions are delegated to the table background
    1292                 :     // painter, which handles borders and backgrounds for the table.
    1293               0 :     if (aBuilder->IsForEventDelivery() ||
    1294               0 :         AnyTablePartHasBorderOrBackground(this, GetNextSibling()) ||
    1295               0 :         AnyTablePartHasBorderOrBackground(mColGroups.FirstChild(), nsnull)) {
    1296               0 :       item = new (aBuilder) nsDisplayTableBorderBackground(aBuilder, this);
    1297               0 :       nsresult rv = aLists.BorderBackground()->AppendNewToTop(item);
    1298               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1299                 :     }
    1300                 :   }
    1301               0 :   return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
    1302                 : }
    1303                 : 
    1304                 : nsMargin
    1305               0 : nsTableFrame::GetDeflationForBackground(nsPresContext* aPresContext) const
    1306                 : {
    1307               0 :   if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode() ||
    1308               0 :       !IsBorderCollapse())
    1309               0 :     return nsMargin(0,0,0,0);
    1310                 : 
    1311               0 :   return GetOuterBCBorder();
    1312                 : }
    1313                 : 
    1314                 : // XXX We don't put the borders and backgrounds in tree order like we should.
    1315                 : // That requires some major surgery which we aren't going to do right now.
    1316                 : void
    1317               0 : nsTableFrame::PaintTableBorderBackground(nsRenderingContext& aRenderingContext,
    1318                 :                                          const nsRect& aDirtyRect,
    1319                 :                                          nsPoint aPt, PRUint32 aBGPaintFlags)
    1320                 : {
    1321               0 :   nsPresContext* presContext = PresContext();
    1322                 : 
    1323                 :   TableBackgroundPainter painter(this, TableBackgroundPainter::eOrigin_Table,
    1324                 :                                  presContext, aRenderingContext,
    1325               0 :                                  aDirtyRect, aPt, aBGPaintFlags);
    1326               0 :   nsMargin deflate = GetDeflationForBackground(presContext);
    1327                 :   // If 'deflate' is (0,0,0,0) then we'll paint the table background
    1328                 :   // in a separate display item, so don't do it here.
    1329               0 :   nsresult rv = painter.PaintTable(this, deflate, deflate != nsMargin(0, 0, 0, 0));
    1330               0 :   if (NS_FAILED(rv)) return;
    1331                 : 
    1332               0 :   if (GetStyleVisibility()->IsVisible()) {
    1333               0 :     if (!IsBorderCollapse()) {
    1334               0 :       PRIntn skipSides = GetSkipSides();
    1335               0 :       nsRect rect(aPt, mRect.Size());
    1336                 :       nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
    1337               0 :                                   aDirtyRect, rect, mStyleContext, skipSides);
    1338                 :     }
    1339                 :     else {
    1340                 :       // XXX we should probably get rid of this translation at some stage
    1341                 :       // But that would mean modifying PaintBCBorders, ugh
    1342               0 :       nsRenderingContext::AutoPushTranslation translate(&aRenderingContext, aPt);
    1343               0 :       PaintBCBorders(aRenderingContext, aDirtyRect - aPt);
    1344                 :     }
    1345                 :   }
    1346                 : }
    1347                 : 
    1348                 : PRIntn
    1349               0 : nsTableFrame::GetSkipSides() const
    1350                 : {
    1351               0 :   PRIntn skip = 0;
    1352                 :   // frame attribute was accounted for in nsHTMLTableElement::MapTableBorderInto
    1353                 :   // account for pagination
    1354               0 :   if (nsnull != GetPrevInFlow()) {
    1355               0 :     skip |= 1 << NS_SIDE_TOP;
    1356                 :   }
    1357               0 :   if (nsnull != GetNextInFlow()) {
    1358               0 :     skip |= 1 << NS_SIDE_BOTTOM;
    1359                 :   }
    1360               0 :   return skip;
    1361                 : }
    1362                 : 
    1363                 : void
    1364               0 : nsTableFrame::SetColumnDimensions(nscoord         aHeight,
    1365                 :                                   const nsMargin& aBorderPadding)
    1366                 : {
    1367               0 :   nscoord cellSpacingX = GetCellSpacingX();
    1368               0 :   nscoord cellSpacingY = GetCellSpacingY();
    1369                 :   nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom +
    1370               0 :                                  2* cellSpacingY;
    1371                 : 
    1372               0 :   nsTableIterator iter(mColGroups);
    1373               0 :   nsIFrame* colGroupFrame = iter.First();
    1374               0 :   bool tableIsLTR = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR;
    1375               0 :   PRInt32 colX =tableIsLTR ? 0 : NS_MAX(0, GetColCount() - 1);
    1376               0 :   PRInt32 tableColIncr = tableIsLTR ? 1 : -1;
    1377                 :   nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX,
    1378               0 :                          aBorderPadding.top + cellSpacingY);
    1379               0 :   while (nsnull != colGroupFrame) {
    1380               0 :     nscoord colGroupWidth = 0;
    1381               0 :     nsTableIterator iterCol(*colGroupFrame);
    1382               0 :     nsIFrame* colFrame = iterCol.First();
    1383               0 :     nsPoint colOrigin(0,0);
    1384               0 :     while (nsnull != colFrame) {
    1385               0 :       if (NS_STYLE_DISPLAY_TABLE_COLUMN ==
    1386               0 :           colFrame->GetStyleDisplay()->mDisplay) {
    1387               0 :         NS_ASSERTION(colX < GetColCount(), "invalid number of columns");
    1388               0 :         nscoord colWidth = GetColumnWidth(colX);
    1389               0 :         nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight);
    1390               0 :         colFrame->SetRect(colRect);
    1391               0 :         colOrigin.x += colWidth + cellSpacingX;
    1392               0 :         colGroupWidth += colWidth + cellSpacingX;
    1393               0 :         colX += tableColIncr;
    1394                 :       }
    1395               0 :       colFrame = iterCol.Next();
    1396                 :     }
    1397               0 :     if (colGroupWidth) {
    1398               0 :       colGroupWidth -= cellSpacingX;
    1399                 :     }
    1400                 : 
    1401               0 :     nsRect colGroupRect(colGroupOrigin.x, colGroupOrigin.y, colGroupWidth, colHeight);
    1402               0 :     colGroupFrame->SetRect(colGroupRect);
    1403               0 :     colGroupFrame = iter.Next();
    1404               0 :     colGroupOrigin.x += colGroupWidth + cellSpacingX;
    1405                 :   }
    1406               0 : }
    1407                 : 
    1408                 : // SEC: TODO need to worry about continuing frames prev/next in flow for splitting across pages.
    1409                 : 
    1410                 : // XXX this could be made more general to handle row modifications that change the
    1411                 : // table height, but first we need to scrutinize every Invalidate
    1412                 : void
    1413               0 : nsTableFrame::ProcessRowInserted(nscoord aNewHeight)
    1414                 : {
    1415               0 :   SetRowInserted(false); // reset the bit that got us here
    1416               0 :   nsTableFrame::RowGroupArray rowGroups;
    1417               0 :   OrderRowGroups(rowGroups);
    1418                 :   // find the row group containing the inserted row
    1419               0 :   for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
    1420               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    1421               0 :     NS_ASSERTION(rgFrame, "Must have rgFrame here");
    1422               0 :     nsIFrame* childFrame = rgFrame->GetFirstPrincipalChild();
    1423                 :     // find the row that was inserted first
    1424               0 :     while (childFrame) {
    1425               0 :       nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
    1426               0 :       if (rowFrame) {
    1427               0 :         if (rowFrame->IsFirstInserted()) {
    1428               0 :           rowFrame->SetFirstInserted(false);
    1429                 :           // damage the table from the 1st row inserted to the end of the table
    1430               0 :           nscoord damageY = rgFrame->GetPosition().y + rowFrame->GetPosition().y;
    1431               0 :           nsRect damageRect(0, damageY, GetSize().width, aNewHeight - damageY);
    1432                 : 
    1433               0 :           Invalidate(damageRect);
    1434                 :           // XXXbz didn't we do this up front?  Why do we need to do it again?
    1435               0 :           SetRowInserted(false);
    1436                 :           return; // found it, so leave
    1437                 :         }
    1438                 :       }
    1439               0 :       childFrame = childFrame->GetNextSibling();
    1440                 :     }
    1441                 :   }
    1442                 : }
    1443                 : 
    1444                 : /* virtual */ void
    1445               0 : nsTableFrame::MarkIntrinsicWidthsDirty()
    1446                 : {
    1447               0 :   nsITableLayoutStrategy* tls = LayoutStrategy();
    1448               0 :   if (NS_UNLIKELY(!tls)) {
    1449                 :     // This is a FrameNeedsReflow() from nsBlockFrame::RemoveFrame()
    1450                 :     // walking up the ancestor chain in a table next-in-flow.  In this case
    1451                 :     // our original first-in-flow (which owns the TableLayoutStrategy) has
    1452                 :     // already been destroyed and unhooked from the flow chain and thusly
    1453                 :     // LayoutStrategy() returns null.  All the frames in the flow will be
    1454                 :     // destroyed so no need to mark anything dirty here.  See bug 595758.
    1455               0 :     return;
    1456                 :   }
    1457               0 :   tls->MarkIntrinsicWidthsDirty();
    1458                 : 
    1459                 :   // XXXldb Call SetBCDamageArea?
    1460                 : 
    1461               0 :   nsContainerFrame::MarkIntrinsicWidthsDirty();
    1462                 : }
    1463                 : 
    1464                 : /* virtual */ nscoord
    1465               0 : nsTableFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
    1466                 : {
    1467               0 :   if (NeedToCalcBCBorders())
    1468               0 :     CalcBCBorders();
    1469                 : 
    1470               0 :   ReflowColGroups(aRenderingContext);
    1471                 : 
    1472               0 :   return LayoutStrategy()->GetMinWidth(aRenderingContext);
    1473                 : }
    1474                 : 
    1475                 : /* virtual */ nscoord
    1476               0 : nsTableFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
    1477                 : {
    1478               0 :   if (NeedToCalcBCBorders())
    1479               0 :     CalcBCBorders();
    1480                 : 
    1481               0 :   ReflowColGroups(aRenderingContext);
    1482                 : 
    1483               0 :   return LayoutStrategy()->GetPrefWidth(aRenderingContext, false);
    1484                 : }
    1485                 : 
    1486                 : /* virtual */ nsIFrame::IntrinsicWidthOffsetData
    1487               0 : nsTableFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
    1488                 : {
    1489                 :   IntrinsicWidthOffsetData result =
    1490               0 :     nsContainerFrame::IntrinsicWidthOffsets(aRenderingContext);
    1491                 : 
    1492               0 :   result.hMargin = 0;
    1493               0 :   result.hPctMargin = 0;
    1494                 : 
    1495               0 :   if (IsBorderCollapse()) {
    1496               0 :     result.hPadding = 0;
    1497               0 :     result.hPctPadding = 0;
    1498                 : 
    1499               0 :     nsMargin outerBC = GetIncludedOuterBCBorder();
    1500               0 :     result.hBorder = outerBC.LeftRight();
    1501                 :   }
    1502                 : 
    1503                 :   return result;
    1504                 : }
    1505                 : 
    1506                 : /* virtual */ nsSize
    1507               0 : nsTableFrame::ComputeSize(nsRenderingContext *aRenderingContext,
    1508                 :                           nsSize aCBSize, nscoord aAvailableWidth,
    1509                 :                           nsSize aMargin, nsSize aBorder, nsSize aPadding,
    1510                 :                           bool aShrinkWrap)
    1511                 : {
    1512                 :   nsSize result =
    1513                 :     nsContainerFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth,
    1514               0 :                                   aMargin, aBorder, aPadding, aShrinkWrap);
    1515                 : 
    1516                 :   // If we're a container for font size inflation, then shrink
    1517                 :   // wrapping inside of us should not apply font size inflation.
    1518               0 :   AutoMaybeNullInflationContainer an(this);
    1519                 : 
    1520                 :   // Tables never shrink below their min width.
    1521               0 :   nscoord minWidth = GetMinWidth(aRenderingContext);
    1522               0 :   if (minWidth > result.width)
    1523               0 :     result.width = minWidth;
    1524                 : 
    1525                 :   return result;
    1526                 : }
    1527                 : 
    1528                 : nscoord
    1529               0 : nsTableFrame::TableShrinkWidthToFit(nsRenderingContext *aRenderingContext,
    1530                 :                                     nscoord aWidthInCB)
    1531                 : {
    1532                 :   // If we're a container for font size inflation, then shrink
    1533                 :   // wrapping inside of us should not apply font size inflation.
    1534               0 :   AutoMaybeNullInflationContainer an(this);
    1535                 : 
    1536                 :   nscoord result;
    1537               0 :   nscoord minWidth = GetMinWidth(aRenderingContext);
    1538               0 :   if (minWidth > aWidthInCB) {
    1539               0 :     result = minWidth;
    1540                 :   } else {
    1541                 :     // Tables shrink width to fit with a slightly different algorithm
    1542                 :     // from the one they use for their intrinsic widths (the difference
    1543                 :     // relates to handling of percentage widths on columns).  So this
    1544                 :     // function differs from nsFrame::ShrinkWidthToFit by only the
    1545                 :     // following line.
    1546                 :     // Since we've already called GetMinWidth, we don't need to do any
    1547                 :     // of the other stuff GetPrefWidth does.
    1548                 :     nscoord prefWidth =
    1549               0 :       LayoutStrategy()->GetPrefWidth(aRenderingContext, true);
    1550               0 :     if (prefWidth > aWidthInCB) {
    1551               0 :       result = aWidthInCB;
    1552                 :     } else {
    1553               0 :       result = prefWidth;
    1554                 :     }
    1555                 :   }
    1556               0 :   return result;
    1557                 : }
    1558                 : 
    1559                 : /* virtual */ nsSize
    1560               0 : nsTableFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
    1561                 :                               nsSize aCBSize, nscoord aAvailableWidth,
    1562                 :                               nsSize aMargin, nsSize aBorder, nsSize aPadding,
    1563                 :                               bool aShrinkWrap)
    1564                 : {
    1565                 :   // Tables always shrink-wrap.
    1566                 :   nscoord cbBased = aAvailableWidth - aMargin.width - aBorder.width -
    1567               0 :                     aPadding.width;
    1568                 :   return nsSize(TableShrinkWidthToFit(aRenderingContext, cbBased),
    1569               0 :                 NS_UNCONSTRAINEDSIZE);
    1570                 : }
    1571                 : 
    1572                 : // Return true if aParentReflowState.frame or any of its ancestors within
    1573                 : // the containing table have non-auto height. (e.g. pct or fixed height)
    1574                 : bool
    1575               0 : nsTableFrame::AncestorsHaveStyleHeight(const nsHTMLReflowState& aParentReflowState)
    1576                 : {
    1577               0 :   for (const nsHTMLReflowState* rs = &aParentReflowState;
    1578                 :        rs && rs->frame; rs = rs->parentReflowState) {
    1579               0 :     nsIAtom* frameType = rs->frame->GetType();
    1580               0 :     if (IS_TABLE_CELL(frameType)                     ||
    1581                 :         (nsGkAtoms::tableRowFrame      == frameType) ||
    1582                 :         (nsGkAtoms::tableRowGroupFrame == frameType)) {
    1583               0 :       const nsStyleCoord &height = rs->mStylePosition->mHeight;
    1584                 :       // calc() treated like 'auto' on internal table elements
    1585               0 :       if (height.GetUnit() != eStyleUnit_Auto && !height.IsCalcUnit()) {
    1586               0 :         return true;
    1587                 :       }
    1588                 :     }
    1589               0 :     else if (nsGkAtoms::tableFrame == frameType) {
    1590                 :       // we reached the containing table, so always return
    1591               0 :       if (rs->mStylePosition->mHeight.GetUnit() != eStyleUnit_Auto) {
    1592               0 :         return true;
    1593                 :       }
    1594               0 :       else return false;
    1595                 :     }
    1596                 :   }
    1597               0 :   return false;
    1598                 : }
    1599                 : 
    1600                 : // See if a special height reflow needs to occur and if so, call RequestSpecialHeightReflow
    1601                 : void
    1602               0 : nsTableFrame::CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
    1603                 : {
    1604               0 :   NS_ASSERTION(IS_TABLE_CELL(aReflowState.frame->GetType()) ||
    1605                 :                aReflowState.frame->GetType() == nsGkAtoms::tableRowFrame ||
    1606                 :                aReflowState.frame->GetType() == nsGkAtoms::tableRowGroupFrame ||
    1607                 :                aReflowState.frame->GetType() == nsGkAtoms::tableFrame,
    1608                 :                "unexpected frame type");
    1609               0 :   if (!aReflowState.frame->GetPrevInFlow() &&  // 1st in flow
    1610               0 :       (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedHeight() ||  // no computed height
    1611               0 :        0                    == aReflowState.ComputedHeight()) &&
    1612               0 :       eStyleUnit_Percent == aReflowState.mStylePosition->mHeight.GetUnit() && // pct height
    1613               0 :       nsTableFrame::AncestorsHaveStyleHeight(*aReflowState.parentReflowState)) {
    1614               0 :     nsTableFrame::RequestSpecialHeightReflow(aReflowState);
    1615                 :   }
    1616               0 : }
    1617                 : 
    1618                 : // Notify the frame and its ancestors (up to the containing table) that a special
    1619                 : // height reflow will occur. During a special height reflow, a table, row group,
    1620                 : // row, or cell returns the last size it was reflowed at. However, the table may
    1621                 : // change the height of row groups, rows, cells in DistributeHeightToRows after.
    1622                 : // And the row group can change the height of rows, cells in CalculateRowHeights.
    1623                 : void
    1624               0 : nsTableFrame::RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
    1625                 : {
    1626                 :   // notify the frame and its ancestors of the special reflow, stopping at the containing table
    1627               0 :   for (const nsHTMLReflowState* rs = &aReflowState; rs && rs->frame; rs = rs->parentReflowState) {
    1628               0 :     nsIAtom* frameType = rs->frame->GetType();
    1629               0 :     NS_ASSERTION(IS_TABLE_CELL(frameType) ||
    1630                 :                  nsGkAtoms::tableRowFrame == frameType ||
    1631                 :                  nsGkAtoms::tableRowGroupFrame == frameType ||
    1632                 :                  nsGkAtoms::tableFrame == frameType,
    1633                 :                  "unexpected frame type");
    1634                 : 
    1635               0 :     rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
    1636               0 :     if (nsGkAtoms::tableFrame == frameType) {
    1637               0 :       NS_ASSERTION(rs != &aReflowState,
    1638                 :                    "should not request special height reflow for table");
    1639                 :       // always stop when we reach a table
    1640               0 :       break;
    1641                 :     }
    1642                 :   }
    1643               0 : }
    1644                 : 
    1645                 : /******************************************************************************************
    1646                 :  * Before reflow, intrinsic width calculation is done using GetMinWidth
    1647                 :  * and GetPrefWidth.  This used to be known as pass 1 reflow.
    1648                 :  *
    1649                 :  * After the intrinsic width calculation, the table determines the
    1650                 :  * column widths using BalanceColumnWidths() and
    1651                 :  * then reflows each child again with a constrained avail width. This reflow is referred to
    1652                 :  * as the pass 2 reflow.
    1653                 :  *
    1654                 :  * A special height reflow (pass 3 reflow) can occur during an initial or resize reflow
    1655                 :  * if (a) a row group, row, cell, or a frame inside a cell has a percent height but no computed
    1656                 :  * height or (b) in paginated mode, a table has a height. (a) supports percent nested tables
    1657                 :  * contained inside cells whose heights aren't known until after the pass 2 reflow. (b) is
    1658                 :  * necessary because the table cannot split until after the pass 2 reflow. The mechanics of
    1659                 :  * the special height reflow (variety a) are as follows:
    1660                 :  *
    1661                 :  * 1) Each table related frame (table, row group, row, cell) implements NeedsSpecialReflow()
    1662                 :  *    to indicate that it should get the reflow. It does this when it has a percent height but
    1663                 :  *    no computed height by calling CheckRequestSpecialHeightReflow(). This method calls
    1664                 :  *    RequestSpecialHeightReflow() which calls SetNeedSpecialReflow() on its ancestors until
    1665                 :  *    it reaches the containing table and calls SetNeedToInitiateSpecialReflow() on it. For
    1666                 :  *    percent height frames inside cells, during DidReflow(), the cell's NotifyPercentHeight()
    1667                 :  *    is called (the cell is the reflow state's mPercentHeightObserver in this case).
    1668                 :  *    NotifyPercentHeight() calls RequestSpecialHeightReflow().
    1669                 :  *
    1670                 :  * 2) After the pass 2 reflow, if the table's NeedToInitiateSpecialReflow(true) was called, it
    1671                 :  *    will do the special height reflow, setting the reflow state's mFlags.mSpecialHeightReflow
    1672                 :  *    to true and mSpecialHeightInitiator to itself. It won't do this if IsPrematureSpecialHeightReflow()
    1673                 :  *    returns true because in that case another special height reflow will be coming along with the
    1674                 :  *    containing table as the mSpecialHeightInitiator. It is only relevant to do the reflow when
    1675                 :  *    the mSpecialHeightInitiator is the containing table, because if it is a remote ancestor, then
    1676                 :  *    appropriate heights will not be known.
    1677                 :  *
    1678                 :  * 3) Since the heights of the table, row groups, rows, and cells was determined during the pass 2
    1679                 :  *    reflow, they return their last desired sizes during the special height reflow. The reflow only
    1680                 :  *    permits percent height frames inside the cells to resize based on the cells height and that height
    1681                 :  *    was determined during the pass 2 reflow.
    1682                 :  *
    1683                 :  * So, in the case of deeply nested tables, all of the tables that were told to initiate a special
    1684                 :  * reflow will do so, but if a table is already in a special reflow, it won't inititate the reflow
    1685                 :  * until the current initiator is its containing table. Since these reflows are only received by
    1686                 :  * frames that need them and they don't cause any rebalancing of tables, the extra overhead is minimal.
    1687                 :  *
    1688                 :  * The type of special reflow that occurs during printing (variety b) follows the same mechanism except
    1689                 :  * that all frames will receive the reflow even if they don't really need them.
    1690                 :  *
    1691                 :  * Open issues with the special height reflow:
    1692                 :  *
    1693                 :  * 1) At some point there should be 2 kinds of special height reflows because (a) and (b) above are
    1694                 :  *    really quite different. This would avoid unnecessary reflows during printing.
    1695                 :  * 2) When a cell contains frames whose percent heights > 100%, there is data loss (see bug 115245).
    1696                 :  *    However, this can also occur if a cell has a fixed height and there is no special height reflow.
    1697                 :  *
    1698                 :  * XXXldb Special height reflow should really be its own method, not
    1699                 :  * part of nsIFrame::Reflow.  It should then call nsIFrame::Reflow on
    1700                 :  * the contents of the cells to do the necessary vertical resizing.
    1701                 :  *
    1702                 :  ******************************************************************************************/
    1703                 : 
    1704                 : /* Layout the entire inner table. */
    1705               0 : NS_METHOD nsTableFrame::Reflow(nsPresContext*           aPresContext,
    1706                 :                                nsHTMLReflowMetrics&     aDesiredSize,
    1707                 :                                const nsHTMLReflowState& aReflowState,
    1708                 :                                nsReflowStatus&          aStatus)
    1709                 : {
    1710               0 :   DO_GLOBAL_REFLOW_COUNT("nsTableFrame");
    1711               0 :   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
    1712               0 :   bool isPaginated = aPresContext->IsPaginated();
    1713                 : 
    1714               0 :   aStatus = NS_FRAME_COMPLETE;
    1715               0 :   if (!GetPrevInFlow() && !mTableLayoutStrategy) {
    1716               0 :     NS_ASSERTION(false, "strategy should have been created in Init");
    1717               0 :     return NS_ERROR_NULL_POINTER;
    1718                 :   }
    1719               0 :   nsresult rv = NS_OK;
    1720                 : 
    1721                 :   // see if collapsing borders need to be calculated
    1722               0 :   if (!GetPrevInFlow() && IsBorderCollapse() && NeedToCalcBCBorders()) {
    1723               0 :     CalcBCBorders();
    1724                 :   }
    1725                 : 
    1726               0 :   aDesiredSize.width = aReflowState.availableWidth;
    1727                 : 
    1728                 :   // Check for an overflow list, and append any row group frames being pushed
    1729               0 :   MoveOverflowToChildList(aPresContext);
    1730                 : 
    1731               0 :   bool haveDesiredHeight = false;
    1732               0 :   SetHaveReflowedColGroups(false);
    1733                 : 
    1734                 :   // Reflow the entire table (pass 2 and possibly pass 3). This phase is necessary during a
    1735                 :   // constrained initial reflow and other reflows which require either a strategy init or balance.
    1736                 :   // This isn't done during an unconstrained reflow, because it will occur later when the parent
    1737                 :   // reflows with a constrained width.
    1738               0 :   if (NS_SUBTREE_DIRTY(this) ||
    1739               0 :       aReflowState.ShouldReflowAllKids() ||
    1740               0 :       IsGeometryDirty() ||
    1741                 :       aReflowState.mFlags.mVResize) {
    1742                 : 
    1743               0 :     if (aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE ||
    1744                 :         // Also check mVResize, to handle the first Reflow preceding a
    1745                 :         // special height Reflow, when we've already had a special height
    1746                 :         // Reflow (where mComputedHeight would not be
    1747                 :         // NS_UNCONSTRAINEDSIZE, but without a style change in between).
    1748                 :         aReflowState.mFlags.mVResize) {
    1749                 :       // XXX Eventually, we should modify DistributeHeightToRows to use
    1750                 :       // nsTableRowFrame::GetHeight instead of nsIFrame::GetSize().height.
    1751                 :       // That way, it will make its calculations based on internal table
    1752                 :       // frame heights as they are before they ever had any extra height
    1753                 :       // distributed to them.  In the meantime, this reflows all the
    1754                 :       // internal table frames, which restores them to their state before
    1755                 :       // DistributeHeightToRows was called.
    1756               0 :       SetGeometryDirty();
    1757                 :     }
    1758                 : 
    1759                 :     bool needToInitiateSpecialReflow =
    1760               0 :       !!(GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
    1761                 :     // see if an extra reflow will be necessary in pagination mode when there is a specified table height
    1762               0 :     if (isPaginated && !GetPrevInFlow() && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
    1763               0 :       nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
    1764               0 :       if ((tableSpecifiedHeight > 0) &&
    1765                 :           (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
    1766               0 :         needToInitiateSpecialReflow = true;
    1767                 :       }
    1768                 :     }
    1769               0 :     nsIFrame* lastChildReflowed = nsnull;
    1770                 : 
    1771               0 :     NS_ASSERTION(!aReflowState.mFlags.mSpecialHeightReflow,
    1772                 :                  "Shouldn't be in special height reflow here!");
    1773                 : 
    1774                 :     // do the pass 2 reflow unless this is a special height reflow and we will be
    1775                 :     // initiating a special height reflow
    1776                 :     // XXXldb I changed this.  Should I change it back?
    1777                 : 
    1778                 :     // if we need to initiate a special height reflow, then don't constrain the
    1779                 :     // height of the reflow before that
    1780                 :     nscoord availHeight = needToInitiateSpecialReflow
    1781               0 :                           ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight;
    1782                 : 
    1783                 :     ReflowTable(aDesiredSize, aReflowState, availHeight,
    1784               0 :                 lastChildReflowed, aStatus);
    1785                 : 
    1786                 :     // reevaluate special height reflow conditions
    1787               0 :     if (GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)
    1788               0 :       needToInitiateSpecialReflow = true;
    1789                 : 
    1790                 :     // XXXldb Are all these conditions correct?
    1791               0 :     if (needToInitiateSpecialReflow && NS_FRAME_IS_COMPLETE(aStatus)) {
    1792                 :       // XXXldb Do we need to set the mVResize flag on any reflow states?
    1793                 : 
    1794                 :       nsHTMLReflowState &mutable_rs =
    1795               0 :         const_cast<nsHTMLReflowState&>(aReflowState);
    1796                 : 
    1797                 :       // distribute extra vertical space to rows
    1798               0 :       CalcDesiredHeight(aReflowState, aDesiredSize);
    1799               0 :       mutable_rs.mFlags.mSpecialHeightReflow = true;
    1800                 : 
    1801                 :       ReflowTable(aDesiredSize, aReflowState, aReflowState.availableHeight,
    1802               0 :                   lastChildReflowed, aStatus);
    1803                 : 
    1804               0 :       if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
    1805                 :         // if there is an incomplete child, then set the desired height to include it but not the next one
    1806               0 :         nsMargin borderPadding = GetChildAreaOffset(&aReflowState);
    1807               0 :         aDesiredSize.height = borderPadding.bottom + GetCellSpacingY() +
    1808               0 :                               lastChildReflowed->GetRect().YMost();
    1809                 :       }
    1810               0 :       haveDesiredHeight = true;
    1811                 : 
    1812               0 :       mutable_rs.mFlags.mSpecialHeightReflow = false;
    1813                 :     }
    1814                 :   }
    1815                 :   else {
    1816                 :     // Calculate the overflow area contribution from our children.
    1817               0 :     for (nsIFrame* kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
    1818               0 :       ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kid);
    1819                 :     }
    1820                 :   }
    1821                 : 
    1822               0 :   aDesiredSize.width = aReflowState.ComputedWidth() +
    1823               0 :                        aReflowState.mComputedBorderPadding.LeftRight();
    1824               0 :   if (!haveDesiredHeight) {
    1825               0 :     CalcDesiredHeight(aReflowState, aDesiredSize);
    1826                 :   }
    1827               0 :   if (IsRowInserted()) {
    1828               0 :     ProcessRowInserted(aDesiredSize.height);
    1829                 :   }
    1830                 : 
    1831               0 :   nsMargin borderPadding = GetChildAreaOffset(&aReflowState);
    1832               0 :   SetColumnDimensions(aDesiredSize.height, borderPadding);
    1833               0 :   if (NeedToCollapse() &&
    1834                 :       (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)) {
    1835               0 :     AdjustForCollapsingRowsCols(aDesiredSize, borderPadding);
    1836                 :   }
    1837                 : 
    1838                 :   // make sure the table overflow area does include the table rect.
    1839               0 :   nsRect tableRect(0, 0, aDesiredSize.width, aDesiredSize.height) ;
    1840                 : 
    1841               0 :   if (!ApplyOverflowClipping(this, aReflowState.mStyleDisplay)) {
    1842                 :     // collapsed border may leak out
    1843               0 :     nsMargin bcMargin = GetExcludedOuterBCBorder();
    1844               0 :     tableRect.Inflate(bcMargin);
    1845                 :   }
    1846               0 :   aDesiredSize.mOverflowAreas.UnionAllWith(tableRect);
    1847                 : 
    1848               0 :   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
    1849                 :     // Fulfill the promise InvalidateFrame makes.
    1850               0 :     Invalidate(aDesiredSize.VisualOverflow());
    1851                 :   } else {
    1852               0 :     CheckInvalidateSizeChange(aDesiredSize);
    1853                 :   }
    1854                 : 
    1855               0 :   FinishAndStoreOverflow(&aDesiredSize);
    1856               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
    1857               0 :   return rv;
    1858                 : }
    1859                 : 
    1860                 : bool
    1861               0 : nsTableFrame::UpdateOverflow()
    1862                 : {
    1863               0 :   nsRect bounds(nsPoint(0, 0), GetSize());
    1864                 : 
    1865                 :   // As above in Reflow, make sure the table overflow area includes the table
    1866                 :   // rect, and check for collapsed borders leaking out.
    1867               0 :   if (!ApplyOverflowClipping(this, GetStyleDisplay())) {
    1868               0 :     nsMargin bcMargin = GetExcludedOuterBCBorder();
    1869               0 :     bounds.Inflate(bcMargin);
    1870                 :   }
    1871                 : 
    1872               0 :   nsOverflowAreas overflowAreas(bounds, bounds);
    1873               0 :   nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
    1874                 : 
    1875               0 :   return FinishAndStoreOverflow(overflowAreas, GetSize());
    1876                 : }
    1877                 : 
    1878                 : nsresult
    1879               0 : nsTableFrame::ReflowTable(nsHTMLReflowMetrics&     aDesiredSize,
    1880                 :                           const nsHTMLReflowState& aReflowState,
    1881                 :                           nscoord                  aAvailHeight,
    1882                 :                           nsIFrame*&               aLastChildReflowed,
    1883                 :                           nsReflowStatus&          aStatus)
    1884                 : {
    1885               0 :   nsresult rv = NS_OK;
    1886               0 :   aLastChildReflowed = nsnull;
    1887                 : 
    1888               0 :   if (!GetPrevInFlow()) {
    1889               0 :     mTableLayoutStrategy->ComputeColumnWidths(aReflowState);
    1890                 :   }
    1891                 :   // Constrain our reflow width to the computed table width (of the 1st in flow).
    1892                 :   // and our reflow height to our avail height minus border, padding, cellspacing
    1893               0 :   aDesiredSize.width = aReflowState.ComputedWidth() +
    1894               0 :                        aReflowState.mComputedBorderPadding.LeftRight();
    1895               0 :   nsTableReflowState reflowState(*PresContext(), aReflowState, *this,
    1896               0 :                                  aDesiredSize.width, aAvailHeight);
    1897                 :   ReflowChildren(reflowState, aStatus, aLastChildReflowed,
    1898               0 :                  aDesiredSize.mOverflowAreas);
    1899                 : 
    1900               0 :   ReflowColGroups(aReflowState.rendContext);
    1901               0 :   return rv;
    1902                 : }
    1903                 : 
    1904                 : nsIFrame*
    1905               0 : nsTableFrame::GetFirstBodyRowGroupFrame()
    1906                 : {
    1907               0 :   nsIFrame* headerFrame = nsnull;
    1908               0 :   nsIFrame* footerFrame = nsnull;
    1909                 : 
    1910               0 :   for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) {
    1911               0 :     const nsStyleDisplay* childDisplay = kidFrame->GetStyleDisplay();
    1912                 : 
    1913                 :     // We expect the header and footer row group frames to be first, and we only
    1914                 :     // allow one header and one footer
    1915               0 :     if (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay) {
    1916               0 :       if (headerFrame) {
    1917                 :         // We already have a header frame and so this header frame is treated
    1918                 :         // like an ordinary body row group frame
    1919               0 :         return kidFrame;
    1920                 :       }
    1921               0 :       headerFrame = kidFrame;
    1922                 : 
    1923               0 :     } else if (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay) {
    1924               0 :       if (footerFrame) {
    1925                 :         // We already have a footer frame and so this footer frame is treated
    1926                 :         // like an ordinary body row group frame
    1927               0 :         return kidFrame;
    1928                 :       }
    1929               0 :       footerFrame = kidFrame;
    1930                 : 
    1931               0 :     } else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) {
    1932               0 :       return kidFrame;
    1933                 :     }
    1934                 : 
    1935                 :     // Get the next child
    1936               0 :     kidFrame = kidFrame->GetNextSibling();
    1937                 :   }
    1938                 : 
    1939               0 :   return nsnull;
    1940                 : }
    1941                 : 
    1942                 : // Table specific version that takes into account repeated header and footer
    1943                 : // frames when continuing table frames
    1944                 : void
    1945               0 : nsTableFrame::PushChildren(const RowGroupArray& aRowGroups,
    1946                 :                            PRInt32 aPushFrom)
    1947                 : {
    1948               0 :   NS_PRECONDITION(aPushFrom > 0, "pushing first child");
    1949                 : 
    1950                 :   // extract the frames from the array into a sibling list
    1951               0 :   nsFrameList frames;
    1952                 :   PRUint32 childX;
    1953               0 :   for (childX = aPushFrom; childX < aRowGroups.Length(); ++childX) {
    1954               0 :     nsTableRowGroupFrame* rgFrame = aRowGroups[childX];
    1955               0 :     if (!rgFrame->IsRepeatable()) {
    1956               0 :       mFrames.RemoveFrame(rgFrame);
    1957               0 :       frames.AppendFrame(nsnull, rgFrame);
    1958                 :     }
    1959                 :   }
    1960                 : 
    1961               0 :   if (frames.IsEmpty()) {
    1962                 :     return;
    1963                 :   }
    1964                 : 
    1965               0 :   nsTableFrame* nextInFlow = static_cast<nsTableFrame*>(GetNextInFlow());
    1966               0 :   if (nextInFlow) {
    1967                 :     // Insert the frames after any repeated header and footer frames.
    1968               0 :     nsIFrame* firstBodyFrame = nextInFlow->GetFirstBodyRowGroupFrame();
    1969               0 :     nsIFrame* prevSibling = nsnull;
    1970               0 :     if (firstBodyFrame) {
    1971               0 :       prevSibling = firstBodyFrame->GetPrevSibling();
    1972                 :     }
    1973                 :     // When pushing and pulling frames we need to check for whether any
    1974                 :     // views need to be reparented.
    1975               0 :     ReparentFrameViewList(PresContext(), frames, this, nextInFlow);
    1976                 :     nextInFlow->mFrames.InsertFrames(nextInFlow, prevSibling,
    1977               0 :                                      frames);
    1978                 :   }
    1979                 :   else {
    1980                 :     // Add the frames to our overflow list.
    1981               0 :     SetOverflowFrames(PresContext(), frames);
    1982                 :   }
    1983                 : }
    1984                 : 
    1985                 : // collapsing row groups, rows, col groups and cols are accounted for after both passes of
    1986                 : // reflow so that it has no effect on the calculations of reflow.
    1987                 : void
    1988               0 : nsTableFrame::AdjustForCollapsingRowsCols(nsHTMLReflowMetrics& aDesiredSize,
    1989                 :                                           nsMargin             aBorderPadding)
    1990                 : {
    1991               0 :   nscoord yTotalOffset = 0; // total offset among all rows in all row groups
    1992                 : 
    1993                 :   // reset the bit, it will be set again if row/rowgroup or col/colgroup are
    1994                 :   // collapsed
    1995               0 :   SetNeedToCollapse(false);
    1996                 : 
    1997                 :   // collapse the rows and/or row groups as necessary
    1998                 :   // Get the ordered children
    1999               0 :   RowGroupArray rowGroups;
    2000               0 :   OrderRowGroups(rowGroups);
    2001                 : 
    2002               0 :   nsTableFrame* firstInFlow = static_cast<nsTableFrame*> (GetFirstInFlow());
    2003               0 :   nscoord width = firstInFlow->GetCollapsedWidth(aBorderPadding);
    2004               0 :   nscoord rgWidth = width - 2 * GetCellSpacingX();
    2005               0 :   nsOverflowAreas overflow;
    2006                 :   // Walk the list of children
    2007               0 :   for (PRUint32 childX = 0; childX < rowGroups.Length(); childX++) {
    2008               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[childX];
    2009               0 :     NS_ASSERTION(rgFrame, "Must have row group frame here");
    2010               0 :     yTotalOffset += rgFrame->CollapseRowGroupIfNecessary(yTotalOffset, rgWidth);
    2011               0 :     ConsiderChildOverflow(overflow, rgFrame);
    2012                 :   }
    2013                 : 
    2014               0 :   aDesiredSize.height -= yTotalOffset;
    2015               0 :   aDesiredSize.width   = width;
    2016               0 :   overflow.UnionAllWith(nsRect(0, 0, aDesiredSize.width, aDesiredSize.height));
    2017                 :   FinishAndStoreOverflow(overflow,
    2018               0 :                          nsSize(aDesiredSize.width, aDesiredSize.height));
    2019               0 : }
    2020                 : 
    2021                 : 
    2022                 : nscoord
    2023               0 : nsTableFrame::GetCollapsedWidth(nsMargin aBorderPadding)
    2024                 : {
    2025               0 :   NS_ASSERTION(!GetPrevInFlow(), "GetCollapsedWidth called on next in flow");
    2026               0 :   nscoord cellSpacingX = GetCellSpacingX();
    2027               0 :   nscoord width = cellSpacingX;
    2028               0 :   width += aBorderPadding.left + aBorderPadding.right;
    2029               0 :   for (nsIFrame* groupFrame = mColGroups.FirstChild(); groupFrame;
    2030                 :          groupFrame = groupFrame->GetNextSibling()) {
    2031               0 :     const nsStyleVisibility* groupVis = groupFrame->GetStyleVisibility();
    2032               0 :     bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
    2033               0 :     nsTableColGroupFrame* cgFrame = (nsTableColGroupFrame*)groupFrame;
    2034               0 :     for (nsTableColFrame* colFrame = cgFrame->GetFirstColumn(); colFrame;
    2035                 :          colFrame = colFrame->GetNextCol()) {
    2036               0 :       const nsStyleDisplay* colDisplay = colFrame->GetStyleDisplay();
    2037               0 :       PRInt32 colX = colFrame->GetColIndex();
    2038               0 :       if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) {
    2039               0 :         const nsStyleVisibility* colVis = colFrame->GetStyleVisibility();
    2040               0 :         bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible);
    2041               0 :         PRInt32 colWidth = GetColumnWidth(colX);
    2042               0 :         if (!collapseGroup && !collapseCol) {
    2043               0 :           width += colWidth;
    2044               0 :           if (ColumnHasCellSpacingBefore(colX))
    2045               0 :             width += cellSpacingX;
    2046                 :         }
    2047                 :         else {
    2048               0 :           SetNeedToCollapse(true);
    2049                 :         }
    2050                 :       }
    2051                 :     }
    2052                 :   }
    2053               0 :   return width;
    2054                 : }
    2055                 : 
    2056                 : /* virtual */ void
    2057               0 : nsTableFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
    2058                 : {
    2059               0 :   if (!aOldStyleContext) //avoid this on init
    2060               0 :     return;
    2061                 : 
    2062               0 :   if (IsBorderCollapse() &&
    2063               0 :       BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
    2064               0 :     SetFullBCDamageArea();
    2065                 :   }
    2066                 : 
    2067                 :   //avoid this on init or nextinflow
    2068               0 :   if (!mTableLayoutStrategy || GetPrevInFlow())
    2069               0 :     return;
    2070                 : 
    2071               0 :   bool isAuto = IsAutoLayout();
    2072               0 :   if (isAuto != (LayoutStrategy()->GetType() == nsITableLayoutStrategy::Auto)) {
    2073                 :     nsITableLayoutStrategy* temp;
    2074               0 :     if (isAuto)
    2075               0 :       temp = new BasicTableLayoutStrategy(this);
    2076                 :     else
    2077               0 :       temp = new FixedTableLayoutStrategy(this);
    2078                 : 
    2079               0 :     if (temp) {
    2080               0 :       delete mTableLayoutStrategy;
    2081               0 :       mTableLayoutStrategy = temp;
    2082                 :     }
    2083                 :   }
    2084                 : }
    2085                 : 
    2086                 : 
    2087                 : 
    2088                 : NS_IMETHODIMP
    2089               0 : nsTableFrame::AppendFrames(ChildListID     aListID,
    2090                 :                            nsFrameList&    aFrameList)
    2091                 : {
    2092               0 :   NS_ASSERTION(aListID == kPrincipalList || aListID == kColGroupList,
    2093                 :                "unexpected child list");
    2094                 : 
    2095                 :   // Because we actually have two child lists, one for col group frames and one
    2096                 :   // for everything else, we need to look at each frame individually
    2097                 :   // XXX The frame construction code should be separating out child frames
    2098                 :   // based on the type, bug 343048.
    2099               0 :   while (!aFrameList.IsEmpty()) {
    2100               0 :     nsIFrame* f = aFrameList.FirstChild();
    2101               0 :     aFrameList.RemoveFrame(f);
    2102                 : 
    2103                 :     // See what kind of frame we have
    2104               0 :     const nsStyleDisplay* display = f->GetStyleDisplay();
    2105                 : 
    2106               0 :     if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
    2107                 :       nsTableColGroupFrame* lastColGroup =
    2108               0 :         nsTableColGroupFrame::GetLastRealColGroup(this);
    2109                 :       PRInt32 startColIndex = (lastColGroup)
    2110               0 :         ? lastColGroup->GetStartColumnIndex() + lastColGroup->GetColCount() : 0;
    2111               0 :       mColGroups.InsertFrame(nsnull, lastColGroup, f);
    2112                 :       // Insert the colgroup and its cols into the table
    2113                 :       InsertColGroups(startColIndex,
    2114               0 :                       nsFrameList::Slice(mColGroups, f, f->GetNextSibling()));
    2115               0 :     } else if (IsRowGroup(display->mDisplay)) {
    2116                 :       // Append the new row group frame to the sibling chain
    2117               0 :       mFrames.AppendFrame(nsnull, f);
    2118                 : 
    2119                 :       // insert the row group and its rows into the table
    2120               0 :       InsertRowGroups(nsFrameList::Slice(mFrames, f, nsnull));
    2121                 :     } else {
    2122                 :       // Nothing special to do, just add the frame to our child list
    2123               0 :       NS_NOTREACHED("How did we get here?  Frame construction screwed up");
    2124               0 :       mFrames.AppendFrame(nsnull, f);
    2125                 :     }
    2126                 :   }
    2127                 : 
    2128                 : #ifdef DEBUG_TABLE_CELLMAP
    2129                 :   printf("=== TableFrame::AppendFrames\n");
    2130                 :   Dump(true, true, true);
    2131                 : #endif
    2132               0 :   PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    2133               0 :                                                NS_FRAME_HAS_DIRTY_CHILDREN);
    2134               0 :   SetGeometryDirty();
    2135                 : 
    2136               0 :   return NS_OK;
    2137                 : }
    2138                 : 
    2139                 : NS_IMETHODIMP
    2140               0 : nsTableFrame::InsertFrames(ChildListID     aListID,
    2141                 :                            nsIFrame*       aPrevFrame,
    2142                 :                            nsFrameList&    aFrameList)
    2143                 : {
    2144                 :   // Asssume there's only one frame being inserted. The problem is that
    2145                 :   // row group frames and col group frames go in separate child lists and
    2146                 :   // so if there's more than one type of frames this gets messy...
    2147                 :   // XXX The frame construction code should be separating out child frames
    2148                 :   // based on the type, bug 343048.
    2149                 : 
    2150               0 :   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
    2151                 :                "inserting after sibling frame with different parent");
    2152                 : 
    2153               0 :   if ((aPrevFrame && !aPrevFrame->GetNextSibling()) ||
    2154               0 :       (!aPrevFrame && GetChildList(aListID).IsEmpty())) {
    2155                 :     // Treat this like an append; still a workaround for bug 343048.
    2156               0 :     return AppendFrames(aListID, aFrameList);
    2157                 :   }
    2158                 : 
    2159                 :   // See what kind of frame we have
    2160               0 :   const nsStyleDisplay* display = aFrameList.FirstChild()->GetStyleDisplay();
    2161                 : #ifdef DEBUG
    2162                 :   // verify that all sibling have the same type, if they do not, expect cellmap issues
    2163               0 :   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
    2164               0 :     const nsStyleDisplay* nextDisplay = e.get()->GetStyleDisplay();
    2165               0 :     NS_ASSERTION((display->mDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP) ==
    2166                 :         (nextDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP),
    2167                 :       "heterogenous childlist");
    2168                 :   }
    2169                 : #endif
    2170               0 :   if (aPrevFrame) {
    2171               0 :     const nsStyleDisplay* prevDisplay = aPrevFrame->GetStyleDisplay();
    2172                 :     // Make sure they belong on the same frame list
    2173               0 :     if ((display->mDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP) !=
    2174                 :         (prevDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP)) {
    2175                 :       // the previous frame is not valid, see comment at ::AppendFrames
    2176                 :       // XXXbz Using content indices here means XBL will get screwed
    2177                 :       // over...  Oh, well.
    2178               0 :       nsIFrame* pseudoFrame = aFrameList.FirstChild();
    2179               0 :       nsIContent* parentContent = GetContent();
    2180                 :       nsIContent* content;
    2181               0 :       aPrevFrame = nsnull;
    2182               0 :       while (pseudoFrame  && (parentContent ==
    2183                 :                               (content = pseudoFrame->GetContent()))) {
    2184               0 :         pseudoFrame = pseudoFrame->GetFirstPrincipalChild();
    2185                 :       }
    2186               0 :       nsCOMPtr<nsIContent> container = content->GetParent();
    2187               0 :       if (NS_LIKELY(container)) { // XXX need this null-check, see bug 411823.
    2188               0 :         PRInt32 newIndex = container->IndexOf(content);
    2189                 :         nsIFrame* kidFrame;
    2190                 :         bool isColGroup = (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP ==
    2191               0 :                              display->mDisplay);
    2192                 :         nsTableColGroupFrame* lastColGroup;
    2193               0 :         if (isColGroup) {
    2194               0 :           kidFrame = mColGroups.FirstChild();
    2195               0 :           lastColGroup = nsTableColGroupFrame::GetLastRealColGroup(this);
    2196                 :         }
    2197                 :         else {
    2198               0 :           kidFrame = mFrames.FirstChild();
    2199                 :         }
    2200                 :         // Important: need to start at a value smaller than all valid indices
    2201               0 :         PRInt32 lastIndex = -1;
    2202               0 :         while (kidFrame) {
    2203               0 :           if (isColGroup) {
    2204               0 :             if (kidFrame == lastColGroup) {
    2205               0 :               aPrevFrame = kidFrame; // there is no real colgroup after this one
    2206               0 :               break;
    2207                 :             }
    2208                 :           }
    2209               0 :           pseudoFrame = kidFrame;
    2210               0 :           while (pseudoFrame  && (parentContent ==
    2211                 :                                   (content = pseudoFrame->GetContent()))) {
    2212               0 :             pseudoFrame = pseudoFrame->GetFirstPrincipalChild();
    2213                 :           }
    2214               0 :           PRInt32 index = container->IndexOf(content);
    2215               0 :           if (index > lastIndex && index < newIndex) {
    2216               0 :             lastIndex = index;
    2217               0 :             aPrevFrame = kidFrame;
    2218                 :           }
    2219               0 :           kidFrame = kidFrame->GetNextSibling();
    2220                 :         }
    2221                 :       }
    2222                 :     }
    2223                 :   }
    2224               0 :   if (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == display->mDisplay) {
    2225               0 :     NS_ASSERTION(aListID == kPrincipalList || aListID == kColGroupList,
    2226                 :                  "unexpected child list");
    2227                 :     // Insert the column group frames
    2228                 :     const nsFrameList::Slice& newColgroups =
    2229               0 :       mColGroups.InsertFrames(nsnull, aPrevFrame, aFrameList);
    2230                 :     // find the starting col index for the first new col group
    2231               0 :     PRInt32 startColIndex = 0;
    2232               0 :     if (aPrevFrame) {
    2233                 :       nsTableColGroupFrame* prevColGroup =
    2234                 :         (nsTableColGroupFrame*)GetFrameAtOrBefore(this, aPrevFrame,
    2235               0 :                                                   nsGkAtoms::tableColGroupFrame);
    2236               0 :       if (prevColGroup) {
    2237               0 :         startColIndex = prevColGroup->GetStartColumnIndex() + prevColGroup->GetColCount();
    2238                 :       }
    2239                 :     }
    2240               0 :     InsertColGroups(startColIndex, newColgroups);
    2241               0 :   } else if (IsRowGroup(display->mDisplay)) {
    2242               0 :     NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
    2243                 :     // Insert the frames in the sibling chain
    2244                 :     const nsFrameList::Slice& newRowGroups =
    2245               0 :       mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
    2246                 : 
    2247               0 :     InsertRowGroups(newRowGroups);
    2248                 :   } else {
    2249               0 :     NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
    2250               0 :     NS_NOTREACHED("How did we even get here?");
    2251                 :     // Just insert the frame and don't worry about reflowing it
    2252               0 :     mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
    2253               0 :     return NS_OK;
    2254                 :   }
    2255                 : 
    2256               0 :   PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    2257               0 :                                                NS_FRAME_HAS_DIRTY_CHILDREN);
    2258               0 :   SetGeometryDirty();
    2259                 : #ifdef DEBUG_TABLE_CELLMAP
    2260                 :   printf("=== TableFrame::InsertFrames\n");
    2261                 :   Dump(true, true, true);
    2262                 : #endif
    2263               0 :   return NS_OK;
    2264                 : }
    2265                 : 
    2266                 : NS_IMETHODIMP
    2267               0 : nsTableFrame::RemoveFrame(ChildListID     aListID,
    2268                 :                           nsIFrame*       aOldFrame)
    2269                 : {
    2270               0 :   NS_ASSERTION(aListID == kColGroupList ||
    2271                 :                NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP !=
    2272                 :                  aOldFrame->GetStyleDisplay()->mDisplay,
    2273                 :                "Wrong list name; use kColGroupList iff colgroup");
    2274               0 :   if (aListID == kColGroupList) {
    2275               0 :     nsIFrame* nextColGroupFrame = aOldFrame->GetNextSibling();
    2276               0 :     nsTableColGroupFrame* colGroup = (nsTableColGroupFrame*)aOldFrame;
    2277               0 :     PRInt32 firstColIndex = colGroup->GetStartColumnIndex();
    2278               0 :     PRInt32 lastColIndex  = firstColIndex + colGroup->GetColCount() - 1;
    2279               0 :     mColGroups.DestroyFrame(aOldFrame);
    2280               0 :     nsTableColGroupFrame::ResetColIndices(nextColGroupFrame, firstColIndex);
    2281                 :     // remove the cols from the table
    2282                 :     PRInt32 colX;
    2283               0 :     for (colX = lastColIndex; colX >= firstColIndex; colX--) {
    2284               0 :       nsTableColFrame* colFrame = mColFrames.SafeElementAt(colX);
    2285               0 :       if (colFrame) {
    2286               0 :         RemoveCol(colGroup, colX, true, false);
    2287                 :       }
    2288                 :     }
    2289                 : 
    2290               0 :     PRInt32 numAnonymousColsToAdd = GetColCount() - mColFrames.Length();
    2291               0 :     if (numAnonymousColsToAdd > 0) {
    2292                 :       // this sets the child list, updates the col cache and cell map
    2293               0 :       AppendAnonymousColFrames(numAnonymousColsToAdd);
    2294                 :     }
    2295                 : 
    2296                 :   } else {
    2297               0 :     NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
    2298                 :     nsTableRowGroupFrame* rgFrame =
    2299               0 :       static_cast<nsTableRowGroupFrame*>(aOldFrame);
    2300                 :     // remove the row group from the cell map
    2301               0 :     nsTableCellMap* cellMap = GetCellMap();
    2302               0 :     if (cellMap) {
    2303               0 :       cellMap->RemoveGroupCellMap(rgFrame);
    2304                 :     }
    2305                 : 
    2306                 :     // remove the row group frame from the sibling chain
    2307               0 :     mFrames.DestroyFrame(aOldFrame);
    2308                 : 
    2309                 :     // the removal of a row group changes the cellmap, the columns might change
    2310               0 :     if (cellMap) {
    2311               0 :       cellMap->Synchronize(this);
    2312                 :       // Create an empty slice
    2313               0 :       ResetRowIndices(nsFrameList::Slice(mFrames, nsnull, nsnull));
    2314               0 :       nsIntRect damageArea;
    2315               0 :       cellMap->RebuildConsideringCells(nsnull, nsnull, 0, 0, false, damageArea);
    2316                 : 
    2317               0 :       MatchCellMapToColCache(cellMap);
    2318                 :     }
    2319                 :   }
    2320                 :   // for now, just bail and recalc all of the collapsing borders
    2321                 :   // as the cellmap changes we need to recalc
    2322               0 :   if (IsBorderCollapse()) {
    2323               0 :     SetFullBCDamageArea();
    2324                 :   }
    2325               0 :   PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    2326               0 :                                                NS_FRAME_HAS_DIRTY_CHILDREN);
    2327               0 :   SetGeometryDirty();
    2328                 : #ifdef DEBUG_TABLE_CELLMAP
    2329                 :   printf("=== TableFrame::RemoveFrame\n");
    2330                 :   Dump(true, true, true);
    2331                 : #endif
    2332               0 :   return NS_OK;
    2333                 : }
    2334                 : 
    2335                 : /* virtual */ nsMargin
    2336               0 : nsTableFrame::GetUsedBorder() const
    2337                 : {
    2338               0 :   if (!IsBorderCollapse())
    2339               0 :     return nsContainerFrame::GetUsedBorder();
    2340                 : 
    2341               0 :   return GetIncludedOuterBCBorder();
    2342                 : }
    2343                 : 
    2344                 : /* virtual */ nsMargin
    2345               0 : nsTableFrame::GetUsedPadding() const
    2346                 : {
    2347               0 :   if (!IsBorderCollapse())
    2348               0 :     return nsContainerFrame::GetUsedPadding();
    2349                 : 
    2350               0 :   return nsMargin(0,0,0,0);
    2351                 : }
    2352                 : 
    2353                 : /* virtual */ nsMargin
    2354               0 : nsTableFrame::GetUsedMargin() const
    2355                 : {
    2356                 :   // The margin is inherited to the outer table frame via
    2357                 :   // the ::-moz-table-outer rule in ua.css.
    2358               0 :   return nsMargin(0, 0, 0, 0);
    2359                 : }
    2360                 : 
    2361                 : // Destructor function for BCPropertyData properties
    2362                 : static void
    2363               0 : DestroyBCProperty(void* aPropertyValue)
    2364                 : {
    2365                 :   delete static_cast<BCPropertyData*>(aPropertyValue);
    2366               0 : }
    2367                 : 
    2368               0 : NS_DECLARE_FRAME_PROPERTY(TableBCProperty, DestroyBCProperty)
    2369                 : 
    2370                 : BCPropertyData*
    2371               0 : nsTableFrame::GetBCProperty(bool aCreateIfNecessary) const
    2372                 : {
    2373               0 :   FrameProperties props = Properties();
    2374                 :   BCPropertyData* value = static_cast<BCPropertyData*>
    2375               0 :                           (props.Get(TableBCProperty()));
    2376               0 :   if (!value && aCreateIfNecessary) {
    2377               0 :     value = new BCPropertyData();
    2378               0 :     props.Set(TableBCProperty(), value);
    2379                 :   }
    2380                 : 
    2381               0 :   return value;
    2382                 : }
    2383                 : 
    2384                 : static void
    2385               0 : DivideBCBorderSize(BCPixelSize  aPixelSize,
    2386                 :                    BCPixelSize& aSmallHalf,
    2387                 :                    BCPixelSize& aLargeHalf)
    2388                 : {
    2389               0 :   aSmallHalf = aPixelSize / 2;
    2390               0 :   aLargeHalf = aPixelSize - aSmallHalf;
    2391               0 : }
    2392                 : 
    2393                 : nsMargin
    2394               0 : nsTableFrame::GetOuterBCBorder() const
    2395                 : {
    2396               0 :   if (NeedToCalcBCBorders())
    2397               0 :     const_cast<nsTableFrame*>(this)->CalcBCBorders();
    2398                 : 
    2399               0 :   nsMargin border(0, 0, 0, 0);
    2400               0 :   PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
    2401               0 :   BCPropertyData* propData = GetBCProperty();
    2402               0 :   if (propData) {
    2403               0 :     border.top    = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
    2404               0 :     border.right  = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth);
    2405               0 :     border.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
    2406               0 :     border.left   = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth);
    2407                 :   }
    2408                 :   return border;
    2409                 : }
    2410                 : 
    2411                 : nsMargin
    2412               0 : nsTableFrame::GetIncludedOuterBCBorder() const
    2413                 : {
    2414               0 :   if (NeedToCalcBCBorders())
    2415               0 :     const_cast<nsTableFrame*>(this)->CalcBCBorders();
    2416                 : 
    2417               0 :   nsMargin border(0, 0, 0, 0);
    2418               0 :   PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
    2419               0 :   BCPropertyData* propData = GetBCProperty();
    2420               0 :   if (propData) {
    2421               0 :     border.top += BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
    2422               0 :     border.right += BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightCellBorderWidth);
    2423               0 :     border.bottom += BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
    2424               0 :     border.left += BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftCellBorderWidth);
    2425                 :   }
    2426                 :   return border;
    2427                 : }
    2428                 : 
    2429                 : nsMargin
    2430               0 : nsTableFrame::GetExcludedOuterBCBorder() const
    2431                 : {
    2432               0 :   return GetOuterBCBorder() - GetIncludedOuterBCBorder();
    2433                 : }
    2434                 : 
    2435                 : static
    2436               0 : void GetSeparateModelBorderPadding(const nsHTMLReflowState* aReflowState,
    2437                 :                                    nsStyleContext&          aStyleContext,
    2438                 :                                    nsMargin&                aBorderPadding)
    2439                 : {
    2440                 :   // XXXbz Either we _do_ have a reflow state and then we can use its
    2441                 :   // mComputedBorderPadding or we don't and then we get the padding
    2442                 :   // wrong!
    2443               0 :   const nsStyleBorder* border = aStyleContext.GetStyleBorder();
    2444               0 :   aBorderPadding = border->GetActualBorder();
    2445               0 :   if (aReflowState) {
    2446               0 :     aBorderPadding += aReflowState->mComputedPadding;
    2447                 :   }
    2448               0 : }
    2449                 : 
    2450                 : nsMargin
    2451               0 : nsTableFrame::GetChildAreaOffset(const nsHTMLReflowState* aReflowState) const
    2452                 : {
    2453               0 :   nsMargin offset(0,0,0,0);
    2454               0 :   if (IsBorderCollapse()) {
    2455               0 :     offset = GetIncludedOuterBCBorder();
    2456                 :   }
    2457                 :   else {
    2458               0 :     GetSeparateModelBorderPadding(aReflowState, *mStyleContext, offset);
    2459                 :   }
    2460                 :   return offset;
    2461                 : }
    2462                 : 
    2463                 : void
    2464               0 : nsTableFrame::InitChildReflowState(nsHTMLReflowState& aReflowState)
    2465                 : {
    2466               0 :   nsMargin collapseBorder;
    2467               0 :   nsMargin padding(0,0,0,0);
    2468               0 :   nsMargin* pCollapseBorder = nsnull;
    2469               0 :   nsPresContext* presContext = PresContext();
    2470               0 :   if (IsBorderCollapse()) {
    2471                 :     nsTableRowGroupFrame* rgFrame =
    2472               0 :        static_cast<nsTableRowGroupFrame*>(aReflowState.frame);
    2473               0 :     pCollapseBorder = rgFrame->GetBCBorderWidth(collapseBorder);
    2474                 :   }
    2475               0 :   aReflowState.Init(presContext, -1, -1, pCollapseBorder, &padding);
    2476                 : 
    2477               0 :   NS_ASSERTION(!mBits.mResizedColumns ||
    2478                 :                !aReflowState.parentReflowState->mFlags.mSpecialHeightReflow,
    2479                 :                "should not resize columns on special height reflow");
    2480               0 :   if (mBits.mResizedColumns) {
    2481               0 :     aReflowState.mFlags.mHResize = true;
    2482                 :   }
    2483               0 : }
    2484                 : 
    2485                 : // Position and size aKidFrame and update our reflow state. The origin of
    2486                 : // aKidRect is relative to the upper-left origin of our frame
    2487               0 : void nsTableFrame::PlaceChild(nsTableReflowState&  aReflowState,
    2488                 :                               nsIFrame*            aKidFrame,
    2489                 :                               nsHTMLReflowMetrics& aKidDesiredSize,
    2490                 :                               const nsRect&        aOriginalKidRect,
    2491                 :                               const nsRect&        aOriginalKidVisualOverflow)
    2492                 : {
    2493                 :   bool isFirstReflow =
    2494               0 :     (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
    2495                 : 
    2496                 :   // Place and size the child
    2497                 :   FinishReflowChild(aKidFrame, PresContext(), nsnull, aKidDesiredSize,
    2498               0 :                     aReflowState.x, aReflowState.y, 0);
    2499                 : 
    2500                 :   InvalidateFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow,
    2501               0 :                   isFirstReflow);
    2502                 : 
    2503                 :   // Adjust the running y-offset
    2504               0 :   aReflowState.y += aKidDesiredSize.height;
    2505                 : 
    2506                 :   // If our height is constrained, then update the available height
    2507               0 :   if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
    2508               0 :     aReflowState.availSize.height -= aKidDesiredSize.height;
    2509                 :   }
    2510               0 : }
    2511                 : 
    2512                 : void
    2513               0 : nsTableFrame::OrderRowGroups(RowGroupArray& aChildren,
    2514                 :                              nsTableRowGroupFrame** aHead,
    2515                 :                              nsTableRowGroupFrame** aFoot) const
    2516                 : {
    2517               0 :   aChildren.Clear();
    2518               0 :   nsTableRowGroupFrame* head = nsnull;
    2519               0 :   nsTableRowGroupFrame* foot = nsnull;
    2520                 : 
    2521               0 :   nsIFrame* kidFrame = mFrames.FirstChild();
    2522               0 :   while (kidFrame) {
    2523               0 :     const nsStyleDisplay* kidDisplay = kidFrame->GetStyleDisplay();
    2524                 :     nsTableRowGroupFrame* rowGroup =
    2525               0 :       static_cast<nsTableRowGroupFrame*>(kidFrame);
    2526                 : 
    2527               0 :     switch (kidDisplay->mDisplay) {
    2528                 :     case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
    2529               0 :       if (head) { // treat additional thead like tbody
    2530               0 :         aChildren.AppendElement(rowGroup);
    2531                 :       }
    2532                 :       else {
    2533               0 :         head = rowGroup;
    2534                 :       }
    2535               0 :       break;
    2536                 :     case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
    2537               0 :       if (foot) { // treat additional tfoot like tbody
    2538               0 :         aChildren.AppendElement(rowGroup);
    2539                 :       }
    2540                 :       else {
    2541               0 :         foot = rowGroup;
    2542                 :       }
    2543               0 :       break;
    2544                 :     case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
    2545               0 :       aChildren.AppendElement(rowGroup);
    2546               0 :       break;
    2547                 :     default:
    2548               0 :       NS_NOTREACHED("How did this produce an nsTableRowGroupFrame?");
    2549                 :       // Just ignore it
    2550               0 :       break;
    2551                 :     }
    2552                 :     // Get the next sibling but skip it if it's also the next-in-flow, since
    2553                 :     // a next-in-flow will not be part of the current table.
    2554               0 :     while (kidFrame) {
    2555               0 :       nsIFrame* nif = kidFrame->GetNextInFlow();
    2556               0 :       kidFrame = kidFrame->GetNextSibling();
    2557               0 :       if (kidFrame != nif)
    2558               0 :         break;
    2559                 :     }
    2560                 :   }
    2561                 : 
    2562                 :   // put the thead first
    2563               0 :   if (head) {
    2564               0 :     aChildren.InsertElementAt(0, head);
    2565                 :   }
    2566               0 :   if (aHead)
    2567               0 :     *aHead = head;
    2568                 :   // put the tfoot after the last tbody
    2569               0 :   if (foot) {
    2570               0 :     aChildren.AppendElement(foot);
    2571                 :   }
    2572               0 :   if (aFoot)
    2573               0 :     *aFoot = foot;
    2574               0 : }
    2575                 : 
    2576                 : nsTableRowGroupFrame*
    2577               0 : nsTableFrame::GetTHead() const
    2578                 : {
    2579               0 :   nsIFrame* kidFrame = mFrames.FirstChild();
    2580               0 :   while (kidFrame) {
    2581               0 :     if (kidFrame->GetStyleDisplay()->mDisplay ==
    2582                 :           NS_STYLE_DISPLAY_TABLE_HEADER_GROUP) {
    2583               0 :       return static_cast<nsTableRowGroupFrame*>(kidFrame);
    2584                 :     }
    2585                 : 
    2586                 :     // Get the next sibling but skip it if it's also the next-in-flow, since
    2587                 :     // a next-in-flow will not be part of the current table.
    2588               0 :     while (kidFrame) {
    2589               0 :       nsIFrame* nif = kidFrame->GetNextInFlow();
    2590               0 :       kidFrame = kidFrame->GetNextSibling();
    2591               0 :       if (kidFrame != nif)
    2592               0 :         break;
    2593                 :     }
    2594                 :   }
    2595                 : 
    2596               0 :   return nsnull;
    2597                 : }
    2598                 : 
    2599                 : nsTableRowGroupFrame*
    2600               0 : nsTableFrame::GetTFoot() const
    2601                 : {
    2602               0 :   nsIFrame* kidFrame = mFrames.FirstChild();
    2603               0 :   while (kidFrame) {
    2604               0 :     if (kidFrame->GetStyleDisplay()->mDisplay ==
    2605                 :           NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP) {
    2606               0 :       return static_cast<nsTableRowGroupFrame*>(kidFrame);
    2607                 :     }
    2608                 : 
    2609                 :     // Get the next sibling but skip it if it's also the next-in-flow, since
    2610                 :     // a next-in-flow will not be part of the current table.
    2611               0 :     while (kidFrame) {
    2612               0 :       nsIFrame* nif = kidFrame->GetNextInFlow();
    2613               0 :       kidFrame = kidFrame->GetNextSibling();
    2614               0 :       if (kidFrame != nif)
    2615               0 :         break;
    2616                 :     }
    2617                 :   }
    2618                 : 
    2619               0 :   return nsnull;
    2620                 : }
    2621                 : 
    2622                 : static bool
    2623               0 : IsRepeatable(nscoord aFrameHeight, nscoord aPageHeight)
    2624                 : {
    2625               0 :   return aFrameHeight < (aPageHeight / 4);
    2626                 : }
    2627                 : 
    2628                 : nsresult
    2629               0 : nsTableFrame::SetupHeaderFooterChild(const nsTableReflowState& aReflowState,
    2630                 :                                      nsTableRowGroupFrame* aFrame,
    2631                 :                                      nscoord* aDesiredHeight)
    2632                 : {
    2633               0 :   nsPresContext* presContext = PresContext();
    2634               0 :   nscoord pageHeight = presContext->GetPageSize().height;
    2635                 : 
    2636                 :   // Reflow the child with unconstrainted height
    2637                 :   nsHTMLReflowState kidReflowState(presContext, aReflowState.reflowState,
    2638                 :                                    aFrame,
    2639                 :                                    nsSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE),
    2640               0 :                                    -1, -1, false);
    2641               0 :   InitChildReflowState(kidReflowState);
    2642               0 :   kidReflowState.mFlags.mIsTopOfPage = true;
    2643               0 :   nsHTMLReflowMetrics desiredSize;
    2644               0 :   desiredSize.width = desiredSize.height = 0;
    2645                 :   nsReflowStatus status;
    2646                 :   nsresult rv = ReflowChild(aFrame, presContext, desiredSize, kidReflowState,
    2647               0 :                             aReflowState.x, aReflowState.y, 0, status);
    2648               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2649                 :   // The child will be reflowed again "for real" so no need to place it now
    2650                 : 
    2651               0 :   aFrame->SetRepeatable(IsRepeatable(desiredSize.height, pageHeight));
    2652               0 :   *aDesiredHeight = desiredSize.height;
    2653               0 :   return NS_OK;
    2654                 : }
    2655                 : 
    2656                 : void 
    2657               0 : nsTableFrame::PlaceRepeatedFooter(nsTableReflowState& aReflowState,
    2658                 :                                   nsTableRowGroupFrame *aTfoot,
    2659                 :                                   nscoord aFooterHeight)
    2660                 : {
    2661               0 :   nsPresContext* presContext = PresContext();
    2662               0 :   nsSize kidAvailSize(aReflowState.availSize);
    2663               0 :   kidAvailSize.height = aFooterHeight;
    2664                 :   nsHTMLReflowState footerReflowState(presContext,
    2665                 :                                       aReflowState.reflowState,
    2666                 :                                       aTfoot, kidAvailSize,
    2667               0 :                                       -1, -1, false);
    2668               0 :   InitChildReflowState(footerReflowState);
    2669               0 :   aReflowState.y += GetCellSpacingY();
    2670                 : 
    2671               0 :   nsRect origTfootRect = aTfoot->GetRect();
    2672               0 :   nsRect origTfootVisualOverflow = aTfoot->GetVisualOverflowRect();
    2673                 :           
    2674                 :   nsReflowStatus footerStatus;
    2675               0 :   nsHTMLReflowMetrics desiredSize;
    2676               0 :   desiredSize.width = desiredSize.height = 0;
    2677                 :   ReflowChild(aTfoot, presContext, desiredSize, footerReflowState,
    2678                 :               aReflowState.x, aReflowState.y,
    2679               0 :               NS_FRAME_INVALIDATE_ON_MOVE, footerStatus);
    2680                 :   PlaceChild(aReflowState, aTfoot, desiredSize, origTfootRect,
    2681               0 :              origTfootVisualOverflow);
    2682               0 : }
    2683                 :                     
    2684                 : // Reflow the children based on the avail size and reason in aReflowState
    2685                 : // update aReflowMetrics a aStatus
    2686                 : nsresult
    2687               0 : nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
    2688                 :                              nsReflowStatus&     aStatus,
    2689                 :                              nsIFrame*&          aLastChildReflowed,
    2690                 :                              nsOverflowAreas&    aOverflowAreas)
    2691                 : {
    2692               0 :   aStatus = NS_FRAME_COMPLETE;
    2693               0 :   aLastChildReflowed = nsnull;
    2694                 : 
    2695               0 :   nsIFrame* prevKidFrame = nsnull;
    2696               0 :   nsresult  rv = NS_OK;
    2697               0 :   nscoord   cellSpacingY = GetCellSpacingY();
    2698                 : 
    2699               0 :   nsPresContext* presContext = PresContext();
    2700                 :   // XXXldb Should we be checking constrained height instead?
    2701                 :   // tables are not able to pull back children from its next inflow, so even
    2702                 :   // under paginated contexts tables are should not paginate if they are inside
    2703                 :   // column set
    2704               0 :   bool isPaginated = presContext->IsPaginated() &&
    2705                 :                        NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height &&
    2706               0 :                        aReflowState.reflowState.mFlags.mTableIsSplittable;
    2707                 : 
    2708               0 :   aOverflowAreas.Clear();
    2709                 : 
    2710               0 :   bool reflowAllKids = aReflowState.reflowState.ShouldReflowAllKids() ||
    2711                 :                          mBits.mResizedColumns ||
    2712               0 :                          IsGeometryDirty();
    2713                 : 
    2714               0 :   RowGroupArray rowGroups;
    2715                 :   nsTableRowGroupFrame *thead, *tfoot;
    2716               0 :   OrderRowGroups(rowGroups, &thead, &tfoot);
    2717               0 :   bool pageBreak = false;
    2718               0 :   nscoord footerHeight = 0;
    2719                 : 
    2720                 :   // Determine the repeatablility of headers and footers, and also the desired
    2721                 :   // height of any repeatable footer.
    2722                 :   // The repeatability of headers on continued tables is handled
    2723                 :   // when they are created in nsCSSFrameConstructor::CreateContinuingTableFrame.
    2724                 :   // We handle the repeatability of footers again here because we need to
    2725                 :   // determine the footer's height anyway. We could perhaps optimize by
    2726                 :   // using the footer's prev-in-flow's height instead of reflowing it again,
    2727                 :   // but there's no real need.
    2728               0 :   if (isPaginated) {
    2729               0 :     if (thead && !GetPrevInFlow()) {
    2730                 :       nscoord desiredHeight;
    2731               0 :       rv = SetupHeaderFooterChild(aReflowState, thead, &desiredHeight);
    2732               0 :       if (NS_FAILED(rv))
    2733               0 :         return rv;
    2734                 :     }
    2735               0 :     if (tfoot) {
    2736               0 :       rv = SetupHeaderFooterChild(aReflowState, tfoot, &footerHeight);
    2737               0 :       if (NS_FAILED(rv))
    2738               0 :         return rv;
    2739                 :     }
    2740                 :   }
    2741                 :    // if the child is a tbody in paginated mode reduce the height by a repeated footer
    2742               0 :   bool allowRepeatedFooter = false;
    2743               0 :   for (PRUint32 childX = 0; childX < rowGroups.Length(); childX++) {
    2744               0 :     nsIFrame* kidFrame = rowGroups[childX];
    2745                 :     // Get the frame state bits
    2746                 :     // See if we should only reflow the dirty child frames
    2747               0 :     if (reflowAllKids ||
    2748               0 :         NS_SUBTREE_DIRTY(kidFrame) ||
    2749                 :         (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
    2750               0 :          (isPaginated || (kidFrame->GetStateBits() &
    2751                 :                           NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
    2752               0 :       if (pageBreak) {
    2753               0 :         if (allowRepeatedFooter) {
    2754               0 :           PlaceRepeatedFooter(aReflowState, tfoot, footerHeight);
    2755                 :         }
    2756               0 :         else if (tfoot && tfoot->IsRepeatable()) {
    2757               0 :           tfoot->SetRepeatable(false);
    2758                 :         }
    2759               0 :         PushChildren(rowGroups, childX);
    2760               0 :         aStatus = NS_FRAME_NOT_COMPLETE;
    2761               0 :         break;
    2762                 :       }
    2763                 : 
    2764               0 :       nsSize kidAvailSize(aReflowState.availSize);
    2765               0 :       allowRepeatedFooter = false;
    2766               0 :       if (isPaginated && (NS_UNCONSTRAINEDSIZE != kidAvailSize.height)) {
    2767                 :         nsTableRowGroupFrame* kidRG =
    2768               0 :           static_cast<nsTableRowGroupFrame*>(kidFrame);
    2769               0 :         if (kidRG != thead && kidRG != tfoot && tfoot && tfoot->IsRepeatable()) {
    2770                 :           // the child is a tbody and there is a repeatable footer
    2771               0 :           NS_ASSERTION(tfoot == rowGroups[rowGroups.Length() - 1], "Missing footer!");
    2772               0 :           if (footerHeight + cellSpacingY < kidAvailSize.height) {
    2773               0 :             allowRepeatedFooter = true;
    2774               0 :             kidAvailSize.height -= footerHeight + cellSpacingY;
    2775                 :           }
    2776                 :         }
    2777                 :       }
    2778                 : 
    2779               0 :       nsRect oldKidRect = kidFrame->GetRect();
    2780               0 :       nsRect oldKidVisualOverflow = kidFrame->GetVisualOverflowRect();
    2781                 : 
    2782               0 :       nsHTMLReflowMetrics desiredSize;
    2783               0 :       desiredSize.width = desiredSize.height = 0;
    2784                 : 
    2785                 :       // Reflow the child into the available space
    2786                 :       nsHTMLReflowState kidReflowState(presContext, aReflowState.reflowState,
    2787                 :                                        kidFrame, kidAvailSize,
    2788               0 :                                        -1, -1, false);
    2789               0 :       InitChildReflowState(kidReflowState);
    2790                 : 
    2791                 :       // If this isn't the first row group, and the previous row group has a
    2792                 :       // nonzero YMost, then we can't be at the top of the page.
    2793                 :       // We ignore the head row group in this check, because a head row group
    2794                 :       // may be automatically added at the top of *every* page.  This prevents
    2795                 :       // infinite loops in some circumstances - see bug 344883.
    2796               0 :       if (childX > (thead ? 1 : 0) &&
    2797               0 :           (rowGroups[childX - 1]->GetRect().YMost() > 0)) {
    2798               0 :         kidReflowState.mFlags.mIsTopOfPage = false;
    2799                 :       }
    2800               0 :       aReflowState.y += cellSpacingY;
    2801               0 :       if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
    2802               0 :         aReflowState.availSize.height -= cellSpacingY;
    2803                 :       }
    2804                 :       // record the presence of a next in flow, it might get destroyed so we
    2805                 :       // need to reorder the row group array
    2806               0 :       bool reorder = false;
    2807               0 :       if (kidFrame->GetNextInFlow())
    2808               0 :         reorder = true;
    2809                 : 
    2810                 :       rv = ReflowChild(kidFrame, presContext, desiredSize, kidReflowState,
    2811                 :                        aReflowState.x, aReflowState.y,
    2812               0 :                        NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
    2813                 : 
    2814               0 :       if (reorder) {
    2815                 :         // reorder row groups the reflow may have changed the nextinflows
    2816               0 :         OrderRowGroups(rowGroups, &thead, &tfoot);
    2817               0 :         childX = rowGroups.IndexOf(kidFrame);
    2818               0 :         if (childX == RowGroupArray::NoIndex) {
    2819                 :           // XXXbz can this happen?
    2820               0 :           childX = rowGroups.Length();
    2821                 :         }
    2822                 :       }
    2823                 :       // see if the rowgroup did not fit on this page might be pushed on
    2824                 :       // the next page
    2825               0 :       if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated &&
    2826                 :           (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight) &&
    2827                 :           kidReflowState.availableHeight < desiredSize.height) {
    2828                 :         // if we are on top of the page place with dataloss
    2829               0 :         if (kidReflowState.mFlags.mIsTopOfPage) {
    2830               0 :           if (childX+1 < rowGroups.Length()) {
    2831               0 :             nsIFrame* nextRowGroupFrame = rowGroups[childX + 1];
    2832               0 :             if (nextRowGroupFrame) {
    2833                 :               PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect,
    2834               0 :                          oldKidVisualOverflow);
    2835               0 :               if (allowRepeatedFooter) {
    2836               0 :                 PlaceRepeatedFooter(aReflowState, tfoot, footerHeight);
    2837                 :               }
    2838               0 :               else if (tfoot && tfoot->IsRepeatable()) {
    2839               0 :                 tfoot->SetRepeatable(false);
    2840                 :               }
    2841               0 :               aStatus = NS_FRAME_NOT_COMPLETE;
    2842               0 :               PushChildren(rowGroups, childX + 1);
    2843               0 :               aLastChildReflowed = kidFrame;
    2844                 :               break;
    2845                 :             }
    2846                 :           }
    2847                 :         }
    2848                 :         else { // we are not on top, push this rowgroup onto the next page
    2849               0 :           if (prevKidFrame) { // we had a rowgroup before so push this
    2850               0 :             if (allowRepeatedFooter) {
    2851               0 :               PlaceRepeatedFooter(aReflowState, tfoot, footerHeight);
    2852                 :             }
    2853               0 :             else if (tfoot && tfoot->IsRepeatable()) {
    2854               0 :               tfoot->SetRepeatable(false);
    2855                 :             }
    2856               0 :             aStatus = NS_FRAME_NOT_COMPLETE;
    2857               0 :             PushChildren(rowGroups, childX);
    2858               0 :             aLastChildReflowed = prevKidFrame;
    2859                 :             break;
    2860                 :           }
    2861                 :           else { // we can't push so lets make clear how much space we need
    2862                 :             PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect,
    2863               0 :                                      oldKidVisualOverflow);
    2864               0 :             aLastChildReflowed = kidFrame;
    2865               0 :             if (allowRepeatedFooter) {
    2866               0 :               PlaceRepeatedFooter(aReflowState, tfoot, footerHeight);
    2867               0 :               aLastChildReflowed = tfoot;
    2868                 :             }
    2869                 :             break;
    2870                 :           }
    2871                 :         }
    2872                 :       }
    2873                 : 
    2874               0 :       aLastChildReflowed   = kidFrame;
    2875                 : 
    2876               0 :       pageBreak = false;
    2877                 :       // see if there is a page break after this row group or before the next one
    2878               0 :       if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated &&
    2879                 :           (NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight)) {
    2880                 :         nsIFrame* nextKid =
    2881               0 :           (childX + 1 < rowGroups.Length()) ? rowGroups[childX + 1] : nsnull;
    2882               0 :         pageBreak = PageBreakAfter(kidFrame, nextKid);
    2883                 :       }
    2884                 : 
    2885                 :       // Place the child
    2886                 :       PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect,
    2887               0 :                  oldKidVisualOverflow);
    2888                 : 
    2889                 :       // Remember where we just were in case we end up pushing children
    2890               0 :       prevKidFrame = kidFrame;
    2891                 : 
    2892                 :       // Special handling for incomplete children
    2893               0 :       if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
    2894               0 :         nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    2895               0 :         if (!kidNextInFlow) {
    2896                 :           // The child doesn't have a next-in-flow so create a continuing
    2897                 :           // frame. This hooks the child into the flow
    2898                 :           rv = presContext->PresShell()->FrameConstructor()->
    2899               0 :             CreateContinuingFrame(presContext, kidFrame, this, &kidNextInFlow);
    2900               0 :           if (NS_FAILED(rv)) {
    2901               0 :             aStatus = NS_FRAME_COMPLETE;
    2902                 :             break;
    2903                 :           }
    2904                 : 
    2905                 :           // Insert the continuing frame into the sibling list.
    2906               0 :           mFrames.InsertFrame(nsnull, kidFrame, kidNextInFlow);
    2907                 : 
    2908                 :           // Fall through and update |rowGroups| with the new rowgroup, just as
    2909                 :           // it would have been if we had called OrderRowGroups again.
    2910                 :           // Note that rowGroups doesn't get used again after we PushChildren
    2911                 :           // below, anyway.
    2912                 :         }
    2913                 : 
    2914                 :         // Put the nextinflow so that it will get pushed
    2915                 :         rowGroups.InsertElementAt(childX + 1,
    2916               0 :                            static_cast <nsTableRowGroupFrame*>(kidNextInFlow));
    2917                 : 
    2918                 :         // We've used up all of our available space so push the remaining
    2919                 :         // children to the next-in-flow
    2920               0 :         if (allowRepeatedFooter) {
    2921               0 :           PlaceRepeatedFooter(aReflowState, tfoot, footerHeight);
    2922                 :         }
    2923               0 :         else if (tfoot && tfoot->IsRepeatable()) {
    2924               0 :           tfoot->SetRepeatable(false);
    2925                 :         }
    2926               0 :         nsIFrame* nextSibling = kidFrame->GetNextSibling();
    2927               0 :         if (nsnull != nextSibling) {
    2928               0 :           PushChildren(rowGroups, childX + 1);
    2929                 :         }
    2930                 :         break;
    2931                 :       }
    2932                 :     }
    2933                 :     else { // it isn't being reflowed
    2934               0 :       aReflowState.y += cellSpacingY;
    2935               0 :       nsRect kidRect = kidFrame->GetRect();
    2936               0 :       if (kidRect.y != aReflowState.y) {
    2937                 :         // invalidate the old position
    2938               0 :         kidFrame->InvalidateFrameSubtree();
    2939               0 :         kidRect.y = aReflowState.y;
    2940               0 :         kidFrame->SetRect(kidRect);        // move to the new position
    2941               0 :         RePositionViews(kidFrame);
    2942                 :         // invalidate the new position
    2943               0 :         kidFrame->InvalidateFrameSubtree();
    2944                 :       }
    2945               0 :       aReflowState.y += kidRect.height;
    2946                 : 
    2947                 :       // If our height is constrained then update the available height.
    2948               0 :       if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
    2949               0 :         aReflowState.availSize.height -= cellSpacingY + kidRect.height;
    2950                 :       }
    2951                 :     }
    2952               0 :     ConsiderChildOverflow(aOverflowAreas, kidFrame);
    2953                 :   }
    2954                 : 
    2955                 :   // We've now propagated the column resizes and geometry changes to all
    2956                 :   // the children.
    2957               0 :   mBits.mResizedColumns = false;
    2958               0 :   ClearGeometryDirty();
    2959                 : 
    2960               0 :   return rv;
    2961                 : }
    2962                 : 
    2963                 : void
    2964               0 : nsTableFrame::ReflowColGroups(nsRenderingContext *aRenderingContext)
    2965                 : {
    2966               0 :   if (!GetPrevInFlow() && !HaveReflowedColGroups()) {
    2967               0 :     nsHTMLReflowMetrics kidMet;
    2968               0 :     nsPresContext *presContext = PresContext();
    2969               0 :     for (nsIFrame* kidFrame = mColGroups.FirstChild(); kidFrame;
    2970                 :          kidFrame = kidFrame->GetNextSibling()) {
    2971               0 :       if (NS_SUBTREE_DIRTY(kidFrame)) {
    2972                 :         // The column groups don't care about dimensions or reflow states.
    2973                 :         nsHTMLReflowState kidReflowState(presContext, kidFrame,
    2974               0 :                                        aRenderingContext, nsSize(0,0));
    2975                 :         nsReflowStatus cgStatus;
    2976                 :         ReflowChild(kidFrame, presContext, kidMet, kidReflowState, 0, 0, 0,
    2977               0 :                     cgStatus);
    2978               0 :         FinishReflowChild(kidFrame, presContext, nsnull, kidMet, 0, 0, 0);
    2979                 :       }
    2980                 :     }
    2981               0 :     SetHaveReflowedColGroups(true);
    2982                 :   }
    2983               0 : }
    2984                 : 
    2985                 : void
    2986               0 : nsTableFrame::CalcDesiredHeight(const nsHTMLReflowState& aReflowState, nsHTMLReflowMetrics& aDesiredSize)
    2987                 : {
    2988               0 :   nsTableCellMap* cellMap = GetCellMap();
    2989               0 :   if (!cellMap) {
    2990               0 :     NS_ASSERTION(false, "never ever call me until the cell map is built!");
    2991               0 :     aDesiredSize.height = 0;
    2992               0 :     return;
    2993                 :   }
    2994               0 :   nscoord  cellSpacingY = GetCellSpacingY();
    2995               0 :   nsMargin borderPadding = GetChildAreaOffset(&aReflowState);
    2996                 : 
    2997                 :   // get the natural height based on the last child's (row group) rect
    2998               0 :   RowGroupArray rowGroups;
    2999               0 :   OrderRowGroups(rowGroups);
    3000               0 :   if (rowGroups.IsEmpty()) {
    3001                 :     // tables can be used as rectangular items without content
    3002               0 :     nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
    3003               0 :     if ((NS_UNCONSTRAINEDSIZE != tableSpecifiedHeight) &&
    3004                 :         (tableSpecifiedHeight > 0) &&
    3005               0 :         eCompatibility_NavQuirks != PresContext()->CompatibilityMode()) {
    3006                 :           // empty tables should not have a size in quirks mode
    3007               0 :       aDesiredSize.height = tableSpecifiedHeight;
    3008                 :     }
    3009                 :     else
    3010               0 :       aDesiredSize.height = 0;
    3011                 :     return;
    3012                 :   }
    3013               0 :   PRInt32 rowCount = cellMap->GetRowCount();
    3014               0 :   PRInt32 colCount = cellMap->GetColCount();
    3015               0 :   nscoord desiredHeight = borderPadding.top + borderPadding.bottom;
    3016               0 :   if (rowCount > 0 && colCount > 0) {
    3017               0 :     desiredHeight += cellSpacingY;
    3018               0 :     for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
    3019               0 :       desiredHeight += rowGroups[rgX]->GetSize().height + cellSpacingY;
    3020                 :     }
    3021                 :   }
    3022                 : 
    3023                 :   // see if a specified table height requires dividing additional space to rows
    3024               0 :   if (!GetPrevInFlow()) {
    3025               0 :     nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
    3026               0 :     if ((tableSpecifiedHeight > 0) &&
    3027                 :         (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) &&
    3028                 :         (tableSpecifiedHeight > desiredHeight)) {
    3029                 :       // proportionately distribute the excess height to unconstrained rows in each
    3030                 :       // unconstrained row group.
    3031               0 :       DistributeHeightToRows(aReflowState, tableSpecifiedHeight - desiredHeight);
    3032                 :       // this might have changed the overflow area incorporate the childframe overflow area.
    3033               0 :       for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) {
    3034               0 :         ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
    3035                 :       }
    3036               0 :       desiredHeight = tableSpecifiedHeight;
    3037                 :     }
    3038                 :   }
    3039               0 :   aDesiredSize.height = desiredHeight;
    3040                 : }
    3041                 : 
    3042                 : static
    3043               0 : void ResizeCells(nsTableFrame& aTableFrame)
    3044                 : {
    3045               0 :   nsTableFrame::RowGroupArray rowGroups;
    3046               0 :   aTableFrame.OrderRowGroups(rowGroups);
    3047               0 :   nsHTMLReflowMetrics tableDesiredSize;
    3048               0 :   nsRect tableRect = aTableFrame.GetRect();
    3049               0 :   tableDesiredSize.width = tableRect.width;
    3050               0 :   tableDesiredSize.height = tableRect.height;
    3051               0 :   tableDesiredSize.SetOverflowAreasToDesiredBounds();
    3052                 : 
    3053               0 :   for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
    3054               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    3055                 : 
    3056               0 :     nsRect rowGroupRect = rgFrame->GetRect();
    3057               0 :     nsHTMLReflowMetrics groupDesiredSize;
    3058               0 :     groupDesiredSize.width = rowGroupRect.width;
    3059               0 :     groupDesiredSize.height = rowGroupRect.height;
    3060               0 :     groupDesiredSize.SetOverflowAreasToDesiredBounds();
    3061                 : 
    3062               0 :     nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
    3063               0 :     while (rowFrame) {
    3064               0 :       rowFrame->DidResize();
    3065               0 :       rgFrame->ConsiderChildOverflow(groupDesiredSize.mOverflowAreas, rowFrame);
    3066               0 :       rowFrame = rowFrame->GetNextRow();
    3067                 :     }
    3068               0 :     rgFrame->FinishAndStoreOverflow(&groupDesiredSize);
    3069                 :     tableDesiredSize.mOverflowAreas.UnionWith(groupDesiredSize.mOverflowAreas +
    3070               0 :                                               rgFrame->GetPosition());
    3071                 :   }
    3072               0 :   aTableFrame.FinishAndStoreOverflow(&tableDesiredSize);
    3073               0 : }
    3074                 : 
    3075                 : void
    3076               0 : nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
    3077                 :                                      nscoord                  aAmount)
    3078                 : {
    3079               0 :   nscoord cellSpacingY = GetCellSpacingY();
    3080                 : 
    3081               0 :   nsMargin borderPadding = GetChildAreaOffset(&aReflowState);
    3082                 : 
    3083               0 :   RowGroupArray rowGroups;
    3084               0 :   OrderRowGroups(rowGroups);
    3085                 : 
    3086               0 :   nscoord amountUsed = 0;
    3087                 :   // distribute space to each pct height row whose row group doesn't have a computed
    3088                 :   // height, and base the pct on the table height. If the row group had a computed
    3089                 :   // height, then this was already done in nsTableRowGroupFrame::CalculateRowHeights
    3090               0 :   nscoord pctBasis = aReflowState.ComputedHeight() - (GetCellSpacingY() * (GetRowCount() + 1));
    3091               0 :   nscoord yOriginRG = borderPadding.top + GetCellSpacingY();
    3092               0 :   nscoord yEndRG = yOriginRG;
    3093                 :   PRUint32 rgX;
    3094               0 :   for (rgX = 0; rgX < rowGroups.Length(); rgX++) {
    3095               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    3096               0 :     nscoord amountUsedByRG = 0;
    3097               0 :     nscoord yOriginRow = 0;
    3098               0 :     nsRect rgRect = rgFrame->GetRect();
    3099               0 :     if (!rgFrame->HasStyleHeight()) {
    3100               0 :       nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
    3101               0 :       while (rowFrame) {
    3102               0 :         nsRect rowRect = rowFrame->GetRect();
    3103               0 :         if ((amountUsed < aAmount) && rowFrame->HasPctHeight()) {
    3104               0 :           nscoord pctHeight = rowFrame->GetHeight(pctBasis);
    3105               0 :           nscoord amountForRow = NS_MIN(aAmount - amountUsed, pctHeight - rowRect.height);
    3106               0 :           if (amountForRow > 0) {
    3107               0 :             nsRect oldRowRect = rowRect;
    3108               0 :             rowRect.height += amountForRow;
    3109                 :             // XXXbz we don't need to change rowRect.y to be yOriginRow?
    3110               0 :             rowFrame->SetRect(rowRect);
    3111               0 :             yOriginRow += rowRect.height + cellSpacingY;
    3112               0 :             yEndRG += rowRect.height + cellSpacingY;
    3113               0 :             amountUsed += amountForRow;
    3114               0 :             amountUsedByRG += amountForRow;
    3115                 :             //rowFrame->DidResize();
    3116               0 :             nsTableFrame::RePositionViews(rowFrame);
    3117                 : 
    3118               0 :             rgFrame->InvalidateRectDifference(oldRowRect, rowRect);
    3119                 :           }
    3120                 :         }
    3121                 :         else {
    3122               0 :           if (amountUsed > 0 && yOriginRow != rowRect.y &&
    3123               0 :               !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
    3124               0 :             rowFrame->InvalidateFrameSubtree();
    3125               0 :             rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
    3126               0 :             nsTableFrame::RePositionViews(rowFrame);
    3127               0 :             rowFrame->InvalidateFrameSubtree();
    3128                 :           }
    3129               0 :           yOriginRow += rowRect.height + cellSpacingY;
    3130               0 :           yEndRG += rowRect.height + cellSpacingY;
    3131                 :         }
    3132               0 :         rowFrame = rowFrame->GetNextRow();
    3133                 :       }
    3134               0 :       if (amountUsed > 0) {
    3135               0 :         if (rgRect.y != yOriginRG) {
    3136               0 :           rgFrame->InvalidateFrameSubtree();
    3137                 :         }
    3138                 : 
    3139               0 :         nsRect origRgRect = rgRect;
    3140               0 :         nsRect origRgVisualOverflow = rgFrame->GetVisualOverflowRect();
    3141                 : 
    3142               0 :         rgRect.y = yOriginRG;
    3143               0 :         rgRect.height += amountUsedByRG;
    3144                 : 
    3145               0 :         rgFrame->SetRect(rgRect);
    3146                 : 
    3147                 :         nsTableFrame::InvalidateFrame(rgFrame, origRgRect,
    3148               0 :                                       origRgVisualOverflow, false);
    3149                 :       }
    3150                 :     }
    3151               0 :     else if (amountUsed > 0 && yOriginRG != rgRect.y) {
    3152               0 :       rgFrame->InvalidateFrameSubtree();
    3153               0 :       rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG));
    3154                 :       // Make sure child views are properly positioned
    3155               0 :       nsTableFrame::RePositionViews(rgFrame);
    3156               0 :       rgFrame->InvalidateFrameSubtree();
    3157                 :     }
    3158               0 :     yOriginRG = yEndRG;
    3159                 :   }
    3160                 : 
    3161               0 :   if (amountUsed >= aAmount) {
    3162               0 :     ResizeCells(*this);
    3163                 :     return;
    3164                 :   }
    3165                 : 
    3166                 :   // get the first row without a style height where its row group has an
    3167                 :   // unconstrained height
    3168               0 :   nsTableRowGroupFrame* firstUnStyledRG  = nsnull;
    3169               0 :   nsTableRowFrame*      firstUnStyledRow = nsnull;
    3170               0 :   for (rgX = 0; rgX < rowGroups.Length() && !firstUnStyledRG; rgX++) {
    3171               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    3172               0 :     if (!rgFrame->HasStyleHeight()) {
    3173               0 :       nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
    3174               0 :       while (rowFrame) {
    3175               0 :         if (!rowFrame->HasStyleHeight()) {
    3176               0 :           firstUnStyledRG = rgFrame;
    3177               0 :           firstUnStyledRow = rowFrame;
    3178               0 :           break;
    3179                 :         }
    3180               0 :         rowFrame = rowFrame->GetNextRow();
    3181                 :       }
    3182                 :     }
    3183                 :   }
    3184                 : 
    3185               0 :   nsTableRowFrame* lastEligibleRow = nsnull;
    3186                 :   // Accumulate the correct divisor. This will be the total total height of all
    3187                 :   // unstyled rows inside unstyled row groups, unless there are none, in which
    3188                 :   // case, it will be number of all rows. If the unstyled rows don't have a
    3189                 :   // height, divide the space equally among them.
    3190               0 :   nscoord divisor = 0;
    3191               0 :   PRInt32 eligibleRows = 0;
    3192               0 :   bool expandEmptyRows = false;
    3193                 : 
    3194               0 :   if (!firstUnStyledRow) {
    3195                 :     // there is no unstyled row
    3196               0 :     divisor = GetRowCount();
    3197                 :   }
    3198                 :   else {
    3199               0 :     for (rgX = 0; rgX < rowGroups.Length(); rgX++) {
    3200               0 :       nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    3201               0 :       if (!firstUnStyledRG || !rgFrame->HasStyleHeight()) {
    3202               0 :         nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
    3203               0 :         while (rowFrame) {
    3204               0 :           if (!firstUnStyledRG || !rowFrame->HasStyleHeight()) {
    3205               0 :             NS_ASSERTION(rowFrame->GetSize().height >= 0,
    3206                 :                          "negative row frame height");
    3207               0 :             divisor += rowFrame->GetSize().height;
    3208               0 :             eligibleRows++;
    3209               0 :             lastEligibleRow = rowFrame;
    3210                 :           }
    3211               0 :           rowFrame = rowFrame->GetNextRow();
    3212                 :         }
    3213                 :       }
    3214                 :     }
    3215               0 :     if (divisor <= 0) {
    3216               0 :       if (eligibleRows > 0) {
    3217               0 :         expandEmptyRows = true;
    3218                 :       }
    3219                 :       else {
    3220               0 :         NS_ERROR("invalid divisor");
    3221                 :         return;
    3222                 :       }
    3223                 :     }
    3224                 :   }
    3225                 :   // allocate the extra height to the unstyled row groups and rows
    3226               0 :   nscoord heightToDistribute = aAmount - amountUsed;
    3227               0 :   yOriginRG = borderPadding.top + cellSpacingY;
    3228               0 :   yEndRG = yOriginRG;
    3229               0 :   for (rgX = 0; rgX < rowGroups.Length(); rgX++) {
    3230               0 :     nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    3231               0 :     nscoord amountUsedByRG = 0;
    3232               0 :     nscoord yOriginRow = 0;
    3233               0 :     nsRect rgRect = rgFrame->GetRect();
    3234               0 :     nsRect rgVisualOverflow = rgFrame->GetVisualOverflowRect();
    3235                 :     // see if there is an eligible row group or we distribute to all rows
    3236               0 :     if (!firstUnStyledRG || !rgFrame->HasStyleHeight() || !eligibleRows) {
    3237               0 :       nsTableRowFrame* rowFrame = rgFrame->GetFirstRow();
    3238               0 :       while (rowFrame) {
    3239               0 :         nsRect rowRect = rowFrame->GetRect();
    3240               0 :         nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
    3241                 :         // see if there is an eligible row or we distribute to all rows
    3242               0 :         if (!firstUnStyledRow || !rowFrame->HasStyleHeight() || !eligibleRows) {
    3243                 :           float ratio;
    3244               0 :           if (eligibleRows) {
    3245               0 :             if (!expandEmptyRows) {
    3246                 :               // The amount of additional space each row gets is proportional to
    3247                 :               // its height
    3248               0 :               ratio = float(rowRect.height) / float(divisor);
    3249                 :             } else {
    3250                 :               // empty rows get all the same additional space
    3251               0 :               ratio = 1.0f / float(eligibleRows);
    3252                 :             }
    3253                 :           }
    3254                 :           else {
    3255                 :             // all rows get the same additional space
    3256               0 :             ratio = 1.0f / float(divisor);
    3257                 :           }
    3258                 :           // give rows their additional space, except for the last row which
    3259                 :           // gets the remainder
    3260                 :           nscoord amountForRow = (rowFrame == lastEligibleRow)
    3261               0 :                                  ? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio);
    3262               0 :           amountForRow = NS_MIN(amountForRow, aAmount - amountUsed);
    3263                 : 
    3264               0 :           if (yOriginRow != rowRect.y) {
    3265               0 :             rowFrame->InvalidateFrameSubtree();
    3266                 :           }
    3267                 : 
    3268                 :           // update the row height
    3269                 :           nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width,
    3270               0 :                             rowRect.height + amountForRow);
    3271               0 :           rowFrame->SetRect(newRowRect);
    3272                 : 
    3273               0 :           yOriginRow += newRowRect.height + cellSpacingY;
    3274               0 :           yEndRG += newRowRect.height + cellSpacingY;
    3275                 : 
    3276               0 :           amountUsed += amountForRow;
    3277               0 :           amountUsedByRG += amountForRow;
    3278               0 :           NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
    3279                 :           //rowFrame->DidResize();
    3280               0 :           nsTableFrame::RePositionViews(rowFrame);
    3281                 : 
    3282                 :           nsTableFrame::InvalidateFrame(rowFrame, rowRect, rowVisualOverflow,
    3283               0 :                                         false);
    3284                 :         }
    3285                 :         else {
    3286               0 :           if (amountUsed > 0 && yOriginRow != rowRect.y) {
    3287               0 :             rowFrame->InvalidateFrameSubtree();
    3288               0 :             rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
    3289               0 :             nsTableFrame::RePositionViews(rowFrame);
    3290               0 :             rowFrame->InvalidateFrameSubtree();
    3291                 :           }
    3292               0 :           yOriginRow += rowRect.height + cellSpacingY;
    3293               0 :           yEndRG += rowRect.height + cellSpacingY;
    3294                 :         }
    3295               0 :         rowFrame = rowFrame->GetNextRow();
    3296                 :       }
    3297               0 :       if (amountUsed > 0) {
    3298               0 :         if (rgRect.y != yOriginRG) {
    3299               0 :           rgFrame->InvalidateFrameSubtree();
    3300                 :         }
    3301                 : 
    3302                 :         rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width,
    3303               0 :                                 rgRect.height + amountUsedByRG));
    3304                 : 
    3305                 :         nsTableFrame::InvalidateFrame(rgFrame, rgRect, rgVisualOverflow,
    3306               0 :                                       false);
    3307                 :       }
    3308                 :       // Make sure child views are properly positioned
    3309                 :     }
    3310               0 :     else if (amountUsed > 0 && yOriginRG != rgRect.y) {
    3311               0 :       rgFrame->InvalidateFrameSubtree();
    3312               0 :       rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG));
    3313                 :       // Make sure child views are properly positioned
    3314               0 :       nsTableFrame::RePositionViews(rgFrame);
    3315               0 :       rgFrame->InvalidateFrameSubtree();
    3316                 :     }
    3317               0 :     yOriginRG = yEndRG;
    3318                 :   }
    3319                 : 
    3320               0 :   ResizeCells(*this);
    3321                 : }
    3322                 : 
    3323               0 : PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
    3324                 : {
    3325               0 :   nsTableFrame* firstInFlow = static_cast<nsTableFrame*>(GetFirstInFlow());
    3326               0 :   if (this == firstInFlow) {
    3327               0 :     nsTableColFrame* colFrame = GetColFrame(aColIndex);
    3328               0 :     return colFrame ? colFrame->GetFinalWidth() : 0;
    3329                 :   }
    3330               0 :   return firstInFlow->GetColumnWidth(aColIndex);
    3331                 : }
    3332                 : 
    3333                 : // XXX: could cache this.  But be sure to check style changes if you do!
    3334               0 : nscoord nsTableFrame::GetCellSpacingX()
    3335                 : {
    3336               0 :   if (IsBorderCollapse())
    3337               0 :     return 0;
    3338                 : 
    3339               0 :   return GetStyleTableBorder()->mBorderSpacingX;
    3340                 : }
    3341                 : 
    3342                 : // XXX: could cache this. But be sure to check style changes if you do!
    3343               0 : nscoord nsTableFrame::GetCellSpacingY()
    3344                 : {
    3345               0 :   if (IsBorderCollapse())
    3346               0 :     return 0;
    3347                 : 
    3348               0 :   return GetStyleTableBorder()->mBorderSpacingY;
    3349                 : }
    3350                 : 
    3351                 : 
    3352                 : /* virtual */ nscoord
    3353               0 : nsTableFrame::GetBaseline() const
    3354                 : {
    3355               0 :   nscoord ascent = 0;
    3356               0 :   RowGroupArray orderedRowGroups;
    3357               0 :   OrderRowGroups(orderedRowGroups);
    3358               0 :   nsTableRowFrame* firstRow = nsnull;
    3359               0 :   for (PRUint32 rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
    3360               0 :     nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex];
    3361               0 :     if (rgFrame->GetRowCount()) {
    3362               0 :       firstRow = rgFrame->GetFirstRow();
    3363               0 :       ascent = rgFrame->GetRect().y + firstRow->GetRect().y + firstRow->GetRowBaseline();
    3364               0 :       break;
    3365                 :     }
    3366                 :   }
    3367               0 :   if (!firstRow)
    3368               0 :     ascent = GetRect().height;
    3369               0 :   return ascent;
    3370                 : }
    3371                 : /* ----- global methods ----- */
    3372                 : 
    3373                 : nsIFrame*
    3374               0 : NS_NewTableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    3375                 : {
    3376               0 :   return new (aPresShell) nsTableFrame(aContext);
    3377                 : }
    3378                 : 
    3379               0 : NS_IMPL_FRAMEARENA_HELPERS(nsTableFrame)
    3380                 : 
    3381                 : nsTableFrame*
    3382               0 : nsTableFrame::GetTableFrame(nsIFrame* aFrame)
    3383                 : {
    3384               0 :   for (nsIFrame* ancestor = aFrame->GetParent(); ancestor;
    3385                 :        ancestor = ancestor->GetParent()) {
    3386               0 :     if (nsGkAtoms::tableFrame == ancestor->GetType()) {
    3387               0 :       return static_cast<nsTableFrame*>(ancestor);
    3388                 :     }
    3389                 :   }
    3390               0 :   NS_RUNTIMEABORT("unable to find table parent");
    3391               0 :   return nsnull;
    3392                 : }
    3393                 : 
    3394                 : bool
    3395               0 : nsTableFrame::IsAutoHeight()
    3396                 : {
    3397               0 :   const nsStyleCoord &height = GetStylePosition()->mHeight;
    3398                 :   // Don't consider calc() here like this quirk for percent.
    3399               0 :   return height.GetUnit() == eStyleUnit_Auto ||
    3400               0 :          (height.GetUnit() == eStyleUnit_Percent &&
    3401               0 :           height.GetPercentValue() <= 0.0f);
    3402                 : }
    3403                 : 
    3404                 : nscoord
    3405               0 : nsTableFrame::CalcBorderBoxHeight(const nsHTMLReflowState& aState)
    3406                 : {
    3407               0 :   nscoord height = aState.ComputedHeight();
    3408               0 :   if (NS_AUTOHEIGHT != height) {
    3409               0 :     nsMargin borderPadding = GetChildAreaOffset(&aState);
    3410               0 :     height += borderPadding.top + borderPadding.bottom;
    3411                 :   }
    3412               0 :   height = NS_MAX(0, height);
    3413                 : 
    3414               0 :   return height;
    3415                 : }
    3416                 : 
    3417                 : bool
    3418               0 : nsTableFrame::IsAutoLayout()
    3419                 : {
    3420               0 :   if (GetStyleTable()->mLayoutStrategy == NS_STYLE_TABLE_LAYOUT_AUTO)
    3421               0 :     return true;
    3422                 :   // a fixed-layout inline-table must have a width
    3423                 :   // and tables with 'width: -moz-max-content' must be auto-layout
    3424                 :   // (at least as long as FixedTableLayoutStrategy::GetPrefWidth returns
    3425                 :   // nscoord_MAX)
    3426               0 :   const nsStyleCoord &width = GetStylePosition()->mWidth;
    3427               0 :   return (width.GetUnit() == eStyleUnit_Auto) ||
    3428               0 :          (width.GetUnit() == eStyleUnit_Enumerated &&
    3429               0 :           width.GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT);
    3430                 : }
    3431                 : 
    3432                 : #ifdef DEBUG
    3433                 : NS_IMETHODIMP
    3434               0 : nsTableFrame::GetFrameName(nsAString& aResult) const
    3435                 : {
    3436               0 :   return MakeFrameName(NS_LITERAL_STRING("Table"), aResult);
    3437                 : }
    3438                 : #endif
    3439                 : 
    3440                 : // Find the closet sibling before aPriorChildFrame (including aPriorChildFrame) that
    3441                 : // is of type aChildType
    3442                 : nsIFrame*
    3443               0 : nsTableFrame::GetFrameAtOrBefore(nsIFrame*       aParentFrame,
    3444                 :                                  nsIFrame*       aPriorChildFrame,
    3445                 :                                  nsIAtom*        aChildType)
    3446                 : {
    3447               0 :   nsIFrame* result = nsnull;
    3448               0 :   if (!aPriorChildFrame) {
    3449               0 :     return result;
    3450                 :   }
    3451               0 :   if (aChildType == aPriorChildFrame->GetType()) {
    3452               0 :     return aPriorChildFrame;
    3453                 :   }
    3454                 : 
    3455                 :   // aPriorChildFrame is not of type aChildType, so we need start from
    3456                 :   // the beginnng and find the closest one
    3457               0 :   nsIFrame* lastMatchingFrame = nsnull;
    3458               0 :   nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild();
    3459               0 :   while (childFrame && (childFrame != aPriorChildFrame)) {
    3460               0 :     if (aChildType == childFrame->GetType()) {
    3461               0 :       lastMatchingFrame = childFrame;
    3462                 :     }
    3463               0 :     childFrame = childFrame->GetNextSibling();
    3464                 :   }
    3465               0 :   return lastMatchingFrame;
    3466                 : }
    3467                 : 
    3468                 : #ifdef DEBUG
    3469                 : void
    3470               0 : nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame)
    3471                 : {
    3472               0 :   if (!aKidFrame)
    3473               0 :     return;
    3474                 : 
    3475               0 :   nsIFrame* cFrame = aKidFrame->GetFirstPrincipalChild();
    3476               0 :   while (cFrame) {
    3477               0 :     nsTableRowFrame *rowFrame = do_QueryFrame(cFrame);
    3478               0 :     if (rowFrame) {
    3479               0 :       printf("row(%d)=%p ", rowFrame->GetRowIndex(),
    3480               0 :              static_cast<void*>(rowFrame));
    3481               0 :       nsIFrame* childFrame = cFrame->GetFirstPrincipalChild();
    3482               0 :       while (childFrame) {
    3483               0 :         nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
    3484               0 :         if (cellFrame) {
    3485                 :           PRInt32 colIndex;
    3486               0 :           cellFrame->GetColIndex(colIndex);
    3487               0 :           printf("cell(%d)=%p ", colIndex, static_cast<void*>(childFrame));
    3488                 :         }
    3489               0 :         childFrame = childFrame->GetNextSibling();
    3490                 :       }
    3491               0 :       printf("\n");
    3492                 :     }
    3493                 :     else {
    3494               0 :       DumpRowGroup(rowFrame);
    3495                 :     }
    3496               0 :     cFrame = cFrame->GetNextSibling();
    3497                 :   }
    3498                 : }
    3499                 : 
    3500                 : void
    3501               0 : nsTableFrame::Dump(bool            aDumpRows,
    3502                 :                    bool            aDumpCols,
    3503                 :                    bool            aDumpCellMap)
    3504                 : {
    3505               0 :   printf("***START TABLE DUMP*** \n");
    3506                 :   // dump the columns widths array
    3507               0 :   printf("mColWidths=");
    3508               0 :   PRInt32 numCols = GetColCount();
    3509                 :   PRInt32 colX;
    3510               0 :   for (colX = 0; colX < numCols; colX++) {
    3511               0 :     printf("%d ", GetColumnWidth(colX));
    3512                 :   }
    3513               0 :   printf("\n");
    3514                 : 
    3515               0 :   if (aDumpRows) {
    3516               0 :     nsIFrame* kidFrame = mFrames.FirstChild();
    3517               0 :     while (kidFrame) {
    3518               0 :       DumpRowGroup(kidFrame);
    3519               0 :       kidFrame = kidFrame->GetNextSibling();
    3520                 :     }
    3521                 :   }
    3522                 : 
    3523               0 :   if (aDumpCols) {
    3524                 :           // output col frame cache
    3525               0 :     printf("\n col frame cache ->");
    3526               0 :            for (colX = 0; colX < numCols; colX++) {
    3527               0 :       nsTableColFrame* colFrame = mColFrames.ElementAt(colX);
    3528               0 :       if (0 == (colX % 8)) {
    3529               0 :         printf("\n");
    3530                 :       }
    3531               0 :       printf ("%d=%p ", colX, static_cast<void*>(colFrame));
    3532               0 :       nsTableColType colType = colFrame->GetColType();
    3533               0 :       switch (colType) {
    3534                 :       case eColContent:
    3535               0 :         printf(" content ");
    3536               0 :         break;
    3537                 :       case eColAnonymousCol:
    3538               0 :         printf(" anonymous-column ");
    3539               0 :         break;
    3540                 :       case eColAnonymousColGroup:
    3541               0 :         printf(" anonymous-colgroup ");
    3542               0 :         break;
    3543                 :       case eColAnonymousCell:
    3544               0 :         printf(" anonymous-cell ");
    3545               0 :         break;
    3546                 :       }
    3547                 :     }
    3548               0 :     printf("\n colgroups->");
    3549               0 :     for (nsIFrame* childFrame = mColGroups.FirstChild(); childFrame;
    3550                 :          childFrame = childFrame->GetNextSibling()) {
    3551               0 :       if (nsGkAtoms::tableColGroupFrame == childFrame->GetType()) {
    3552               0 :         nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame *)childFrame;
    3553               0 :         colGroupFrame->Dump(1);
    3554                 :       }
    3555                 :     }
    3556               0 :     for (colX = 0; colX < numCols; colX++) {
    3557               0 :       printf("\n");
    3558               0 :       nsTableColFrame* colFrame = GetColFrame(colX);
    3559               0 :       colFrame->Dump(1);
    3560                 :     }
    3561                 :   }
    3562               0 :   if (aDumpCellMap) {
    3563               0 :     nsTableCellMap* cellMap = GetCellMap();
    3564               0 :     cellMap->Dump();
    3565                 :   }
    3566               0 :   printf(" ***END TABLE DUMP*** \n");
    3567               0 : }
    3568                 : #endif
    3569                 : 
    3570                 : // nsTableIterator
    3571               0 : nsTableIterator::nsTableIterator(nsIFrame& aSource)
    3572                 : {
    3573               0 :   nsIFrame* firstChild = aSource.GetFirstPrincipalChild();
    3574               0 :   Init(firstChild);
    3575               0 : }
    3576                 : 
    3577               0 : nsTableIterator::nsTableIterator(nsFrameList& aSource)
    3578                 : {
    3579               0 :   nsIFrame* firstChild = aSource.FirstChild();
    3580               0 :   Init(firstChild);
    3581               0 : }
    3582                 : 
    3583               0 : void nsTableIterator::Init(nsIFrame* aFirstChild)
    3584                 : {
    3585               0 :   mFirstListChild = aFirstChild;
    3586               0 :   mFirstChild     = aFirstChild;
    3587               0 :   mCurrentChild   = nsnull;
    3588               0 :   mLeftToRight    = true;
    3589               0 :   mCount          = -1;
    3590                 : 
    3591               0 :   if (!mFirstChild) {
    3592               0 :     return;
    3593                 :   }
    3594                 : 
    3595               0 :   nsTableFrame* table = nsTableFrame::GetTableFrame(mFirstChild);
    3596                 :   mLeftToRight = (NS_STYLE_DIRECTION_LTR ==
    3597               0 :                   table->GetStyleVisibility()->mDirection);
    3598                 : 
    3599               0 :   if (!mLeftToRight) {
    3600               0 :     mCount = 0;
    3601               0 :     nsIFrame* nextChild = mFirstChild->GetNextSibling();
    3602               0 :     while (nsnull != nextChild) {
    3603               0 :       mCount++;
    3604               0 :       mFirstChild = nextChild;
    3605               0 :       nextChild = nextChild->GetNextSibling();
    3606                 :     }
    3607                 :   }
    3608                 : }
    3609                 : 
    3610               0 : nsIFrame* nsTableIterator::First()
    3611                 : {
    3612               0 :   mCurrentChild = mFirstChild;
    3613               0 :   return mCurrentChild;
    3614                 : }
    3615                 : 
    3616               0 : nsIFrame* nsTableIterator::Next()
    3617                 : {
    3618               0 :   if (!mCurrentChild) {
    3619               0 :     return nsnull;
    3620                 :   }
    3621                 : 
    3622               0 :   if (mLeftToRight) {
    3623               0 :     mCurrentChild = mCurrentChild->GetNextSibling();
    3624               0 :     return mCurrentChild;
    3625                 :   }
    3626                 :   else {
    3627               0 :     nsIFrame* targetChild = mCurrentChild;
    3628               0 :     mCurrentChild = nsnull;
    3629               0 :     nsIFrame* child = mFirstListChild;
    3630               0 :     while (child && (child != targetChild)) {
    3631               0 :       mCurrentChild = child;
    3632               0 :       child = child->GetNextSibling();
    3633                 :     }
    3634               0 :     return mCurrentChild;
    3635                 :   }
    3636                 : }
    3637                 : 
    3638               0 : bool nsTableIterator::IsLeftToRight()
    3639                 : {
    3640               0 :   return mLeftToRight;
    3641                 : }
    3642                 : 
    3643               0 : PRInt32 nsTableIterator::Count()
    3644                 : {
    3645               0 :   if (-1 == mCount) {
    3646               0 :     mCount = 0;
    3647               0 :     nsIFrame* child = mFirstListChild;
    3648               0 :     while (nsnull != child) {
    3649               0 :       mCount++;
    3650               0 :       child = child->GetNextSibling();
    3651                 :     }
    3652                 :   }
    3653               0 :   return mCount;
    3654                 : }
    3655                 : 
    3656                 : /*------------------ nsITableLayout methods ------------------------------*/
    3657                 : NS_IMETHODIMP
    3658               0 : nsTableFrame::GetCellDataAt(PRInt32        aRowIndex,
    3659                 :                             PRInt32        aColIndex,
    3660                 :                             nsIDOMElement* &aCell,   //out params
    3661                 :                             PRInt32&       aStartRowIndex,
    3662                 :                             PRInt32&       aStartColIndex,
    3663                 :                             PRInt32&       aRowSpan,
    3664                 :                             PRInt32&       aColSpan,
    3665                 :                             PRInt32&       aActualRowSpan,
    3666                 :                             PRInt32&       aActualColSpan,
    3667                 :                             bool&          aIsSelected)
    3668                 : {
    3669                 :   // Initialize out params
    3670               0 :   aCell = nsnull;
    3671               0 :   aStartRowIndex = 0;
    3672               0 :   aStartColIndex = 0;
    3673               0 :   aRowSpan = 0;
    3674               0 :   aColSpan = 0;
    3675               0 :   aIsSelected = false;
    3676                 : 
    3677               0 :   nsTableCellMap* cellMap = GetCellMap();
    3678               0 :   if (!cellMap) { return NS_ERROR_NOT_INITIALIZED;}
    3679                 : 
    3680                 :   bool originates;
    3681                 :   PRInt32 colSpan; // Is this the "effective" or "html" value?
    3682                 : 
    3683               0 :   nsTableCellFrame *cellFrame = cellMap->GetCellInfoAt(aRowIndex, aColIndex, &originates, &colSpan);
    3684               0 :   if (!cellFrame) return NS_TABLELAYOUT_CELL_NOT_FOUND;
    3685                 : 
    3686               0 :   nsresult result= cellFrame->GetRowIndex(aStartRowIndex);
    3687               0 :   if (NS_FAILED(result)) return result;
    3688               0 :   result = cellFrame->GetColIndex(aStartColIndex);
    3689               0 :   if (NS_FAILED(result)) return result;
    3690                 :   //This returns HTML value, which may be 0
    3691               0 :   aRowSpan = cellFrame->GetRowSpan();
    3692               0 :   aColSpan = cellFrame->GetColSpan();
    3693               0 :   aActualRowSpan = GetEffectiveRowSpan(*cellFrame);
    3694               0 :   aActualColSpan = GetEffectiveColSpan(*cellFrame);
    3695                 : 
    3696                 :   // If these aren't at least 1, we have a cellmap error
    3697               0 :   if (aActualRowSpan == 0 || aActualColSpan == 0)
    3698               0 :     return NS_ERROR_FAILURE;
    3699                 : 
    3700               0 :   aIsSelected = cellFrame->IsSelected();
    3701                 : 
    3702                 :   // do this last, because it addrefs,
    3703                 :   // and we don't want the caller leaking it on error
    3704               0 :   nsIContent* content = cellFrame->GetContent();
    3705               0 :   if (!content) return NS_ERROR_FAILURE;
    3706                 : 
    3707               0 :   return CallQueryInterface(content, &aCell);
    3708                 : }
    3709                 : 
    3710               0 : NS_IMETHODIMP nsTableFrame::GetTableSize(PRInt32& aRowCount, PRInt32& aColCount)
    3711                 : {
    3712               0 :   nsTableCellMap* cellMap = GetCellMap();
    3713                 :   // Initialize out params
    3714               0 :   aRowCount = 0;
    3715               0 :   aColCount = 0;
    3716               0 :   if (!cellMap) { return NS_ERROR_NOT_INITIALIZED;}
    3717                 : 
    3718               0 :   aRowCount = cellMap->GetRowCount();
    3719               0 :   aColCount = cellMap->GetColCount();
    3720               0 :   return NS_OK;
    3721                 : }
    3722                 : 
    3723                 : NS_IMETHODIMP
    3724               0 : nsTableFrame::GetIndexByRowAndColumn(PRInt32 aRow, PRInt32 aColumn,
    3725                 :                                      PRInt32 *aIndex)
    3726                 : {
    3727               0 :   NS_ENSURE_ARG_POINTER(aIndex);
    3728               0 :   *aIndex = -1;
    3729                 : 
    3730               0 :   nsTableCellMap* cellMap = GetCellMap();
    3731               0 :   if (!cellMap)
    3732               0 :     return NS_ERROR_NOT_INITIALIZED;
    3733                 : 
    3734               0 :   *aIndex = cellMap->GetIndexByRowAndColumn(aRow, aColumn);
    3735               0 :   return (*aIndex == -1) ? NS_TABLELAYOUT_CELL_NOT_FOUND : NS_OK;
    3736                 : }
    3737                 : 
    3738                 : NS_IMETHODIMP
    3739               0 : nsTableFrame::GetRowAndColumnByIndex(PRInt32 aIndex,
    3740                 :                                     PRInt32 *aRow, PRInt32 *aColumn)
    3741                 : {
    3742               0 :   NS_ENSURE_ARG_POINTER(aRow);
    3743               0 :   *aRow = -1;
    3744                 : 
    3745               0 :   NS_ENSURE_ARG_POINTER(aColumn);
    3746               0 :   *aColumn = -1;
    3747                 : 
    3748               0 :   nsTableCellMap* cellMap = GetCellMap();
    3749               0 :   if (!cellMap)
    3750               0 :     return NS_ERROR_NOT_INITIALIZED;
    3751                 : 
    3752               0 :   cellMap->GetRowAndColumnByIndex(aIndex, aRow, aColumn);
    3753               0 :   return NS_OK;
    3754                 : }
    3755                 : 
    3756                 : /*---------------- end of nsITableLayout implementation ------------------*/
    3757                 : 
    3758                 : bool
    3759               0 : nsTableFrame::ColumnHasCellSpacingBefore(PRInt32 aColIndex) const
    3760                 : {
    3761                 :   // Since fixed-layout tables should not have their column sizes change
    3762                 :   // as they load, we assume that all columns are significant.
    3763               0 :   if (LayoutStrategy()->GetType() == nsITableLayoutStrategy::Fixed)
    3764               0 :     return true;
    3765                 :   // the first column is always significant
    3766               0 :   if (aColIndex == 0)
    3767               0 :     return true;
    3768               0 :   nsTableCellMap* cellMap = GetCellMap();
    3769               0 :   if (!cellMap)
    3770               0 :     return false;
    3771               0 :   return cellMap->GetNumCellsOriginatingInCol(aColIndex) > 0;
    3772                 : }
    3773                 : 
    3774                 : /********************************************************************************
    3775                 :  * Collapsing Borders
    3776                 :  *
    3777                 :  *  The CSS spec says to resolve border conflicts in this order:
    3778                 :  *  1) any border with the style HIDDEN wins
    3779                 :  *  2) the widest border with a style that is not NONE wins
    3780                 :  *  3) the border styles are ranked in this order, highest to lowest precedence:
    3781                 :  *     double, solid, dashed, dotted, ridge, outset, groove, inset
    3782                 :  *  4) borders that are of equal width and style (differ only in color) have this precedence:
    3783                 :  *     cell, row, rowgroup, col, colgroup, table
    3784                 :  *  5) if all border styles are NONE, then that's the computed border style.
    3785                 :  *******************************************************************************/
    3786                 : 
    3787                 : #ifdef DEBUG
    3788                 : #define VerifyNonNegativeDamageRect(r)                                  \
    3789                 :   NS_ASSERTION((r).x >= 0, "negative col index");                       \
    3790                 :   NS_ASSERTION((r).y >= 0, "negative row index");                       \
    3791                 :   NS_ASSERTION((r).width >= 0, "negative horizontal damage");           \
    3792                 :   NS_ASSERTION((r).height >= 0, "negative vertical damage");
    3793                 : #define VerifyDamageRect(r)                                             \
    3794                 :   VerifyNonNegativeDamageRect(r);                                       \
    3795                 :   NS_ASSERTION((r).XMost() <= GetColCount(),                            \
    3796                 :                "horizontal damage extends outside table");              \
    3797                 :   NS_ASSERTION((r).YMost() <= GetRowCount(),                            \
    3798                 :                "vertical damage extends outside table");
    3799                 : #endif
    3800                 : 
    3801                 : void
    3802               0 : nsTableFrame::AddBCDamageArea(const nsIntRect& aValue)
    3803                 : {
    3804               0 :   NS_ASSERTION(IsBorderCollapse(), "invalid AddBCDamageArea call");
    3805                 : #ifdef DEBUG
    3806               0 :   VerifyDamageRect(aValue);
    3807                 : #endif
    3808                 : 
    3809               0 :   SetNeedToCalcBCBorders(true);
    3810                 :   // Get the property
    3811               0 :   BCPropertyData* value = GetBCProperty(true);
    3812               0 :   if (value) {
    3813                 : #ifdef DEBUG
    3814               0 :     VerifyNonNegativeDamageRect(value->mDamageArea);
    3815                 : #endif
    3816                 :     // Clamp the old damage area to the current table area in case it shrunk.
    3817               0 :     PRInt32 cols = GetColCount();
    3818               0 :     if (value->mDamageArea.XMost() > cols) {
    3819               0 :       if (value->mDamageArea.x > cols) {
    3820               0 :         value->mDamageArea.x = cols;
    3821               0 :         value->mDamageArea.width = 0;
    3822                 :       }
    3823                 :       else {
    3824               0 :         value->mDamageArea.width = cols - value->mDamageArea.x;
    3825                 :       }
    3826                 :     }
    3827               0 :     PRInt32 rows = GetRowCount();
    3828               0 :     if (value->mDamageArea.YMost() > rows) {
    3829               0 :       if (value->mDamageArea.y > rows) {
    3830               0 :         value->mDamageArea.y = rows;
    3831               0 :         value->mDamageArea.height = 0;
    3832                 :       }
    3833                 :       else {
    3834               0 :         value->mDamageArea.height = rows - value->mDamageArea.y;
    3835                 :       }
    3836                 :     }
    3837                 : 
    3838                 :     // Construct a union of the new and old damage areas.
    3839               0 :     value->mDamageArea.UnionRect(value->mDamageArea, aValue);
    3840                 :   }
    3841               0 : }
    3842                 : 
    3843                 : 
    3844                 : void
    3845               0 : nsTableFrame::SetFullBCDamageArea()
    3846                 : {
    3847               0 :   NS_ASSERTION(IsBorderCollapse(), "invalid SetFullBCDamageArea call");
    3848                 : 
    3849               0 :   SetNeedToCalcBCBorders(true);
    3850                 : 
    3851               0 :   BCPropertyData* value = GetBCProperty(true);
    3852               0 :   if (value) {
    3853               0 :     value->mDamageArea = nsIntRect(0, 0, GetColCount(), GetRowCount());
    3854                 :   }
    3855               0 : }
    3856                 : 
    3857                 : 
    3858                 : /* BCCellBorder represents a border segment which can be either a horizontal
    3859                 :  * or a vertical segment. For each segment we need to know the color, width,
    3860                 :  * style, who owns it and how long it is in cellmap coordinates.
    3861                 :  * Ownership of these segments is important to calculate which corners should
    3862                 :  * be bevelled. This structure has dual use, its used first to compute the
    3863                 :  * dominant border for horizontal and vertical segments and to store the
    3864                 :  * preliminary computed border results in the BCCellBorders structure.
    3865                 :  * This temporary storage is not symmetric with respect to horizontal and
    3866                 :  * vertical border segments, its always column oriented. For each column in
    3867                 :  * the cellmap there is a temporary stored vertical and horizontal segment.
    3868                 :  * XXX_Bernd this asymmetry is the root of those rowspan bc border errors
    3869                 :  */
    3870                 : struct BCCellBorder
    3871                 : {
    3872               0 :   BCCellBorder() { Reset(0, 1); }
    3873                 :   void Reset(PRUint32 aRowIndex, PRUint32 aRowSpan);
    3874                 :   nscolor       color;    // border segment color
    3875                 :   BCPixelSize   width;    // border segment width in pixel coordinates !!
    3876                 :   PRUint8       style;    // border segment style, possible values are defined
    3877                 :                           // in nsStyleConsts.h as NS_STYLE_BORDER_STYLE_*
    3878                 :   BCBorderOwner owner;    // border segment owner, possible values are defined
    3879                 :                           // in celldata.h. In the cellmap for each border
    3880                 :                           // segment we store the owner and later when
    3881                 :                           // painting we know the owner and can retrieve the
    3882                 :                           // style info from the corresponding frame
    3883                 :   PRInt32       rowIndex; // rowIndex of temporary stored horizontal border
    3884                 :                           // segments relative to the table
    3885                 :   PRInt32       rowSpan;  // row span of temporary stored horizontal border
    3886                 :                           // segments
    3887                 : };
    3888                 : 
    3889                 : void
    3890               0 : BCCellBorder::Reset(PRUint32 aRowIndex,
    3891                 :                     PRUint32 aRowSpan)
    3892                 : {
    3893               0 :   style = NS_STYLE_BORDER_STYLE_NONE;
    3894               0 :   color = 0;
    3895               0 :   width = 0;
    3896               0 :   owner = eTableOwner;
    3897               0 :   rowIndex = aRowIndex;
    3898               0 :   rowSpan  = aRowSpan;
    3899               0 : }
    3900                 : 
    3901                 : class BCMapCellIterator;
    3902                 : 
    3903                 : /*****************************************************************
    3904                 :  *  BCMapCellInfo
    3905                 :  * This structure stores information about the cellmap and all involved
    3906                 :  * table related frames that are used during the computation of winning borders
    3907                 :  * in CalcBCBorders so that they do need to be looked up again and again when
    3908                 :  * iterating over the cells.
    3909                 :  ****************************************************************/
    3910                 : struct BCMapCellInfo
    3911                 : {
    3912                 :   BCMapCellInfo(nsTableFrame* aTableFrame);
    3913                 :   void ResetCellInfo();
    3914                 :   void SetInfo(nsTableRowFrame*   aNewRow,
    3915                 :                PRInt32            aColIndex,
    3916                 :                BCCellData*        aCellData,
    3917                 :                BCMapCellIterator* aIter,
    3918                 :                nsCellMap*         aCellMap = nsnull);
    3919                 :   // The BCMapCellInfo has functions to set the continous
    3920                 :   // border widths (see nsTablePainter.cpp for a description of the continous
    3921                 :   // borders concept). The widths are computed inside these functions based on
    3922                 :   // the current position inside the table and the cached frames that correspond
    3923                 :   // to this position. The widths are stored in member variables of the internal
    3924                 :   // table frames.
    3925                 :   void SetTableTopLeftContBCBorder();
    3926                 :   void SetRowGroupLeftContBCBorder();
    3927                 :   void SetRowGroupRightContBCBorder();
    3928                 :   void SetRowGroupBottomContBCBorder();
    3929                 :   void SetRowLeftContBCBorder();
    3930                 :   void SetRowRightContBCBorder();
    3931                 :   void SetColumnTopRightContBCBorder();
    3932                 :   void SetColumnBottomContBCBorder();
    3933                 :   void SetColGroupBottomContBCBorder();
    3934                 :   void SetInnerRowGroupBottomContBCBorder(const nsIFrame* aNextRowGroup,
    3935                 :                                           nsTableRowFrame* aNextRow);
    3936                 : 
    3937                 :   // functions to set the border widths on the table related frames, where the
    3938                 :   // knowledge about the current position in the table is used.
    3939                 :   void SetTableTopBorderWidth(BCPixelSize aWidth);
    3940                 :   void SetTableLeftBorderWidth(PRInt32 aRowY, BCPixelSize aWidth);
    3941                 :   void SetTableRightBorderWidth(PRInt32 aRowY, BCPixelSize aWidth);
    3942                 :   void SetTableBottomBorderWidth(BCPixelSize aWidth);
    3943                 :   void SetLeftBorderWidths(BCPixelSize aWidth);
    3944                 :   void SetRightBorderWidths(BCPixelSize aWidth);
    3945                 :   void SetTopBorderWidths(BCPixelSize aWidth);
    3946                 :   void SetBottomBorderWidths(BCPixelSize aWidth);
    3947                 : 
    3948                 :   // functions to compute the borders; they depend on the
    3949                 :   // knowledge about the current position in the table. The edge functions
    3950                 :   // should be called if a table edge is involved, otherwise the internal
    3951                 :   // functions should be called.
    3952                 :   BCCellBorder GetTopEdgeBorder();
    3953                 :   BCCellBorder GetBottomEdgeBorder();
    3954                 :   BCCellBorder GetLeftEdgeBorder();
    3955                 :   BCCellBorder GetRightEdgeBorder();
    3956                 :   BCCellBorder GetRightInternalBorder();
    3957                 :   BCCellBorder GetLeftInternalBorder();
    3958                 :   BCCellBorder GetTopInternalBorder();
    3959                 :   BCCellBorder GetBottomInternalBorder();
    3960                 : 
    3961                 :   // functions to set the interal position information
    3962                 :   void SetColumn(PRInt32 aColX);
    3963                 :   // Increment the row as we loop over the rows of a rowspan
    3964                 :   void IncrementRow(bool aResetToTopRowOfCell = false);
    3965                 : 
    3966                 :   // Helper functions to get extent of the cell
    3967                 :   PRInt32 GetCellEndRowIndex() const;
    3968                 :   PRInt32 GetCellEndColIndex() const;
    3969                 : 
    3970                 :   // storage of table information
    3971                 :   nsTableFrame*         mTableFrame;
    3972                 :   PRInt32               mNumTableRows;
    3973                 :   PRInt32               mNumTableCols;
    3974                 :   BCPropertyData*       mTableBCData;
    3975                 : 
    3976                 :   // storage of table ltr information, the border collapse code swaps the sides
    3977                 :   // to account for rtl tables, this is done through mStartSide and mEndSide
    3978                 :   bool                  mTableIsLTR;
    3979                 :   mozilla::css::Side    mStartSide;
    3980                 :   mozilla::css::Side    mEndSide;
    3981                 : 
    3982                 :   // a cell can only belong to one rowgroup
    3983                 :   nsTableRowGroupFrame* mRowGroup;
    3984                 : 
    3985                 :   // a cell with a rowspan has a top and a bottom row, and rows in between
    3986                 :   nsTableRowFrame*      mTopRow;
    3987                 :   nsTableRowFrame*      mBottomRow;
    3988                 :   nsTableRowFrame*      mCurrentRowFrame;
    3989                 : 
    3990                 :   // a cell with a colspan has a left and right column and columns in between
    3991                 :   // they can belong to different colgroups
    3992                 :   nsTableColGroupFrame* mColGroup;
    3993                 :   nsTableColGroupFrame* mCurrentColGroupFrame;
    3994                 : 
    3995                 :   nsTableColFrame*      mLeftCol;
    3996                 :   nsTableColFrame*      mRightCol;
    3997                 :   nsTableColFrame*      mCurrentColFrame;
    3998                 : 
    3999                 :   // cell information
    4000                 :   BCCellData*           mCellData;
    4001                 :   nsBCTableCellFrame*   mCell;
    4002                 : 
    4003                 :   PRInt32               mRowIndex;
    4004                 :   PRInt32               mRowSpan;
    4005                 :   PRInt32               mColIndex;
    4006                 :   PRInt32               mColSpan;
    4007                 : 
    4008                 :   // flags to describe the position of the cell with respect to the row- and
    4009                 :   // colgroups, for instance mRgAtTop documents that the top cell border hits
    4010                 :   // a rowgroup border
    4011                 :   bool                  mRgAtTop;
    4012                 :   bool                  mRgAtBottom;
    4013                 :   bool                  mCgAtLeft;
    4014                 :   bool                  mCgAtRight;
    4015                 : 
    4016                 : };
    4017                 : 
    4018                 : 
    4019               0 : BCMapCellInfo::BCMapCellInfo(nsTableFrame* aTableFrame)
    4020                 : {
    4021               0 :   mTableFrame = aTableFrame;
    4022                 :   mTableIsLTR =
    4023               0 :     aTableFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR;
    4024               0 :   if (mTableIsLTR) {
    4025               0 :     mStartSide = NS_SIDE_LEFT;
    4026               0 :     mEndSide = NS_SIDE_RIGHT;
    4027                 :   }
    4028                 :   else {
    4029               0 :     mStartSide = NS_SIDE_RIGHT;
    4030               0 :     mEndSide = NS_SIDE_LEFT;
    4031                 :   }
    4032               0 :   mNumTableRows = mTableFrame->GetRowCount();
    4033               0 :   mNumTableCols = mTableFrame->GetColCount();
    4034                 :   mTableBCData = static_cast<BCPropertyData*>
    4035               0 :     (mTableFrame->Properties().Get(TableBCProperty()));
    4036                 : 
    4037               0 :   ResetCellInfo();
    4038               0 : }
    4039                 : 
    4040               0 : void BCMapCellInfo::ResetCellInfo()
    4041                 : {
    4042               0 :   mCellData  = nsnull;
    4043               0 :   mRowGroup  = nsnull;
    4044               0 :   mTopRow    = nsnull;
    4045               0 :   mBottomRow = nsnull;
    4046               0 :   mColGroup  = nsnull;
    4047               0 :   mLeftCol   = nsnull;
    4048               0 :   mRightCol  = nsnull;
    4049               0 :   mCell      = nsnull;
    4050               0 :   mRowIndex  = mRowSpan = mColIndex = mColSpan = 0;
    4051               0 :   mRgAtTop = mRgAtBottom = mCgAtLeft = mCgAtRight = false;
    4052               0 : }
    4053                 : 
    4054               0 : inline PRInt32 BCMapCellInfo::GetCellEndRowIndex() const
    4055                 : {
    4056               0 :   return mRowIndex + mRowSpan - 1;
    4057                 : }
    4058                 : 
    4059               0 : inline PRInt32 BCMapCellInfo::GetCellEndColIndex() const
    4060                 : {
    4061               0 :   return mColIndex + mColSpan - 1;
    4062                 : }
    4063                 : 
    4064                 : 
    4065                 : class BCMapCellIterator
    4066               0 : {
    4067                 : public:
    4068                 :   BCMapCellIterator(nsTableFrame* aTableFrame,
    4069                 :                     const nsIntRect& aDamageArea);
    4070                 : 
    4071                 :   void First(BCMapCellInfo& aMapCellInfo);
    4072                 : 
    4073                 :   void Next(BCMapCellInfo& aMapCellInfo);
    4074                 : 
    4075                 :   void PeekRight(BCMapCellInfo& aRefInfo,
    4076                 :                  PRUint32     aRowIndex,
    4077                 :                  BCMapCellInfo& aAjaInfo);
    4078                 : 
    4079                 :   void PeekBottom(BCMapCellInfo& aRefInfo,
    4080                 :                   PRUint32     aColIndex,
    4081                 :                   BCMapCellInfo& aAjaInfo);
    4082                 : 
    4083               0 :   bool IsNewRow() { return mIsNewRow; }
    4084                 : 
    4085                 :   nsTableRowFrame* GetPrevRow() const { return mPrevRow; }
    4086               0 :   nsTableRowFrame* GetCurrentRow() const { return mRow; }
    4087               0 :   nsTableRowGroupFrame* GetCurrentRowGroup() const { return mRowGroup;}
    4088                 : 
    4089                 :   PRInt32    mRowGroupStart;
    4090                 :   PRInt32    mRowGroupEnd;
    4091                 :   bool       mAtEnd;
    4092                 :   nsCellMap* mCellMap;
    4093                 : 
    4094                 : private:
    4095                 :   bool SetNewRow(nsTableRowFrame* row = nsnull);
    4096                 :   bool SetNewRowGroup(bool aFindFirstDamagedRow);
    4097                 : 
    4098                 :   nsTableFrame*         mTableFrame;
    4099                 :   nsTableCellMap*       mTableCellMap;
    4100                 :   nsTableFrame::RowGroupArray mRowGroups;
    4101                 :   nsTableRowGroupFrame* mRowGroup;
    4102                 :   PRInt32               mRowGroupIndex;
    4103                 :   PRUint32              mNumTableRows;
    4104                 :   nsTableRowFrame*      mRow;
    4105                 :   nsTableRowFrame*      mPrevRow;
    4106                 :   bool                  mIsNewRow;
    4107                 :   PRInt32               mRowIndex;
    4108                 :   PRUint32              mNumTableCols;
    4109                 :   PRInt32               mColIndex;
    4110                 :   nsPoint               mAreaStart;
    4111                 :   nsPoint               mAreaEnd;
    4112                 : };
    4113                 : 
    4114               0 : BCMapCellIterator::BCMapCellIterator(nsTableFrame* aTableFrame,
    4115                 :                                      const nsIntRect& aDamageArea)
    4116               0 : :mTableFrame(aTableFrame)
    4117                 : {
    4118               0 :   mTableCellMap  = aTableFrame->GetCellMap();
    4119                 : 
    4120               0 :   mAreaStart.x   = aDamageArea.x;
    4121               0 :   mAreaStart.y   = aDamageArea.y;
    4122               0 :   mAreaEnd.y     = aDamageArea.y + aDamageArea.height - 1;
    4123               0 :   mAreaEnd.x     = aDamageArea.x + aDamageArea.width - 1;
    4124                 : 
    4125               0 :   mNumTableRows  = mTableFrame->GetRowCount();
    4126               0 :   mRow           = nsnull;
    4127               0 :   mRowIndex      = 0;
    4128               0 :   mNumTableCols  = mTableFrame->GetColCount();
    4129               0 :   mColIndex      = 0;
    4130               0 :   mRowGroupIndex = -1;
    4131                 : 
    4132                 :   // Get the ordered row groups
    4133               0 :   aTableFrame->OrderRowGroups(mRowGroups);
    4134                 : 
    4135               0 :   mAtEnd = true; // gets reset when First() is called
    4136               0 : }
    4137                 : 
    4138                 : // fill fields that we need for border collapse computation on a given cell
    4139                 : void
    4140               0 : BCMapCellInfo::SetInfo(nsTableRowFrame*   aNewRow,
    4141                 :                        PRInt32            aColIndex,
    4142                 :                        BCCellData*        aCellData,
    4143                 :                        BCMapCellIterator* aIter,
    4144                 :                        nsCellMap*         aCellMap)
    4145                 : {
    4146                 :   // fill the cell information
    4147               0 :   mCellData = aCellData;
    4148               0 :   mColIndex = aColIndex;
    4149                 : 
    4150                 :   // initialize the row information if it was not previously set for cells in
    4151                 :   // this row
    4152               0 :   mRowIndex = 0;
    4153               0 :   if (aNewRow) {
    4154               0 :     mTopRow = aNewRow;
    4155               0 :     mRowIndex = aNewRow->GetRowIndex();
    4156                 :   }
    4157                 : 
    4158                 :   // fill cell frame info and row information
    4159               0 :   mCell      = nsnull;
    4160               0 :   mRowSpan   = 1;
    4161               0 :   mColSpan   = 1;
    4162               0 :   if (aCellData) {
    4163               0 :     mCell = static_cast<nsBCTableCellFrame*>(aCellData->GetCellFrame());
    4164               0 :     if (mCell) {
    4165               0 :       if (!mTopRow) {
    4166               0 :         mTopRow = static_cast<nsTableRowFrame*>(mCell->GetParent());
    4167               0 :         if (!mTopRow) ABORT0();
    4168               0 :         mRowIndex = mTopRow->GetRowIndex();
    4169                 :       }
    4170               0 :       mColSpan = mTableFrame->GetEffectiveColSpan(*mCell, aCellMap);
    4171               0 :       mRowSpan = mTableFrame->GetEffectiveRowSpan(*mCell, aCellMap);
    4172                 :     }
    4173                 :   }
    4174                 : 
    4175               0 :   if (!mTopRow) {
    4176               0 :     mTopRow = aIter->GetCurrentRow();
    4177                 :   }
    4178               0 :   if (1 == mRowSpan) {
    4179               0 :     mBottomRow = mTopRow;
    4180                 :   }
    4181                 :   else {
    4182               0 :     mBottomRow = mTopRow->GetNextRow();
    4183               0 :     if (mBottomRow) {
    4184               0 :       for (PRInt32 spanY = 2; mBottomRow && (spanY < mRowSpan); spanY++) {
    4185               0 :         mBottomRow = mBottomRow->GetNextRow();
    4186                 :       }
    4187               0 :       NS_ASSERTION(mBottomRow, "spanned row not found");
    4188                 :     }
    4189                 :     else {
    4190               0 :       NS_ASSERTION(false, "error in cell map");
    4191               0 :       mRowSpan = 1;
    4192               0 :       mBottomRow = mTopRow;
    4193                 :     }
    4194                 :   }
    4195                 :   // row group frame info
    4196                 :   // try to reuse the rgStart and rgEnd from the iterator as calls to
    4197                 :   // GetRowCount() are computationally expensive and should be avoided if
    4198                 :   // possible
    4199               0 :   PRUint32 rgStart  = aIter->mRowGroupStart;
    4200               0 :   PRUint32 rgEnd    = aIter->mRowGroupEnd;
    4201               0 :   mRowGroup = static_cast<nsTableRowGroupFrame*>(mTopRow->GetParent());
    4202               0 :   if (mRowGroup != aIter->GetCurrentRowGroup()) {
    4203               0 :     rgStart = mRowGroup->GetStartRowIndex();
    4204               0 :     rgEnd   = rgStart + mRowGroup->GetRowCount() - 1;
    4205                 :   }
    4206               0 :   PRUint32 rowIndex = mTopRow->GetRowIndex();
    4207               0 :   mRgAtTop    = (rgStart == rowIndex);
    4208               0 :   mRgAtBottom = (rgEnd == rowIndex + mRowSpan - 1);
    4209                 : 
    4210                 :    // col frame info
    4211               0 :   mLeftCol = mTableFrame->GetColFrame(aColIndex);
    4212               0 :   if (!mLeftCol) ABORT0();
    4213                 : 
    4214               0 :   mRightCol = mLeftCol;
    4215               0 :   if (mColSpan > 1) {
    4216                 :     nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex +
    4217               0 :                                                          mColSpan -1);
    4218               0 :     if (!colFrame) ABORT0();
    4219               0 :     mRightCol = colFrame;
    4220                 :   }
    4221                 : 
    4222                 :   // col group frame info
    4223               0 :   mColGroup = static_cast<nsTableColGroupFrame*>(mLeftCol->GetParent());
    4224               0 :   PRInt32 cgStart = mColGroup->GetStartColumnIndex();
    4225               0 :   PRInt32 cgEnd = NS_MAX(0, cgStart + mColGroup->GetColCount() - 1);
    4226               0 :   mCgAtLeft  = (cgStart == aColIndex);
    4227               0 :   mCgAtRight = (cgEnd == aColIndex + mColSpan - 1);
    4228                 : }
    4229                 : 
    4230                 : bool
    4231               0 : BCMapCellIterator::SetNewRow(nsTableRowFrame* aRow)
    4232                 : {
    4233               0 :   mAtEnd   = true;
    4234               0 :   mPrevRow = mRow;
    4235               0 :   if (aRow) {
    4236               0 :     mRow = aRow;
    4237                 :   }
    4238               0 :   else if (mRow) {
    4239               0 :     mRow = mRow->GetNextRow();
    4240                 :   }
    4241               0 :   if (mRow) {
    4242               0 :     mRowIndex = mRow->GetRowIndex();
    4243                 :     // get to the first entry with an originating cell
    4244               0 :     PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
    4245               0 :     if (PRUint32(rgRowIndex) >= mCellMap->mRows.Length())
    4246               0 :       ABORT1(false);
    4247               0 :     const nsCellMap::CellDataArray& row = mCellMap->mRows[rgRowIndex];
    4248                 : 
    4249               0 :     for (mColIndex = mAreaStart.x; mColIndex <= mAreaEnd.x; mColIndex++) {
    4250               0 :       CellData* cellData = row.SafeElementAt(mColIndex);
    4251               0 :       if (!cellData) { // add a dead cell data
    4252               0 :         nsIntRect damageArea;
    4253                 :         cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex,
    4254               0 :                                         false, 0, damageArea);
    4255               0 :         if (!cellData) ABORT1(false);
    4256                 :       }
    4257               0 :       if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
    4258               0 :         break;
    4259                 :       }
    4260                 :     }
    4261               0 :     mIsNewRow = true;
    4262               0 :     mAtEnd    = false;
    4263                 :   }
    4264               0 :   else ABORT1(false);
    4265                 : 
    4266               0 :   return !mAtEnd;
    4267                 : }
    4268                 : 
    4269                 : bool
    4270               0 : BCMapCellIterator::SetNewRowGroup(bool aFindFirstDamagedRow)
    4271                 : {
    4272               0 :    mAtEnd = true;
    4273               0 :   PRInt32 numRowGroups = mRowGroups.Length();
    4274               0 :   mCellMap = nsnull;
    4275               0 :   for (mRowGroupIndex++; mRowGroupIndex < numRowGroups; mRowGroupIndex++) {
    4276               0 :     mRowGroup = mRowGroups[mRowGroupIndex];
    4277               0 :     PRInt32 rowCount = mRowGroup->GetRowCount();
    4278               0 :     mRowGroupStart = mRowGroup->GetStartRowIndex();
    4279               0 :     mRowGroupEnd   = mRowGroupStart + rowCount - 1;
    4280               0 :     if (rowCount > 0) {
    4281               0 :       mCellMap = mTableCellMap->GetMapFor(mRowGroup, mCellMap);
    4282               0 :       if (!mCellMap) ABORT1(false);
    4283               0 :       nsTableRowFrame* firstRow = mRowGroup->GetFirstRow();
    4284               0 :       if (aFindFirstDamagedRow) {
    4285               0 :         if ((mAreaStart.y >= mRowGroupStart) && (mAreaStart.y <= mRowGroupEnd)) {
    4286                 :           // the damage area starts in the row group
    4287               0 :           if (aFindFirstDamagedRow) {
    4288                 :             // find the correct first damaged row
    4289               0 :             PRInt32 numRows = mAreaStart.y - mRowGroupStart;
    4290               0 :             for (PRInt32 i = 0; i < numRows; i++) {
    4291               0 :               firstRow = firstRow->GetNextRow();
    4292               0 :               if (!firstRow) ABORT1(false);
    4293                 :             }
    4294                 :           }
    4295                 :         }
    4296                 :         else {
    4297               0 :           continue;
    4298                 :         }
    4299                 :       }
    4300               0 :       if (SetNewRow(firstRow)) { // sets mAtEnd
    4301               0 :         break;
    4302                 :       }
    4303                 :     }
    4304                 :   }
    4305                 : 
    4306               0 :   return !mAtEnd;
    4307                 : }
    4308                 : 
    4309                 : void
    4310               0 : BCMapCellIterator::First(BCMapCellInfo& aMapInfo)
    4311                 : {
    4312               0 :   aMapInfo.ResetCellInfo();
    4313                 : 
    4314               0 :   SetNewRowGroup(true); // sets mAtEnd
    4315               0 :   while (!mAtEnd) {
    4316               0 :     if ((mAreaStart.y >= mRowGroupStart) && (mAreaStart.y <= mRowGroupEnd)) {
    4317                 :       BCCellData* cellData =
    4318                 :         static_cast<BCCellData*>(mCellMap->GetDataAt(mAreaStart.y -
    4319                 :                                                       mRowGroupStart,
    4320               0 :                                                       mAreaStart.x));
    4321               0 :       if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
    4322               0 :         aMapInfo.SetInfo(mRow, mAreaStart.x, cellData, this);
    4323               0 :         return;
    4324                 :       }
    4325                 :       else {
    4326               0 :         NS_ASSERTION(((0 == mAreaStart.x) && (mRowGroupStart == mAreaStart.y)) ,
    4327                 :                      "damage area expanded incorrectly");
    4328                 :       }
    4329                 :     }
    4330               0 :     SetNewRowGroup(true); // sets mAtEnd
    4331                 :   }
    4332                 : }
    4333                 : 
    4334                 : void
    4335               0 : BCMapCellIterator::Next(BCMapCellInfo& aMapInfo)
    4336                 : {
    4337               0 :   if (mAtEnd) ABORT0();
    4338               0 :   aMapInfo.ResetCellInfo();
    4339                 : 
    4340               0 :   mIsNewRow = false;
    4341               0 :   mColIndex++;
    4342               0 :   while ((mRowIndex <= mAreaEnd.y) && !mAtEnd) {
    4343               0 :     for (; mColIndex <= mAreaEnd.x; mColIndex++) {
    4344               0 :       PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
    4345                 :       BCCellData* cellData =
    4346               0 :          static_cast<BCCellData*>(mCellMap->GetDataAt(rgRowIndex, mColIndex));
    4347               0 :       if (!cellData) { // add a dead cell data
    4348               0 :         nsIntRect damageArea;
    4349                 :         cellData =
    4350                 :           static_cast<BCCellData*>(mCellMap->AppendCell(*mTableCellMap, nsnull,
    4351                 :                                                          rgRowIndex, false, 0,
    4352               0 :                                                          damageArea));
    4353               0 :         if (!cellData) ABORT0();
    4354                 :       }
    4355               0 :       if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
    4356               0 :         aMapInfo.SetInfo(mRow, mColIndex, cellData, this);
    4357               0 :         return;
    4358                 :       }
    4359                 :     }
    4360               0 :     if (mRowIndex >= mRowGroupEnd) {
    4361               0 :       SetNewRowGroup(false); // could set mAtEnd
    4362                 :     }
    4363                 :     else {
    4364               0 :       SetNewRow(); // could set mAtEnd
    4365                 :     }
    4366                 :   }
    4367               0 :   mAtEnd = true;
    4368                 : }
    4369                 : 
    4370                 : void
    4371               0 : BCMapCellIterator::PeekRight(BCMapCellInfo&   aRefInfo,
    4372                 :                              PRUint32         aRowIndex,
    4373                 :                              BCMapCellInfo&   aAjaInfo)
    4374                 : {
    4375               0 :   aAjaInfo.ResetCellInfo();
    4376               0 :   PRInt32 colIndex = aRefInfo.mColIndex + aRefInfo.mColSpan;
    4377               0 :   PRUint32 rgRowIndex = aRowIndex - mRowGroupStart;
    4378                 : 
    4379                 :   BCCellData* cellData =
    4380               0 :     static_cast<BCCellData*>(mCellMap->GetDataAt(rgRowIndex, colIndex));
    4381               0 :   if (!cellData) { // add a dead cell data
    4382               0 :     NS_ASSERTION(colIndex < mTableCellMap->GetColCount(), "program error");
    4383               0 :     nsIntRect damageArea;
    4384                 :     cellData =
    4385                 :       static_cast<BCCellData*>(mCellMap->AppendCell(*mTableCellMap, nsnull,
    4386                 :                                                      rgRowIndex, false, 0,
    4387               0 :                                                      damageArea));
    4388               0 :     if (!cellData) ABORT0();
    4389                 :   }
    4390               0 :   nsTableRowFrame* row = nsnull;
    4391               0 :   if (cellData->IsRowSpan()) {
    4392               0 :     rgRowIndex -= cellData->GetRowSpanOffset();
    4393                 :     cellData =
    4394               0 :       static_cast<BCCellData*>(mCellMap->GetDataAt(rgRowIndex, colIndex));
    4395               0 :     if (!cellData)
    4396               0 :       ABORT0();
    4397                 :   }
    4398                 :   else {
    4399               0 :     row = mRow;
    4400                 :   }
    4401               0 :   aAjaInfo.SetInfo(row, colIndex, cellData, this);
    4402                 : }
    4403                 : 
    4404                 : void
    4405               0 : BCMapCellIterator::PeekBottom(BCMapCellInfo&   aRefInfo,
    4406                 :                               PRUint32         aColIndex,
    4407                 :                               BCMapCellInfo&   aAjaInfo)
    4408                 : {
    4409               0 :   aAjaInfo.ResetCellInfo();
    4410               0 :   PRInt32 rowIndex = aRefInfo.mRowIndex + aRefInfo.mRowSpan;
    4411               0 :   PRInt32 rgRowIndex = rowIndex - mRowGroupStart;
    4412               0 :   nsTableRowGroupFrame* rg = mRowGroup;
    4413               0 :   nsCellMap* cellMap = mCellMap;
    4414               0 :   nsTableRowFrame* nextRow = nsnull;
    4415               0 :   if (rowIndex > mRowGroupEnd) {
    4416               0 :     PRInt32 nextRgIndex = mRowGroupIndex;
    4417               0 :     do {
    4418               0 :       nextRgIndex++;
    4419               0 :       rg = mRowGroups.SafeElementAt(nextRgIndex);
    4420               0 :       if (rg) {
    4421               0 :         cellMap = mTableCellMap->GetMapFor(rg, cellMap); if (!cellMap) ABORT0();
    4422               0 :         rgRowIndex = 0;
    4423               0 :         nextRow = rg->GetFirstRow();
    4424                 :       }
    4425                 :     }
    4426                 :     while (rg && !nextRow);
    4427               0 :     if(!rg) return;
    4428                 :   }
    4429                 :   else {
    4430                 :     // get the row within the same row group
    4431               0 :     nextRow = mRow;
    4432               0 :     for (PRInt32 i = 0; i < aRefInfo.mRowSpan; i++) {
    4433               0 :       nextRow = nextRow->GetNextRow(); if (!nextRow) ABORT0();
    4434                 :     }
    4435                 :   }
    4436                 : 
    4437                 :   BCCellData* cellData =
    4438               0 :     static_cast<BCCellData*>(cellMap->GetDataAt(rgRowIndex, aColIndex));
    4439               0 :   if (!cellData) { // add a dead cell data
    4440               0 :     NS_ASSERTION(rgRowIndex < cellMap->GetRowCount(), "program error");
    4441               0 :     nsIntRect damageArea;
    4442                 :     cellData =
    4443                 :       static_cast<BCCellData*>(cellMap->AppendCell(*mTableCellMap, nsnull,
    4444                 :                                                     rgRowIndex, false, 0,
    4445               0 :                                                     damageArea));
    4446               0 :     if (!cellData) ABORT0();
    4447                 :   }
    4448               0 :   if (cellData->IsColSpan()) {
    4449               0 :     aColIndex -= cellData->GetColSpanOffset();
    4450                 :     cellData =
    4451               0 :       static_cast<BCCellData*>(cellMap->GetDataAt(rgRowIndex, aColIndex));
    4452                 :   }
    4453               0 :   aAjaInfo.SetInfo(nextRow, aColIndex, cellData, this, cellMap);
    4454                 : }
    4455                 : 
    4456                 : // Assign priorities to border styles. For example, styleToPriority(NS_STYLE_BORDER_STYLE_SOLID)
    4457                 : // will return the priority of NS_STYLE_BORDER_STYLE_SOLID.
    4458                 : static PRUint8 styleToPriority[13] = { 0,  // NS_STYLE_BORDER_STYLE_NONE
    4459                 :                                        2,  // NS_STYLE_BORDER_STYLE_GROOVE
    4460                 :                                        4,  // NS_STYLE_BORDER_STYLE_RIDGE
    4461                 :                                        5,  // NS_STYLE_BORDER_STYLE_DOTTED
    4462                 :                                        6,  // NS_STYLE_BORDER_STYLE_DASHED
    4463                 :                                        7,  // NS_STYLE_BORDER_STYLE_SOLID
    4464                 :                                        8,  // NS_STYLE_BORDER_STYLE_DOUBLE
    4465                 :                                        1,  // NS_STYLE_BORDER_STYLE_INSET
    4466                 :                                        3,  // NS_STYLE_BORDER_STYLE_OUTSET
    4467                 :                                        9 };// NS_STYLE_BORDER_STYLE_HIDDEN
    4468                 : // priority rules follow CSS 2.1 spec
    4469                 : // 'hidden', 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove',
    4470                 : // and the lowest: 'inset'. none is even weaker
    4471                 : #define CELL_CORNER true
    4472                 : 
    4473                 : /** return the border style, border color for a given frame and side
    4474                 :   * @param aFrame           - query the info for this frame
    4475                 :   * @param aSide            - the side of the frame
    4476                 :   * @param aStyle           - the border style
    4477                 :   * @param aColor           - the border color
    4478                 :   * @param aTableIsLTR      - table direction is LTR
    4479                 :   */
    4480                 : static void
    4481               0 : GetColorAndStyle(const nsIFrame*  aFrame,
    4482                 :                  mozilla::css::Side aSide,
    4483                 :                  PRUint8&         aStyle,
    4484                 :                  nscolor&         aColor,
    4485                 :                  bool             aTableIsLTR)
    4486                 : {
    4487               0 :   NS_PRECONDITION(aFrame, "null frame");
    4488                 :   // initialize out arg
    4489               0 :   aColor = 0;
    4490               0 :   const nsStyleBorder* styleData = aFrame->GetStyleBorder();
    4491               0 :   if(!aTableIsLTR) { // revert the directions
    4492               0 :     if (NS_SIDE_RIGHT == aSide) {
    4493               0 :       aSide = NS_SIDE_LEFT;
    4494                 :     }
    4495               0 :     else if (NS_SIDE_LEFT == aSide) {
    4496               0 :       aSide = NS_SIDE_RIGHT;
    4497                 :     }
    4498                 :   }
    4499               0 :   aStyle = styleData->GetBorderStyle(aSide);
    4500                 : 
    4501               0 :   if ((NS_STYLE_BORDER_STYLE_NONE == aStyle) ||
    4502                 :       (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle)) {
    4503               0 :     return;
    4504                 :   }
    4505                 :   aColor = aFrame->GetStyleContext()->GetVisitedDependentColor(
    4506               0 :              nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color)[aSide]);
    4507                 : }
    4508                 : 
    4509                 : /** coerce the paint style as required by CSS2.1
    4510                 :   * @param aFrame           - query the info for this frame
    4511                 :   * @param aSide            - the side of the frame
    4512                 :   * @param aStyle           - the border style
    4513                 :   * @param aColor           - the border color
    4514                 :   * @param aTableIsLTR      - table direction is LTR
    4515                 :   */
    4516                 : static void
    4517               0 : GetPaintStyleInfo(const nsIFrame*  aFrame,
    4518                 :                   mozilla::css::Side aSide,
    4519                 :                   PRUint8&         aStyle,
    4520                 :                   nscolor&         aColor,
    4521                 :                   bool             aTableIsLTR)
    4522                 : {
    4523               0 :   GetColorAndStyle(aFrame, aSide, aStyle, aColor, aTableIsLTR);
    4524               0 :   if (NS_STYLE_BORDER_STYLE_INSET    == aStyle) {
    4525               0 :     aStyle = NS_STYLE_BORDER_STYLE_RIDGE;
    4526                 :   }
    4527               0 :   else if (NS_STYLE_BORDER_STYLE_OUTSET    == aStyle) {
    4528               0 :     aStyle = NS_STYLE_BORDER_STYLE_GROOVE;
    4529                 :   }
    4530               0 : }
    4531                 : 
    4532                 : /** return the border style, border color and the width in pixel for a given
    4533                 :   * frame and side
    4534                 :   * @param aFrame           - query the info for this frame
    4535                 :   * @param aSide            - the side of the frame
    4536                 :   * @param aStyle           - the border style
    4537                 :   * @param aColor           - the border color
    4538                 :   * @param aTableIsLTR      - table direction is LTR
    4539                 :   * @param aWidth           - the border width in px.
    4540                 :   * @param aTwipsToPixels   - conversion factor from twips to pixel
    4541                 :   */
    4542                 : static void
    4543               0 : GetColorAndStyle(const nsIFrame*  aFrame,
    4544                 :                  mozilla::css::Side aSide,
    4545                 :                  PRUint8&         aStyle,
    4546                 :                  nscolor&         aColor,
    4547                 :                  bool             aTableIsLTR,
    4548                 :                  BCPixelSize&     aWidth)
    4549                 : {
    4550               0 :   GetColorAndStyle(aFrame, aSide, aStyle, aColor, aTableIsLTR);
    4551               0 :   if ((NS_STYLE_BORDER_STYLE_NONE == aStyle) ||
    4552                 :       (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle)) {
    4553               0 :     aWidth = 0;
    4554               0 :     return;
    4555                 :   }
    4556               0 :   const nsStyleBorder* styleData = aFrame->GetStyleBorder();
    4557                 :   nscoord width;
    4558               0 :   if(!aTableIsLTR) { // revert the directions
    4559               0 :     if (NS_SIDE_RIGHT == aSide) {
    4560               0 :       aSide = NS_SIDE_LEFT;
    4561                 :     }
    4562               0 :     else if (NS_SIDE_LEFT == aSide) {
    4563               0 :       aSide = NS_SIDE_RIGHT;
    4564                 :     }
    4565                 :   }
    4566               0 :   width = styleData->GetActualBorderWidth(aSide);
    4567               0 :   aWidth = nsPresContext::AppUnitsToIntCSSPixels(width);
    4568                 : }
    4569                 : 
    4570               0 : class nsDelayedCalcBCBorders : public nsRunnable {
    4571                 : public:
    4572               0 :   nsDelayedCalcBCBorders(nsIFrame* aFrame) :
    4573               0 :     mFrame(aFrame) {}
    4574                 : 
    4575               0 :   NS_IMETHOD Run() {
    4576               0 :     if (mFrame) {
    4577               0 :       nsTableFrame* tableFrame = static_cast <nsTableFrame*>(mFrame.GetFrame());
    4578               0 :       if (tableFrame->NeedToCalcBCBorders()) {
    4579               0 :         tableFrame->CalcBCBorders();
    4580                 :       }
    4581                 :     }
    4582               0 :     return NS_OK;
    4583                 :   }
    4584                 : private:
    4585                 :   nsWeakFrame mFrame;
    4586                 : };
    4587                 : 
    4588                 : bool
    4589               0 : nsTableFrame::BCRecalcNeeded(nsStyleContext* aOldStyleContext,
    4590                 :                              nsStyleContext* aNewStyleContext)
    4591                 : {
    4592                 :   // Attention: the old style context is the one we're forgetting,
    4593                 :   // and hence possibly completely bogus for GetStyle* purposes.
    4594                 :   // We use PeekStyleData instead.
    4595                 : 
    4596               0 :   const nsStyleBorder* oldStyleData = aOldStyleContext->PeekStyleBorder();
    4597               0 :   if (!oldStyleData)
    4598               0 :     return false;
    4599                 : 
    4600               0 :   const nsStyleBorder* newStyleData = aNewStyleContext->GetStyleBorder();
    4601               0 :   nsChangeHint change = newStyleData->CalcDifference(*oldStyleData);
    4602               0 :   if (!change)
    4603               0 :     return false;
    4604               0 :   if (change & nsChangeHint_ReflowFrame)
    4605               0 :     return true; // the caller only needs to mark the bc damage area
    4606               0 :   if (change & nsChangeHint_RepaintFrame) {
    4607                 :     // we need to recompute the borders and the caller needs to mark
    4608                 :     // the bc damage area
    4609                 :     // XXX In principle this should only be necessary for border style changes
    4610                 :     // However the bc painting code tries to maximize the drawn border segments
    4611                 :     // so it stores in the cellmap where a new border segment starts and this
    4612                 :     // introduces a unwanted cellmap data dependence on color
    4613               0 :     nsCOMPtr<nsIRunnable> evt = new nsDelayedCalcBCBorders(this);
    4614               0 :     NS_DispatchToCurrentThread(evt);
    4615               0 :     return true;
    4616                 :   }
    4617               0 :   return false;
    4618                 : }
    4619                 : 
    4620                 : 
    4621                 : // Compare two border segments, this comparison depends whether the two
    4622                 : // segments meet at a corner and whether the second segment is horizontal.
    4623                 : // The return value is whichever of aBorder1 or aBorder2 dominates.
    4624                 : static const BCCellBorder&
    4625               0 : CompareBorders(bool                aIsCorner, // Pass true for corner calculations
    4626                 :                const BCCellBorder& aBorder1,
    4627                 :                const BCCellBorder& aBorder2,
    4628                 :                bool                aSecondIsHorizontal,
    4629                 :                bool*             aFirstDominates = nsnull)
    4630                 : {
    4631               0 :   bool firstDominates = true;
    4632                 : 
    4633               0 :   if (NS_STYLE_BORDER_STYLE_HIDDEN == aBorder1.style) {
    4634               0 :     firstDominates = (aIsCorner) ? false : true;
    4635                 :   }
    4636               0 :   else if (NS_STYLE_BORDER_STYLE_HIDDEN == aBorder2.style) {
    4637               0 :     firstDominates = (aIsCorner) ? true : false;
    4638                 :   }
    4639               0 :   else if (aBorder1.width < aBorder2.width) {
    4640               0 :     firstDominates = false;
    4641                 :   }
    4642               0 :   else if (aBorder1.width == aBorder2.width) {
    4643               0 :     if (styleToPriority[aBorder1.style] < styleToPriority[aBorder2.style]) {
    4644               0 :       firstDominates = false;
    4645                 :     }
    4646               0 :     else if (styleToPriority[aBorder1.style] == styleToPriority[aBorder2.style]) {
    4647               0 :       if (aBorder1.owner == aBorder2.owner) {
    4648               0 :         firstDominates = !aSecondIsHorizontal;
    4649                 :       }
    4650               0 :       else if (aBorder1.owner < aBorder2.owner) {
    4651               0 :         firstDominates = false;
    4652                 :       }
    4653                 :     }
    4654                 :   }
    4655                 : 
    4656               0 :   if (aFirstDominates)
    4657               0 :     *aFirstDominates = firstDominates;
    4658                 : 
    4659               0 :   if (firstDominates)
    4660               0 :     return aBorder1;
    4661               0 :   return aBorder2;
    4662                 : }
    4663                 : 
    4664                 : /** calc the dominant border by considering the table, row/col group, row/col,
    4665                 :   * cell.
    4666                 :   * Depending on whether the side is vertical or horizontal and whether
    4667                 :   * adjacent frames are taken into account the ownership of a single border
    4668                 :   * segment is defined. The return value is the dominating border
    4669                 :   * The cellmap stores only top and left borders for each cellmap position.
    4670                 :   * If the cell border is owned by the cell that is left of the border
    4671                 :   * it will be an adjacent owner aka eAjaCellOwner. See celldata.h for the other
    4672                 :   * scenarios with a adjacent owner.
    4673                 :   * @param xxxFrame         - the frame for style information, might be zero if
    4674                 :   *                           it should not be considered
    4675                 :   * @param aSide            - side of the frames that should be considered
    4676                 :   * @param aAja             - the border comparison takes place from the point of
    4677                 :   *                           a frame that is adjacent to the cellmap entry, for
    4678                 :   *                           when a cell owns its lower border it will be the
    4679                 :   *                           adjacent owner as in the cellmap only top and left
    4680                 :   *                           borders are stored.
    4681                 :   * @param aTwipsToPixels   - conversion factor as borders need to be drawn pixel
    4682                 :   *                           aligned.
    4683                 :   */
    4684                 : static BCCellBorder
    4685               0 : CompareBorders(const nsIFrame*  aTableFrame,
    4686                 :                const nsIFrame*  aColGroupFrame,
    4687                 :                const nsIFrame*  aColFrame,
    4688                 :                const nsIFrame*  aRowGroupFrame,
    4689                 :                const nsIFrame*  aRowFrame,
    4690                 :                const nsIFrame*  aCellFrame,
    4691                 :                bool             aTableIsLTR,
    4692                 :                mozilla::css::Side aSide,
    4693                 :                bool             aAja)
    4694                 : {
    4695               0 :   BCCellBorder border, tempBorder;
    4696               0 :   bool horizontal = (NS_SIDE_TOP == aSide) || (NS_SIDE_BOTTOM == aSide);
    4697                 : 
    4698                 :   // start with the table as dominant if present
    4699               0 :   if (aTableFrame) {
    4700               0 :     GetColorAndStyle(aTableFrame, aSide, border.style, border.color, aTableIsLTR, border.width);
    4701               0 :     border.owner = eTableOwner;
    4702               0 :     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
    4703               0 :       return border;
    4704                 :     }
    4705                 :   }
    4706                 :   // see if the colgroup is dominant
    4707               0 :   if (aColGroupFrame) {
    4708               0 :     GetColorAndStyle(aColGroupFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
    4709               0 :     tempBorder.owner = (aAja && !horizontal) ? eAjaColGroupOwner : eColGroupOwner;
    4710                 :     // pass here and below false for aSecondIsHorizontal as it is only used for corner calculations.
    4711               0 :     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
    4712               0 :     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
    4713               0 :       return border;
    4714                 :     }
    4715                 :   }
    4716                 :   // see if the col is dominant
    4717               0 :   if (aColFrame) {
    4718               0 :     GetColorAndStyle(aColFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
    4719               0 :     tempBorder.owner = (aAja && !horizontal) ? eAjaColOwner : eColOwner;
    4720               0 :     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
    4721               0 :     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
    4722               0 :       return border;
    4723                 :     }
    4724                 :   }
    4725                 :   // see if the rowgroup is dominant
    4726               0 :   if (aRowGroupFrame) {
    4727               0 :     GetColorAndStyle(aRowGroupFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
    4728               0 :     tempBorder.owner = (aAja && horizontal) ? eAjaRowGroupOwner : eRowGroupOwner;
    4729               0 :     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
    4730               0 :     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
    4731               0 :       return border;
    4732                 :     }
    4733                 :   }
    4734                 :   // see if the row is dominant
    4735               0 :   if (aRowFrame) {
    4736               0 :     GetColorAndStyle(aRowFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
    4737               0 :     tempBorder.owner = (aAja && horizontal) ? eAjaRowOwner : eRowOwner;
    4738               0 :     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
    4739               0 :     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
    4740               0 :       return border;
    4741                 :     }
    4742                 :   }
    4743                 :   // see if the cell is dominant
    4744               0 :   if (aCellFrame) {
    4745               0 :     GetColorAndStyle(aCellFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
    4746               0 :     tempBorder.owner = (aAja) ? eAjaCellOwner : eCellOwner;
    4747               0 :     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
    4748                 :   }
    4749               0 :   return border;
    4750                 : }
    4751                 : 
    4752                 : static bool
    4753               0 : Perpendicular(mozilla::css::Side aSide1,
    4754                 :               mozilla::css::Side aSide2)
    4755                 : {
    4756               0 :   switch (aSide1) {
    4757                 :   case NS_SIDE_TOP:
    4758               0 :     return (NS_SIDE_BOTTOM != aSide2);
    4759                 :   case NS_SIDE_RIGHT:
    4760               0 :     return (NS_SIDE_LEFT != aSide2);
    4761                 :   case NS_SIDE_BOTTOM:
    4762               0 :     return (NS_SIDE_TOP != aSide2);
    4763                 :   default: // NS_SIDE_LEFT
    4764               0 :     return (NS_SIDE_RIGHT != aSide2);
    4765                 :   }
    4766                 : }
    4767                 : 
    4768                 : // XXX allocate this as number-of-cols+1 instead of number-of-cols+1 * number-of-rows+1
    4769                 : struct BCCornerInfo
    4770                 : {
    4771               0 :   BCCornerInfo() { ownerColor = 0; ownerWidth = subWidth = ownerElem = subSide =
    4772               0 :                    subElem = hasDashDot = numSegs = bevel = 0; ownerSide = NS_SIDE_TOP;
    4773               0 :                    ownerStyle = 0xFF; subStyle = NS_STYLE_BORDER_STYLE_SOLID;  }
    4774                 :   void Set(mozilla::css::Side aSide,
    4775                 :            BCCellBorder  border);
    4776                 : 
    4777                 :   void Update(mozilla::css::Side aSide,
    4778                 :               BCCellBorder  border);
    4779                 : 
    4780                 :   nscolor   ownerColor;     // color of borderOwner
    4781                 :   PRUint16  ownerWidth;     // pixel width of borderOwner
    4782                 :   PRUint16  subWidth;       // pixel width of the largest border intersecting the border perpendicular
    4783                 :                             // to ownerSide
    4784                 :   PRUint32  ownerSide:2;    // mozilla::css::Side (e.g NS_SIDE_TOP, NS_SIDE_RIGHT, etc) of the border
    4785                 :                             // owning the corner relative to the corner
    4786                 :   PRUint32  ownerElem:3;    // elem type (e.g. eTable, eGroup, etc) owning the corner
    4787                 :   PRUint32  ownerStyle:8;   // border style of ownerElem
    4788                 :   PRUint32  subSide:2;      // side of border with subWidth relative to the corner
    4789                 :   PRUint32  subElem:3;      // elem type (e.g. eTable, eGroup, etc) of sub owner
    4790                 :   PRUint32  subStyle:8;     // border style of subElem
    4791                 :   PRUint32  hasDashDot:1;   // does a dashed, dotted segment enter the corner, they cannot be beveled
    4792                 :   PRUint32  numSegs:3;      // number of segments entering corner
    4793                 :   PRUint32  bevel:1;        // is the corner beveled (uses the above two fields together with subWidth)
    4794                 :   PRUint32  unused:1;
    4795                 : };
    4796                 : 
    4797                 : void
    4798               0 : BCCornerInfo::Set(mozilla::css::Side aSide,
    4799                 :                   BCCellBorder  aBorder)
    4800                 : {
    4801               0 :   ownerElem  = aBorder.owner;
    4802               0 :   ownerStyle = aBorder.style;
    4803               0 :   ownerWidth = aBorder.width;
    4804               0 :   ownerColor = aBorder.color;
    4805               0 :   ownerSide  = aSide;
    4806               0 :   hasDashDot = 0;
    4807               0 :   numSegs    = 0;
    4808               0 :   if (aBorder.width > 0) {
    4809               0 :     numSegs++;
    4810                 :     hasDashDot = (NS_STYLE_BORDER_STYLE_DASHED == aBorder.style) ||
    4811               0 :                  (NS_STYLE_BORDER_STYLE_DOTTED == aBorder.style);
    4812                 :   }
    4813               0 :   bevel      = 0;
    4814               0 :   subWidth   = 0;
    4815                 :   // the following will get set later
    4816               0 :   subSide    = ((aSide == NS_SIDE_LEFT) || (aSide == NS_SIDE_RIGHT)) ? NS_SIDE_TOP : NS_SIDE_LEFT;
    4817               0 :   subElem    = eTableOwner;
    4818               0 :   subStyle   = NS_STYLE_BORDER_STYLE_SOLID;
    4819               0 : }
    4820                 : 
    4821                 : void
    4822               0 : BCCornerInfo::Update(mozilla::css::Side aSide,
    4823                 :                      BCCellBorder  aBorder)
    4824                 : {
    4825               0 :   bool existingWins = false;
    4826               0 :   if (0xFF == ownerStyle) { // initial value indiating that it hasn't been set yet
    4827               0 :     Set(aSide, aBorder);
    4828                 :   }
    4829                 :   else {
    4830               0 :     bool horizontal = (NS_SIDE_LEFT == aSide) || (NS_SIDE_RIGHT == aSide); // relative to the corner
    4831               0 :     BCCellBorder oldBorder, tempBorder;
    4832               0 :     oldBorder.owner  = (BCBorderOwner) ownerElem;
    4833               0 :     oldBorder.style =  ownerStyle;
    4834               0 :     oldBorder.width =  ownerWidth;
    4835               0 :     oldBorder.color =  ownerColor;
    4836                 : 
    4837               0 :     mozilla::css::Side oldSide  = mozilla::css::Side(ownerSide);
    4838                 : 
    4839               0 :     tempBorder = CompareBorders(CELL_CORNER, oldBorder, aBorder, horizontal, &existingWins);
    4840                 : 
    4841               0 :     ownerElem  = tempBorder.owner;
    4842               0 :     ownerStyle = tempBorder.style;
    4843               0 :     ownerWidth = tempBorder.width;
    4844               0 :     ownerColor = tempBorder.color;
    4845               0 :     if (existingWins) { // existing corner is dominant
    4846               0 :       if (::Perpendicular(mozilla::css::Side(ownerSide), aSide)) {
    4847                 :         // see if the new sub info replaces the old
    4848               0 :         BCCellBorder subBorder;
    4849               0 :         subBorder.owner = (BCBorderOwner) subElem;
    4850               0 :         subBorder.style =  subStyle;
    4851               0 :         subBorder.width =  subWidth;
    4852               0 :         subBorder.color = 0; // we are not interested in subBorder color
    4853                 :         bool firstWins;
    4854                 : 
    4855               0 :         tempBorder = CompareBorders(CELL_CORNER, subBorder, aBorder, horizontal, &firstWins);
    4856                 : 
    4857               0 :         subElem  = tempBorder.owner;
    4858               0 :         subStyle = tempBorder.style;
    4859               0 :         subWidth = tempBorder.width;
    4860               0 :         if (!firstWins) {
    4861               0 :           subSide = aSide;
    4862                 :         }
    4863                 :       }
    4864                 :     }
    4865                 :     else { // input args are dominant
    4866               0 :       ownerSide = aSide;
    4867               0 :       if (::Perpendicular(oldSide, mozilla::css::Side(ownerSide))) {
    4868               0 :         subElem  = oldBorder.owner;
    4869               0 :         subStyle = oldBorder.style;
    4870               0 :         subWidth = oldBorder.width;
    4871               0 :         subSide  = oldSide;
    4872                 :       }
    4873                 :     }
    4874               0 :     if (aBorder.width > 0) {
    4875               0 :       numSegs++;
    4876               0 :       if (!hasDashDot && ((NS_STYLE_BORDER_STYLE_DASHED == aBorder.style) ||
    4877                 :                           (NS_STYLE_BORDER_STYLE_DOTTED == aBorder.style))) {
    4878               0 :         hasDashDot = 1;
    4879                 :       }
    4880                 :     }
    4881                 : 
    4882                 :     // bevel the corner if only two perpendicular non dashed/dotted segments enter the corner
    4883               0 :     bevel = (2 == numSegs) && (subWidth > 1) && (0 == hasDashDot);
    4884                 :   }
    4885               0 : }
    4886                 : 
    4887                 : struct BCCorners
    4888                 : {
    4889                 :   BCCorners(PRInt32 aNumCorners,
    4890                 :             PRInt32 aStartIndex);
    4891                 : 
    4892               0 :   ~BCCorners() { delete [] corners; }
    4893                 : 
    4894               0 :   BCCornerInfo& operator [](PRInt32 i) const
    4895               0 :   { NS_ASSERTION((i >= startIndex) && (i <= endIndex), "program error");
    4896               0 :     return corners[clamped(i, startIndex, endIndex) - startIndex]; }
    4897                 : 
    4898                 :   PRInt32       startIndex;
    4899                 :   PRInt32       endIndex;
    4900                 :   BCCornerInfo* corners;
    4901                 : };
    4902                 : 
    4903               0 : BCCorners::BCCorners(PRInt32 aNumCorners,
    4904                 :                      PRInt32 aStartIndex)
    4905                 : {
    4906               0 :   NS_ASSERTION((aNumCorners > 0) && (aStartIndex >= 0), "program error");
    4907               0 :   startIndex = aStartIndex;
    4908               0 :   endIndex   = aStartIndex + aNumCorners - 1;
    4909               0 :   corners    = new BCCornerInfo[aNumCorners];
    4910               0 : }
    4911                 : 
    4912                 : 
    4913                 : struct BCCellBorders
    4914                 : {
    4915                 :   BCCellBorders(PRInt32 aNumBorders,
    4916                 :                 PRInt32 aStartIndex);
    4917                 : 
    4918               0 :   ~BCCellBorders() { delete [] borders; }
    4919                 : 
    4920               0 :   BCCellBorder& operator [](PRInt32 i) const
    4921               0 :   { NS_ASSERTION((i >= startIndex) && (i <= endIndex), "program error");
    4922               0 :     return borders[clamped(i, startIndex, endIndex) - startIndex]; }
    4923                 : 
    4924                 :   PRInt32       startIndex;
    4925                 :   PRInt32       endIndex;
    4926                 :   BCCellBorder* borders;
    4927                 : };
    4928                 : 
    4929               0 : BCCellBorders::BCCellBorders(PRInt32 aNumBorders,
    4930                 :                              PRInt32 aStartIndex)
    4931                 : {
    4932               0 :   NS_ASSERTION((aNumBorders > 0) && (aStartIndex >= 0), "program error");
    4933               0 :   startIndex = aStartIndex;
    4934               0 :   endIndex   = aStartIndex + aNumBorders - 1;
    4935               0 :   borders    = new BCCellBorder[aNumBorders];
    4936               0 : }
    4937                 : 
    4938                 : // this function sets the new border properties and returns true if the border
    4939                 : // segment will start a new segment and not be accumulated into the previous
    4940                 : // segment.
    4941                 : static bool
    4942               0 : SetBorder(const BCCellBorder&   aNewBorder,
    4943                 :           BCCellBorder&         aBorder)
    4944                 : {
    4945                 :   bool changed = (aNewBorder.style != aBorder.style) ||
    4946                 :                    (aNewBorder.width != aBorder.width) ||
    4947               0 :                    (aNewBorder.color != aBorder.color);
    4948               0 :   aBorder.color        = aNewBorder.color;
    4949               0 :   aBorder.width        = aNewBorder.width;
    4950               0 :   aBorder.style        = aNewBorder.style;
    4951               0 :   aBorder.owner        = aNewBorder.owner;
    4952                 : 
    4953               0 :   return changed;
    4954                 : }
    4955                 : 
    4956                 : // this function will set the horizontal border. It will return true if the
    4957                 : // existing segment will not be continued. Having a vertical owner of a corner
    4958                 : // should also start a new segment.
    4959                 : static bool
    4960               0 : SetHorBorder(const BCCellBorder& aNewBorder,
    4961                 :              const BCCornerInfo& aCorner,
    4962                 :              BCCellBorder&       aBorder)
    4963                 : {
    4964               0 :   bool startSeg = ::SetBorder(aNewBorder, aBorder);
    4965               0 :   if (!startSeg) {
    4966               0 :     startSeg = ((NS_SIDE_LEFT != aCorner.ownerSide) && (NS_SIDE_RIGHT != aCorner.ownerSide));
    4967                 :   }
    4968               0 :   return startSeg;
    4969                 : }
    4970                 : 
    4971                 : // Make the damage area larger on the top and bottom by at least one row and on the left and right
    4972                 : // at least one column. This is done so that adjacent elements are part of the border calculations.
    4973                 : // The extra segments and borders outside the actual damage area will not be updated in the cell map,
    4974                 : // because they in turn would need info from adjacent segments outside the damage area to be accurate.
    4975                 : void
    4976               0 : nsTableFrame::ExpandBCDamageArea(nsIntRect& aRect) const
    4977                 : {
    4978               0 :   PRInt32 numRows = GetRowCount();
    4979               0 :   PRInt32 numCols = GetColCount();
    4980                 : 
    4981               0 :   PRInt32 dStartX = aRect.x;
    4982               0 :   PRInt32 dEndX   = aRect.XMost() - 1;
    4983               0 :   PRInt32 dStartY = aRect.y;
    4984               0 :   PRInt32 dEndY   = aRect.YMost() - 1;
    4985                 : 
    4986                 :   // expand the damage area in each direction
    4987               0 :   if (dStartX > 0) {
    4988               0 :     dStartX--;
    4989                 :   }
    4990               0 :   if (dEndX < (numCols - 1)) {
    4991               0 :     dEndX++;
    4992                 :   }
    4993               0 :   if (dStartY > 0) {
    4994               0 :     dStartY--;
    4995                 :   }
    4996               0 :   if (dEndY < (numRows - 1)) {
    4997               0 :     dEndY++;
    4998                 :   }
    4999                 :   // Check the damage area so that there are no cells spanning in or out. If there are any then
    5000                 :   // make the damage area as big as the table, similarly to the way the cell map decides whether
    5001                 :   // to rebuild versus expand. This could be optimized to expand to the smallest area that contains
    5002                 :   // no spanners, but it may not be worth the effort in general, and it would need to be done in the
    5003                 :   // cell map as well.
    5004               0 :   bool haveSpanner = false;
    5005               0 :   if ((dStartX > 0) || (dEndX < (numCols - 1)) || (dStartY > 0) || (dEndY < (numRows - 1))) {
    5006               0 :     nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
    5007                 :     // Get the ordered row groups
    5008               0 :     RowGroupArray rowGroups;
    5009               0 :     OrderRowGroups(rowGroups);
    5010                 : 
    5011                 :     // Scope outside loop to be used as hint.
    5012               0 :     nsCellMap* cellMap = nsnull;
    5013               0 :     for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
    5014               0 :       nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
    5015               0 :       PRInt32 rgStartY = rgFrame->GetStartRowIndex();
    5016               0 :       PRInt32 rgEndY   = rgStartY + rgFrame->GetRowCount() - 1;
    5017               0 :       if (dEndY < rgStartY)
    5018               0 :         break;
    5019               0 :       cellMap = tableCellMap->GetMapFor(rgFrame, cellMap);
    5020               0 :       if (!cellMap) ABORT0();
    5021                 :       // check for spanners from above and below
    5022               0 :       if ((dStartY > 0) && (dStartY >= rgStartY) && (dStartY <= rgEndY)) {
    5023               0 :         if (PRUint32(dStartY - rgStartY) >= cellMap->mRows.Length())
    5024               0 :           ABORT0();
    5025                 :         const nsCellMap::CellDataArray& row =
    5026               0 :           cellMap->mRows[dStartY - rgStartY];
    5027               0 :         for (PRInt32 x = dStartX; x <= dEndX; x++) {
    5028               0 :           CellData* cellData = row.SafeElementAt(x);
    5029               0 :           if (cellData && (cellData->IsRowSpan())) {
    5030               0 :              haveSpanner = true;
    5031               0 :              break;
    5032                 :           }
    5033                 :         }
    5034               0 :         if (dEndY < rgEndY) {
    5035               0 :           if (PRUint32(dEndY + 1 - rgStartY) >= cellMap->mRows.Length())
    5036               0 :             ABORT0();
    5037                 :           const nsCellMap::CellDataArray& row2 =
    5038               0 :             cellMap->mRows[dEndY + 1 - rgStartY];
    5039               0 :           for (PRInt32 x = dStartX; x <= dEndX; x++) {
    5040               0 :             CellData* cellData = row2.SafeElementAt(x);
    5041               0 :             if (cellData && (cellData->IsRowSpan())) {
    5042               0 :               haveSpanner = true;
    5043               0 :               break;
    5044                 :             }
    5045                 :           }
    5046                 :         }
    5047                 :       }
    5048                 :       // check for spanners on the left and right
    5049               0 :       PRInt32 iterStartY = -1;
    5050               0 :       PRInt32 iterEndY   = -1;
    5051               0 :       if ((dStartY >= rgStartY) && (dStartY <= rgEndY)) {
    5052                 :         // the damage area starts in the row group
    5053               0 :         iterStartY = dStartY;
    5054               0 :         iterEndY   = NS_MIN(dEndY, rgEndY);
    5055                 :       }
    5056               0 :       else if ((dEndY >= rgStartY) && (dEndY <= rgEndY)) {
    5057                 :         // the damage area ends in the row group
    5058               0 :         iterStartY = rgStartY;
    5059               0 :         iterEndY   = dEndY;
    5060                 :       }
    5061               0 :       else if ((rgStartY >= dStartY) && (rgEndY <= dEndY)) {
    5062                 :         // the damage area contains the row group
    5063               0 :         iterStartY = rgStartY;
    5064               0 :         iterEndY   = rgEndY;
    5065                 :       }
    5066               0 :       if ((iterStartY >= 0) && (iterEndY >= 0)) {
    5067               0 :         for (PRInt32 y = iterStartY; y <= iterEndY; y++) {
    5068               0 :           if (PRUint32(y - rgStartY) >= cellMap->mRows.Length())
    5069               0 :             ABORT0();
    5070                 :           const nsCellMap::CellDataArray& row =
    5071               0 :             cellMap->mRows[y - rgStartY];
    5072               0 :           CellData* cellData = row.SafeElementAt(dStartX);
    5073               0 :           if (cellData && (cellData->IsColSpan())) {
    5074               0 :             haveSpanner = true;
    5075               0 :             break;
    5076                 :           }
    5077               0 :           if (dEndX < (numCols - 1)) {
    5078               0 :             cellData = row.SafeElementAt(dEndX + 1);
    5079               0 :             if (cellData && (cellData->IsColSpan())) {
    5080               0 :               haveSpanner = true;
    5081               0 :               break;
    5082                 :             }
    5083                 :           }
    5084                 :         }
    5085                 :       }
    5086                 :     }
    5087                 :   }
    5088               0 :   if (haveSpanner) {
    5089                 :     // make the damage area the whole table
    5090               0 :     aRect.x      = 0;
    5091               0 :     aRect.y      = 0;
    5092               0 :     aRect.width  = numCols;
    5093               0 :     aRect.height = numRows;
    5094                 :   }
    5095                 :   else {
    5096               0 :     aRect.x      = dStartX;
    5097               0 :     aRect.y      = dStartY;
    5098               0 :     aRect.width  = 1 + dEndX - dStartX;
    5099               0 :     aRect.height = 1 + dEndY - dStartY;
    5100                 :   }
    5101                 : }
    5102                 : 
    5103                 : 
    5104                 : #define ADJACENT    true
    5105                 : #define HORIZONTAL  true
    5106                 : 
    5107                 : void
    5108               0 : BCMapCellInfo::SetTableTopLeftContBCBorder()
    5109                 : {
    5110               0 :   BCCellBorder currentBorder;
    5111                 :   //calculate continuous top first row & rowgroup border: special case
    5112                 :   //because it must include the table in the collapse
    5113               0 :   if (mTopRow) {
    5114                 :     currentBorder = CompareBorders(mTableFrame, nsnull, nsnull, mRowGroup,
    5115                 :                                    mTopRow, nsnull, mTableIsLTR,
    5116               0 :                                    NS_SIDE_TOP, !ADJACENT);
    5117               0 :     mTopRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, currentBorder.width);
    5118                 :   }
    5119               0 :   if (mCgAtRight && mColGroup) {
    5120                 :     //calculate continuous top colgroup border once per colgroup
    5121                 :     currentBorder = CompareBorders(mTableFrame, mColGroup, nsnull, mRowGroup,
    5122                 :                                    mTopRow, nsnull, mTableIsLTR,
    5123               0 :                                    NS_SIDE_TOP, !ADJACENT);
    5124               0 :     mColGroup->SetContinuousBCBorderWidth(NS_SIDE_TOP, currentBorder.width);
    5125                 :   }
    5126               0 :   if (0 == mColIndex) {
    5127                 :     currentBorder = CompareBorders(mTableFrame, mColGroup, mLeftCol, nsnull,
    5128                 :                                    nsnull, nsnull, mTableIsLTR, NS_SIDE_LEFT,
    5129               0 :                                    !ADJACENT);
    5130               0 :     mTableFrame->SetContinuousLeftBCBorderWidth(currentBorder.width);
    5131                 :   }
    5132               0 : }
    5133                 : 
    5134                 : void
    5135               0 : BCMapCellInfo::SetRowGroupLeftContBCBorder()
    5136                 : {
    5137               0 :   BCCellBorder currentBorder;
    5138                 :   //get row group continuous borders
    5139               0 :   if (mRgAtBottom && mRowGroup) { //once per row group, so check for bottom
    5140                 :      currentBorder = CompareBorders(mTableFrame, mColGroup, mLeftCol, mRowGroup,
    5141                 :                                     nsnull, nsnull, mTableIsLTR, NS_SIDE_LEFT,
    5142               0 :                                     !ADJACENT);
    5143               0 :      mRowGroup->SetContinuousBCBorderWidth(mStartSide, currentBorder.width);
    5144                 :   }
    5145               0 : }
    5146                 : 
    5147                 : void
    5148               0 : BCMapCellInfo::SetRowGroupRightContBCBorder()
    5149                 : {
    5150               0 :   BCCellBorder currentBorder;
    5151                 :   //get row group continuous borders
    5152               0 :   if (mRgAtBottom && mRowGroup) { //once per mRowGroup, so check for bottom
    5153                 :     currentBorder = CompareBorders(mTableFrame, mColGroup, mRightCol, mRowGroup,
    5154                 :                                    nsnull, nsnull, mTableIsLTR, NS_SIDE_RIGHT,
    5155               0 :                                    ADJACENT);
    5156               0 :     mRowGroup->SetContinuousBCBorderWidth(mEndSide, currentBorder.width);
    5157                 :   }
    5158               0 : }
    5159                 : 
    5160                 : void
    5161               0 : BCMapCellInfo::SetColumnTopRightContBCBorder()
    5162                 : {
    5163               0 :   BCCellBorder currentBorder;
    5164                 :   //calculate column continuous borders
    5165                 :   //we only need to do this once, so we'll do it only on the first row
    5166                 :   currentBorder = CompareBorders(mTableFrame, mCurrentColGroupFrame,
    5167                 :                                  mCurrentColFrame, mRowGroup, mTopRow, nsnull,
    5168               0 :                                  mTableIsLTR, NS_SIDE_TOP, !ADJACENT);
    5169                 :   ((nsTableColFrame*) mCurrentColFrame)->SetContinuousBCBorderWidth(NS_SIDE_TOP,
    5170               0 :                                                            currentBorder.width);
    5171               0 :   if (mNumTableCols == GetCellEndColIndex() + 1) {
    5172                 :     currentBorder = CompareBorders(mTableFrame, mCurrentColGroupFrame,
    5173                 :                                    mCurrentColFrame, nsnull, nsnull, nsnull,
    5174               0 :                                    mTableIsLTR, NS_SIDE_RIGHT, !ADJACENT);
    5175                 :   }
    5176                 :   else {
    5177                 :     currentBorder = CompareBorders(nsnull, mCurrentColGroupFrame,
    5178                 :                                    mCurrentColFrame, nsnull,nsnull, nsnull,
    5179               0 :                                    mTableIsLTR, NS_SIDE_RIGHT, !ADJACENT);
    5180                 :   }
    5181                 :   mCurrentColFrame->SetContinuousBCBorderWidth(NS_SIDE_RIGHT,
    5182               0 :                                                currentBorder.width);
    5183               0 : }
    5184                 : 
    5185                 : void
    5186               0 : BCMapCellInfo::SetColumnBottomContBCBorder()
    5187                 : {
    5188               0 :   BCCellBorder currentBorder;
    5189                 :   //get col continuous border
    5190                 :   currentBorder = CompareBorders(mTableFrame, mCurrentColGroupFrame,
    5191                 :                                  mCurrentColFrame, mRowGroup, mBottomRow,
    5192               0 :                                  nsnull, mTableIsLTR, NS_SIDE_BOTTOM, ADJACENT);
    5193                 :   mCurrentColFrame->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM,
    5194               0 :                                                currentBorder.width);
    5195               0 : }
    5196                 : 
    5197                 : void
    5198               0 : BCMapCellInfo::SetColGroupBottomContBCBorder()
    5199                 : {
    5200               0 :   BCCellBorder currentBorder;
    5201               0 :   if (mColGroup) {
    5202                 :     currentBorder = CompareBorders(mTableFrame, mColGroup, nsnull, mRowGroup,
    5203                 :                                    mBottomRow, nsnull, mTableIsLTR,
    5204               0 :                                    NS_SIDE_BOTTOM, ADJACENT);
    5205               0 :     mColGroup->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, currentBorder.width);
    5206                 :   }
    5207               0 : }
    5208                 : 
    5209                 : void
    5210               0 : BCMapCellInfo::SetRowGroupBottomContBCBorder()
    5211                 : {
    5212               0 :   BCCellBorder currentBorder;
    5213               0 :   if (mRowGroup) {
    5214                 :     currentBorder = CompareBorders(mTableFrame, nsnull, nsnull, mRowGroup,
    5215                 :                                    mBottomRow, nsnull, mTableIsLTR,
    5216               0 :                                    NS_SIDE_BOTTOM, ADJACENT);
    5217               0 :     mRowGroup->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, currentBorder.width);
    5218                 :   }
    5219               0 : }
    5220                 : 
    5221                 : void
    5222               0 : BCMapCellInfo::SetInnerRowGroupBottomContBCBorder(const nsIFrame* aNextRowGroup,
    5223                 :                                                   nsTableRowFrame* aNextRow)
    5224                 : {
    5225               0 :   BCCellBorder currentBorder, adjacentBorder;
    5226                 : 
    5227               0 :   const nsIFrame* rowgroup = (mRgAtBottom) ? mRowGroup : nsnull;
    5228                 :   currentBorder = CompareBorders(nsnull, nsnull, nsnull, rowgroup, mBottomRow,
    5229               0 :                                  nsnull, mTableIsLTR, NS_SIDE_BOTTOM, ADJACENT);
    5230                 : 
    5231                 :   adjacentBorder = CompareBorders(nsnull, nsnull, nsnull, aNextRowGroup,
    5232                 :                                   aNextRow, nsnull, mTableIsLTR, NS_SIDE_TOP,
    5233               0 :                                   !ADJACENT);
    5234                 :   currentBorder = CompareBorders(false, currentBorder, adjacentBorder,
    5235               0 :                                  HORIZONTAL);
    5236               0 :   if (aNextRow) {
    5237               0 :     aNextRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, currentBorder.width);
    5238                 :   }
    5239               0 :   if (mRgAtBottom && mRowGroup) {
    5240               0 :     mRowGroup->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, currentBorder.width);
    5241                 :   }
    5242               0 : }
    5243                 : 
    5244                 : void
    5245               0 : BCMapCellInfo::SetRowLeftContBCBorder()
    5246                 : {
    5247                 :   //get row continuous borders
    5248               0 :   if (mCurrentRowFrame) {
    5249               0 :     BCCellBorder currentBorder;
    5250                 :     currentBorder = CompareBorders(mTableFrame, mColGroup, mLeftCol, mRowGroup,
    5251                 :                                    mCurrentRowFrame, nsnull, mTableIsLTR,
    5252               0 :                                    NS_SIDE_LEFT, !ADJACENT);
    5253                 :     mCurrentRowFrame->SetContinuousBCBorderWidth(mStartSide,
    5254               0 :                                                  currentBorder.width);
    5255                 :   }
    5256               0 : }
    5257                 : 
    5258                 : void
    5259               0 : BCMapCellInfo::SetRowRightContBCBorder()
    5260                 : {
    5261               0 :   if (mCurrentRowFrame) {
    5262               0 :     BCCellBorder currentBorder;
    5263                 :     currentBorder = CompareBorders(mTableFrame, mColGroup, mRightCol, mRowGroup,
    5264                 :                                    mCurrentRowFrame, nsnull, mTableIsLTR,
    5265               0 :                                    NS_SIDE_RIGHT, ADJACENT);
    5266                 :     mCurrentRowFrame->SetContinuousBCBorderWidth(mEndSide,
    5267               0 :                                                  currentBorder.width);
    5268                 :   }
    5269               0 : }
    5270                 : void
    5271               0 : BCMapCellInfo::SetTableTopBorderWidth(BCPixelSize aWidth)
    5272                 : {
    5273               0 :   mTableBCData->mTopBorderWidth = NS_MAX(mTableBCData->mTopBorderWidth, aWidth);
    5274               0 : }
    5275                 : 
    5276                 : void
    5277               0 : BCMapCellInfo::SetTableLeftBorderWidth(PRInt32 aRowY, BCPixelSize aWidth)
    5278                 : {
    5279                 :   // update the left/right first cell border
    5280               0 :   if (aRowY == 0) {
    5281               0 :     if (mTableIsLTR) {
    5282               0 :       mTableBCData->mLeftCellBorderWidth = aWidth;
    5283                 :     }
    5284                 :     else {
    5285               0 :       mTableBCData->mRightCellBorderWidth = aWidth;
    5286                 :     }
    5287                 :   }
    5288                 :   mTableBCData->mLeftBorderWidth = NS_MAX(mTableBCData->mLeftBorderWidth,
    5289               0 :                                           aWidth);
    5290               0 : }
    5291                 : 
    5292                 : void
    5293               0 : BCMapCellInfo::SetTableRightBorderWidth(PRInt32 aRowY, BCPixelSize aWidth)
    5294                 : {
    5295                 :   // update the left/right first cell border
    5296               0 :   if (aRowY == 0) {
    5297               0 :     if (mTableIsLTR) {
    5298               0 :       mTableBCData->mRightCellBorderWidth = aWidth;
    5299                 :     }
    5300                 :     else {
    5301               0 :       mTableBCData->mLeftCellBorderWidth = aWidth;
    5302                 :     }
    5303                 :   }
    5304                 :   mTableBCData->mRightBorderWidth = NS_MAX(mTableBCData->mRightBorderWidth,
    5305               0 :                                            aWidth);
    5306               0 : }
    5307                 : 
    5308                 : void
    5309               0 : BCMapCellInfo::SetRightBorderWidths(BCPixelSize aWidth)
    5310                 : {
    5311                 :    // update the borders of the cells and cols affected
    5312               0 :   if (mCell) {
    5313                 :     mCell->SetBorderWidth(mEndSide, NS_MAX(aWidth,
    5314               0 :                           mCell->GetBorderWidth(mEndSide)));
    5315                 :   }
    5316               0 :   if (mRightCol) {
    5317               0 :     BCPixelSize half = BC_BORDER_LEFT_HALF(aWidth);
    5318                 :     mRightCol->SetRightBorderWidth(NS_MAX(nscoord(half),
    5319               0 :                                    mRightCol->GetRightBorderWidth()));
    5320                 :   }
    5321               0 : }
    5322                 : 
    5323                 : void
    5324               0 : BCMapCellInfo::SetBottomBorderWidths(BCPixelSize aWidth)
    5325                 : {
    5326                 :   // update the borders of the affected cells and rows
    5327               0 :   if (mCell) {
    5328                 :     mCell->SetBorderWidth(NS_SIDE_BOTTOM, NS_MAX(aWidth,
    5329               0 :                           mCell->GetBorderWidth(NS_SIDE_BOTTOM)));
    5330                 :   }
    5331               0 :   if (mBottomRow) {
    5332               0 :     BCPixelSize half = BC_BORDER_TOP_HALF(aWidth);
    5333                 :     mBottomRow->SetBottomBCBorderWidth(NS_MAX(nscoord(half),
    5334               0 :                                        mBottomRow->GetBottomBCBorderWidth()));
    5335                 :   }
    5336               0 : }
    5337                 : void
    5338               0 : BCMapCellInfo::SetTopBorderWidths(BCPixelSize aWidth)
    5339                 : {
    5340               0 :  if (mCell) {
    5341                 :      mCell->SetBorderWidth(NS_SIDE_TOP, NS_MAX(aWidth,
    5342               0 :                            mCell->GetBorderWidth(NS_SIDE_TOP)));
    5343                 :   }
    5344               0 :   if (mTopRow) {
    5345               0 :     BCPixelSize half = BC_BORDER_BOTTOM_HALF(aWidth);
    5346                 :     mTopRow->SetTopBCBorderWidth(NS_MAX(nscoord(half),
    5347               0 :                                         mTopRow->GetTopBCBorderWidth()));
    5348                 :   }
    5349               0 : }
    5350                 : void
    5351               0 : BCMapCellInfo::SetLeftBorderWidths(BCPixelSize aWidth)
    5352                 : {
    5353               0 :   if (mCell) {
    5354                 :     mCell->SetBorderWidth(mStartSide, NS_MAX(aWidth,
    5355               0 :                           mCell->GetBorderWidth(mStartSide)));
    5356                 :   }
    5357               0 :   if (mLeftCol) {
    5358               0 :     BCPixelSize half = BC_BORDER_RIGHT_HALF(aWidth);
    5359                 :     mLeftCol->SetLeftBorderWidth(NS_MAX(nscoord(half),
    5360               0 :                                         mLeftCol->GetLeftBorderWidth()));
    5361                 :   }
    5362               0 : }
    5363                 : 
    5364                 : void
    5365               0 : BCMapCellInfo::SetTableBottomBorderWidth(BCPixelSize aWidth)
    5366                 : {
    5367                 :   mTableBCData->mBottomBorderWidth = NS_MAX(mTableBCData->mBottomBorderWidth,
    5368               0 :                                             aWidth);
    5369               0 : }
    5370                 : 
    5371                 : void
    5372               0 : BCMapCellInfo::SetColumn(PRInt32 aColX)
    5373                 : {
    5374               0 :   mCurrentColFrame = mTableFrame->GetColFrame(aColX);
    5375               0 :   if (!mCurrentColFrame) {
    5376               0 :     NS_ERROR("null mCurrentColFrame");
    5377                 :   }
    5378                 :   mCurrentColGroupFrame = static_cast<nsTableColGroupFrame*>
    5379               0 :                             (mCurrentColFrame->GetParent());
    5380               0 :   if (!mCurrentColGroupFrame) {
    5381               0 :     NS_ERROR("null mCurrentColGroupFrame");
    5382                 :   }
    5383               0 : }
    5384                 : 
    5385                 : void
    5386               0 : BCMapCellInfo::IncrementRow(bool aResetToTopRowOfCell)
    5387                 : {
    5388                 :   mCurrentRowFrame = (aResetToTopRowOfCell) ? mTopRow :
    5389               0 :                                                 mCurrentRowFrame->GetNextRow();
    5390               0 : }
    5391                 : 
    5392                 : BCCellBorder
    5393               0 : BCMapCellInfo::GetTopEdgeBorder()
    5394                 : {
    5395                 :   return CompareBorders(mTableFrame, mCurrentColGroupFrame, mCurrentColFrame,
    5396                 :                         mRowGroup, mTopRow, mCell, mTableIsLTR, NS_SIDE_TOP,
    5397               0 :                         !ADJACENT);
    5398                 : }
    5399                 : 
    5400                 : BCCellBorder
    5401               0 : BCMapCellInfo::GetBottomEdgeBorder()
    5402                 : {
    5403                 :   return CompareBorders(mTableFrame, mCurrentColGroupFrame, mCurrentColFrame,
    5404                 :                         mRowGroup, mBottomRow, mCell, mTableIsLTR,
    5405               0 :                         NS_SIDE_BOTTOM, ADJACENT);
    5406                 : }
    5407                 : BCCellBorder
    5408               0 : BCMapCellInfo::GetLeftEdgeBorder()
    5409                 : {
    5410                 :   return CompareBorders(mTableFrame, mColGroup, mLeftCol, mRowGroup,
    5411                 :                         mCurrentRowFrame, mCell, mTableIsLTR, NS_SIDE_LEFT,
    5412               0 :                         !ADJACENT);
    5413                 : }
    5414                 : BCCellBorder
    5415               0 : BCMapCellInfo::GetRightEdgeBorder()
    5416                 : {
    5417                 :   return CompareBorders(mTableFrame, mColGroup, mRightCol, mRowGroup,
    5418                 :                         mCurrentRowFrame, mCell, mTableIsLTR, NS_SIDE_RIGHT,
    5419               0 :                         ADJACENT);
    5420                 : }
    5421                 : BCCellBorder
    5422               0 : BCMapCellInfo::GetRightInternalBorder()
    5423                 : {
    5424               0 :   const nsIFrame* cg = (mCgAtRight) ? mColGroup : nsnull;
    5425                 :   return CompareBorders(nsnull, cg, mRightCol, nsnull, nsnull, mCell,
    5426               0 :                         mTableIsLTR, NS_SIDE_RIGHT, ADJACENT);
    5427                 : }
    5428                 : 
    5429                 : BCCellBorder
    5430               0 : BCMapCellInfo::GetLeftInternalBorder()
    5431                 : {
    5432               0 :   const nsIFrame* cg = (mCgAtLeft) ? mColGroup : nsnull;
    5433                 :   return CompareBorders(nsnull, cg, mLeftCol, nsnull, nsnull, mCell,
    5434               0 :                         mTableIsLTR, NS_SIDE_LEFT, !ADJACENT);
    5435                 : }
    5436                 : 
    5437                 : BCCellBorder
    5438               0 : BCMapCellInfo::GetBottomInternalBorder()
    5439                 : {
    5440               0 :   const nsIFrame* rg = (mRgAtBottom) ? mRowGroup : nsnull;
    5441                 :   return CompareBorders(nsnull, nsnull, nsnull, rg, mBottomRow, mCell,
    5442               0 :                         mTableIsLTR, NS_SIDE_BOTTOM, ADJACENT);
    5443                 : }
    5444                 : 
    5445                 : BCCellBorder
    5446               0 : BCMapCellInfo::GetTopInternalBorder()
    5447                 : {
    5448               0 :   const nsIFrame* rg = (mRgAtTop) ? mRowGroup : nsnull;
    5449                 :   return CompareBorders(nsnull, nsnull, nsnull, rg, mTopRow, mCell,
    5450               0 :                         mTableIsLTR, NS_SIDE_TOP, !ADJACENT);
    5451                 : }
    5452                 : 
    5453                 : /* Here is the order for storing border edges in the cell map as a cell is processed. There are
    5454                 :    n=colspan top and bottom border edges per cell and n=rowspan left and right border edges per cell.
    5455                 : 
    5456                 :    1) On the top edge of the table, store the top edge. Never store the top edge otherwise, since
    5457                 :       a bottom edge from a cell above will take care of it.
    5458                 :    2) On the left edge of the table, store the left edge. Never store the left edge othewise, since
    5459                 :       a right edge from a cell to the left will take care of it.
    5460                 :    3) Store the right edge (or edges if a row span)
    5461                 :    4) Store the bottom edge (or edges if a col span)
    5462                 : 
    5463                 :    Since corners are computed with only an array of BCCornerInfo indexed by the number-of-cols, corner
    5464                 :    calculations are somewhat complicated. Using an array with number-of-rows * number-of-col entries
    5465                 :    would simplify this, but at an extra in memory cost of nearly 12 bytes per cell map entry. Collapsing
    5466                 :    borders already have about an extra 8 byte per cell map entry overhead (this could be
    5467                 :    reduced to 4 bytes if we are willing to not store border widths in nsTableCellFrame), Here are the
    5468                 :    rules in priority order for storing cornes in the cell map as a cell is processed. top-left means the
    5469                 :    left endpoint of the border edge on the top of the cell. There are n=colspan top and bottom border
    5470                 :    edges per cell and n=rowspan left and right border edges per cell.
    5471                 : 
    5472                 :    1) On the top edge of the table, store the top-left corner, unless on the left edge of the table.
    5473                 :       Never store the top-right corner, since it will get stored as a right-top corner.
    5474                 :    2) On the left edge of the table, store the left-top corner. Never store the left-bottom corner,
    5475                 :       since it will get stored as a bottom-left corner.
    5476                 :    3) Store the right-top corner if (a) it is the top right corner of the table or (b) it is not on
    5477                 :       the top edge of the table. Never store the right-bottom corner since it will get stored as a
    5478                 :       bottom-right corner.
    5479                 :    4) Store the bottom-right corner, if it is the bottom right corner of the table. Never store it
    5480                 :       otherwise, since it will get stored as either a right-top corner by a cell below or
    5481                 :       a bottom-left corner from a cell to the right.
    5482                 :    5) Store the bottom-left corner, if (a) on the bottom edge of the table or (b) if the left edge hits
    5483                 :       the top side of a colspan in its interior. Never store the corner otherwise, since it will
    5484                 :       get stored as a right-top corner by a cell from below.
    5485                 : 
    5486                 :    XXX the BC-RTL hack - The correct fix would be a rewrite as described in bug 203686.
    5487                 :    In order to draw borders in rtl conditions somehow correct, the existing structure which relies
    5488                 :    heavily on the assumption that the next cell sibling will be on the right side, has been modified.
    5489                 :    We flip the border during painting and during style lookup. Look for tableIsLTR for places where
    5490                 :    the flipping is done.
    5491                 :  */
    5492                 : 
    5493                 : 
    5494                 : 
    5495                 : // Calc the dominant border at every cell edge and corner within the current damage area
    5496                 : void
    5497               0 : nsTableFrame::CalcBCBorders()
    5498                 : {
    5499               0 :   NS_ASSERTION(IsBorderCollapse(),
    5500                 :                "calling CalcBCBorders on separated-border table");
    5501               0 :   nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
    5502               0 :   PRInt32 numRows = GetRowCount();
    5503               0 :   PRInt32 numCols = GetColCount();
    5504               0 :   if (!numRows || !numCols)
    5505               0 :     return; // nothing to do
    5506                 : 
    5507                 :   // Get the property holding the table damage area and border widths
    5508               0 :   BCPropertyData* propData = GetBCProperty();
    5509               0 :   if (!propData) ABORT0();
    5510                 : 
    5511                 : 
    5512                 : 
    5513                 :   // calculate an expanded damage area
    5514               0 :   nsIntRect damageArea(propData->mDamageArea);
    5515               0 :   ExpandBCDamageArea(damageArea);
    5516                 : 
    5517                 :   // segments that are on the table border edges need
    5518                 :   // to be initialized only once
    5519                 :   bool tableBorderReset[4];
    5520               0 :   for (PRUint32 sideX = NS_SIDE_TOP; sideX <= NS_SIDE_LEFT; sideX++) {
    5521               0 :     tableBorderReset[sideX] = false;
    5522                 :   }
    5523                 : 
    5524                 :   // vertical borders indexed in x-direction (cols)
    5525               0 :   BCCellBorders lastVerBorders(damageArea.width + 1, damageArea.x);
    5526               0 :   if (!lastVerBorders.borders) ABORT0();
    5527               0 :   BCCellBorder  lastTopBorder, lastBottomBorder;
    5528                 :   // horizontal borders indexed in x-direction (cols)
    5529               0 :   BCCellBorders lastBottomBorders(damageArea.width + 1, damageArea.x);
    5530               0 :   if (!lastBottomBorders.borders) ABORT0();
    5531                 :   bool startSeg;
    5532               0 :   bool gotRowBorder = false;
    5533                 : 
    5534               0 :   BCMapCellInfo  info(this), ajaInfo(this);
    5535                 : 
    5536               0 :   BCCellBorder currentBorder, adjacentBorder;
    5537               0 :   BCCorners topCorners(damageArea.width + 1, damageArea.x);
    5538               0 :   if (!topCorners.corners) ABORT0();
    5539               0 :   BCCorners bottomCorners(damageArea.width + 1, damageArea.x);
    5540               0 :   if (!bottomCorners.corners) ABORT0();
    5541                 : 
    5542               0 :   BCMapCellIterator iter(this, damageArea);
    5543               0 :   for (iter.First(info); !iter.mAtEnd; iter.Next(info)) {
    5544                 :     // see if lastTopBorder, lastBottomBorder need to be reset
    5545               0 :     if (iter.IsNewRow()) {
    5546               0 :       gotRowBorder = false;
    5547               0 :       lastTopBorder.Reset(info.mRowIndex, info.mRowSpan);
    5548               0 :       lastBottomBorder.Reset(info.GetCellEndRowIndex() + 1, info.mRowSpan);
    5549                 :     }
    5550               0 :     else if (info.mColIndex > damageArea.x) {
    5551               0 :       lastBottomBorder = lastBottomBorders[info.mColIndex - 1];
    5552               0 :       if (info.mRowIndex >
    5553                 :           (lastBottomBorder.rowIndex - lastBottomBorder.rowSpan)) {
    5554                 :         // the top border's left edge butts against the middle of a rowspan
    5555               0 :         lastTopBorder.Reset(info.mRowIndex, info.mRowSpan);
    5556                 :       }
    5557               0 :       if (lastBottomBorder.rowIndex > (info.GetCellEndRowIndex() + 1)) {
    5558                 :         // the bottom border's left edge butts against the middle of a rowspan
    5559               0 :         lastBottomBorder.Reset(info.GetCellEndRowIndex() + 1, info.mRowSpan);
    5560                 :       }
    5561                 :     }
    5562                 : 
    5563                 :     // find the dominant border considering the cell's top border and the table,
    5564                 :     // row group, row if the border is at the top of the table, otherwise it was
    5565                 :     // processed in a previous row
    5566               0 :     if (0 == info.mRowIndex) {
    5567               0 :       if (!tableBorderReset[NS_SIDE_TOP]) {
    5568               0 :         propData->mTopBorderWidth = 0;
    5569               0 :         tableBorderReset[NS_SIDE_TOP] = true;
    5570                 :       }
    5571               0 :       for (PRInt32 colX = info.mColIndex; colX <= info.GetCellEndColIndex();
    5572                 :            colX++) {
    5573               0 :         info.SetColumn(colX);
    5574               0 :         currentBorder = info.GetTopEdgeBorder();
    5575                 :         // update/store the top left & top right corners of the seg
    5576               0 :         BCCornerInfo& tlCorner = topCorners[colX]; // top left
    5577               0 :         if (0 == colX) {
    5578                 :           // we are on right hand side of the corner
    5579               0 :           tlCorner.Set(NS_SIDE_RIGHT, currentBorder);
    5580                 :         }
    5581                 :         else {
    5582               0 :           tlCorner.Update(NS_SIDE_RIGHT, currentBorder);
    5583                 :           tableCellMap->SetBCBorderCorner(eTopLeft, *iter.mCellMap, 0, 0, colX,
    5584                 :                                           mozilla::css::Side(tlCorner.ownerSide),
    5585                 :                                           tlCorner.subWidth,
    5586               0 :                                           tlCorner.bevel);
    5587                 :         }
    5588               0 :         topCorners[colX + 1].Set(NS_SIDE_LEFT, currentBorder); // top right
    5589                 :         // update lastTopBorder and see if a new segment starts
    5590               0 :         startSeg = SetHorBorder(currentBorder, tlCorner, lastTopBorder);
    5591                 :         // store the border segment in the cell map
    5592                 :         tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *iter.mCellMap, 0, 0, colX,
    5593                 :                                       1, currentBorder.owner,
    5594               0 :                                       currentBorder.width, startSeg);
    5595                 : 
    5596               0 :         info.SetTableTopBorderWidth(currentBorder.width);
    5597               0 :         info.SetTopBorderWidths(currentBorder.width);
    5598               0 :         info.SetColumnTopRightContBCBorder();
    5599                 :       }
    5600               0 :       info.SetTableTopLeftContBCBorder();
    5601                 :     }
    5602                 :     else {
    5603                 :       // see if the top border needs to be the start of a segment due to a
    5604                 :       // vertical border owning the corner
    5605               0 :       if (info.mColIndex > 0) {
    5606               0 :         BCData& data = info.mCellData->mData;
    5607               0 :         if (!data.IsTopStart()) {
    5608                 :           mozilla::css::Side cornerSide;
    5609                 :           bool bevel;
    5610               0 :           data.GetCorner(cornerSide, bevel);
    5611               0 :           if ((NS_SIDE_TOP == cornerSide) || (NS_SIDE_BOTTOM == cornerSide)) {
    5612               0 :             data.SetTopStart(true);
    5613                 :           }
    5614                 :         }
    5615                 :       }
    5616                 :     }
    5617                 : 
    5618                 :     // find the dominant border considering the cell's left border and the
    5619                 :     // table, col group, col if the border is at the left of the table,
    5620                 :     // otherwise it was processed in a previous col
    5621               0 :     if (0 == info.mColIndex) {
    5622               0 :       if (!tableBorderReset[NS_SIDE_LEFT]) {
    5623               0 :         propData->mLeftBorderWidth = 0;
    5624               0 :         tableBorderReset[NS_SIDE_LEFT] = true;
    5625                 :       }
    5626               0 :       info.mCurrentRowFrame = nsnull;
    5627               0 :       for (PRInt32 rowY = info.mRowIndex; rowY <= info.GetCellEndRowIndex();
    5628                 :            rowY++) {
    5629               0 :         info.IncrementRow(rowY == info.mRowIndex);
    5630               0 :         currentBorder = info.GetLeftEdgeBorder();
    5631               0 :         BCCornerInfo& tlCorner = (0 == rowY) ? topCorners[0] : bottomCorners[0];
    5632               0 :         tlCorner.Update(NS_SIDE_BOTTOM, currentBorder);
    5633                 :         tableCellMap->SetBCBorderCorner(eTopLeft, *iter.mCellMap,
    5634                 :                                         iter.mRowGroupStart, rowY, 0,
    5635                 :                                         mozilla::css::Side(tlCorner.ownerSide),
    5636                 :                                         tlCorner.subWidth,
    5637               0 :                                         tlCorner.bevel);
    5638               0 :         bottomCorners[0].Set(NS_SIDE_TOP, currentBorder); // bottom left
    5639                 : 
    5640                 :         // update lastVerBordersBorder and see if a new segment starts
    5641               0 :         startSeg = SetBorder(currentBorder, lastVerBorders[0]);
    5642                 :         // store the border segment in the cell map
    5643                 :         tableCellMap->SetBCBorderEdge(NS_SIDE_LEFT, *iter.mCellMap,
    5644                 :                                       iter.mRowGroupStart, rowY, info.mColIndex,
    5645                 :                                       1, currentBorder.owner,
    5646               0 :                                       currentBorder.width, startSeg);
    5647               0 :         info.SetTableLeftBorderWidth(rowY , currentBorder.width);
    5648               0 :         info.SetLeftBorderWidths(currentBorder.width);
    5649               0 :         info.SetRowLeftContBCBorder();
    5650                 :       }
    5651               0 :       info.SetRowGroupLeftContBCBorder();
    5652                 :     }
    5653                 : 
    5654                 :     // find the dominant border considering the cell's right border, adjacent
    5655                 :     // cells and the table, row group, row
    5656               0 :     if (info.mNumTableCols == info.GetCellEndColIndex() + 1) {
    5657                 :       // touches right edge of table
    5658               0 :       if (!tableBorderReset[NS_SIDE_RIGHT]) {
    5659               0 :         propData->mRightBorderWidth = 0;
    5660               0 :         tableBorderReset[NS_SIDE_RIGHT] = true;
    5661                 :       }
    5662               0 :       info.mCurrentRowFrame = nsnull;
    5663               0 :       for (PRInt32 rowY = info.mRowIndex; rowY <= info.GetCellEndRowIndex();
    5664                 :            rowY++) {
    5665               0 :         info.IncrementRow(rowY == info.mRowIndex);
    5666               0 :         currentBorder = info.GetRightEdgeBorder();
    5667                 :         // update/store the top right & bottom right corners
    5668                 :         BCCornerInfo& trCorner = (0 == rowY) ?
    5669               0 :                                  topCorners[info.GetCellEndColIndex() + 1] :
    5670               0 :                                  bottomCorners[info.GetCellEndColIndex() + 1];
    5671               0 :         trCorner.Update(NS_SIDE_BOTTOM, currentBorder);   // top right
    5672                 :         tableCellMap->SetBCBorderCorner(eTopRight, *iter.mCellMap,
    5673                 :                                         iter.mRowGroupStart, rowY,
    5674               0 :                                         info.GetCellEndColIndex(),
    5675                 :                                         mozilla::css::Side(trCorner.ownerSide),
    5676                 :                                         trCorner.subWidth,
    5677               0 :                                         trCorner.bevel);
    5678               0 :         BCCornerInfo& brCorner = bottomCorners[info.GetCellEndColIndex() + 1];
    5679               0 :         brCorner.Set(NS_SIDE_TOP, currentBorder); // bottom right
    5680                 :         tableCellMap->SetBCBorderCorner(eBottomRight, *iter.mCellMap,
    5681                 :                                         iter.mRowGroupStart, rowY,
    5682               0 :                                         info.GetCellEndColIndex(),
    5683                 :                                         mozilla::css::Side(brCorner.ownerSide),
    5684                 :                                         brCorner.subWidth,
    5685               0 :                                         brCorner.bevel);
    5686                 :         // update lastVerBorders and see if a new segment starts
    5687                 :         startSeg = SetBorder(currentBorder,
    5688               0 :                              lastVerBorders[info.GetCellEndColIndex() + 1]);
    5689                 :         // store the border segment in the cell map and update cellBorders
    5690                 :         tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *iter.mCellMap,
    5691                 :                                       iter.mRowGroupStart, rowY,
    5692               0 :                                       info.GetCellEndColIndex(), 1,
    5693                 :                                       currentBorder.owner, currentBorder.width,
    5694               0 :                                       startSeg);
    5695               0 :         info.SetTableRightBorderWidth(rowY, currentBorder.width);
    5696               0 :         info.SetRightBorderWidths(currentBorder.width);
    5697               0 :         info.SetRowRightContBCBorder();
    5698                 :       }
    5699               0 :       info.SetRowGroupRightContBCBorder();
    5700                 :     }
    5701                 :     else {
    5702               0 :       PRInt32 segLength = 0;
    5703               0 :       BCMapCellInfo priorAjaInfo(this);
    5704               0 :       for (PRInt32 rowY = info.mRowIndex; rowY <= info.GetCellEndRowIndex();
    5705                 :            rowY += segLength) {
    5706               0 :         iter.PeekRight(info, rowY, ajaInfo);
    5707               0 :         currentBorder  = info.GetRightInternalBorder();
    5708               0 :         adjacentBorder = ajaInfo.GetLeftInternalBorder();
    5709                 :         currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
    5710               0 :                                         adjacentBorder, !HORIZONTAL);
    5711                 : 
    5712               0 :         segLength = NS_MAX(1, ajaInfo.mRowIndex + ajaInfo.mRowSpan - rowY);
    5713               0 :         segLength = NS_MIN(segLength, info.mRowIndex + info.mRowSpan - rowY);
    5714                 : 
    5715                 :         // update lastVerBorders and see if a new segment starts
    5716                 :         startSeg = SetBorder(currentBorder,
    5717               0 :                              lastVerBorders[info.GetCellEndColIndex() + 1]);
    5718                 :         // store the border segment in the cell map and update cellBorders
    5719               0 :         if (info.GetCellEndColIndex() < damageArea.XMost() &&
    5720               0 :             rowY >= damageArea.y && rowY < damageArea.YMost()) {
    5721                 :           tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *iter.mCellMap,
    5722                 :                                         iter.mRowGroupStart, rowY,
    5723               0 :                                         info.GetCellEndColIndex(), segLength,
    5724                 :                                         currentBorder.owner,
    5725               0 :                                         currentBorder.width, startSeg);
    5726               0 :           info.SetRightBorderWidths(currentBorder.width);
    5727               0 :           ajaInfo.SetLeftBorderWidths(currentBorder.width);
    5728                 :         }
    5729                 :         // update the top right corner
    5730                 :         bool hitsSpanOnRight = (rowY > ajaInfo.mRowIndex) &&
    5731               0 :                                   (rowY < ajaInfo.mRowIndex + ajaInfo.mRowSpan);
    5732                 :         BCCornerInfo* trCorner = ((0 == rowY) || hitsSpanOnRight) ?
    5733               0 :                                  &topCorners[info.GetCellEndColIndex() + 1] :
    5734               0 :                                  &bottomCorners[info.GetCellEndColIndex() + 1];
    5735               0 :         trCorner->Update(NS_SIDE_BOTTOM, currentBorder);
    5736                 :         // if this is not the first time through,
    5737                 :         // consider the segment to the right
    5738               0 :         if (rowY != info.mRowIndex) {
    5739               0 :           currentBorder  = priorAjaInfo.GetBottomInternalBorder();
    5740               0 :           adjacentBorder = ajaInfo.GetTopInternalBorder();
    5741                 :           currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
    5742               0 :                                           adjacentBorder, HORIZONTAL);
    5743               0 :           trCorner->Update(NS_SIDE_RIGHT, currentBorder);
    5744                 :         }
    5745                 :         // store the top right corner in the cell map
    5746               0 :         if (info.GetCellEndColIndex() < damageArea.XMost() &&
    5747                 :             rowY >= damageArea.y) {
    5748               0 :           if (0 != rowY) {
    5749                 :             tableCellMap->SetBCBorderCorner(eTopRight, *iter.mCellMap,
    5750                 :                                             iter.mRowGroupStart, rowY,
    5751               0 :                                             info.GetCellEndColIndex(),
    5752                 :                                             mozilla::css::Side(trCorner->ownerSide),
    5753                 :                                             trCorner->subWidth,
    5754               0 :                                             trCorner->bevel);
    5755                 :           }
    5756                 :           // store any corners this cell spans together with the aja cell
    5757               0 :           for (PRInt32 rX = rowY + 1; rX < rowY + segLength; rX++) {
    5758                 :             tableCellMap->SetBCBorderCorner(eBottomRight, *iter.mCellMap,
    5759                 :                                             iter.mRowGroupStart, rX,
    5760               0 :                                             info.GetCellEndColIndex(),
    5761                 :                                             mozilla::css::Side(trCorner->ownerSide),
    5762               0 :                                             trCorner->subWidth, false);
    5763                 :           }
    5764                 :         }
    5765                 :         // update bottom right corner, topCorners, bottomCorners
    5766                 :         hitsSpanOnRight = (rowY + segLength <
    5767               0 :                            ajaInfo.mRowIndex + ajaInfo.mRowSpan);
    5768                 :         BCCornerInfo& brCorner = (hitsSpanOnRight) ?
    5769               0 :                                  topCorners[info.GetCellEndColIndex() + 1] :
    5770               0 :                                  bottomCorners[info.GetCellEndColIndex() + 1];
    5771               0 :         brCorner.Set(NS_SIDE_TOP, currentBorder);
    5772               0 :         priorAjaInfo = ajaInfo;
    5773                 :       }
    5774                 :     }
    5775               0 :     for (PRInt32 colX = info.mColIndex + 1; colX <= info.GetCellEndColIndex();
    5776                 :          colX++) {
    5777               0 :       lastVerBorders[colX].Reset(0,1);
    5778                 :     }
    5779                 : 
    5780                 :     // find the dominant border considering the cell's bottom border, adjacent
    5781                 :     // cells and the table, row group, row
    5782               0 :     if (info.mNumTableRows == info.GetCellEndRowIndex() + 1) {
    5783                 :       // touches bottom edge of table
    5784               0 :       if (!tableBorderReset[NS_SIDE_BOTTOM]) {
    5785               0 :         propData->mBottomBorderWidth = 0;
    5786               0 :         tableBorderReset[NS_SIDE_BOTTOM] = true;
    5787                 :       }
    5788               0 :       for (PRInt32 colX = info.mColIndex; colX <= info.GetCellEndColIndex();
    5789                 :            colX++) {
    5790               0 :         info.SetColumn(colX);
    5791               0 :         currentBorder = info.GetBottomEdgeBorder();
    5792                 :         // update/store the bottom left & bottom right corners
    5793               0 :         BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
    5794               0 :         blCorner.Update(NS_SIDE_RIGHT, currentBorder);
    5795                 :         tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap,
    5796                 :                                         iter.mRowGroupStart,
    5797               0 :                                         info.GetCellEndRowIndex(),
    5798                 :                                         colX,
    5799                 :                                         mozilla::css::Side(blCorner.ownerSide),
    5800               0 :                                         blCorner.subWidth, blCorner.bevel);
    5801               0 :         BCCornerInfo& brCorner = bottomCorners[colX + 1]; // bottom right
    5802               0 :         brCorner.Update(NS_SIDE_LEFT, currentBorder);
    5803               0 :         if (info.mNumTableCols == colX + 1) { // lower right corner of the table
    5804                 :           tableCellMap->SetBCBorderCorner(eBottomRight, *iter.mCellMap,
    5805                 :                                           iter.mRowGroupStart,
    5806               0 :                                           info.GetCellEndRowIndex(),colX,
    5807                 :                                           mozilla::css::Side(brCorner.ownerSide),
    5808                 :                                           brCorner.subWidth,
    5809               0 :                                           brCorner.bevel, true);
    5810                 :         }
    5811                 :         // update lastBottomBorder and see if a new segment starts
    5812               0 :         startSeg = SetHorBorder(currentBorder, blCorner, lastBottomBorder);
    5813               0 :         if (!startSeg) {
    5814                 :            // make sure that we did not compare apples to oranges i.e. the
    5815                 :            // current border should be a continuation of the lastBottomBorder,
    5816                 :            // as it is a bottom border
    5817                 :            // add 1 to the info.GetCellEndRowIndex()
    5818                 :            startSeg = (lastBottomBorder.rowIndex !=
    5819               0 :                        (info.GetCellEndRowIndex() + 1));
    5820                 :         }
    5821                 :         // store the border segment in the cell map and update cellBorders
    5822                 :         tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *iter.mCellMap,
    5823                 :                                       iter.mRowGroupStart,
    5824               0 :                                       info.GetCellEndRowIndex(),
    5825                 :                                       colX, 1, currentBorder.owner,
    5826               0 :                                       currentBorder.width, startSeg);
    5827                 :         // update lastBottomBorders
    5828               0 :         lastBottomBorder.rowIndex = info.GetCellEndRowIndex() + 1;
    5829               0 :         lastBottomBorder.rowSpan = info.mRowSpan;
    5830               0 :         lastBottomBorders[colX] = lastBottomBorder;
    5831                 : 
    5832               0 :         info.SetBottomBorderWidths(currentBorder.width);
    5833               0 :         info.SetTableBottomBorderWidth(currentBorder.width);
    5834               0 :         info.SetColumnBottomContBCBorder();
    5835                 :       }
    5836               0 :       info.SetRowGroupBottomContBCBorder();
    5837               0 :       info.SetColGroupBottomContBCBorder();
    5838                 :     }
    5839                 :     else {
    5840               0 :       PRInt32 segLength = 0;
    5841               0 :       for (PRInt32 colX = info.mColIndex; colX <= info.GetCellEndColIndex();
    5842                 :            colX += segLength) {
    5843               0 :         iter.PeekBottom(info, colX, ajaInfo);
    5844               0 :         currentBorder  = info.GetBottomInternalBorder();
    5845               0 :         adjacentBorder = ajaInfo.GetTopInternalBorder();
    5846                 :         currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
    5847               0 :                                         adjacentBorder, HORIZONTAL);
    5848               0 :         segLength = NS_MAX(1, ajaInfo.mColIndex + ajaInfo.mColSpan - colX);
    5849               0 :         segLength = NS_MIN(segLength, info.mColIndex + info.mColSpan - colX);
    5850                 : 
    5851                 :         // update, store the bottom left corner
    5852               0 :         BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
    5853                 :         bool hitsSpanBelow = (colX > ajaInfo.mColIndex) &&
    5854               0 :                                (colX < ajaInfo.mColIndex + ajaInfo.mColSpan);
    5855               0 :         bool update = true;
    5856               0 :         if ((colX == info.mColIndex) && (colX > damageArea.x)) {
    5857               0 :           PRInt32 prevRowIndex = lastBottomBorders[colX - 1].rowIndex;
    5858               0 :           if (prevRowIndex > info.GetCellEndRowIndex() + 1) {
    5859                 :             // hits a rowspan on the right
    5860               0 :             update = false;
    5861                 :             // the corner was taken care of during the cell on the left
    5862                 :           }
    5863               0 :           else if (prevRowIndex < info.GetCellEndRowIndex() + 1) {
    5864                 :             // spans below the cell to the left
    5865               0 :             topCorners[colX] = blCorner;
    5866               0 :             blCorner.Set(NS_SIDE_RIGHT, currentBorder);
    5867               0 :             update = false;
    5868                 :           }
    5869                 :         }
    5870               0 :         if (update) {
    5871               0 :           blCorner.Update(NS_SIDE_RIGHT, currentBorder);
    5872                 :         }
    5873               0 :         if (info.GetCellEndRowIndex() < damageArea.YMost() &&
    5874                 :             (colX >= damageArea.x)) {
    5875               0 :           if (hitsSpanBelow) {
    5876                 :             tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap,
    5877                 :                                             iter.mRowGroupStart,
    5878               0 :                                             info.GetCellEndRowIndex(), colX,
    5879                 :                                             mozilla::css::Side(blCorner.ownerSide),
    5880               0 :                                             blCorner.subWidth, blCorner.bevel);
    5881                 :           }
    5882                 :           // store any corners this cell spans together with the aja cell
    5883               0 :           for (PRInt32 cX = colX + 1; cX < colX + segLength; cX++) {
    5884               0 :             BCCornerInfo& corner = bottomCorners[cX];
    5885               0 :             corner.Set(NS_SIDE_RIGHT, currentBorder);
    5886                 :             tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap,
    5887                 :                                             iter.mRowGroupStart,
    5888               0 :                                             info.GetCellEndRowIndex(), cX,
    5889                 :                                             mozilla::css::Side(corner.ownerSide),
    5890                 :                                             corner.subWidth,
    5891               0 :                                             false);
    5892                 :           }
    5893                 :         }
    5894                 :         // update lastBottomBorders and see if a new segment starts
    5895               0 :         startSeg = SetHorBorder(currentBorder, blCorner, lastBottomBorder);
    5896               0 :         if (!startSeg) {
    5897                 :            // make sure that we did not compare apples to oranges i.e. the
    5898                 :            // current border should be a continuation of the lastBottomBorder,
    5899                 :            // as it is a bottom border
    5900                 :            // add 1 to the info.GetCellEndRowIndex()
    5901                 :            startSeg = (lastBottomBorder.rowIndex !=
    5902               0 :                        info.GetCellEndRowIndex() + 1);
    5903                 :         }
    5904               0 :         lastBottomBorder.rowIndex = info.GetCellEndRowIndex() + 1;
    5905               0 :         lastBottomBorder.rowSpan = info.mRowSpan;
    5906               0 :         for (PRInt32 cX = colX; cX < colX + segLength; cX++) {
    5907               0 :           lastBottomBorders[cX] = lastBottomBorder;
    5908                 :         }
    5909                 : 
    5910                 :         // store the border segment the cell map and update cellBorders
    5911               0 :         if (info.GetCellEndRowIndex() < damageArea.YMost() &&
    5912                 :             (colX >= damageArea.x) &&
    5913               0 :             (colX < damageArea.XMost())) {
    5914                 :           tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *iter.mCellMap,
    5915                 :                                         iter.mRowGroupStart,
    5916               0 :                                         info.GetCellEndRowIndex(),
    5917                 :                                         colX, segLength, currentBorder.owner,
    5918               0 :                                         currentBorder.width, startSeg);
    5919               0 :           info.SetBottomBorderWidths(currentBorder.width);
    5920               0 :           ajaInfo.SetTopBorderWidths(currentBorder.width);
    5921                 :         }
    5922                 :         // update bottom right corner
    5923               0 :         BCCornerInfo& brCorner = bottomCorners[colX + segLength];
    5924               0 :         brCorner.Update(NS_SIDE_LEFT, currentBorder);
    5925                 :       }
    5926               0 :       if (!gotRowBorder && 1 == info.mRowSpan &&
    5927                 :           (ajaInfo.mTopRow || info.mRgAtBottom)) {
    5928                 :         //get continuous row/row group border
    5929                 :         //we need to check the row group's bottom border if this is
    5930                 :         //the last row in the row group, but only a cell with rowspan=1
    5931                 :         //will know whether *this* row is at the bottom
    5932                 :         const nsIFrame* nextRowGroup = (ajaInfo.mRgAtTop) ? ajaInfo.mRowGroup :
    5933               0 :                                                              nsnull;
    5934               0 :         info.SetInnerRowGroupBottomContBCBorder(nextRowGroup, ajaInfo.mTopRow);
    5935               0 :         gotRowBorder = true;
    5936                 :       }
    5937                 :     }
    5938                 : 
    5939                 :     // see if the cell to the right had a rowspan and its lower left border
    5940                 :     // needs be joined with this one's bottom
    5941                 :     // if  there is a cell to the right and the cell to right was a rowspan
    5942               0 :     if ((info.mNumTableCols != info.GetCellEndColIndex() + 1) &&
    5943               0 :         (lastBottomBorders[info.GetCellEndColIndex() + 1].rowSpan > 1)) {
    5944               0 :       BCCornerInfo& corner = bottomCorners[info.GetCellEndColIndex() + 1];
    5945               0 :       if ((NS_SIDE_TOP != corner.ownerSide) &&
    5946                 :           (NS_SIDE_BOTTOM != corner.ownerSide)) {
    5947                 :         // not a vertical owner
    5948               0 :         BCCellBorder& thisBorder = lastBottomBorder;
    5949               0 :         BCCellBorder& nextBorder = lastBottomBorders[info.mColIndex + 1];
    5950               0 :         if ((thisBorder.color == nextBorder.color) &&
    5951                 :             (thisBorder.width == nextBorder.width) &&
    5952                 :             (thisBorder.style == nextBorder.style)) {
    5953                 :           // set the flag on the next border indicating it is not the start of a
    5954                 :           // new segment
    5955               0 :           if (iter.mCellMap) {
    5956                 :             tableCellMap->ResetTopStart(NS_SIDE_BOTTOM, *iter.mCellMap,
    5957               0 :                                         info.GetCellEndRowIndex(),
    5958               0 :                                         info.GetCellEndColIndex() + 1);
    5959                 :           }
    5960                 :         }
    5961                 :       }
    5962                 :     }
    5963                 :   } // for (iter.First(info); info.mCell; iter.Next(info)) {
    5964                 :   // reset the bc flag and damage area
    5965               0 :   SetNeedToCalcBCBorders(false);
    5966               0 :   propData->mDamageArea = nsIntRect(0,0,0,0);
    5967                 : #ifdef DEBUG_TABLE_CELLMAP
    5968                 :   mCellMap->Dump();
    5969                 : #endif
    5970                 : }
    5971                 : 
    5972                 : class BCPaintBorderIterator;
    5973                 : 
    5974                 : struct BCVerticalSeg
    5975                 : {
    5976                 :   BCVerticalSeg();
    5977                 : 
    5978                 :   void Start(BCPaintBorderIterator& aIter,
    5979                 :              BCBorderOwner          aBorderOwner,
    5980                 :              BCPixelSize            aVerSegWidth,
    5981                 :              BCPixelSize            aHorSegHeight);
    5982                 : 
    5983                 :   void Initialize(BCPaintBorderIterator& aIter);
    5984                 :   void GetBottomCorner(BCPaintBorderIterator& aIter,
    5985                 :                        BCPixelSize            aHorSegHeight);
    5986                 : 
    5987                 : 
    5988                 :    void Paint(BCPaintBorderIterator& aIter,
    5989                 :               nsRenderingContext&   aRenderingContext,
    5990                 :               BCPixelSize            aHorSegHeight);
    5991                 :   void AdvanceOffsetY();
    5992                 :   void IncludeCurrentBorder(BCPaintBorderIterator& aIter);
    5993                 : 
    5994                 : 
    5995                 :   union {
    5996                 :     nsTableColFrame*  mCol;
    5997                 :     PRInt32           mColWidth;
    5998                 :   };
    5999                 :   nscoord               mOffsetX;    // x-offset with respect to the table edge
    6000                 :   nscoord               mOffsetY;    // y-offset with respect to the table edge
    6001                 :   nscoord               mLength;     // vertical length including corners
    6002                 :   BCPixelSize           mWidth;      // width in pixels
    6003                 : 
    6004                 :   nsTableCellFrame*     mAjaCell;       // previous sibling to the first cell
    6005                 :                                         // where the segment starts, it can be
    6006                 :                                         // the owner of a segment
    6007                 :   nsTableCellFrame*     mFirstCell;     // cell at the start of the segment
    6008                 :   nsTableRowGroupFrame* mFirstRowGroup; // row group at the start of the segment
    6009                 :   nsTableRowFrame*      mFirstRow;      // row at the start of the segment
    6010                 :   nsTableCellFrame*     mLastCell;      // cell at the current end of the
    6011                 :                                         // segment
    6012                 : 
    6013                 : 
    6014                 :   PRUint8               mOwner;         // owner of the border, defines the
    6015                 :                                         // style
    6016                 :   mozilla::css::Side    mTopBevelSide;  // direction to bevel at the top
    6017                 :   nscoord               mTopBevelOffset; // how much to bevel at the top
    6018                 :   BCPixelSize           mBottomHorSegHeight; // height of the crossing
    6019                 :                                         //horizontal border
    6020                 :   nscoord               mBottomOffset;  // how much longer is the segment due
    6021                 :                                         // to the horizontal border, by this
    6022                 :                                         // amount the next segment needs to be
    6023                 :                                         // shifted.
    6024                 :   bool                  mIsBottomBevel; // should we bevel at the bottom
    6025                 : };
    6026                 : 
    6027                 : struct BCHorizontalSeg
    6028                 : {
    6029                 :   BCHorizontalSeg();
    6030                 : 
    6031                 :   void Start(BCPaintBorderIterator& aIter,
    6032                 :              BCBorderOwner          aBorderOwner,
    6033                 :              BCPixelSize            aBottomVerSegWidth,
    6034                 :              BCPixelSize            aHorSegHeight);
    6035                 :    void GetRightCorner(BCPaintBorderIterator& aIter,
    6036                 :                        BCPixelSize            aLeftSegWidth);
    6037                 :    void AdvanceOffsetX(PRInt32 aIncrement);
    6038                 :    void IncludeCurrentBorder(BCPaintBorderIterator& aIter);
    6039                 :    void Paint(BCPaintBorderIterator& aIter,
    6040                 :               nsRenderingContext&   aRenderingContext);
    6041                 : 
    6042                 :   nscoord            mOffsetX;       // x-offset with respect to the table edge
    6043                 :   nscoord            mOffsetY;       // y-offset with respect to the table edge
    6044                 :   nscoord            mLength;        // horizontal length including corners
    6045                 :   BCPixelSize        mWidth;         // border width in pixels
    6046                 :   nscoord            mLeftBevelOffset;   // how much to bevel at the left
    6047                 :   mozilla::css::Side mLeftBevelSide;     // direction to bevel at the left
    6048                 :   bool               mIsRightBevel;      // should we bevel at the right end
    6049                 :   nscoord            mRightBevelOffset;  // how much to bevel at the right
    6050                 :   mozilla::css::Side mRightBevelSide;    // direction to bevel at the right
    6051                 :   nscoord            mEndOffset;         // how much longer is the segment due
    6052                 :                                          // to the vertical border, by this
    6053                 :                                          // amount the next segment needs to be
    6054                 :                                          // shifted.
    6055                 :   PRUint8            mOwner;             // owner of the border, defines the
    6056                 :                                          // style
    6057                 :   nsTableCellFrame*  mFirstCell;         // cell at the start of the segment
    6058                 :   nsTableCellFrame*  mAjaCell;           // neighboring cell to the first cell
    6059                 :                                          // where the segment starts, it can be
    6060                 :                                          // the owner of a segment
    6061                 : };
    6062                 : 
    6063                 : // Iterates over borders (left border, corner, top border) in the cell map within a damage area
    6064                 : // from left to right, top to bottom. All members are in terms of the 1st in flow frames, except
    6065                 : // where suffixed by InFlow.
    6066                 : class BCPaintBorderIterator
    6067                 : {
    6068                 : public:
    6069                 : 
    6070                 : 
    6071                 :   BCPaintBorderIterator(nsTableFrame* aTable);
    6072               0 :   ~BCPaintBorderIterator() { if (mVerInfo) {
    6073               0 :                               delete [] mVerInfo;
    6074               0 :                            }}
    6075                 :   void Reset();
    6076                 : 
    6077                 :   /**
    6078                 :    * Determine the damage area in terms of rows and columns and finalize
    6079                 :    * mInitialOffsetX and mInitialOffsetY.
    6080                 :    * @param aDirtyRect - dirty rect in table coordinates
    6081                 :    * @return - true if we need to paint something given dirty rect
    6082                 :    */
    6083                 :   bool SetDamageArea(const nsRect& aDamageRect);
    6084                 :   void First();
    6085                 :   void Next();
    6086                 :   void AccumulateOrPaintHorizontalSegment(nsRenderingContext& aRenderingContext);
    6087                 :   void AccumulateOrPaintVerticalSegment(nsRenderingContext& aRenderingContext);
    6088                 :   void ResetVerInfo();
    6089                 :   void StoreColumnWidth(PRInt32 aIndex);
    6090                 :   bool VerticalSegmentOwnsCorner();
    6091                 : 
    6092                 :   nsTableFrame*         mTable;
    6093                 :   nsTableFrame*         mTableFirstInFlow;
    6094                 :   nsTableCellMap*       mTableCellMap;
    6095                 :   nsCellMap*            mCellMap;
    6096                 :   bool                  mTableIsLTR;
    6097                 :   PRInt32               mColInc;            // +1 for ltr -1 for rtl
    6098                 :   const nsStyleBackground* mTableBgColor;
    6099                 :   nsTableFrame::RowGroupArray mRowGroups;
    6100                 : 
    6101                 :   nsTableRowGroupFrame* mPrevRg;
    6102                 :   nsTableRowGroupFrame* mRg;
    6103                 :   bool                  mIsRepeatedHeader;
    6104                 :   bool                  mIsRepeatedFooter;
    6105                 :   nsTableRowGroupFrame* mStartRg; // first row group in the damagearea
    6106                 :   PRInt32               mRgIndex; // current row group index in the
    6107                 :                                         // mRowgroups array
    6108                 :   PRInt32               mFifRgFirstRowIndex; // start row index of the first in
    6109                 :                                            // flow of the row group
    6110                 :   PRInt32               mRgFirstRowIndex; // row index of the first row in the
    6111                 :                                           // row group
    6112                 :   PRInt32               mRgLastRowIndex; // row index of the last row in the row
    6113                 :                                          // group
    6114                 :   PRInt32               mNumTableRows;   // number of rows in the table and all
    6115                 :                                          // continuations
    6116                 :   PRInt32               mNumTableCols;   // number of columns in the table
    6117                 :   PRInt32               mColIndex;       // with respect to the table
    6118                 :   PRInt32               mRowIndex;       // with respect to the table
    6119                 :   PRInt32               mRepeatedHeaderRowIndex; // row index in a repeated
    6120                 :                                             //header, it's equivalent to
    6121                 :                                             // mRowIndex when we're in a repeated
    6122                 :                                             // header, and set to the last row
    6123                 :                                             // index of a repeated header when
    6124                 :                                             // we're not
    6125                 :   bool                  mIsNewRow;
    6126                 :   bool                  mAtEnd;             // the iterator cycled over all
    6127                 :                                              // borders
    6128                 :   nsTableRowFrame*      mPrevRow;
    6129                 :   nsTableRowFrame*      mRow;
    6130                 :   nsTableRowFrame*      mStartRow;    //first row in a inside the damagearea
    6131                 : 
    6132                 : 
    6133                 :   // cell properties
    6134                 :   nsTableCellFrame*     mPrevCell;
    6135                 :   nsTableCellFrame*     mCell;
    6136                 :   BCCellData*           mPrevCellData;
    6137                 :   BCCellData*           mCellData;
    6138                 :   BCData*               mBCData;
    6139                 : 
    6140               0 :   bool                  IsTableTopMost()    {return (mRowIndex == 0) && !mTable->GetPrevInFlow();}
    6141               0 :   bool                  IsTableRightMost()  {return (mColIndex >= mNumTableCols);}
    6142               0 :   bool                  IsTableBottomMost() {return (mRowIndex >= mNumTableRows) && !mTable->GetNextInFlow();}
    6143               0 :   bool                  IsTableLeftMost()   {return (mColIndex == 0);}
    6144               0 :   bool                  IsDamageAreaTopMost()    {return (mRowIndex == mDamageArea.y);}
    6145               0 :   bool                  IsDamageAreaRightMost()  {return (mColIndex >= mDamageArea.XMost());}
    6146               0 :   bool                  IsDamageAreaBottomMost() {return (mRowIndex >= mDamageArea.YMost());}
    6147               0 :   bool                  IsDamageAreaLeftMost()   {return (mColIndex == mDamageArea.x);}
    6148               0 :   PRInt32               GetRelativeColIndex() {return (mColIndex - mDamageArea.x);}
    6149                 : 
    6150                 :   nsIntRect             mDamageArea;        // damageArea in cellmap coordinates
    6151               0 :   bool                  IsAfterRepeatedHeader() { return !mIsRepeatedHeader && (mRowIndex == (mRepeatedHeaderRowIndex + 1));}
    6152               0 :   bool                  StartRepeatedFooter() {return mIsRepeatedFooter && (mRowIndex == mRgFirstRowIndex) && (mRowIndex != mDamageArea.y);}
    6153                 :   nscoord               mInitialOffsetX;  // offsetX of the first border with
    6154                 :                                             // respect to the table
    6155                 :   nscoord               mInitialOffsetY;    // offsetY of the first border with
    6156                 :                                             // respect to the table
    6157                 :   nscoord               mNextOffsetY;       // offsetY of the next segment
    6158                 :   BCVerticalSeg*        mVerInfo; // this array is used differently when
    6159                 :                                   // horizontal and vertical borders are drawn
    6160                 :                                   // When horizontal border are drawn we cache
    6161                 :                                   // the column widths and the width of the
    6162                 :                                   // vertical borders that arrive from top
    6163                 :                                   // When we draw vertical borders we store
    6164                 :                                   // lengths and width for vertical borders
    6165                 :                                   // before they are drawn while we  move over
    6166                 :                                   // the columns in the damage area
    6167                 :                                   // It has one more elements than columns are
    6168                 :                                   //in the table.
    6169                 :   BCHorizontalSeg       mHorSeg;            // the horizontal segment while we
    6170                 :                                             // move over the colums
    6171                 :   BCPixelSize           mPrevHorSegHeight;  // the height of the previous
    6172                 :                                             // horizontal border
    6173                 : 
    6174                 : private:
    6175                 : 
    6176                 :   bool SetNewRow(nsTableRowFrame* aRow = nsnull);
    6177                 :   bool SetNewRowGroup();
    6178                 :   void   SetNewData(PRInt32 aRowIndex, PRInt32 aColIndex);
    6179                 : 
    6180                 : };
    6181                 : 
    6182                 : 
    6183                 : 
    6184               0 : BCPaintBorderIterator::BCPaintBorderIterator(nsTableFrame* aTable)
    6185                 : {
    6186               0 :   mTable      = aTable;
    6187               0 :   mVerInfo    = nsnull;
    6188               0 :   nsMargin childAreaOffset = mTable->GetChildAreaOffset(nsnull);
    6189               0 :   mTableFirstInFlow    = (nsTableFrame*) mTable->GetFirstInFlow();
    6190               0 :   mTableCellMap        = mTable->GetCellMap();
    6191                 :   // y position of first row in damage area
    6192               0 :   mInitialOffsetY = mTable->GetPrevInFlow() ? 0 : childAreaOffset.top;
    6193               0 :   mNumTableRows  = mTable->GetRowCount();
    6194               0 :   mNumTableCols  = mTable->GetColCount();
    6195                 : 
    6196                 :   // Get the ordered row groups
    6197               0 :   mTable->OrderRowGroups(mRowGroups);
    6198                 :   // initialize to a non existing index
    6199               0 :   mRepeatedHeaderRowIndex = -99;
    6200                 : 
    6201               0 :   mTableIsLTR = mTable->GetStyleVisibility()->mDirection ==
    6202               0 :                    NS_STYLE_DIRECTION_LTR;
    6203               0 :   mColInc = (mTableIsLTR) ? 1 : -1;
    6204                 : 
    6205                 :   nsIFrame* bgFrame =
    6206               0 :     nsCSSRendering::FindNonTransparentBackgroundFrame(aTable);
    6207               0 :   mTableBgColor = bgFrame->GetStyleBackground();
    6208               0 : }
    6209                 : 
    6210                 : bool
    6211               0 : BCPaintBorderIterator::SetDamageArea(const nsRect& aDirtyRect)
    6212                 : {
    6213                 : 
    6214                 :   PRUint32 startRowIndex, endRowIndex, startColIndex, endColIndex;
    6215               0 :   startRowIndex = endRowIndex = startColIndex = endColIndex = 0;
    6216               0 :   bool done = false;
    6217               0 :   bool haveIntersect = false;
    6218                 :   // find startRowIndex, endRowIndex
    6219               0 :   nscoord rowY = mInitialOffsetY;
    6220               0 :   for (PRUint32 rgX = 0; rgX < mRowGroups.Length() && !done; rgX++) {
    6221               0 :     nsTableRowGroupFrame* rgFrame = mRowGroups[rgX];
    6222               0 :     for (nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); rowFrame;
    6223                 :          rowFrame = rowFrame->GetNextRow()) {
    6224                 :       // conservatively estimate the half border widths outside the row
    6225               0 :       nscoord topBorderHalf    = (mTable->GetPrevInFlow()) ? 0 :
    6226               0 :        nsPresContext::CSSPixelsToAppUnits(rowFrame->GetTopBCBorderWidth() + 1);
    6227               0 :       nscoord bottomBorderHalf = (mTable->GetNextInFlow()) ? 0 :
    6228               0 :         nsPresContext::CSSPixelsToAppUnits(rowFrame->GetBottomBCBorderWidth() + 1);
    6229                 :       // get the row rect relative to the table rather than the row group
    6230               0 :       nsSize rowSize = rowFrame->GetSize();
    6231               0 :       if (haveIntersect) {
    6232               0 :         if (aDirtyRect.YMost() >= (rowY - topBorderHalf)) {
    6233                 :           nsTableRowFrame* fifRow =
    6234               0 :             static_cast<nsTableRowFrame*>(rowFrame->GetFirstInFlow());
    6235               0 :           endRowIndex = fifRow->GetRowIndex();
    6236                 :         }
    6237               0 :         else done = true;
    6238                 :       }
    6239                 :       else {
    6240               0 :         if ((rowY + rowSize.height + bottomBorderHalf) >= aDirtyRect.y) {
    6241               0 :           mStartRg  = rgFrame;
    6242               0 :           mStartRow = rowFrame;
    6243                 :           nsTableRowFrame* fifRow =
    6244               0 :             static_cast<nsTableRowFrame*>(rowFrame->GetFirstInFlow());
    6245               0 :           startRowIndex = endRowIndex = fifRow->GetRowIndex();
    6246               0 :           haveIntersect = true;
    6247                 :         }
    6248                 :         else {
    6249               0 :           mInitialOffsetY += rowSize.height;
    6250                 :         }
    6251                 :       }
    6252               0 :       rowY += rowSize.height;
    6253                 :     }
    6254                 :   }
    6255               0 :   mNextOffsetY = mInitialOffsetY;
    6256                 : 
    6257                 :   // XXX comment refers to the obsolete NS_FRAME_OUTSIDE_CHILDREN flag
    6258                 :   // XXX but I don't understand it, so not changing it for now
    6259                 :   // outer table borders overflow the table, so the table might be
    6260                 :   // target to other areas as the NS_FRAME_OUTSIDE_CHILDREN is set
    6261                 :   // on the table
    6262               0 :   if (!haveIntersect)
    6263               0 :     return false;
    6264                 :   // find startColIndex, endColIndex, startColX
    6265               0 :   haveIntersect = false;
    6266               0 :   if (0 == mNumTableCols)
    6267               0 :     return false;
    6268                 :   PRInt32 leftCol, rightCol; // columns are in the range [leftCol, rightCol)
    6269                 : 
    6270               0 :   nsMargin childAreaOffset = mTable->GetChildAreaOffset(nsnull);
    6271               0 :   if (mTableIsLTR) {
    6272               0 :     mInitialOffsetX = childAreaOffset.left; // x position of first col in
    6273                 :                                             // damage area
    6274               0 :     leftCol = 0;
    6275               0 :     rightCol = mNumTableCols;
    6276                 :   } else {
    6277                 :     // x position of first col in damage area
    6278               0 :     mInitialOffsetX = mTable->GetRect().width - childAreaOffset.right;
    6279               0 :     leftCol = mNumTableCols-1;
    6280               0 :     rightCol = -1;
    6281                 :   }
    6282               0 :   nscoord x = 0;
    6283                 :   PRInt32 colX;
    6284               0 :   for (colX = leftCol; colX != rightCol; colX += mColInc) {
    6285               0 :     nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(colX);
    6286               0 :     if (!colFrame) ABORT1(false);
    6287                 :     // get the col rect relative to the table rather than the col group
    6288               0 :     nsSize size = colFrame->GetSize();
    6289               0 :     if (haveIntersect) {
    6290                 :       // conservatively estimate the left half border width outside the col
    6291                 :       nscoord leftBorderHalf =
    6292               0 :         nsPresContext::CSSPixelsToAppUnits(colFrame->GetLeftBorderWidth() + 1);
    6293               0 :       if (aDirtyRect.XMost() >= (x - leftBorderHalf)) {
    6294               0 :         endColIndex = colX;
    6295                 :       }
    6296               0 :       else break;
    6297                 :     }
    6298                 :     else {
    6299                 :       // conservatively estimate the right half border width outside the col
    6300                 :       nscoord rightBorderHalf =
    6301               0 :         nsPresContext::CSSPixelsToAppUnits(colFrame->GetRightBorderWidth() + 1);
    6302               0 :       if ((x + size.width + rightBorderHalf) >= aDirtyRect.x) {
    6303               0 :         startColIndex = endColIndex = colX;
    6304               0 :         haveIntersect = true;
    6305                 :       }
    6306                 :       else {
    6307               0 :         mInitialOffsetX += mColInc * size.width;
    6308                 :       }
    6309                 :     }
    6310               0 :     x += size.width;
    6311                 :   }
    6312               0 :   if (!mTableIsLTR) {
    6313                 :     PRUint32 temp;
    6314               0 :     mInitialOffsetX = mTable->GetRect().width - childAreaOffset.right;
    6315               0 :     temp = startColIndex; startColIndex = endColIndex; endColIndex = temp;
    6316               0 :     for (PRUint32 column = 0; column < startColIndex; column++) {
    6317               0 :       nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(column);
    6318               0 :       if (!colFrame) ABORT1(false);
    6319               0 :       nsSize size = colFrame->GetSize();
    6320               0 :       mInitialOffsetX += mColInc * size.width;
    6321                 :     }
    6322                 :   }
    6323               0 :   if (!haveIntersect)
    6324               0 :     return false;
    6325                 :   mDamageArea = nsIntRect(startColIndex, startRowIndex,
    6326               0 :                           1 + NS_ABS(PRInt32(endColIndex - startColIndex)),
    6327               0 :                           1 + endRowIndex - startRowIndex);
    6328                 : 
    6329               0 :   Reset();
    6330               0 :   mVerInfo = new BCVerticalSeg[mDamageArea.width + 1];
    6331               0 :   if (!mVerInfo)
    6332               0 :     return false;
    6333               0 :   return true;
    6334                 : }
    6335                 : 
    6336                 : void
    6337               0 : BCPaintBorderIterator::Reset()
    6338                 : {
    6339               0 :   mAtEnd = true; // gets reset when First() is called
    6340               0 :   mRg = mStartRg;
    6341               0 :   mPrevRow  = nsnull;
    6342               0 :   mRow      = mStartRow;
    6343               0 :   mRowIndex      = 0;
    6344               0 :   mColIndex      = 0;
    6345               0 :   mRgIndex       = -1;
    6346               0 :   mPrevCell      = nsnull;
    6347               0 :   mCell          = nsnull;
    6348               0 :   mPrevCellData  = nsnull;
    6349               0 :   mCellData      = nsnull;
    6350               0 :   mBCData        = nsnull;
    6351               0 :   ResetVerInfo();
    6352               0 : }
    6353                 : 
    6354                 : /**
    6355                 :  * Set the iterator data to a new cellmap coordinate
    6356                 :  * @param aRowIndex - the row index
    6357                 :  * @param aColIndex - the col index
    6358                 :  */
    6359                 : void
    6360               0 : BCPaintBorderIterator::SetNewData(PRInt32 aY,
    6361                 :                                 PRInt32 aX)
    6362                 : {
    6363               0 :   if (!mTableCellMap || !mTableCellMap->mBCInfo) ABORT0();
    6364                 : 
    6365               0 :   mColIndex    = aX;
    6366               0 :   mRowIndex    = aY;
    6367               0 :   mPrevCellData = mCellData;
    6368               0 :   if (IsTableRightMost() && IsTableBottomMost()) {
    6369               0 :    mCell = nsnull;
    6370               0 :    mBCData = &mTableCellMap->mBCInfo->mLowerRightCorner;
    6371                 :   }
    6372               0 :   else if (IsTableRightMost()) {
    6373               0 :     mCellData = nsnull;
    6374               0 :     mBCData = &mTableCellMap->mBCInfo->mRightBorders.ElementAt(aY);
    6375                 :   }
    6376               0 :   else if (IsTableBottomMost()) {
    6377               0 :     mCellData = nsnull;
    6378               0 :     mBCData = &mTableCellMap->mBCInfo->mBottomBorders.ElementAt(aX);
    6379                 :   }
    6380                 :   else {
    6381               0 :     if (PRUint32(mRowIndex - mFifRgFirstRowIndex) < mCellMap->mRows.Length()) {
    6382               0 :       mBCData = nsnull;
    6383                 :       mCellData =
    6384               0 :         (BCCellData*)mCellMap->mRows[mRowIndex - mFifRgFirstRowIndex].SafeElementAt(mColIndex);
    6385               0 :       if (mCellData) {
    6386               0 :         mBCData = &mCellData->mData;
    6387               0 :         if (!mCellData->IsOrig()) {
    6388               0 :           if (mCellData->IsRowSpan()) {
    6389               0 :             aY -= mCellData->GetRowSpanOffset();
    6390                 :           }
    6391               0 :           if (mCellData->IsColSpan()) {
    6392               0 :             aX -= mCellData->GetColSpanOffset();
    6393                 :           }
    6394               0 :           if ((aX >= 0) && (aY >= 0)) {
    6395               0 :             mCellData = (BCCellData*)mCellMap->mRows[aY - mFifRgFirstRowIndex][aX];
    6396                 :           }
    6397                 :         }
    6398               0 :         if (mCellData->IsOrig()) {
    6399               0 :           mPrevCell = mCell;
    6400               0 :           mCell = mCellData->GetCellFrame();
    6401                 :         }
    6402                 :       }
    6403                 :     }
    6404                 :   }
    6405                 : }
    6406                 : 
    6407                 : /**
    6408                 :  * Set the iterator to a new row
    6409                 :  * @param aRow - the new row frame, if null the iterator will advance to the
    6410                 :  *               next row
    6411                 :  */
    6412                 : bool
    6413               0 : BCPaintBorderIterator::SetNewRow(nsTableRowFrame* aRow)
    6414                 : {
    6415               0 :   mPrevRow = mRow;
    6416               0 :   mRow     = (aRow) ? aRow : mRow->GetNextRow();
    6417               0 :   if (mRow) {
    6418               0 :     mIsNewRow = true;
    6419               0 :     mRowIndex = mRow->GetRowIndex();
    6420               0 :     mColIndex = mDamageArea.x;
    6421               0 :     mPrevHorSegHeight = 0;
    6422               0 :     if (mIsRepeatedHeader) {
    6423               0 :       mRepeatedHeaderRowIndex = mRowIndex;
    6424                 :     }
    6425                 :   }
    6426                 :   else {
    6427               0 :     mAtEnd = true;
    6428                 :   }
    6429               0 :   return !mAtEnd;
    6430                 : }
    6431                 : 
    6432                 : /**
    6433                 :  * Advance the iterator to the next row group
    6434                 :  */
    6435                 : bool
    6436               0 : BCPaintBorderIterator::SetNewRowGroup()
    6437                 : {
    6438                 : 
    6439               0 :   mRgIndex++;
    6440                 : 
    6441               0 :   mIsRepeatedHeader = false;
    6442               0 :   mIsRepeatedFooter = false;
    6443                 : 
    6444               0 :   NS_ASSERTION(mRgIndex >= 0, "mRgIndex out of bounds");
    6445               0 :   if (PRUint32(mRgIndex) < mRowGroups.Length()) {
    6446               0 :     mPrevRg = mRg;
    6447               0 :     mRg = mRowGroups[mRgIndex];
    6448                 :     nsTableRowGroupFrame* fifRg =
    6449               0 :       static_cast<nsTableRowGroupFrame*>(mRg->GetFirstInFlow());
    6450               0 :     mFifRgFirstRowIndex = fifRg->GetStartRowIndex();
    6451               0 :     mRgFirstRowIndex    = mRg->GetStartRowIndex();
    6452               0 :     mRgLastRowIndex     = mRgFirstRowIndex + mRg->GetRowCount() - 1;
    6453                 : 
    6454               0 :     if (SetNewRow(mRg->GetFirstRow())) {
    6455               0 :       mCellMap = mTableCellMap->GetMapFor(fifRg, nsnull);
    6456               0 :       if (!mCellMap) ABORT1(false);
    6457                 :     }
    6458               0 :     if (mRg && mTable->GetPrevInFlow() && !mRg->GetPrevInFlow()) {
    6459                 :       // if mRowGroup doesn't have a prev in flow, then it may be a repeated
    6460                 :       // header or footer
    6461               0 :       const nsStyleDisplay* display = mRg->GetStyleDisplay();
    6462               0 :       if (mRowIndex == mDamageArea.y) {
    6463               0 :         mIsRepeatedHeader = (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == display->mDisplay);
    6464                 :       }
    6465                 :       else {
    6466               0 :         mIsRepeatedFooter = (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay);
    6467                 :       }
    6468                 :     }
    6469                 :   }
    6470                 :   else {
    6471               0 :     mAtEnd = true;
    6472                 :   }
    6473               0 :   return !mAtEnd;
    6474                 : }
    6475                 : 
    6476                 : /**
    6477                 :  *  Move the iterator to the first position in the damageArea
    6478                 :  */
    6479                 : void
    6480               0 : BCPaintBorderIterator::First()
    6481                 : {
    6482               0 :   if (!mTable || (mDamageArea.x >= mNumTableCols) ||
    6483               0 :       (mDamageArea.y >= mNumTableRows)) ABORT0();
    6484                 : 
    6485               0 :   mAtEnd = false;
    6486                 : 
    6487               0 :   PRUint32 numRowGroups = mRowGroups.Length();
    6488               0 :   for (PRUint32 rgY = 0; rgY < numRowGroups; rgY++) {
    6489               0 :     nsTableRowGroupFrame* rowG = mRowGroups[rgY];
    6490               0 :     PRInt32 start = rowG->GetStartRowIndex();
    6491               0 :     PRInt32 end   = start + rowG->GetRowCount() - 1;
    6492               0 :     if ((mDamageArea.y >= start) && (mDamageArea.y <= end)) {
    6493               0 :       mRgIndex = rgY - 1; // SetNewRowGroup increments rowGroupIndex
    6494               0 :       if (SetNewRowGroup()) {
    6495               0 :         while ((mRowIndex < mDamageArea.y) && !mAtEnd) {
    6496               0 :           SetNewRow();
    6497                 :         }
    6498               0 :         if (!mAtEnd) {
    6499               0 :           SetNewData(mDamageArea.y, mDamageArea.x);
    6500                 :         }
    6501                 :       }
    6502               0 :       return;
    6503                 :     }
    6504                 :   }
    6505               0 :   mAtEnd = true;
    6506                 : }
    6507                 : 
    6508                 : /**
    6509                 :  * Advance the iterator to the next position
    6510                 :  */
    6511                 : void
    6512               0 : BCPaintBorderIterator::Next()
    6513                 : {
    6514               0 :   if (mAtEnd) ABORT0();
    6515               0 :   mIsNewRow = false;
    6516                 : 
    6517               0 :   mColIndex++;
    6518               0 :   if (mColIndex > mDamageArea.XMost()) {
    6519               0 :     mRowIndex++;
    6520               0 :     if (mRowIndex == mDamageArea.YMost()) {
    6521               0 :       mColIndex = mDamageArea.x;
    6522                 :     }
    6523               0 :     else if (mRowIndex < mDamageArea.YMost()) {
    6524               0 :       if (mRowIndex <= mRgLastRowIndex) {
    6525               0 :         SetNewRow();
    6526                 :       }
    6527                 :       else {
    6528               0 :         SetNewRowGroup();
    6529                 :       }
    6530                 :     }
    6531                 :     else {
    6532               0 :       mAtEnd = true;
    6533                 :     }
    6534                 :   }
    6535               0 :   if (!mAtEnd) {
    6536               0 :     SetNewData(mRowIndex, mColIndex);
    6537                 :   }
    6538                 : }
    6539                 : 
    6540                 : // XXX if CalcVerCornerOffset and CalcHorCornerOffset remain similar, combine
    6541                 : // them
    6542                 : /** Compute the vertical offset of a vertical border segment
    6543                 :   * @param aCornerOwnerSide - which side owns the corner
    6544                 :   * @param aCornerSubWidth  - how wide is the nonwinning side of the corner
    6545                 :   * @param aHorWidth        - how wide is the horizontal edge of the corner
    6546                 :   * @param aIsStartOfSeg    - does this corner start a new segment
    6547                 :   * @param aIsBevel         - is this corner beveled
    6548                 :   * @return                 - offset in twips
    6549                 :   */
    6550                 : static nscoord
    6551               0 : CalcVerCornerOffset(mozilla::css::Side aCornerOwnerSide,
    6552                 :                     BCPixelSize aCornerSubWidth,
    6553                 :                     BCPixelSize aHorWidth,
    6554                 :                     bool        aIsStartOfSeg,
    6555                 :                     bool        aIsBevel)
    6556                 : {
    6557               0 :   nscoord offset = 0;
    6558                 :   // XXX These should be replaced with appropriate side-specific macros (which?)
    6559                 :   BCPixelSize smallHalf, largeHalf;
    6560               0 :   if ((NS_SIDE_TOP == aCornerOwnerSide) ||
    6561                 :       (NS_SIDE_BOTTOM == aCornerOwnerSide)) {
    6562               0 :     DivideBCBorderSize(aCornerSubWidth, smallHalf, largeHalf);
    6563               0 :     if (aIsBevel) {
    6564               0 :       offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
    6565                 :     }
    6566                 :     else {
    6567               0 :       offset = (NS_SIDE_TOP == aCornerOwnerSide) ? smallHalf : -largeHalf;
    6568                 :     }
    6569                 :   }
    6570                 :   else {
    6571               0 :     DivideBCBorderSize(aHorWidth, smallHalf, largeHalf);
    6572               0 :     if (aIsBevel) {
    6573               0 :       offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
    6574                 :     }
    6575                 :     else {
    6576               0 :       offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
    6577                 :     }
    6578                 :   }
    6579               0 :   return nsPresContext::CSSPixelsToAppUnits(offset);
    6580                 : }
    6581                 : 
    6582                 : /** Compute the horizontal offset of a horizontal border segment
    6583                 :   * @param aCornerOwnerSide - which side owns the corner
    6584                 :   * @param aCornerSubWidth  - how wide is the nonwinning side of the corner
    6585                 :   * @param aVerWidth        - how wide is the vertical edge of the corner
    6586                 :   * @param aIsStartOfSeg    - does this corner start a new segment
    6587                 :   * @param aIsBevel         - is this corner beveled
    6588                 :   * @param aTableIsLTR      - direction, the computation depends on ltr or rtl
    6589                 :   * @return                 - offset in twips
    6590                 :   */
    6591                 : static nscoord
    6592               0 : CalcHorCornerOffset(mozilla::css::Side aCornerOwnerSide,
    6593                 :                     BCPixelSize aCornerSubWidth,
    6594                 :                     BCPixelSize aVerWidth,
    6595                 :                     bool        aIsStartOfSeg,
    6596                 :                     bool        aIsBevel,
    6597                 :                     bool        aTableIsLTR)
    6598                 : {
    6599               0 :   nscoord offset = 0;
    6600                 :   // XXX These should be replaced with appropriate side-specific macros (which?)
    6601                 :   BCPixelSize smallHalf, largeHalf;
    6602               0 :   if ((NS_SIDE_LEFT == aCornerOwnerSide) ||
    6603                 :       (NS_SIDE_RIGHT == aCornerOwnerSide)) {
    6604               0 :     if (aTableIsLTR) {
    6605               0 :       DivideBCBorderSize(aCornerSubWidth, smallHalf, largeHalf);
    6606                 :     }
    6607                 :     else {
    6608               0 :       DivideBCBorderSize(aCornerSubWidth, largeHalf, smallHalf);
    6609                 :     }
    6610               0 :     if (aIsBevel) {
    6611               0 :       offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
    6612                 :     }
    6613                 :     else {
    6614               0 :       offset = (NS_SIDE_LEFT == aCornerOwnerSide) ? smallHalf : -largeHalf;
    6615                 :     }
    6616                 :   }
    6617                 :   else {
    6618               0 :     if (aTableIsLTR) {
    6619               0 :       DivideBCBorderSize(aVerWidth, smallHalf, largeHalf);
    6620                 :     }
    6621                 :     else {
    6622               0 :       DivideBCBorderSize(aVerWidth, largeHalf, smallHalf);
    6623                 :     }
    6624               0 :     if (aIsBevel) {
    6625               0 :       offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
    6626                 :     }
    6627                 :     else {
    6628               0 :       offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
    6629                 :     }
    6630                 :   }
    6631               0 :   return nsPresContext::CSSPixelsToAppUnits(offset);
    6632                 : }
    6633                 : 
    6634               0 : BCVerticalSeg::BCVerticalSeg()
    6635                 : {
    6636               0 :   mCol = nsnull;
    6637               0 :   mFirstCell = mLastCell = mAjaCell = nsnull;
    6638               0 :   mOffsetX = mOffsetY = mLength = mWidth = mTopBevelOffset = 0;
    6639               0 :   mTopBevelSide = NS_SIDE_TOP;
    6640               0 :   mOwner = eCellOwner;
    6641               0 : }
    6642                 : 
    6643                 : /**
    6644                 :  * Start a new vertical segment
    6645                 :  * @param aIter         - iterator containing the structural information
    6646                 :  * @param aBorderOwner  - determines the border style
    6647                 :  * @param aVerSegWidth  - the width of segment in pixel
    6648                 :  * @param aHorSegHeight - the width of the horizontal segment joining the corner
    6649                 :  *                        at the start
    6650                 :  */
    6651                 : void
    6652               0 : BCVerticalSeg::Start(BCPaintBorderIterator& aIter,
    6653                 :                      BCBorderOwner          aBorderOwner,
    6654                 :                      BCPixelSize            aVerSegWidth,
    6655                 :                      BCPixelSize            aHorSegHeight)
    6656                 : {
    6657               0 :   mozilla::css::Side ownerSide   = NS_SIDE_TOP;
    6658               0 :   bool bevel       = false;
    6659                 : 
    6660                 : 
    6661                 :   nscoord cornerSubWidth  = (aIter.mBCData) ?
    6662               0 :                                aIter.mBCData->GetCorner(ownerSide, bevel) : 0;
    6663                 : 
    6664               0 :   bool    topBevel        = (aVerSegWidth > 0) ? bevel : false;
    6665               0 :   BCPixelSize maxHorSegHeight = NS_MAX(aIter.mPrevHorSegHeight, aHorSegHeight);
    6666                 :   nscoord offset          = CalcVerCornerOffset(ownerSide, cornerSubWidth,
    6667                 :                                                 maxHorSegHeight, true,
    6668               0 :                                                 topBevel);
    6669                 : 
    6670                 :   mTopBevelOffset = topBevel ?
    6671               0 :     nsPresContext::CSSPixelsToAppUnits(maxHorSegHeight): 0;
    6672                 :   // XXX this assumes that only corners where 2 segments join can be beveled
    6673               0 :   mTopBevelSide     = (aHorSegHeight > 0) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
    6674               0 :   mOffsetY      += offset;
    6675               0 :   mLength        = -offset;
    6676               0 :   mWidth         = aVerSegWidth;
    6677               0 :   mOwner         = aBorderOwner;
    6678               0 :   mFirstCell     = aIter.mCell;
    6679               0 :   mFirstRowGroup = aIter.mRg;
    6680               0 :   mFirstRow      = aIter.mRow;
    6681               0 :   if (aIter.GetRelativeColIndex() > 0) {
    6682               0 :     mAjaCell = aIter.mVerInfo[aIter.GetRelativeColIndex() - 1].mLastCell;
    6683                 :   }
    6684               0 : }
    6685                 : 
    6686                 : /**
    6687                 :  * Initialize the vertical segments with information that will persist for any
    6688                 :  * vertical segment in this column
    6689                 :  * @param aIter - iterator containing the structural information
    6690                 :  */
    6691                 : void
    6692               0 : BCVerticalSeg::Initialize(BCPaintBorderIterator& aIter)
    6693                 : {
    6694               0 :   PRInt32 relColIndex = aIter.GetRelativeColIndex();
    6695               0 :   mCol = aIter.IsTableRightMost() ? aIter.mVerInfo[relColIndex - 1].mCol :
    6696               0 :            aIter.mTableFirstInFlow->GetColFrame(aIter.mColIndex);
    6697               0 :   if (!mCol) ABORT0();
    6698               0 :   if (0 == relColIndex) {
    6699               0 :     mOffsetX = aIter.mInitialOffsetX;
    6700                 :   }
    6701                 :   // set colX for the next column
    6702               0 :   if (!aIter.IsDamageAreaRightMost()) {
    6703               0 :     aIter.mVerInfo[relColIndex + 1].mOffsetX = mOffsetX +
    6704               0 :                                          aIter.mColInc * mCol->GetSize().width;
    6705                 :   }
    6706               0 :   mOffsetY = aIter.mInitialOffsetY;
    6707               0 :   mLastCell = aIter.mCell;
    6708                 : }
    6709                 : 
    6710                 : /**
    6711                 :  * Compute the offsets for the bottom corner of a vertical segment
    6712                 :  * @param aIter         - iterator containing the structural information
    6713                 :  * @param aHorSegHeight - the width of the horizontal segment joining the corner
    6714                 :  *                        at the start
    6715                 :  */
    6716                 : void
    6717               0 : BCVerticalSeg::GetBottomCorner(BCPaintBorderIterator& aIter,
    6718                 :                                BCPixelSize            aHorSegHeight)
    6719                 : {
    6720               0 :    mozilla::css::Side ownerSide = NS_SIDE_TOP;
    6721               0 :    nscoord cornerSubWidth = 0;
    6722               0 :    bool bevel = false;
    6723               0 :    if (aIter.mBCData) {
    6724               0 :      cornerSubWidth = aIter.mBCData->GetCorner(ownerSide, bevel);
    6725                 :    }
    6726               0 :    mIsBottomBevel = (mWidth > 0) ? bevel : false;
    6727               0 :    mBottomHorSegHeight = NS_MAX(aIter.mPrevHorSegHeight, aHorSegHeight);
    6728                 :    mBottomOffset = CalcVerCornerOffset(ownerSide, cornerSubWidth,
    6729                 :                                     mBottomHorSegHeight,
    6730               0 :                                     false, mIsBottomBevel);
    6731               0 :    mLength += mBottomOffset;
    6732               0 : }
    6733                 : 
    6734                 : /**
    6735                 :  * Paint the vertical segment
    6736                 :  * @param aIter         - iterator containing the structural information
    6737                 :  * @param aRenderingContext - the rendering context
    6738                 :  * @param aHorSegHeight - the width of the horizontal segment joining the corner
    6739                 :  *                        at the start
    6740                 :  */
    6741                 : void
    6742               0 : BCVerticalSeg::Paint(BCPaintBorderIterator& aIter,
    6743                 :                      nsRenderingContext&   aRenderingContext,
    6744                 :                      BCPixelSize            aHorSegHeight)
    6745                 : {
    6746                 :   // get the border style, color and paint the segment
    6747               0 :   mozilla::css::Side side = (aIter.IsDamageAreaRightMost()) ? NS_SIDE_RIGHT :
    6748               0 :                                                     NS_SIDE_LEFT;
    6749               0 :   PRInt32 relColIndex = aIter.GetRelativeColIndex();
    6750               0 :   nsTableColFrame* col           = mCol; if (!col) ABORT0();
    6751               0 :   nsTableCellFrame* cell         = mFirstCell; // ???
    6752               0 :   nsIFrame* owner = nsnull;
    6753               0 :   PRUint8 style = NS_STYLE_BORDER_STYLE_SOLID;
    6754               0 :   nscolor color = 0xFFFFFFFF;
    6755                 : 
    6756               0 :   switch (mOwner) {
    6757                 :     case eTableOwner:
    6758               0 :       owner = aIter.mTable;
    6759               0 :       break;
    6760                 :     case eAjaColGroupOwner:
    6761               0 :       side = NS_SIDE_RIGHT;
    6762               0 :       if (!aIter.IsTableRightMost() && (relColIndex > 0)) {
    6763               0 :         col = aIter.mVerInfo[relColIndex - 1].mCol;
    6764                 :       } // and fall through
    6765                 :     case eColGroupOwner:
    6766               0 :       if (col) {
    6767               0 :         owner = col->GetParent();
    6768                 :       }
    6769               0 :       break;
    6770                 :     case eAjaColOwner:
    6771               0 :       side = NS_SIDE_RIGHT;
    6772               0 :       if (!aIter.IsTableRightMost() && (relColIndex > 0)) {
    6773               0 :         col = aIter.mVerInfo[relColIndex - 1].mCol;
    6774                 :       } // and fall through
    6775                 :     case eColOwner:
    6776               0 :       owner = col;
    6777               0 :       break;
    6778                 :     case eAjaRowGroupOwner:
    6779               0 :       NS_ERROR("a neighboring rowgroup can never own a vertical border");
    6780                 :       // and fall through
    6781                 :     case eRowGroupOwner:
    6782               0 :       NS_ASSERTION(aIter.IsTableLeftMost() || aIter.IsTableRightMost(),
    6783                 :                   "row group can own border only at table edge");
    6784               0 :       owner = mFirstRowGroup;
    6785               0 :       break;
    6786                 :     case eAjaRowOwner:
    6787               0 :       NS_ASSERTION(false, "program error"); // and fall through
    6788                 :     case eRowOwner:
    6789               0 :       NS_ASSERTION(aIter.IsTableLeftMost() || aIter.IsTableRightMost(),
    6790                 :                    "row can own border only at table edge");
    6791               0 :       owner = mFirstRow;
    6792               0 :       break;
    6793                 :     case eAjaCellOwner:
    6794               0 :       side = NS_SIDE_RIGHT;
    6795               0 :       cell = mAjaCell; // and fall through
    6796                 :     case eCellOwner:
    6797               0 :       owner = cell;
    6798               0 :       break;
    6799                 :   }
    6800               0 :   if (owner) {
    6801               0 :     ::GetPaintStyleInfo(owner, side, style, color, aIter.mTableIsLTR);
    6802                 :   }
    6803                 :   BCPixelSize smallHalf, largeHalf;
    6804               0 :   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
    6805               0 :   nsRect segRect(mOffsetX - nsPresContext::CSSPixelsToAppUnits(largeHalf),
    6806                 :                  mOffsetY,
    6807               0 :                  nsPresContext::CSSPixelsToAppUnits(mWidth), mLength);
    6808                 :   nscoord bottomBevelOffset = (mIsBottomBevel) ?
    6809               0 :                   nsPresContext::CSSPixelsToAppUnits(mBottomHorSegHeight) : 0;
    6810               0 :   mozilla::css::Side bottomBevelSide = ((aHorSegHeight > 0) ^ !aIter.mTableIsLTR) ?
    6811               0 :                             NS_SIDE_RIGHT : NS_SIDE_LEFT;
    6812               0 :   mozilla::css::Side topBevelSide = ((mTopBevelSide == NS_SIDE_RIGHT) ^ !aIter.mTableIsLTR)?
    6813               0 :                          NS_SIDE_RIGHT : NS_SIDE_LEFT;
    6814                 :   nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color,
    6815                 :                                          aIter.mTableBgColor, segRect,
    6816                 :                                          nsPresContext::AppUnitsPerCSSPixel(),
    6817                 :                                          topBevelSide, mTopBevelOffset,
    6818               0 :                                          bottomBevelSide, bottomBevelOffset);
    6819                 : }
    6820                 : 
    6821                 : /**
    6822                 :  * Advance the start point of a segment
    6823                 :  */
    6824                 : void
    6825               0 : BCVerticalSeg::AdvanceOffsetY()
    6826                 : {
    6827               0 :   mOffsetY +=  mLength - mBottomOffset;
    6828               0 : }
    6829                 : 
    6830                 : /**
    6831                 :  * Accumulate the current segment
    6832                 :  */
    6833                 : void
    6834               0 : BCVerticalSeg::IncludeCurrentBorder(BCPaintBorderIterator& aIter)
    6835                 : {
    6836               0 :   mLastCell = aIter.mCell;
    6837               0 :   mLength  += aIter.mRow->GetRect().height;
    6838               0 : }
    6839                 : 
    6840               0 : BCHorizontalSeg::BCHorizontalSeg()
    6841                 : {
    6842               0 :   mOffsetX = mOffsetY = mLength = mWidth =  mLeftBevelOffset = 0;
    6843               0 :   mLeftBevelSide = NS_SIDE_TOP;
    6844               0 :   mFirstCell = mAjaCell = nsnull;
    6845               0 : }
    6846                 : 
    6847                 : /** Initialize a horizontal border segment for painting
    6848                 :   * @param aIter              - iterator storing the current and adjacent frames
    6849                 :   * @param aBorderOwner       - which frame owns the border
    6850                 :   * @param aBottomVerSegWidth - vertical segment width coming from up
    6851                 :   * @param aHorSegHeight      - the height of the segment
    6852                 :   +  */
    6853                 : void
    6854               0 : BCHorizontalSeg::Start(BCPaintBorderIterator& aIter,
    6855                 :                        BCBorderOwner        aBorderOwner,
    6856                 :                        BCPixelSize          aBottomVerSegWidth,
    6857                 :                        BCPixelSize          aHorSegHeight)
    6858                 : {
    6859               0 :   mozilla::css::Side cornerOwnerSide = NS_SIDE_TOP;
    6860               0 :   bool bevel     = false;
    6861                 : 
    6862               0 :   mOwner = aBorderOwner;
    6863                 :   nscoord cornerSubWidth  = (aIter.mBCData) ?
    6864                 :                              aIter.mBCData->GetCorner(cornerOwnerSide,
    6865               0 :                                                        bevel) : 0;
    6866                 : 
    6867               0 :   bool    leftBevel = (aHorSegHeight > 0) ? bevel : false;
    6868               0 :   PRInt32 relColIndex = aIter.GetRelativeColIndex();
    6869               0 :   nscoord maxVerSegWidth = NS_MAX(aIter.mVerInfo[relColIndex].mWidth,
    6870               0 :                                   aBottomVerSegWidth);
    6871                 :   nscoord offset = CalcHorCornerOffset(cornerOwnerSide, cornerSubWidth,
    6872                 :                                        maxVerSegWidth, true, leftBevel,
    6873               0 :                                        aIter.mTableIsLTR);
    6874               0 :   mLeftBevelOffset = (leftBevel && (aHorSegHeight > 0)) ? maxVerSegWidth : 0;
    6875                 :   // XXX this assumes that only corners where 2 segments join can be beveled
    6876               0 :   mLeftBevelSide   = (aBottomVerSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
    6877               0 :   if (aIter.mTableIsLTR) {
    6878               0 :     mOffsetX += offset;
    6879                 :   }
    6880                 :   else {
    6881               0 :     mOffsetX -= offset;
    6882                 :   }
    6883               0 :   mLength          = -offset;
    6884               0 :   mWidth           = aHorSegHeight;
    6885               0 :   mFirstCell       = aIter.mCell;
    6886               0 :   mAjaCell         = (aIter.IsDamageAreaTopMost()) ? nsnull :
    6887               0 :                      aIter.mVerInfo[relColIndex].mLastCell;
    6888               0 : }
    6889                 : 
    6890                 : /**
    6891                 :  * Compute the offsets for the right corner of a horizontal segment
    6892                 :  * @param aIter         - iterator containing the structural information
    6893                 :  * @param aLeftSegWidth - the width of the vertical segment joining the corner
    6894                 :  *                        at the start
    6895                 :  */
    6896                 : void
    6897               0 : BCHorizontalSeg::GetRightCorner(BCPaintBorderIterator& aIter,
    6898                 :                                 BCPixelSize            aLeftSegWidth)
    6899                 : {
    6900               0 :   mozilla::css::Side ownerSide = NS_SIDE_TOP;
    6901               0 :   nscoord cornerSubWidth = 0;
    6902               0 :   bool bevel = false;
    6903               0 :   if (aIter.mBCData) {
    6904               0 :     cornerSubWidth = aIter.mBCData->GetCorner(ownerSide, bevel);
    6905                 :   }
    6906                 : 
    6907               0 :   mIsRightBevel = (mWidth > 0) ? bevel : 0;
    6908               0 :   PRInt32 relColIndex = aIter.GetRelativeColIndex();
    6909               0 :   nscoord verWidth = NS_MAX(aIter.mVerInfo[relColIndex].mWidth, aLeftSegWidth);
    6910                 :   mEndOffset = CalcHorCornerOffset(ownerSide, cornerSubWidth, verWidth,
    6911               0 :                                    false, mIsRightBevel, aIter.mTableIsLTR);
    6912               0 :   mLength += mEndOffset;
    6913                 :   mRightBevelOffset = (mIsRightBevel) ?
    6914               0 :                        nsPresContext::CSSPixelsToAppUnits(verWidth) : 0;
    6915               0 :   mRightBevelSide = (aLeftSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
    6916               0 : }
    6917                 : 
    6918                 : /**
    6919                 :  * Paint the horizontal segment
    6920                 :  * @param aIter         - iterator containing the structural information
    6921                 :  * @param aRenderingContext - the rendering context
    6922                 :  */
    6923                 : void
    6924               0 : BCHorizontalSeg::Paint(BCPaintBorderIterator& aIter,
    6925                 :                        nsRenderingContext&   aRenderingContext)
    6926                 : {
    6927                 :   // get the border style, color and paint the segment
    6928               0 :   mozilla::css::Side side = (aIter.IsDamageAreaBottomMost()) ? NS_SIDE_BOTTOM :
    6929               0 :                                                      NS_SIDE_TOP;
    6930               0 :   nsIFrame* rg   = aIter.mRg;  if (!rg) ABORT0();
    6931               0 :   nsIFrame* row  = aIter.mRow; if (!row) ABORT0();
    6932               0 :   nsIFrame* cell = mFirstCell;
    6933                 :   nsIFrame* col;
    6934               0 :   nsIFrame* owner = nsnull;
    6935                 : 
    6936               0 :   PRUint8 style = NS_STYLE_BORDER_STYLE_SOLID;
    6937               0 :   nscolor color = 0xFFFFFFFF;
    6938                 : 
    6939                 : 
    6940               0 :   switch (mOwner) {
    6941                 :     case eTableOwner:
    6942               0 :       owner = aIter.mTable;
    6943               0 :       break;
    6944                 :     case eAjaColGroupOwner:
    6945               0 :       NS_ERROR("neighboring colgroups can never own a horizontal border");
    6946                 :       // and fall through
    6947                 :     case eColGroupOwner:
    6948               0 :       NS_ASSERTION(aIter.IsTableTopMost() || aIter.IsTableBottomMost(),
    6949                 :                    "col group can own border only at the table edge");
    6950               0 :       col = aIter.mTableFirstInFlow->GetColFrame(aIter.mColIndex - 1);
    6951               0 :       if (!col) ABORT0();
    6952               0 :       owner = col->GetParent();
    6953               0 :       break;
    6954                 :     case eAjaColOwner:
    6955               0 :       NS_ERROR("neighboring column can never own a horizontal border");
    6956                 :       // and fall through
    6957                 :     case eColOwner:
    6958               0 :       NS_ASSERTION(aIter.IsTableTopMost() || aIter.IsTableBottomMost(),
    6959                 :                    "col can own border only at the table edge");
    6960               0 :       owner = aIter.mTableFirstInFlow->GetColFrame(aIter.mColIndex - 1);
    6961               0 :       break;
    6962                 :     case eAjaRowGroupOwner:
    6963               0 :       side = NS_SIDE_BOTTOM;
    6964               0 :       rg = (aIter.IsTableBottomMost()) ? aIter.mRg : aIter.mPrevRg;
    6965                 :       // and fall through
    6966                 :     case eRowGroupOwner:
    6967               0 :       owner = rg;
    6968               0 :       break;
    6969                 :     case eAjaRowOwner:
    6970               0 :       side = NS_SIDE_BOTTOM;
    6971               0 :       row = (aIter.IsTableBottomMost()) ? aIter.mRow : aIter.mPrevRow;
    6972                 :       // and fall through
    6973                 :       case eRowOwner:
    6974               0 :       owner = row;
    6975               0 :       break;
    6976                 :     case eAjaCellOwner:
    6977               0 :       side = NS_SIDE_BOTTOM;
    6978                 :       // if this is null due to the damage area origin-y > 0, then the border
    6979                 :       // won't show up anyway
    6980               0 :       cell = mAjaCell;
    6981                 :       // and fall through
    6982                 :     case eCellOwner:
    6983               0 :       owner = cell;
    6984               0 :       break;
    6985                 :   }
    6986               0 :   if (owner) {
    6987               0 :     ::GetPaintStyleInfo(owner, side, style, color, aIter.mTableIsLTR);
    6988                 :   }
    6989                 :   BCPixelSize smallHalf, largeHalf;
    6990               0 :   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
    6991                 :   nsRect segRect(mOffsetX,
    6992               0 :                  mOffsetY - nsPresContext::CSSPixelsToAppUnits(largeHalf),
    6993                 :                  mLength,
    6994               0 :                  nsPresContext::CSSPixelsToAppUnits(mWidth));
    6995               0 :   if (aIter.mTableIsLTR) {
    6996                 :     nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color,
    6997                 :                                            aIter.mTableBgColor, segRect,
    6998                 :                                            nsPresContext::AppUnitsPerCSSPixel(),
    6999                 :                                            mLeftBevelSide,
    7000                 :                                            nsPresContext::CSSPixelsToAppUnits(mLeftBevelOffset),
    7001               0 :                                            mRightBevelSide, mRightBevelOffset);
    7002                 :   }
    7003                 :   else {
    7004               0 :     segRect.x -= segRect.width;
    7005                 :     nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color,
    7006                 :                                            aIter.mTableBgColor, segRect,
    7007                 :                                            nsPresContext::AppUnitsPerCSSPixel(),
    7008                 :                                            mRightBevelSide, mRightBevelOffset,
    7009                 :                                            mLeftBevelSide,
    7010               0 :                                            nsPresContext::CSSPixelsToAppUnits(mLeftBevelOffset));
    7011                 :   }
    7012                 : }
    7013                 : 
    7014                 : /**
    7015                 :  * Advance the start point of a segment
    7016                 :  */
    7017                 : void
    7018               0 : BCHorizontalSeg::AdvanceOffsetX(PRInt32 aIncrement)
    7019                 : {
    7020               0 :   mOffsetX += aIncrement * (mLength - mEndOffset);
    7021               0 : }
    7022                 : 
    7023                 : /**
    7024                 :  * Accumulate the current segment
    7025                 :  */
    7026                 : void
    7027               0 : BCHorizontalSeg::IncludeCurrentBorder(BCPaintBorderIterator& aIter)
    7028                 : {
    7029               0 :   mLength += aIter.mVerInfo[aIter.GetRelativeColIndex()].mColWidth;
    7030               0 : }
    7031                 : 
    7032                 : /**
    7033                 :  * store the column width information while painting horizontal segment
    7034                 :  */
    7035                 : void
    7036               0 : BCPaintBorderIterator::StoreColumnWidth(PRInt32 aIndex)
    7037                 : {
    7038               0 :   if (IsTableRightMost()) {
    7039               0 :       mVerInfo[aIndex].mColWidth = mVerInfo[aIndex - 1].mColWidth;
    7040                 :   }
    7041                 :   else {
    7042               0 :     nsTableColFrame* col = mTableFirstInFlow->GetColFrame(mColIndex);
    7043               0 :     if (!col) ABORT0();
    7044               0 :     mVerInfo[aIndex].mColWidth = col->GetSize().width;
    7045                 :   }
    7046                 : }
    7047                 : /**
    7048                 :  * Determine if a vertical segment owns the corder
    7049                 :  */
    7050                 : bool
    7051               0 : BCPaintBorderIterator::VerticalSegmentOwnsCorner()
    7052                 : {
    7053               0 :   mozilla::css::Side cornerOwnerSide = NS_SIDE_TOP;
    7054               0 :   bool bevel = false;
    7055               0 :   if (mBCData) {
    7056               0 :     mBCData->GetCorner(cornerOwnerSide, bevel);
    7057                 :   }
    7058                 :   // unitialized ownerside, bevel
    7059                 :   return  (NS_SIDE_TOP == cornerOwnerSide) ||
    7060               0 :           (NS_SIDE_BOTTOM == cornerOwnerSide);
    7061                 : }
    7062                 : 
    7063                 : /**
    7064                 :  * Paint if necessary a horizontal segment, otherwise accumulate it
    7065                 :  * @param aRenderingContext - the rendering context
    7066                 :  */
    7067                 : void
    7068               0 : BCPaintBorderIterator::AccumulateOrPaintHorizontalSegment(nsRenderingContext& aRenderingContext)
    7069                 : {
    7070                 : 
    7071               0 :   PRInt32 relColIndex = GetRelativeColIndex();
    7072                 :   // store the current col width if it hasn't been already
    7073               0 :   if (mVerInfo[relColIndex].mColWidth < 0) {
    7074               0 :     StoreColumnWidth(relColIndex);
    7075                 :   }
    7076                 : 
    7077               0 :   BCBorderOwner borderOwner = eCellOwner;
    7078                 :   BCBorderOwner ignoreBorderOwner;
    7079               0 :   bool isSegStart = true;
    7080                 :   bool ignoreSegStart;
    7081                 : 
    7082                 :   nscoord leftSegWidth =
    7083               0 :     mBCData ? mBCData->GetLeftEdge(ignoreBorderOwner, ignoreSegStart) : 0;
    7084                 :   nscoord topSegHeight =
    7085               0 :     mBCData ? mBCData->GetTopEdge(borderOwner, isSegStart) : 0;
    7086                 : 
    7087               0 :   if (mIsNewRow || (IsDamageAreaLeftMost() && IsDamageAreaBottomMost())) {
    7088                 :     // reset for every new row and on the bottom of the last row
    7089               0 :     mHorSeg.mOffsetY = mNextOffsetY;
    7090               0 :     mNextOffsetY     = mNextOffsetY + mRow->GetSize().height;
    7091               0 :     mHorSeg.mOffsetX = mInitialOffsetX;
    7092               0 :     mHorSeg.Start(*this, borderOwner, leftSegWidth, topSegHeight);
    7093                 :   }
    7094                 : 
    7095               0 :   if (!IsDamageAreaLeftMost() && (isSegStart || IsDamageAreaRightMost() ||
    7096               0 :                                   VerticalSegmentOwnsCorner())) {
    7097                 :     // paint the previous seg or the current one if IsDamageAreaRightMost()
    7098               0 :     if (mHorSeg.mLength > 0) {
    7099               0 :       mHorSeg.GetRightCorner(*this, leftSegWidth);
    7100               0 :       if (mHorSeg.mWidth > 0) {
    7101               0 :         mHorSeg.Paint(*this, aRenderingContext);
    7102                 :       }
    7103               0 :       mHorSeg.AdvanceOffsetX(mColInc);
    7104                 :     }
    7105               0 :     mHorSeg.Start(*this, borderOwner, leftSegWidth, topSegHeight);
    7106                 :   }
    7107               0 :   mHorSeg.IncludeCurrentBorder(*this);
    7108               0 :   mVerInfo[relColIndex].mWidth = leftSegWidth;
    7109               0 :   mVerInfo[relColIndex].mLastCell = mCell;
    7110               0 : }
    7111                 : /**
    7112                 :  * Paint if necessary a vertical segment, otherwise  it
    7113                 :  * @param aRenderingContext - the rendering context
    7114                 :  */
    7115                 : void
    7116               0 : BCPaintBorderIterator::AccumulateOrPaintVerticalSegment(nsRenderingContext& aRenderingContext)
    7117                 : {
    7118               0 :   BCBorderOwner borderOwner = eCellOwner;
    7119                 :   BCBorderOwner ignoreBorderOwner;
    7120               0 :   bool isSegStart = true;
    7121                 :   bool ignoreSegStart;
    7122                 : 
    7123                 :   nscoord verSegWidth  =
    7124               0 :     mBCData ? mBCData->GetLeftEdge(borderOwner, isSegStart) : 0;
    7125                 :   nscoord horSegHeight =
    7126               0 :     mBCData ? mBCData->GetTopEdge(ignoreBorderOwner, ignoreSegStart) : 0;
    7127                 : 
    7128               0 :   PRInt32 relColIndex = GetRelativeColIndex();
    7129               0 :   BCVerticalSeg& verSeg = mVerInfo[relColIndex];
    7130               0 :   if (!verSeg.mCol) { // on the first damaged row and the first segment in the
    7131                 :                       // col
    7132               0 :     verSeg.Initialize(*this);
    7133               0 :     verSeg.Start(*this, borderOwner, verSegWidth, horSegHeight);
    7134                 :   }
    7135                 : 
    7136               0 :   if (!IsDamageAreaTopMost() && (isSegStart || IsDamageAreaBottomMost() ||
    7137               0 :                                  IsAfterRepeatedHeader() ||
    7138               0 :                                  StartRepeatedFooter())) {
    7139                 :     // paint the previous seg or the current one if IsDamageAreaBottomMost()
    7140               0 :     if (verSeg.mLength > 0) {
    7141               0 :       verSeg.GetBottomCorner(*this, horSegHeight);
    7142               0 :       if (verSeg.mWidth > 0) {
    7143               0 :         verSeg.Paint(*this, aRenderingContext, horSegHeight);
    7144                 :       }
    7145               0 :       verSeg.AdvanceOffsetY();
    7146                 :     }
    7147               0 :     verSeg.Start(*this, borderOwner, verSegWidth, horSegHeight);
    7148                 :   }
    7149               0 :   verSeg.IncludeCurrentBorder(*this);
    7150               0 :   mPrevHorSegHeight = horSegHeight;
    7151               0 : }
    7152                 : 
    7153                 : /**
    7154                 :  * Reset the vertical information cache
    7155                 :  */
    7156                 : void
    7157               0 : BCPaintBorderIterator::ResetVerInfo()
    7158                 : {
    7159               0 :   if (mVerInfo) {
    7160               0 :     memset(mVerInfo, 0, mDamageArea.width * sizeof(BCVerticalSeg));
    7161                 :     // XXX reinitialize properly
    7162               0 :     for (PRInt32 xIndex = 0; xIndex < mDamageArea.width; xIndex++) {
    7163               0 :       mVerInfo[xIndex].mColWidth = -1;
    7164                 :     }
    7165                 :   }
    7166               0 : }
    7167                 : 
    7168                 : /**
    7169                 :  * Method to paint BCBorders, this does not use currently display lists although
    7170                 :  * it will do this in future
    7171                 :  * @param aRenderingContext - the rendering context
    7172                 :  * @param aDirtyRect        - inside this rectangle the BC Borders will redrawn
    7173                 :  */
    7174                 : void
    7175               0 : nsTableFrame::PaintBCBorders(nsRenderingContext& aRenderingContext,
    7176                 :                              const nsRect&        aDirtyRect)
    7177                 : {
    7178                 :   // We first transfer the aDirtyRect into cellmap coordinates to compute which
    7179                 :   // cell borders need to be painted
    7180               0 :   BCPaintBorderIterator iter(this);
    7181               0 :   if (!iter.SetDamageArea(aDirtyRect))
    7182                 :     return;
    7183                 : 
    7184                 :   // First, paint all of the vertical borders from top to bottom and left to
    7185                 :   // right as they become complete. They are painted first, since they are less
    7186                 :   // efficient to paint than horizontal segments. They were stored with as few
    7187                 :   // segments as possible (since horizontal borders are painted last and
    7188                 :   // possibly over them). For every cell in a row that fails in the damage are
    7189                 :   // we look up if the current border would start a new segment, if so we paint
    7190                 :   // the previously stored vertical segment and start a new segment. After
    7191                 :   // this we  the now active segment with the current border. These
    7192                 :   // segments are stored in mVerInfo to be used on the next row
    7193               0 :   for (iter.First(); !iter.mAtEnd; iter.Next()) {
    7194               0 :     iter.AccumulateOrPaintVerticalSegment(aRenderingContext);
    7195                 :   }
    7196                 : 
    7197                 :   // Next, paint all of the horizontal border segments from top to bottom reuse
    7198                 :   // the mVerInfo array to keep track of col widths and vertical segments for
    7199                 :   // corner calculations
    7200               0 :   iter.Reset();
    7201               0 :   for (iter.First(); !iter.mAtEnd; iter.Next()) {
    7202               0 :     iter.AccumulateOrPaintHorizontalSegment(aRenderingContext);
    7203                 :   }
    7204                 : }
    7205                 : 
    7206               0 : bool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex, PRInt32 aNumEffCols)
    7207                 : {
    7208               0 :   bool result = false;
    7209               0 :   nsTableCellMap* cellMap = GetCellMap();
    7210               0 :   NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated.");
    7211               0 :   if (cellMap) {
    7212               0 :     result = cellMap->RowHasSpanningCells(aRowIndex, aNumEffCols);
    7213                 :   }
    7214               0 :   return result;
    7215                 : }
    7216                 : 
    7217               0 : bool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex, PRInt32 aNumEffCols)
    7218                 : {
    7219               0 :   bool result = false;
    7220               0 :   nsTableCellMap* cellMap = GetCellMap();
    7221               0 :   NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated.");
    7222               0 :   if (cellMap) {
    7223               0 :     result = cellMap->RowIsSpannedInto(aRowIndex, aNumEffCols);
    7224                 :   }
    7225               0 :   return result;
    7226                 : }
    7227                 : 
    7228                 : /* static */
    7229                 : void
    7230               0 : nsTableFrame::InvalidateFrame(nsIFrame* aFrame,
    7231                 :                               const nsRect& aOrigRect,
    7232                 :                               const nsRect& aOrigVisualOverflow,
    7233                 :                               bool aIsFirstReflow)
    7234                 : {
    7235               0 :   nsIFrame* parent = aFrame->GetParent();
    7236               0 :   NS_ASSERTION(parent, "What happened here?");
    7237                 : 
    7238               0 :   if (parent->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
    7239                 :     // Don't bother; we'll invalidate the parent's overflow rect when
    7240                 :     // we finish reflowing it.
    7241               0 :     return;
    7242                 :   }
    7243                 : 
    7244                 :   // The part that looks at both the rect and the overflow rect is a
    7245                 :   // bit of a hack.  See nsBlockFrame::ReflowLine for an eloquent
    7246                 :   // description of its hackishness.
    7247               0 :   nsRect visualOverflow = aFrame->GetVisualOverflowRect();
    7248               0 :   if (aIsFirstReflow ||
    7249               0 :       aOrigRect.TopLeft() != aFrame->GetPosition() ||
    7250               0 :       aOrigVisualOverflow.TopLeft() != visualOverflow.TopLeft()) {
    7251                 :     // Invalidate the old and new overflow rects.  Note that if the
    7252                 :     // frame moved, we can't just use aOrigVisualOverflow, since it's in
    7253                 :     // coordinates relative to the old position.  So invalidate via
    7254                 :     // aFrame's parent, and reposition that overflow rect to the right
    7255                 :     // place.
    7256                 :     // XXXbz this doesn't handle outlines, does it?
    7257               0 :     aFrame->Invalidate(visualOverflow);
    7258               0 :     parent->Invalidate(aOrigVisualOverflow + aOrigRect.TopLeft());
    7259                 :   } else {
    7260               0 :     nsRect rect = aFrame->GetRect();
    7261                 :     aFrame->CheckInvalidateSizeChange(aOrigRect, aOrigVisualOverflow,
    7262               0 :                                       rect.Size());
    7263               0 :     aFrame->InvalidateRectDifference(aOrigVisualOverflow, visualOverflow);
    7264               0 :     parent->InvalidateRectDifference(aOrigRect, rect);
    7265                 :   }
    7266                 : }

Generated by: LCOV version 1.7