Back to index

lightning-sunbird  0.9+nobinonly
BasicTableLayoutStrategy.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
00039 #include "plarena.h"
00040 
00041 #include "BasicTableLayoutStrategy.h"
00042 #include "nsPresContext.h"
00043 #include "nsTableFrame.h"
00044 #include "nsTableColFrame.h"
00045 #include "nsTableCellFrame.h"
00046 #include "nsStyleConsts.h"
00047 #include "nsVoidArray.h"
00048 #include "nsQuickSort.h"
00049 
00050 
00051 #define ARENA_ALLOCATE(var, pool, num, type) \
00052     {void *_tmp_; PL_ARENA_ALLOCATE(_tmp_, pool, (num*sizeof(type))); \
00053     var = NS_REINTERPRET_CAST(type*, _tmp_); }
00054 
00055 // Local class used to hold information about table cells so we do not
00056 // have to look it up multiple times
00057 struct CellInfo {
00058   nsTableCellFrame *cellFrame;
00059   PRInt32 colSpan;
00060 };
00061 
00062 #ifdef DEBUG_TABLE_STRATEGY
00063 static PRInt32 gsDebugCount = 0;
00064 #endif
00065 // The priority of allocations for columns is as follows
00066 //   1) max(MIN, MIN_ADJ)
00067 //   2) max (PCT, PCT_ADJ) 
00068 //   3) FIX 
00069 //   4) FIX_ADJ
00070 //   5) max(DES_CON, DES_ADJ), but use MIN_PRO if present
00071 //   6) for a fixed width table, the column may get more 
00072 //      space if the sum of the col allocations is insufficient 
00073 
00074 
00075 // the logic here is kept in synch with that in CalculateTotals.
00076 PRBool CanAllocate(PRInt32          aType,
00077                    PRInt32          aPrevType,
00078                    nsTableColFrame* aColFrame)
00079 {
00080   switch(aType) {
00081   case PCT:
00082   case FIX:
00083   case DES_CON:
00084     return (WIDTH_NOT_SET == aPrevType);
00085   case FIX_ADJ:
00086     return (WIDTH_NOT_SET == aPrevType) || (FIX == aPrevType);
00087   default:
00088     NS_ASSERTION(PR_FALSE, "invalid call");
00089   }
00090   return PR_FALSE;
00091 }
00092 
00093 // this doesn't work for a col frame which might get its width from a col
00094 PRBool
00095 HasPctValue(const nsIFrame* aFrame) 
00096 {
00097   const nsStylePosition* position = aFrame->GetStylePosition();
00098   if (eStyleUnit_Percent == position->mWidth.GetUnit()) {
00099     float percent = position->mWidth.GetPercentValue();
00100     if (percent > 0.0f) {
00101       return PR_TRUE;
00102     }
00103   }
00104   return PR_FALSE;
00105 }
00106 
00107 /* ---------- BasicTableLayoutStrategy ---------- */
00108 
00109 MOZ_DECL_CTOR_COUNTER(BasicTableLayoutStrategy)
00110 
00111 
00112 BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame, PRBool aIsNavQuirks)
00113 {
00114   MOZ_COUNT_CTOR(BasicTableLayoutStrategy);
00115   NS_ASSERTION(nsnull != aFrame, "bad frame arg");
00116 
00117   mTableFrame            = aFrame;
00118   mCellSpacingTotal      = 0;
00119   mIsNavQuirksMode       = aIsNavQuirks;
00120 }
00121 
00122 BasicTableLayoutStrategy::~BasicTableLayoutStrategy()
00123 {
00124   MOZ_COUNT_DTOR(BasicTableLayoutStrategy);
00125 }
00126 
00127 PRBool BasicTableLayoutStrategy::Initialize(const nsHTMLReflowState& aReflowState)
00128 {
00129 #ifdef DEBUG_TABLE_REFLOW_TIMING
00130   nsTableFrame::DebugTimeMethod(nsTableFrame::eInit, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE);
00131 #endif
00132   ContinuingFrameCheck();
00133 
00134   PRBool result = PR_TRUE;
00135 
00136   // re-init instance variables
00137   mCellSpacingTotal = 0;
00138   mCols             = mTableFrame->GetEffectiveCOLSAttribute();
00139 
00140   mTableFrame->SetHasPctCol(PR_FALSE);
00141 
00142   nscoord boxWidth = mTableFrame->CalcBorderBoxWidth(aReflowState);
00143   PRBool hasPctCol = AssignNonPctColumnWidths(boxWidth, aReflowState);
00144 
00145   mTableFrame->SetHasPctCol(hasPctCol);
00146 
00147   // calc the min, desired, preferred widths from what we know so far
00148   nscoord minWidth, prefWidth;
00149   mTableFrame->CalcMinAndPreferredWidths(aReflowState, PR_FALSE, minWidth, prefWidth);
00150   if (hasPctCol && mTableFrame->IsAutoWidth()) {
00151     prefWidth = CalcPctAdjTableWidth(aReflowState, boxWidth);
00152   }
00153   // calc the desired width, considering if there is a specified width. 
00154   // don't use nsTableFrame::CalcDesiredWidth because it is based on table column widths.
00155   nscoord desWidth = (mTableFrame->IsAutoWidth()) ? PR_MIN(prefWidth, aReflowState.availableWidth)
00156                                                   : prefWidth;
00157   desWidth = PR_MAX(desWidth, minWidth);
00158 
00159   mTableFrame->SetMinWidth(minWidth);
00160   mTableFrame->SetDesiredWidth(desWidth);
00161   mTableFrame->SetPreferredWidth(prefWidth);
00162 
00163   mTableFrame->SetNeedStrategyInit(PR_FALSE);
00164 
00165 #ifdef DEBUG_TABLE_REFLOW_TIMING
00166   nsTableFrame::DebugTimeMethod(nsTableFrame::eInit, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE);
00167 #endif
00168   return result;
00169 }
00170 
00171 void BasicTableLayoutStrategy::ContinuingFrameCheck()
00172 {
00173   NS_ASSERTION(!mTableFrame->GetPrevInFlow(),
00174                "never ever call me on a continuing frame!");
00175 }
00176 
00177 PRBool BCW_Wrapup(const nsHTMLReflowState&  aReflowState,
00178                   BasicTableLayoutStrategy* aStrategy, 
00179                   nsTableFrame*             aTableFrame, 
00180                   PRInt32*                  aAllocTypes)
00181 {
00182   if (aAllocTypes)
00183     delete [] aAllocTypes;
00184 #ifdef DEBUG_TABLE_STRATEGY
00185   printf("BalanceColumnWidths ex \n"); aTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);
00186 #endif
00187 #ifdef DEBUG_TABLE_REFLOW_TIMING
00188   nsTableFrame::DebugTimeMethod(nsTableFrame::eBalanceCols, *aTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE);
00189 #endif
00190   return PR_TRUE;
00191 }
00192 
00193 void
00194 ResetPctValues(nsTableFrame* aTableFrame,
00195                PRInt32       aNumCols)
00196 {
00197   // initialize the col percent and cell percent values to 0.
00198   PRInt32 colX;
00199   for (colX = 0; colX < aNumCols; colX++) { 
00200     nsTableColFrame* colFrame = aTableFrame->GetColFrame(colX); 
00201     if (colFrame) {
00202       colFrame->SetWidth(PCT, WIDTH_NOT_SET);
00203       colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET);
00204     }
00205   }
00206 }
00207 
00208 PRBool 
00209 BasicTableLayoutStrategy::BalanceColumnWidths(const nsHTMLReflowState& aReflowState)
00210 {
00211 #ifdef DEBUG_TABLE_STRATEGY
00212   printf("BalanceColumnWidths en count=%d \n", gsDebugCount++); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);
00213 #endif
00214 #ifdef DEBUG_TABLE_REFLOW_TIMING
00215   nsTableFrame::DebugTimeMethod(nsTableFrame::eBalanceCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE);
00216 #endif
00217   float p2t = mTableFrame->GetPresContext()->ScaledPixelsToTwips();
00218 
00219   ContinuingFrameCheck();
00220 
00221   PRInt32 numCols = mTableFrame->GetColCount();
00222   PRBool tableIsAutoWidth = mTableFrame->IsAutoWidth();
00223 
00224   nscoord horOffset; 
00225   // get the reduction in available horizontal space due to borders and padding
00226   nsMargin offset = mTableFrame->GetChildAreaOffset(&aReflowState);
00227   horOffset = offset.left + offset.right;
00228 
00229   // determine if the table is auto/fixed and get the fixed width if available
00230   nscoord maxWidth = mTableFrame->CalcBorderBoxWidth(aReflowState);
00231   if (NS_UNCONSTRAINEDSIZE == maxWidth) {
00232     maxWidth = PR_MIN(maxWidth, aReflowState.availableWidth);
00233     if (NS_UNCONSTRAINEDSIZE == maxWidth) {
00234       NS_ASSERTION(NS_UNCONSTRAINEDSIZE != maxWidth, "cannot balance with an unconstrained width");
00235       return PR_FALSE;
00236     }
00237   }
00238   // initialize the col percent and cell percent values to 0.
00239   ResetPctValues(mTableFrame, numCols);
00240 
00241   // An auto table returns a new table width based on percent cells/cols if they exist
00242   nscoord perAdjTableWidth = 0;
00243   if (mTableFrame->HasPctCol()) {
00244     perAdjTableWidth = AssignPctColumnWidths(aReflowState, maxWidth, tableIsAutoWidth, p2t);
00245     if (perAdjTableWidth > 0) {
00246       // if an auto table has a pct col or cell, set the preferred table width 
00247       // here so that CalcPctAdjTableWidth wont't need to be called by the table
00248       mTableFrame->SetPreferredWidth(perAdjTableWidth);
00249     }
00250     perAdjTableWidth = PR_MIN(perAdjTableWidth, maxWidth);
00251     perAdjTableWidth -= horOffset;
00252     perAdjTableWidth = PR_MAX(perAdjTableWidth, 0);
00253   }
00254 
00255   // reduce the maxWidth by border and padding, since we will be dealing with content width
00256   maxWidth -= horOffset;
00257   maxWidth = PR_MAX(0, maxWidth);
00258 
00259   // we will re-calc mCellSpacingTotal in case longer rows were added after Initialize was called
00260   mCellSpacingTotal = 0;
00261   nscoord spacingX = mTableFrame->GetCellSpacingX();
00262 
00263   PRInt32 numNonZeroWidthCols = 0;
00264   // set the table's columns to the min width
00265   nscoord minTableWidth = 0;
00266   PRInt32 colX;
00267   for (colX = 0; colX < numCols; colX++) { 
00268     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
00269     if (!colFrame) continue;
00270     nscoord colMinWidth = colFrame->GetMinWidth();
00271     mTableFrame->SetColumnWidth(colX, colMinWidth);
00272     minTableWidth += colMinWidth;
00273     if ((colFrame->GetMinWidth() > 0) || (colFrame->GetDesWidth() > 0) ||
00274         (colFrame->GetFixWidth() > 0) || (colFrame->GetPctWidth() > 0) || 
00275         (colFrame->GetWidth(MIN_PRO) > 0)) {
00276       numNonZeroWidthCols++;
00277     }
00278     if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) {
00279       mCellSpacingTotal += spacingX;
00280     }
00281   }
00282   if (mCellSpacingTotal > 0) {
00283     mCellSpacingTotal += spacingX; // add last cell spacing on right
00284   }
00285   minTableWidth += mCellSpacingTotal;
00286 
00287   // if the max width available is less than the min content width for fixed table, we're done
00288   if (!tableIsAutoWidth && (maxWidth < minTableWidth)) {
00289     return BCW_Wrapup(aReflowState, this, mTableFrame, nsnull);
00290   }
00291 
00292   // if the max width available is less than the min content width for auto table
00293   // that had no % cells/cols, we're done
00294   if (tableIsAutoWidth && (maxWidth < minTableWidth) && (0 == perAdjTableWidth)) {
00295     return BCW_Wrapup(aReflowState, this, mTableFrame, nsnull);
00296   }
00297 
00298   // the following are of size NUM_WIDTHS, but only MIN_CON, DES_CON, FIX, FIX_ADJ, PCT
00299   // are used and they account for colspan ADJusted values
00300   PRInt32 totalWidths[NUM_WIDTHS]; // sum of col widths of a particular type 
00301   PRInt32 totalCounts[NUM_WIDTHS]; // num of cols of a particular type
00302   PRInt32 dupedWidths[NUM_WIDTHS];
00303   PRInt32 num0Proportional;
00304 
00305   CalculateTotals(totalCounts, totalWidths, dupedWidths, num0Proportional);
00306   // auto width table's adjusted width needs cell spacing
00307   if (tableIsAutoWidth && perAdjTableWidth > 0) { 
00308     maxWidth = perAdjTableWidth;
00309   }
00310   nscoord totalAllocated = totalWidths[MIN_CON] + mCellSpacingTotal;
00311   
00312   // allocate and initialize arrays indicating what col gets set
00313   PRInt32* allocTypes = new PRInt32[numCols];
00314   if (!allocTypes) return PR_FALSE;
00315  
00316   for (colX = 0; colX < numCols; colX++) {
00317     allocTypes[colX] = -1;
00318   }
00319 
00320   // allocate PCT/PCT_ADJ cols
00321   if (totalCounts[PCT] > 0) {
00322     if (totalAllocated + totalWidths[PCT] - dupedWidths[PCT] <= maxWidth) {
00323       AllocateFully(totalAllocated, allocTypes, PCT);
00324       //NS_WARN_IF_FALSE(totalAllocated <= maxWidth, "over allocated");
00325     }
00326     else {
00327       AllocateConstrained(maxWidth - totalAllocated, PCT, PR_FALSE, allocTypes, p2t);
00328       return BCW_Wrapup(aReflowState, this, mTableFrame, allocTypes);
00329     }
00330   }
00331   // allocate FIX cols
00332   if ((totalAllocated < maxWidth) && (totalCounts[FIX] > 0)) {
00333     if (totalAllocated + totalWidths[FIX] - dupedWidths[FIX] <= maxWidth) { 
00334       AllocateFully(totalAllocated, allocTypes, FIX);
00335       //NS_WARN_IF_FALSE(totalAllocated <= maxWidth, "over allocated");
00336     }
00337     else {
00338       AllocateConstrained(maxWidth - totalAllocated, FIX, PR_TRUE, allocTypes, p2t);
00339       return BCW_Wrapup(aReflowState, this, mTableFrame, allocTypes);
00340     }
00341   }
00342   // allocate fixed adjusted cols
00343   if ((totalAllocated < maxWidth) && (totalCounts[FIX_ADJ] > 0)) {
00344     if (totalAllocated + totalWidths[FIX_ADJ] - dupedWidths[FIX_ADJ] <= maxWidth) { 
00345       AllocateFully(totalAllocated, allocTypes, FIX_ADJ);
00346       //NS_WARN_IF_FALSE(totalAllocated <= maxWidth, "over allocated");
00347     }
00348     else {
00349       AllocateConstrained(maxWidth - totalAllocated, FIX_ADJ, PR_TRUE, allocTypes, p2t);
00350       return BCW_Wrapup(aReflowState, this, mTableFrame, allocTypes);
00351     }
00352   }
00353 
00354   // allocate proportional and auto cols together
00355   if ((totalAllocated < maxWidth) && (totalCounts[MIN_PRO] + totalCounts[DES_CON] > 0)) {
00356     if (totalAllocated + totalWidths[MIN_PRO] - dupedWidths[MIN_PRO] +
00357         totalWidths[DES_CON] - dupedWidths[DES_CON] <= maxWidth) { 
00358       AllocateFully(totalAllocated, allocTypes, DES_CON);
00359       //NS_WARN_IF_FALSE(totalAllocated <= maxWidth, "over allocated");
00360     }
00361     else {
00362       AllocateConstrained(maxWidth - totalAllocated, DES_CON, PR_TRUE, allocTypes, p2t);
00363       return BCW_Wrapup(aReflowState, this, mTableFrame, allocTypes);
00364     }
00365   }
00366 
00367   // if this is a nested non auto table and pass1 reflow, we are done
00368   if ((maxWidth == NS_UNCONSTRAINEDSIZE) && (!tableIsAutoWidth))  {
00369     return BCW_Wrapup(aReflowState, this, mTableFrame, allocTypes);
00370   }
00371 
00372   // allocate the rest to auto columns, with some exceptions
00373   if ( (tableIsAutoWidth && (perAdjTableWidth - totalAllocated > 0)) ||
00374        (!tableIsAutoWidth && (totalAllocated < maxWidth)) ) {
00375     // determine how many cols have width either because of a min, fixed, des, or pct value
00376     PRBool excludePct  = (totalCounts[PCT] != numNonZeroWidthCols);
00377     PRBool excludeFix  = (totalCounts[PCT] + totalCounts[FIX] + totalCounts[FIX_ADJ] < numNonZeroWidthCols);
00378     PRBool excludePro  = (totalCounts[DES_CON] > 0);
00379     PRBool exclude0Pro = (totalCounts[MIN_PRO] != num0Proportional);
00380     if (tableIsAutoWidth) {
00381       AllocateUnconstrained(perAdjTableWidth - totalAllocated, allocTypes, excludePct,
00382                             excludeFix, excludePro, exclude0Pro, p2t);
00383     }
00384     else {
00385       AllocateUnconstrained(maxWidth - totalAllocated, allocTypes, excludePct,
00386                             excludeFix, excludePro, exclude0Pro, p2t);
00387     }
00388   }
00389 
00390   return BCW_Wrapup(aReflowState, this, mTableFrame, allocTypes);
00391 }
00392 
00393 nscoord GetColWidth(nsTableColFrame* aColFrame,
00394                     PRInt32          aWidthType)
00395 {
00396   switch(aWidthType) {
00397   case DES_CON:
00398     return aColFrame->GetDesWidth();
00399   case FIX:
00400   case FIX_ADJ:
00401     return aColFrame->GetWidth(aWidthType);
00402   case PCT:
00403     return aColFrame->GetPctWidth();
00404   default:
00405     NS_ASSERTION(PR_FALSE, "invalid call");
00406     return WIDTH_NOT_SET;
00407   }
00408 }
00409 
00410 // Allocate aWidthType values to all cols available in aAllocTypes 
00411 void BasicTableLayoutStrategy::AllocateFully(nscoord&        aTotalAllocated,
00412                                              PRInt32*        aAllocTypes,
00413                                              PRInt32         aWidthType)
00414 {
00415   PRInt32 numCols = mTableFrame->GetColCount(); 
00416   for (PRInt32 colX = 0; colX < numCols; colX++) { 
00417     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
00418     if (!colFrame) continue;
00419     if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
00420       continue;
00421     }
00422     nscoord oldWidth = mTableFrame->GetColumnWidth(colX);
00423     nscoord newWidth = GetColWidth(colFrame, aWidthType);
00424     // proportional and desired widths are handled together
00425     PRBool haveProWidth = PR_FALSE;
00426     if (DES_CON == aWidthType) {
00427       nscoord proWidth = colFrame->GetWidth(MIN_PRO);
00428       if (proWidth >= 0) {
00429         haveProWidth = PR_TRUE;
00430         newWidth = proWidth;
00431       }
00432     }
00433 
00434     if (WIDTH_NOT_SET == newWidth) continue;
00435    
00436     if (newWidth > oldWidth) {
00437       mTableFrame->SetColumnWidth(colX, newWidth);
00438       aTotalAllocated += newWidth - oldWidth;
00439     }
00440     aAllocTypes[colX] = (haveProWidth) ? MIN_PRO : aWidthType;
00441   }
00442 }
00443 
00444 // This method is the last allocation method to get called, but just in case
00445 // code gets added later after, set the allocated cols to some final value.
00446 #define FINISHED 99 
00447 void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32  aAllocAmount,
00448                                                      PRInt32* aAllocTypes,
00449                                                      PRBool   aExcludePct,
00450                                                      PRBool   aExcludeFix,
00451                                                      PRBool   aExcludePro,
00452                                                      PRBool   aExclude0Pro,
00453                                                      float    aPixelToTwips)
00454 {
00455   // set up allocTypes to exclude anything but auto cols if possible
00456   PRInt32 colX;
00457   PRInt32 numCols = mTableFrame->GetColCount();
00458   for (colX = 0; colX < numCols; colX++) {
00459     if (aExcludePct && (PCT == aAllocTypes[colX])) {
00460       aAllocTypes[colX] = FINISHED;
00461     }
00462     else if (aExcludeFix && ((FIX == aAllocTypes[colX]) || (FIX_ADJ == aAllocTypes[colX]))) {
00463       aAllocTypes[colX] = FINISHED;
00464     }
00465     else if (MIN_PRO == aAllocTypes[colX]) {
00466       if (aExcludePro) {
00467         aAllocTypes[colX] = FINISHED;
00468       }
00469       else {
00470         if (aExclude0Pro) {
00471           nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
00472           if (!colFrame) continue;
00473           if (colFrame->GetConstraint() == e0ProportionConstraint) {
00474             aAllocTypes[colX] = FINISHED;
00475           }
00476         }
00477       }
00478     }
00479   }
00480     
00481   nscoord divisor          = 0;
00482   PRInt32 numColsAllocated = 0; 
00483   PRInt32 totalAllocated   = 0;
00484   for (colX = 0; colX < numCols; colX++) { 
00485     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
00486     if (!colFrame) continue; 
00487     PRBool skipColumn = aExclude0Pro && (e0ProportionConstraint == colFrame->GetConstraint());
00488     if (FINISHED != aAllocTypes[colX] && !skipColumn ) {
00489       divisor += mTableFrame->GetColumnWidth(colX);
00490       numColsAllocated++;
00491     }
00492   }
00493   if (!numColsAllocated) {
00494     // redistribute the space to all columns and prevent a division by zero
00495     numColsAllocated = numCols;
00496   }
00497   for (colX = 0; colX < numCols; colX++) { 
00498     if (FINISHED != aAllocTypes[colX]) {
00499       if (aExclude0Pro) {
00500         nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
00501         if (!colFrame) continue;
00502         if (e0ProportionConstraint == colFrame->GetConstraint()) {
00503           continue;
00504         }
00505       }
00506       nscoord oldWidth = mTableFrame->GetColumnWidth(colX);
00507       float percent = (divisor == 0) 
00508         ? (1.0f / ((float)numColsAllocated))
00509         : ((float)oldWidth) / ((float)divisor);
00510       nscoord addition = nsTableFrame::RoundToPixel(NSToCoordRound(((float)aAllocAmount) * percent), aPixelToTwips);
00511       if (addition > (aAllocAmount - totalAllocated)) {
00512         addition = nsTableFrame::RoundToPixel(aAllocAmount - totalAllocated, aPixelToTwips);
00513         mTableFrame->SetColumnWidth(colX, oldWidth + addition);
00514         break;
00515       }
00516       mTableFrame->SetColumnWidth(colX, oldWidth + addition);
00517       totalAllocated += addition;
00518     }
00519   }
00520 }
00521 
00522 nscoord GetConstrainedWidth(nsTableColFrame* colFrame,
00523                             PRBool           aConsiderPct)
00524                            
00525 {
00526   nscoord conWidth = WIDTH_NOT_SET;
00527   if (aConsiderPct) {
00528     conWidth = colFrame->GetPctWidth();
00529   }
00530   if (conWidth <= 0 ) {
00531     conWidth = colFrame->GetFixWidth();
00532   }
00533   return conWidth;
00534 }
00535 
00536 #define LIMIT_PCT   0 // retrict allocations to only the pct  width cols
00537 #define LIMIT_FIX   1 // retrict allocations to only the fix  width cols
00538 #define LIMIT_DES   2 // retrict allocations to only the auto width cols
00539 #define LIMIT_NONE  3 // retrict allocations to only the auto widths unless there are none
00540                       // and then restrict fix or pct.
00541 
00542 static int RowSortCB(const void *a, const void *b, void *)
00543 {
00544   const CellInfo *aa = NS_STATIC_CAST(const CellInfo*,a);
00545   const CellInfo *bb = NS_STATIC_CAST(const CellInfo*,b);
00546 
00547   return aa->colSpan - bb->colSpan;
00548 }
00549 
00560 static PRInt32
00561 GetSortedFrames(nsTableFrame *TableFrame,
00562                 PRInt32       colX,
00563                 PRInt32       numRows,
00564                 CellInfo     *cellInfo)
00565 {
00566   PRInt32 rowX, index = 0;
00567   for (rowX = 0; rowX < numRows; rowX++) {
00568     CellInfo *inf = &cellInfo[index];
00569     PRBool orig;
00570     inf->cellFrame =
00571       TableFrame->GetCellInfoAt(rowX, colX, &orig, &inf->colSpan);
00572 
00573     // If the cell is good we keep it.
00574     if(inf->cellFrame && orig && 1 != inf->colSpan) {
00575       index++;
00576     }
00577   }
00578 
00579   if(index>1) {
00580     NS_QuickSort(cellInfo, index, sizeof(cellInfo[0]), RowSortCB, 0);
00581   }
00582 
00583   return index;
00584 }
00585 
00586 void 
00587 BasicTableLayoutStrategy::ComputeNonPctColspanWidths(const nsHTMLReflowState& aReflowState,
00588                                                      PRBool                   aConsiderPct,
00589                                                      float                    aPixelToTwips,
00590                                                      PRBool*                  aHasPctCol)
00591 {
00592 #ifdef DEBUG_TABLE_REFLOW_TIMING
00593   nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctColspans, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE);
00594 #endif
00595   PRInt32 numCols = mTableFrame->GetColCount();
00596   PRInt32 numEffCols = mTableFrame->GetEffectiveColCount();
00597   // zero out prior ADJ values 
00598 
00599   PRInt32 colX;
00600   for (colX = numCols - 1; colX >= 0; colX--) { 
00601     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
00602     if (!colFrame) continue;
00603     colFrame->SetWidth(MIN_ADJ, WIDTH_NOT_SET);
00604     colFrame->SetWidth(FIX_ADJ, WIDTH_NOT_SET);
00605     colFrame->SetWidth(DES_ADJ, WIDTH_NOT_SET);
00606   }
00607 
00608   // For each col, consider the cells originating in it with colspans > 1.
00609   // Adjust the cols that each cell spans if necessary. Iterate backwards 
00610   // so that nested and/or overlaping col spans handle the inner ones first, 
00611   // ensuring more accurated calculations.
00612   // if more than one  colspan originate in one column, resort the access to 
00613   // the rows so that the inner colspans are handled first
00614   PRInt32 numRows = mTableFrame->GetRowCount();
00615 
00616   CellInfo* cellInfo = new CellInfo[numRows];
00617 
00618   if(!cellInfo) {
00619     return;
00620   }
00621 
00622   for (colX = numEffCols - 1; colX >= 0; colX--) { // loop only over effective columns
00623     PRInt32 spannedRows = GetSortedFrames(mTableFrame, colX, numRows, cellInfo);
00624 
00625     for (PRInt32 i = 0; i < spannedRows; i++) {
00626       const CellInfo *inf = &cellInfo[i];
00627       const nsTableCellFrame* cellFrame = inf->cellFrame;
00628 
00629       const PRInt32 colSpan = PR_MIN(inf->colSpan, numEffCols - colX);
00630       // set MIN_ADJ, DES_ADJ, FIX_ADJ
00631       for (PRInt32 widthX = 0; widthX < NUM_MAJOR_WIDTHS; widthX++) {
00632         nscoord cellWidth = 0;
00633         if (MIN_CON == widthX) {
00634           cellWidth = cellFrame->GetPass1MaxElementWidth();
00635         }
00636         else if (DES_CON == widthX) {
00637           cellWidth = cellFrame->GetMaximumWidth();
00638         }
00639         else { // FIX width
00640           // see if the cell has a style width specified
00641           const nsStylePosition* cellPosition = cellFrame->GetStylePosition();
00642           if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) {
00643             // need to add borde and padding into fixed width
00644             nsMargin borderPadding = nsTableFrame::GetBorderPadding(nsSize(aReflowState.mComputedWidth, 0),
00645                                                                     aPixelToTwips, cellFrame);
00646             cellWidth = cellPosition->mWidth.GetCoordValue() + borderPadding.left + borderPadding.right;
00647             cellWidth = PR_MAX(cellWidth, cellFrame->GetPass1MaxElementWidth());
00648           }
00649         }
00650 
00651         if (0 >= cellWidth) continue;
00652 
00653         // first allocate pct cells up to their value if aConsiderPct, then
00654         // allocate fixed cells up to their value, then allocate auto cells 
00655         // up to their value, then allocate auto cells proportionally.
00656         PRInt32 limit = (aConsiderPct) ? LIMIT_PCT : LIMIT_FIX;
00657         if (MIN_CON != widthX) { // FIX and DES only need to allocate NONE
00658           limit = LIMIT_NONE;
00659         }
00660         while (limit <= LIMIT_NONE) {
00661           if (ComputeNonPctColspanWidths(widthX, cellFrame, cellWidth, colX, colSpan, 
00662                                          limit, aPixelToTwips)) {
00663             break;
00664           }
00665           limit++;
00666         }
00667       }
00668       // determine if there is a pct col if we are requested to do so
00669       if (aHasPctCol && !*aHasPctCol) {
00670         *aHasPctCol = HasPctValue(cellFrame);
00671       }
00672     }
00673   }
00674   delete [] cellInfo;
00675 #ifdef DEBUG_TABLE_REFLOW_TIMING
00676   nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctColspans, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE);
00677 #endif
00678 }
00679 
00680 #ifdef DEBUG
00681 static char* widths[] = {"MIN", "DES", "FIX"};
00682 static char* limits[] = {"PCT", "FIX", "DES", "NONE"};
00683 static PRInt32 dumpCount = 0;
00684 void DumpColWidths(nsTableFrame& aTableFrame,
00685                    char*         aMessage,
00686                    const nsTableCellFrame* aCellFrame,
00687                    PRInt32       aColIndex,
00688                    PRInt32       aWidthType,
00689                    PRInt32       aLimitType)
00690 {
00691   PRInt32 rowIndex;
00692   aCellFrame->GetRowIndex(rowIndex);
00693   printf ("%s (row,col)=(%d,%d) width=%s limit=%s count=%d\n", aMessage, rowIndex, aColIndex, 
00694           widths[aWidthType], limits[aLimitType], dumpCount++);
00695   for (PRInt32 i = 0; i < aTableFrame.GetColCount(); i++) {
00696     printf(" col %d = ", i);
00697     nsTableColFrame* colFrame = aTableFrame.GetColFrame(i);
00698     for (PRInt32 j = 0; j < NUM_WIDTHS; j++) {
00699       printf("%d ", colFrame->GetWidth(j));
00700     }
00701     printf("\n");
00702   }
00703 }
00704 #endif
00705 
00706 // (aWidthIndex == MIN_CON) is called with:
00707 //   (aLimitType == LIMIT_PCT)  to give MIN_ADJ to PCT cols (up to their PCT value) 
00708 //   (aLimitType == LIMIT_FIX)  to give MIN_ADJ to FIX cols (up to their FIX value) 
00709 //   (aLimitType == LIMIT_DES)  to give MIN_ADJ to auto cols (up to their preferred value) 
00710 //   (aLimitType == LIMIT_NONE) to give MIN_ADJ to auto cols  
00711 // (aWidthIndex == FIX), (aWidthIndex == DES) is called with:
00712 //   (aLimitType == LIMIT_NONE) to give FIX_ADJ to auto cols  
00713 PRBool 
00714 BasicTableLayoutStrategy::ComputeNonPctColspanWidths(PRInt32           aWidthIndex,
00715                                                      const nsTableCellFrame* aCellFrame,
00716                                                      nscoord           aCellWidth,
00717                                                      PRInt32           aColIndex,
00718                                                      PRInt32           aColSpan,
00719                                                      PRInt32&          aLimitType,
00720                                                      float             aPixelToTwips)
00721 {
00722 #ifdef DEBUG_TABLE_STRATEGY
00723   DumpColWidths(*mTableFrame, "enter ComputeNonPctColspanWidths", aCellFrame, aColIndex, aWidthIndex, aLimitType);
00724 #endif  
00725   PRBool result = PR_TRUE;
00726 
00727   nscoord spanCellSpacing   = 0; // total cell spacing cells being spanned
00728   nscoord minTotal          = 0; // the sum of min widths of spanned cells. 
00729   nscoord autoMinTotal      = 0; // the sum of min widths of spanned auto cells. 
00730   nscoord fixMinTotal       = 0; // the sum of min widths of spanned fix cells. 
00731   nscoord pctMinTotal       = 0; // the sum of min widths of spanned pct cells. 
00732   nscoord pctTotal          = 0; // the sum of pct widths of spanned cells. 
00733   nscoord fixTotal          = 0; // the sum of fix widths of spanned cells
00734   nscoord autoDesTotal      = 0; // the sum of desired widths of spanned cells which are auto
00735   nscoord pctLimitTotal     = 0; // the sum of pct widths not exceeding aCellWidth
00736   nscoord fixLimitTotal     = 0; // the sum of fix widths not exceeding aCellWidth
00737   nscoord desLimitTotal     = 0; // the sum of des widths not exceeding aCellWidth
00738   PRInt32 numAutoCols       = 0;
00739 
00740   nscoord spacingX = mTableFrame->GetCellSpacingX();
00741   PRInt32 spanX;
00742   // accumulate the various divisors to be used later
00743   for (spanX = 0; spanX < aColSpan; spanX++) {
00744     nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); 
00745     if (!colFrame) continue;
00746     nscoord minWidth = PR_MAX(colFrame->GetMinWidth(), 0);
00747     nscoord pctWidth = PR_MAX(colFrame->GetPctWidth(), 0);
00748     nscoord fixWidth = PR_MAX(colFrame->GetFixWidth(), 0);
00749     nscoord desWidth = PR_MAX(colFrame->GetDesWidth(), minWidth);
00750 
00751     minTotal += minWidth;
00752 
00753     if (pctWidth > 0) {
00754       pctTotal += pctWidth;
00755       pctMinTotal += minWidth;
00756     }
00757     else if (fixWidth > 0) {
00758       fixTotal += fixWidth;
00759       fixMinTotal += minWidth;
00760     }
00761     if (colFrame->GetWidth(PCT) + colFrame->GetWidth(FIX) <= 0) {
00762       autoDesTotal += desWidth;
00763       autoMinTotal += minWidth;
00764       numAutoCols++;
00765     }
00766     if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(aColIndex + spanX) > 0)) {
00767       spanCellSpacing += spacingX;
00768     }
00769   }
00770   nscoord availWidth = aCellWidth - spanCellSpacing;
00771   if (MIN_CON == aWidthIndex) {
00772     // MIN widths (unlike the others) are added to existing values, so subtract out the min total
00773     availWidth -= minTotal;
00774 
00775     pctLimitTotal = ((pctTotal - pctMinTotal) < availWidth) ? pctTotal - pctMinTotal : availWidth;
00776     fixLimitTotal = ((fixTotal - fixMinTotal) < availWidth) ? fixTotal - fixMinTotal : availWidth;
00777     desLimitTotal = ((autoDesTotal - autoMinTotal) < availWidth) ? autoDesTotal - autoMinTotal : availWidth;
00778   }
00779   else { // FIX or DES_CON with LIMIT_NONE
00780     if (FIX == aWidthIndex) {
00781       if (autoDesTotal > 0) {
00782         availWidth -= pctTotal + fixTotal;
00783       }
00784       else if (fixTotal > 0) {
00785         availWidth -= pctTotal;
00786       }
00787     }
00788     else if (DES_CON == aWidthIndex) {
00789       availWidth -= pctTotal + fixTotal; 
00790     }
00791   }
00792 
00793   // Below are some optimizations which can skip steps.
00794   if (LIMIT_PCT == aLimitType) {
00795     NS_ASSERTION(MIN_CON == aWidthIndex, "invalid call to ComputeNonPctColspanWidths");
00796     // if there are no pct cols, limit fix cols
00797     if (0 == pctTotal) {
00798       aLimitType = LIMIT_FIX;
00799     }
00800   }
00801   if (LIMIT_FIX == aLimitType) {
00802     NS_ASSERTION(MIN_CON == aWidthIndex, "invalid call to ComputeNonPctColspanWidths");
00803     // if there are no fix cols, limit des
00804     if (0 == fixTotal) {
00805       aLimitType = LIMIT_DES;
00806     }
00807   }
00808   if (LIMIT_DES == aLimitType) {
00809     NS_ASSERTION(MIN_CON == aWidthIndex, "invalid call to ComputeNonPctColspanWidths");
00810     // if there are no auto cols, limit none
00811     if (0 == autoDesTotal) {
00812       aLimitType = LIMIT_NONE;
00813     }
00814   }
00815 
00816   // there are some cases where allocating up to aCellWidth will not be satisfied
00817   switch (aLimitType) {
00818   case LIMIT_PCT:
00819     if (pctLimitTotal < availWidth) {
00820       // the pct cols won't satisfy the request alone
00821       availWidth = pctLimitTotal;
00822       result = PR_FALSE;
00823     }
00824     break;
00825   case LIMIT_FIX:
00826     if (fixLimitTotal < availWidth) {
00827       // the fix cols won't satisfy the request alone
00828       availWidth = fixLimitTotal;
00829       result = PR_FALSE;
00830     }
00831     break;
00832   case LIMIT_DES:
00833     if (desLimitTotal < availWidth) {
00834       // the auto cols won't satisfy the request alone
00835       availWidth = desLimitTotal;
00836       result = PR_FALSE;
00837     }
00838     break;
00839   default: // LIMIT_NONE
00840     break;
00841   }
00842 
00843   if (availWidth > 0) {
00844     nscoord usedWidth = 0;
00845     // get the correct numerator in a similar fashion to getting the divisor
00846     for (spanX = 0; spanX < aColSpan; spanX++) {
00847       if (usedWidth >= availWidth) break;
00848       nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); 
00849       if (!colFrame) continue;
00850       nscoord minWidth = colFrame->GetMinWidth();
00851       nscoord pctWidth = PR_MAX(colFrame->GetPctWidth(), 0);
00852       nscoord fixWidth = PR_MAX(colFrame->GetFixWidth(), 0);
00853       nscoord desWidth = PR_MAX(colFrame->GetDesWidth(), minWidth);
00854 
00855       nscoord colWidth = PR_MAX(colFrame->GetWidth(aWidthIndex), 
00856                                 colFrame->GetWidth(aWidthIndex + NUM_MAJOR_WIDTHS));
00857       colWidth = PR_MAX(colWidth, minWidth);
00858 
00859       nscoord numeratorPct     = 0;
00860       nscoord numeratorFix     = 0;
00861       nscoord numeratorAutoDes = 0;
00862 
00863       if (pctWidth > 0) {
00864         numeratorPct = pctWidth;
00865       }
00866       else if (fixWidth > 0) {
00867         numeratorFix = fixWidth;
00868       }
00869       if (colFrame->GetWidth(PCT) + colFrame->GetWidth(FIX) <= 0) {
00870         numeratorAutoDes = desWidth;
00871       }
00872 
00873       nscoord divisor = 0;
00874       nscoord numerator = 0;
00875 
00876       // let pct cols reach their target 
00877       if (LIMIT_PCT == aLimitType) {
00878         if (pctLimitTotal > 0) {
00879           divisor   = pctTotal - pctMinTotal;
00880           numerator = PR_MAX(numeratorPct - minWidth, 0);
00881         }
00882       }
00883       // let fix cols reach their target 
00884       else if (LIMIT_FIX == aLimitType) {
00885         if (fixLimitTotal > 0) {
00886           divisor   = fixTotal - fixMinTotal;
00887           numerator = PR_MAX(numeratorFix - minWidth, 0);
00888         }
00889       }
00890       // let auto cols reach their target 
00891       else if (LIMIT_DES == aLimitType) {
00892         if (desLimitTotal > 0) {
00893           if (autoDesTotal > 0) { // there were auto cols
00894             divisor   = autoDesTotal - autoMinTotal;
00895             numerator = PR_MAX(numeratorAutoDes - minWidth, 0);
00896           }
00897           else if (fixTotal > 0) {  // there were fix cols but no auto
00898             divisor   = fixTotal - fixMinTotal;
00899             numerator = PR_MAX(numeratorFix - minWidth, 0);
00900           }
00901           else if (pctTotal > 0) {  // there were only pct cols
00902             divisor   = pctTotal - pctMinTotal;
00903             numerator = PR_MAX(numeratorPct - minWidth, 0);
00904           }
00905           else continue;
00906         }
00907       }
00908       else if (LIMIT_NONE == aLimitType) { 
00909         if ((MIN_CON == aWidthIndex) && (0 == minTotal)) {
00910           // divide evenly among the spanned cols
00911           divisor = aColSpan;
00912           numerator = 1;
00913         }
00914         else {
00915           if (autoDesTotal > 0) { // there were auto cols
00916             divisor   = autoDesTotal;
00917             numerator = numeratorAutoDes;
00918           }
00919           else if (fixTotal > 0) {  // there were fix cols but no auto
00920             divisor   = fixTotal;
00921             numerator = numeratorFix;
00922           }
00923           else if (pctTotal > 0) {  // there were only pct cols
00924             divisor   = pctTotal;
00925             numerator = numeratorPct;
00926           }
00927           else continue;
00928 
00929         }
00930       }
00931       // calculate the adj col width
00932       nscoord newColAdjWidth = (0 >= divisor) 
00933         ? NSToCoordRound( ((float)availWidth) / ((float)aColSpan) )
00934         : NSToCoordRound( (((float)numerator) / ((float)divisor)) * availWidth);
00935       newColAdjWidth = nsTableFrame::RoundToPixel(newColAdjWidth, aPixelToTwips);
00936       // don't let the new allocation exceed the avail total
00937       newColAdjWidth = PR_MIN(newColAdjWidth, availWidth - usedWidth);
00938       // put the remainder of the avail total in the last spanned col
00939       if (spanX == aColSpan - 1) {
00940         newColAdjWidth = availWidth - usedWidth;
00941       }
00942       usedWidth += newColAdjWidth;
00943       // MIN_CON gets added to what is there, the others don't
00944       if (MIN_CON == aWidthIndex) {
00945         newColAdjWidth += colWidth;
00946       }
00947       if (newColAdjWidth > colWidth) { 
00948         if (FIX == aWidthIndex) {
00949           // a colspan cannot fix a column below what a cell desires on its own
00950           nscoord desCon = colFrame->GetWidth(DES_CON); // do not consider DES_ADJ
00951           if (desCon > newColAdjWidth) {
00952             newColAdjWidth = desCon;
00953           }
00954         }
00955         colFrame->SetWidth(aWidthIndex + NUM_MAJOR_WIDTHS, newColAdjWidth);
00956       }
00957       else {        
00958         if((newColAdjWidth > 0) && (FIX == aWidthIndex)) {
00959           if(colFrame->GetWidth(FIX) < 0) {
00960             nscoord desCon = colFrame->GetWidth(DES_CON);
00961             if (desCon > newColAdjWidth) {
00962               newColAdjWidth = desCon;
00963             }
00964           }
00965           if(colFrame->GetWidth(FIX_ADJ) < newColAdjWidth) {
00966             colFrame->SetWidth(FIX_ADJ, PR_MAX(colWidth,newColAdjWidth));
00967           }
00968         }
00969       }
00970     }
00971   }
00972 #ifdef DEBUG_TABLE_STRATEGY
00973   DumpColWidths(*mTableFrame, "exit ComputeNonPctColspanWidths", aCellFrame, aColIndex, aWidthIndex, aLimitType);
00974 #endif
00975   return result;
00976 }
00977 
00978 
00979 // XXX percent left and right padding are not figured in the calculations
00980 // The table frame needs to be used as the percent base because the reflow
00981 // state may have an unconstrained width. There should probably be a frame
00982 // state bit indicating that horizontal padding is percentage based.
00983 
00984 // Determine min, desired, fixed, and proportional sizes for the cols and 
00985 // and calculate min/max table width. Return true if there is at least one pct cell or col
00986 PRBool 
00987 BasicTableLayoutStrategy::AssignNonPctColumnWidths(nscoord                  aMaxWidth,
00988                                                    const nsHTMLReflowState& aReflowState)
00989 {
00990 #ifdef DEBUG_TABLE_REFLOW_TIMING
00991   nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE);
00992 #endif
00993 #ifdef DEBUG_TABLE_STRATEGY
00994   printf("AssignNonPctColWidths en max=%d count=%d \n", aMaxWidth, gsDebugCount++); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);
00995 #endif
00996   PRInt32 numRows = mTableFrame->GetRowCount();
00997   PRInt32 numCols = mTableFrame->GetColCount();
00998   nscoord spacingX = mTableFrame->GetCellSpacingX();
00999   PRInt32 colX, rowX; 
01000   mCellSpacingTotal = 0;
01001   PRBool hasPctCol = PR_FALSE; // return value
01002   float pixelToTwips = mTableFrame->GetPresContext()->ScaledPixelsToTwips();
01003 
01004   PRInt32 rawPropTotal = -1; // total of numbers of the type 1*, 2*, etc 
01005   PRInt32 numColsForColsAttr = 0; // Nav Quirks cols attribute for equal width cols
01006   if (NS_STYLE_TABLE_COLS_NONE != mCols) {
01007     numColsForColsAttr = (NS_STYLE_TABLE_COLS_ALL == mCols) ? numCols : mCols;
01008   }
01009 
01010   // For every column, determine it's min and desired width based on cell style
01011   // base on cells which do not span cols. Also, determine mCellSpacingTotal
01012   for (colX = 0; colX < numCols; colX++) { 
01013     nscoord minWidth = 0;
01014     nscoord desWidth = 0;
01015     nscoord fixWidth = WIDTH_NOT_SET;
01016     
01017     // Get column frame and reset it
01018     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01019     if (!colFrame) continue;
01020     NS_ASSERTION(nsnull != colFrame, "bad col frame");
01021     colFrame->ResetSizingInfo();
01022 
01023     if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) {
01024       mCellSpacingTotal += spacingX;
01025     }
01026 
01027     // Scan the cells in the col that have colspan = 1 and find the maximum
01028     // min, desired, and fixed cells.
01029     nsTableCellFrame* fixContributor = nsnull;
01030     nsTableCellFrame* desContributor = nsnull;
01031     for (rowX = 0; rowX < numRows; rowX++) {
01032       PRBool originates;
01033       PRInt32 colSpan;
01034       nsTableCellFrame* cellFrame = mTableFrame->GetCellInfoAt(rowX, colX, &originates, &colSpan);
01035       // skip cells that don't originate at (rowX, colX); colspans are handled in the
01036       // next pass, row spans don't need to be handled
01037       if (!cellFrame || !originates || (colSpan > 1)) { 
01038         continue;
01039       }
01040       // these values include borders and padding
01041       minWidth = PR_MAX(minWidth, cellFrame->GetPass1MaxElementWidth());
01042       nscoord cellDesWidth = cellFrame->GetMaximumWidth();
01043       if (cellDesWidth > desWidth) {
01044         desContributor = cellFrame;
01045         desWidth = cellDesWidth;
01046       }
01047       // see if the cell has a style width specified
01048       const nsStylePosition* cellPosition = cellFrame->GetStylePosition();
01049       if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) {
01050         nscoord coordValue = cellPosition->mWidth.GetCoordValue();
01051         if (coordValue > 0) { // ignore if width == 0
01052           // need to add border and padding into fixed width
01053           nsSize percentBase(aReflowState.mComputedWidth, 0);
01054           nsMargin borderPadding = nsTableFrame::GetBorderPadding(percentBase, pixelToTwips, cellFrame);
01055           nscoord newFixWidth = coordValue + borderPadding.left + borderPadding.right;
01056           // 2nd part of condition is Nav/IE Quirk like below
01057           if ((newFixWidth > fixWidth) || ((newFixWidth == fixWidth) && (desContributor == cellFrame))) {
01058             fixWidth = newFixWidth;
01059             fixContributor = cellFrame;
01060           }
01061         }
01062       }
01063       if (!hasPctCol && HasPctValue(cellFrame)) { // see if there is a pct cell
01064         hasPctCol = PR_TRUE;
01065       }
01066     }
01067 
01068     // Nav/IE Quirk like above
01069     if (fixWidth > 0) {
01070       if (mIsNavQuirksMode && (desWidth > fixWidth) && (fixContributor != desContributor)) {
01071         fixWidth = WIDTH_NOT_SET;
01072         fixContributor = nsnull;
01073       }
01074     }
01075     desWidth = PR_MAX(desWidth, minWidth);
01076 
01077     // cache the computed column info
01078     colFrame->SetWidth(MIN_CON, minWidth);
01079     colFrame->SetWidth(DES_CON, desWidth);
01080     if (fixWidth > 0) {
01081       colFrame->SetWidth(FIX, fixWidth);
01082     }
01083 
01084     nsStyleCoord colStyleWidth = colFrame->GetStyleWidth();
01085     // determine if there is a proportional column either from html4 
01086     // proportional width on a col or Nav Quirks cols attr
01087     if (fixWidth <= 0) {
01088       nscoord proportion = WIDTH_NOT_SET;
01089       if (eStyleUnit_Proportional == colStyleWidth.GetUnit()) {
01090         proportion = colStyleWidth.GetIntValue();
01091       }
01092       else if (colX < numColsForColsAttr) {
01093         proportion = 1;
01094         if ((eStyleUnit_Percent == colStyleWidth.GetUnit()) &&
01095             (colStyleWidth.GetPercentValue() > 0.0f)) {
01096           proportion = WIDTH_NOT_SET;
01097         }
01098       }
01099       if (proportion >= 0) {
01100         rawPropTotal = PR_MAX(rawPropTotal, 0); // it was initialized to -1
01101         colFrame->SetWidth(MIN_PRO, proportion);
01102         nsColConstraint colConstraint = (0 == proportion) 
01103           ? e0ProportionConstraint : eProportionConstraint;
01104         rawPropTotal += proportion;
01105         colFrame->SetConstraint(colConstraint);
01106       }
01107     }
01108     if (!hasPctCol) { // see if there is a pct col
01109       if (eStyleUnit_Percent == colStyleWidth.GetUnit()) {
01110         float percent = colStyleWidth.GetPercentValue();
01111         if (percent > 0.0f) {
01112           hasPctCol = PR_TRUE;
01113         }
01114       }
01115     }
01116   }
01117   if (mCellSpacingTotal > 0) {
01118     mCellSpacingTotal += spacingX; // add last cell spacing on right
01119   }
01120 //set the table col fixed width if present
01121   for (colX = 0; colX < numCols; colX++) { 
01122     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01123     if (!colFrame) continue;
01124     nscoord fixColWidth = colFrame->GetWidth(FIX);
01125     // use the style width of a col only if the col hasn't gotten a fixed width from any cell
01126     if (fixColWidth <= 0) {
01127       nsStyleCoord colStyleWidth = colFrame->GetStyleWidth();
01128       if (eStyleUnit_Coord == colStyleWidth.GetUnit()) {
01129         fixColWidth = colStyleWidth.GetCoordValue();
01130         if (fixColWidth > 0) {
01131           colFrame->SetWidth(FIX, fixColWidth);
01132         }
01133       }
01134     }
01135   }
01136   PRBool* pctRequest = (hasPctCol) ? nsnull : &hasPctCol;
01137   ComputeNonPctColspanWidths(aReflowState, PR_FALSE, pixelToTwips, pctRequest);
01138   PRInt32 numEffCols = mTableFrame->GetEffectiveColCount();
01139   // figure the proportional widths for porportional cols
01140   if (rawPropTotal > 0)  {
01141     // find the largest combined prop size considering each prop col and
01142     // its desired size
01143     nscoord maxPropTotal = 0;
01144     for (colX = 0; colX < numEffCols; colX++) { 
01145       nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
01146       nscoord rawProp = colFrame->GetWidth(MIN_PRO);
01147       if (rawProp > 0) {
01148         nscoord desWidth = colFrame->GetDesWidth();
01149         nscoord propTotal = NSToCoordRound( ((float)desWidth) * ((float)rawPropTotal) / (float)rawProp );
01150         propTotal = nsTableFrame::RoundToPixel(propTotal, pixelToTwips);
01151         maxPropTotal = PR_MAX(maxPropTotal, propTotal);
01152       }
01153     }
01154     // set MIN_PRO widths based on the maxPropTotal
01155     for (colX = 0; colX < numEffCols; colX++) { 
01156       nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
01157       if (!colFrame) continue;
01158       nscoord rawProp = colFrame->GetWidth(MIN_PRO);
01159       if (0 == rawProp) {
01160         // a 0* col gets only the min width
01161         colFrame->SetWidth(MIN_PRO, colFrame->GetMinWidth());
01162       }
01163       else if ((rawProp > 0) && (rawPropTotal > 0)) {
01164         nscoord propWidth = NSToCoordRound( ((float)maxPropTotal) * ((float)rawProp) / (float)rawPropTotal ) ;
01165         propWidth = nsTableFrame::RoundToPixel(propWidth, pixelToTwips);
01166         colFrame->SetWidth(MIN_PRO, PR_MAX(propWidth, colFrame->GetMinWidth()));
01167       }
01168     }
01169   }
01170 
01171   // Set the table col width for each col to the content min. 
01172   for (colX = 0; colX < numCols; colX++) { 
01173     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01174     if (!colFrame) continue;
01175     nscoord minWidth = colFrame->GetMinWidth();
01176     mTableFrame->SetColumnWidth(colX, minWidth);
01177   }
01178 
01179 #ifdef DEBUG_TABLE_STRATEGY
01180   printf("AssignNonPctColWidths ex\n"); mTableFrame->Dump(PR_FALSE, PR_TRUE, PR_FALSE);
01181 #endif
01182 #ifdef DEBUG_TABLE_REFLOW_TIMING
01183   nsTableFrame::DebugTimeMethod(nsTableFrame::eNonPctCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE);
01184 #endif
01185   return hasPctCol;
01186 }
01187 
01188 void
01189 BasicTableLayoutStrategy::ReduceOverSpecifiedPctCols(nscoord aExcess)
01190 {
01191   nscoord numCols = mTableFrame->GetColCount();
01192   for (PRInt32 colX = numCols - 1; (colX >= 0) && (aExcess > 0); colX--) {
01193     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01194     if (!colFrame) continue;
01195     nscoord pctWidth = colFrame->GetWidth(PCT);
01196     nscoord reduction = 0;
01197     if (pctWidth > 0) {
01198       reduction = (aExcess > pctWidth) ? pctWidth : aExcess;
01199       nscoord newPctWidth = (reduction == pctWidth) ? WIDTH_NOT_SET : pctWidth - reduction;
01200       colFrame->SetWidth(PCT, PR_MAX(newPctWidth, colFrame->GetMinWidth()));
01201     }
01202     else {
01203       nscoord pctAdjWidth = colFrame->GetWidth(PCT_ADJ);
01204       if (pctAdjWidth > 0) {
01205         reduction = (aExcess > pctAdjWidth) ? pctAdjWidth : aExcess;
01206         nscoord newPctAdjWidth = (reduction == pctAdjWidth) ? WIDTH_NOT_SET : pctAdjWidth - reduction;
01207         colFrame->SetWidth(PCT_ADJ, PR_MAX(newPctAdjWidth, colFrame->GetMinWidth()));
01208       }
01209     }
01210     aExcess -= reduction;
01211   }
01212 }
01213 
01214 #ifdef DEBUG_TABLE_REFLOW_TIMING
01215 nscoord WrapupAssignPctColumnWidths(nsTableFrame*            aTableFrame,
01216                                     const nsHTMLReflowState& aReflowState,
01217                                     nscoord                  aValue) 
01218 {
01219   nsTableFrame::DebugTimeMethod(nsTableFrame::ePctCols, *aTableFrame, (nsHTMLReflowState&)aReflowState, PR_FALSE);
01220   return aValue;
01221 }
01222 #else
01223 inline nscoord WrapupAssignPctColumnWidths(nsTableFrame*            aTableFrame,
01224                                            const nsHTMLReflowState& aReflowState,
01225                                            nscoord                  aValue) 
01226 {
01227   return aValue;
01228 }
01229 #endif
01230 
01231 nscoord 
01232 BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
01233                                                nscoord                  aAvailWidthIn)
01234 {
01235   NS_ASSERTION(mTableFrame->IsAutoWidth() && mTableFrame->HasPctCol(), "invalid call");
01236 
01237   PRInt32 numRows  = mTableFrame->GetRowCount();
01238   PRInt32 numCols  = mTableFrame->GetColCount(); // consider cols at end without orig cells 
01239   PRInt32 colX, rowX; 
01240   float pixelToTwips = mTableFrame->GetPresContext()->ScaledPixelsToTwips();
01241 
01242   // For an auto table, determine the potentially new percent adjusted width based 
01243   // on percent cells/cols. This probably should only be a NavQuirks thing, since
01244   // a percentage based cell or column on an auto table should force the column to auto
01245   nscoord basis = 0;                 
01246   float* rawPctValues = new float[numCols]; // store the raw pct values, allow for spans past the effective numCols
01247   if (!rawPctValues) return NS_ERROR_OUT_OF_MEMORY;
01248   for (colX = 0; colX < numCols; colX++) {
01249     rawPctValues[colX] = 0.0f;
01250   }
01251 
01252   nsMargin borderPadding = mTableFrame->GetContentAreaOffset(&aReflowState);
01253   nscoord availWidth = aAvailWidthIn;
01254   if (NS_UNCONSTRAINEDSIZE != availWidth) {
01255     // adjust the avail width to exclude table border, padding and cell spacing
01256     availWidth -= borderPadding.left + borderPadding.right + mCellSpacingTotal;
01257   }
01258 
01259   for (colX = 0; colX < numCols; colX++) { 
01260     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01261     if (!colFrame) continue;
01262     nscoord maxColBasis = -1;
01263     // Scan the cells in the col 
01264     for (rowX = 0; rowX < numRows; rowX++) {
01265       PRBool originates;
01266       PRInt32 colSpan;
01267       nsTableCellFrame* cellFrame = mTableFrame->GetCellInfoAt(rowX, colX, &originates, &colSpan);
01268       if (!originates) continue; // skip  cells that don't originate in the col
01269       // see if the cell has a style percent width specified
01270       const nsStylePosition* cellPosition = cellFrame->GetStylePosition();
01271       if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) {
01272         float percent = cellPosition->mWidth.GetPercentValue();
01273         if (percent > 0.0f) {
01274           // calculate the preferred width of the cell based on fix, des, widths of the cols it spans
01275           nscoord cellDesWidth  = 0;
01276           float spanPct = percent / float(colSpan);
01277           for (PRInt32 spanX = 0; spanX < colSpan; spanX++) {
01278             nsTableColFrame* spanFrame = mTableFrame->GetColFrame(colX + spanX);
01279             if (!spanFrame) continue;
01280             cellDesWidth += spanFrame->GetWidth(DES_CON); // don't consider DES_ADJ
01281             // crudely allocate pct values to the spanning cols so that we can check if they exceed 100 pct below
01282             rawPctValues[colX + spanX] = PR_MAX(rawPctValues[colX + spanX], spanPct);
01283           }
01284           // consider the cell's preferred width 
01285           cellDesWidth = PR_MAX(cellDesWidth, cellFrame->GetMaximumWidth());
01286           nscoord colBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)cellDesWidth / percent), pixelToTwips);
01287           maxColBasis = PR_MAX(maxColBasis, colBasis);
01288         }
01289       }
01290     }
01291     if (-1 == maxColBasis) {
01292       // see if the col has a style percent width specified
01293       nsStyleCoord colStyleWidth = colFrame->GetStyleWidth();
01294       if (eStyleUnit_Percent == colStyleWidth.GetUnit()) {
01295         float percent = colStyleWidth.GetPercentValue();
01296         maxColBasis = 0;
01297         if (percent > 0.0f) {
01298           rawPctValues[colX] = PR_MAX(rawPctValues[colX], percent);
01299           nscoord desWidth = colFrame->GetWidth(DES_CON); // don't consider DES_ADJ
01300           maxColBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)desWidth / percent), pixelToTwips);
01301         }
01302       }
01303     }
01304     basis = PR_MAX(basis, maxColBasis);
01305   } // end for (colX ..
01306 
01307   float   perTotal         = 0.0f; // total of percentage constrained cols and/or cells in cols
01308   PRInt32 numPerCols       = 0;    // number of colums that have percentage constraints
01309   nscoord fixDesTotal      = 0;    // total of fix or des widths of cols 
01310   nscoord fixDesTotalNoPct = 0;    // total of fix or des widths of cols without pct
01311 
01312   for (colX = 0; colX < numCols; colX++) {
01313     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01314     if (!colFrame) continue;
01315     nscoord fixWidth = colFrame->GetFixWidth();
01316     nscoord fixDesWidth = (fixWidth > 0) ? fixWidth : colFrame->GetDesWidth();
01317     fixDesTotal += fixDesWidth;
01318     if (rawPctValues[colX] + perTotal > 1.0f) {
01319       rawPctValues[colX] = PR_MAX(1.0f - perTotal, 0.0f);
01320     }
01321     if (rawPctValues[colX] > 0.0f) {
01322       numPerCols++;
01323       perTotal += rawPctValues[colX];
01324     }
01325     else {
01326       fixDesTotalNoPct += fixDesWidth;
01327     }
01328   }
01329   delete [] rawPctValues; // destroy the raw pct values
01330   // If there are no pct cells or cols, there is nothing to do.
01331   if ((0 == numPerCols) || (0.0f == perTotal)) {
01332     NS_ASSERTION(PR_FALSE, "invalid call");
01333     return basis; 
01334   }
01335   // If there is only one col and it is % based, it won't affect anything
01336   if ((1 == numCols) && (numCols == numPerCols)) {
01337     return basis + borderPadding.left + borderPadding.right + mCellSpacingTotal;
01338   }
01339 
01340   // compute a basis considering total percentages and the desired width of everything else
01341   if ((perTotal > 0.0f) && (perTotal < 1.0f)) {
01342     nscoord otherBasis = nsTableFrame::RoundToPixel(NSToCoordRound((float)fixDesTotalNoPct / (1.0f - perTotal)), pixelToTwips);
01343     basis = PR_MAX(basis, otherBasis);
01344   }
01345   else if ((fixDesTotalNoPct > 0) && (NS_UNCONSTRAINEDSIZE != availWidth)) { // make the basis as big as possible 
01346     basis = availWidth; // the 100% cols force as big a width as possible
01347   }
01348   basis = PR_MAX(basis, fixDesTotal);
01349   basis = PR_MIN(basis, availWidth); // don't exceed the max we were given
01350 
01351   if (NS_UNCONSTRAINEDSIZE != availWidth) {
01352     // add back the table border, padding and cell spacing
01353     basis += borderPadding.left + borderPadding.right + mCellSpacingTotal;
01354   }
01355 
01356   return basis;
01357 }
01358 
01359 // Determine percentage col widths for each col frame
01360 nscoord 
01361 BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflowState,
01362                                                 nscoord                  aAvailWidth,
01363                                                 PRBool                   aTableIsAutoWidth,
01364                                                 float                    aPixelToTwips)
01365 {
01366 #ifdef DEBUG_TABLE_REFLOW_TIMING
01367   nsTableFrame::DebugTimeMethod(nsTableFrame::ePctCols, *mTableFrame, (nsHTMLReflowState&)aReflowState, PR_TRUE);
01368 #endif
01369   mTableFrame->SetHasCellSpanningPctCol(PR_FALSE); // this gets refigured below
01370   PRInt32 numRows = mTableFrame->GetRowCount();
01371   PRInt32 numCols = mTableFrame->GetColCount(); // consider cols at end without orig cells 
01372   PRInt32 numEffCols = mTableFrame->GetEffectiveColCount();
01373   nscoord spacingX = mTableFrame->GetCellSpacingX();
01374   PRInt32 colX, rowX; 
01375 
01376   NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aAvailWidth, "AssignPctColumnWidths has unconstrained avail width");  
01377   // For an auto table, determine the potentially new percent adjusted width based 
01378   // on percent cells/cols. This probably should only be a NavQuirks thing, since
01379   // a percentage based cell or column on an auto table should force the column to auto
01380   nscoord basis = (aTableIsAutoWidth) 
01381                   ? CalcPctAdjTableWidth(aReflowState, aAvailWidth)
01382                   : aAvailWidth;
01383 
01384   // adjust the basis to exclude table border, padding and cell spacing
01385   nsMargin borderPadding = mTableFrame->GetContentAreaOffset(&aReflowState);
01386   basis -= borderPadding.left + borderPadding.right + mCellSpacingTotal;
01387 
01388   nscoord colPctTotal = 0;
01389 
01390   struct nsSpannedEle {
01391     nsSpannedEle *next, *prev;
01392     PRInt32 col, colSpan;
01393     nsTableCellFrame *cellFrame;
01394   };
01395 
01396   nsSpannedEle *spanList = 0;
01397   nsSpannedEle *spanTail = 0;
01398   PLArenaPool   spanArena;
01399   
01400   PL_INIT_ARENA_POOL(&spanArena, "AssignPctColumnWidths", 512);
01401   // Determine the percentage contribution for cols and for cells with colspan = 1
01402   // Iterate backwards, similarly to the reasoning in AssignNonPctColumnWidths
01403   for (colX = numCols - 1; colX >= 0; colX--) {
01404     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01405     if (!colFrame) continue;
01406     nscoord maxColPctWidth = WIDTH_NOT_SET;
01407     float maxColPct = 0.0f;
01408 
01409     nsTableCellFrame* percentContributor = nsnull;
01410     // Scan the cells in the col that have colspan = 1; assign PER widths
01411     for (rowX = 0; rowX < numRows; rowX++) {
01412       PRBool originates;
01413       PRInt32 colSpan;
01414       nsTableCellFrame* cellFrame = mTableFrame->GetCellInfoAt(rowX, colX, &originates, &colSpan);
01415       // skip cells that don't originate at (rowX, colX)
01416       if (!cellFrame || !originates) { 
01417         continue;
01418       }
01419 
01420       // colspans are handled in the next pass, but we record them here so we dont have to
01421       // search for the again.  row spans do not need to be handled.
01422       if(colSpan>1) {
01423         nsSpannedEle *spanned;
01424         ARENA_ALLOCATE(spanned, &spanArena, 1, nsSpannedEle);
01425         if(spanned) {
01426           spanned->col = colX;
01427           spanned->colSpan = colSpan;
01428           spanned->cellFrame = cellFrame;
01429           spanned->next = spanList;
01430           spanned->prev = nsnull;
01431           if(spanList) {
01432             spanList->prev = spanned;
01433           } else {
01434             spanTail = spanned;
01435           }
01436           spanList = spanned;
01437         }
01438         continue;
01439       }
01440       // see if the cell has a style percent width specified
01441       const nsStylePosition* cellPosition = cellFrame->GetStylePosition();
01442       if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) {
01443         float percent = cellPosition->mWidth.GetPercentValue();
01444         if (percent > maxColPct) {
01445           maxColPct = percent;
01446           maxColPctWidth = nsTableFrame::RoundToPixel(NSToCoordRound( ((float)basis) * maxColPct ), aPixelToTwips);
01447           percentContributor = cellFrame;
01448           if (!mIsNavQuirksMode) { 
01449             // need to add border and padding
01450             nsMargin cellBorderPadding = nsTableFrame::GetBorderPadding(nsSize(basis, 0), aPixelToTwips, cellFrame);
01451             maxColPctWidth += cellBorderPadding.left + cellBorderPadding.right;
01452           }
01453         }
01454       }
01455     }
01456     if (WIDTH_NOT_SET == maxColPctWidth) {
01457       // see if the col has a style percent width specified
01458       nsStyleCoord colStyleWidth = colFrame->GetStyleWidth();
01459       if (eStyleUnit_Percent == colStyleWidth.GetUnit()) {
01460         maxColPct = colStyleWidth.GetPercentValue();
01461         maxColPctWidth = nsTableFrame::RoundToPixel(NSToCoordRound( ((float)basis) * maxColPct ), aPixelToTwips);
01462       }
01463     }
01464     // conflicting pct/fixed widths are recorded. Nav 4.x may be changing the
01465     // fixed width value if it exceeds the pct value and not recording the pct
01466     // value. This is not being done and IE5 doesn't do it either.
01467     if (maxColPctWidth > 0) {
01468       maxColPctWidth = PR_MAX(maxColPctWidth, colFrame->GetWidth(MIN_CON));
01469       colFrame->SetWidth(PCT, maxColPctWidth);
01470       colPctTotal += NSToCoordRound(100.0f * (float)maxColPct);
01471     }
01472   }
01473 
01474   // if the percent total went over 100%, adjustments need to be made to right most cols
01475   if (colPctTotal > 100) {
01476     ReduceOverSpecifiedPctCols(nsTableFrame::RoundToPixel(NSToCoordRound(((float)(colPctTotal - 100)) * 0.01f * (float)basis), aPixelToTwips));
01477     colPctTotal = 100;
01478   }
01479 
01480   // check to see if a cell spans a percentage col. This will cause the MIN_ADJ,
01481   // FIX_ADJ, and DES_ADJ values to be recomputed 
01482   PRBool done = PR_FALSE;
01483   nsSpannedEle *spannedCell;
01484   for(spannedCell=spanList; !done && spannedCell; spannedCell=spannedCell->next)
01485   {
01486     colX = spannedCell->col;
01487     PRInt32 colSpan = spannedCell->colSpan;
01488     // determine if the cell spans cols which have a pct value
01489     for (PRInt32 spanX = 0; spanX < colSpan; spanX++) {
01490       nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); 
01491       if (!colFrame) continue;
01492       if (colFrame->GetWidth(PCT) > 0) {
01493         mTableFrame->SetHasCellSpanningPctCol(PR_TRUE);
01494         // recompute the MIN_ADJ, FIX_ADJ, and DES_ADJ values
01495         ComputeNonPctColspanWidths(aReflowState, PR_TRUE, aPixelToTwips, nsnull);
01496         done = PR_TRUE;
01497         break;
01498       }
01499     }
01500   }
01501 
01502   // For each col, consider the cells originating in it with colspans > 1.
01503   // Adjust the cols that each cell spans if necessary.
01504   // if more than one  colspan originate in one column, resort the access to 
01505   // the rows so that the inner colspans are handled first
01506 
01507   CellInfo* cellInfo = nsnull;
01508 
01509   if(spanTail)
01510     ARENA_ALLOCATE(cellInfo, &spanArena, numRows, CellInfo);
01511 
01512   if(cellInfo) for(spannedCell=spanTail; spannedCell;) {
01513     PRInt32 spannedRows = 0;
01514     colX = spannedCell->col;
01515     do {
01516       cellInfo[spannedRows].cellFrame = spannedCell->cellFrame;
01517       cellInfo[spannedRows].colSpan   = spannedCell->colSpan;
01518       ++spannedRows;
01519     } while((spannedCell=spannedCell->prev) && (spannedCell->col==colX));
01520     if(spannedRows>1) {
01521       NS_QuickSort(cellInfo, spannedRows, sizeof(cellInfo[0]), RowSortCB, 0);
01522     }
01523 
01524     for (PRInt32 i = 0; i < spannedRows; i++) {
01525       const CellInfo *inf = &cellInfo[i];
01526       const nsTableCellFrame* cellFrame = inf->cellFrame;
01527 
01528       const PRInt32 colSpan = PR_MIN(inf->colSpan, numEffCols - colX);
01529       nscoord cellPctWidth = WIDTH_NOT_SET;
01530       // see if the cell has a style percentage width specified
01531       const nsStylePosition* cellPosition = cellFrame->GetStylePosition();
01532       float cellPct = 0.0f;
01533       if (eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) {
01534         cellPct = cellPosition->mWidth.GetPercentValue();
01535         if (colSpan == numEffCols)
01536           cellPct = 1.0f; // overwrite spurious percent colspan width's - bug 46944
01537         cellPctWidth = nsTableFrame::RoundToPixel(NSToCoordRound( ((float)basis) * cellPct ), aPixelToTwips);
01538         if (!mIsNavQuirksMode) { 
01539           // need to add border and padding 
01540           nsMargin cellBorderPadding = nsTableFrame::GetBorderPadding(nsSize(basis, 0), aPixelToTwips, cellFrame);
01541           cellPctWidth += cellBorderPadding.left + cellBorderPadding.right;
01542         }
01543       }
01544       if (cellPctWidth > 0) {
01545         nscoord spanCellSpacing = 0;
01546         nscoord spanTotal = 0;
01547         nscoord spanTotalNoPctAdj = 0;
01548         nscoord colPctWidthTotal = 0; // accumulate the PCT width 
01549         nscoord colPctAdjTotal = 0;   // accumulate the PCT_ADJ width or  the max of PCT_ADJ and PCT width if a 
01550                                       // PCT width is specified
01551         PRBool canSkipPctAdj = PR_FALSE;
01552         // accumulate the spanTotal as the max of MIN, DES, FIX, PCT
01553         PRInt32 spanX;
01554         for (spanX = 0; spanX < colSpan; spanX++) {
01555           nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); 
01556           if (!colFrame) continue;
01557           nscoord colPctWidth = colFrame->GetWidth(PCT);
01558           if (colPctWidth > 0) { // skip pct cols
01559             colPctWidthTotal += colPctWidth;
01560             colPctAdjTotal += PR_MAX(colFrame->GetWidth(PCT_ADJ), colPctWidth);
01561             continue;
01562           }
01563           colPctAdjTotal += PR_MAX(colFrame->GetWidth(PCT_ADJ), 0);
01564           nscoord colWidth = PR_MAX(colFrame->GetMinWidth(), colFrame->GetFixWidth());
01565           colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); // XXX check this
01566           //colWidth = PR_MAX(colWidth, colFrame->GetPctWidth());
01567           spanTotal += colWidth;
01568           if (colFrame->GetWidth(PCT_ADJ) <= 0) { // if we have a cell that is neither PCT or PCT_ADJ we have
01569                                                   // other places where we can drop the width
01570             canSkipPctAdj = PR_TRUE; 
01571             spanTotalNoPctAdj += colWidth;
01572           }
01573           if ((spanX > 0) && (mTableFrame->GetNumCellsOriginatingInCol(colX + spanX) > 0)) {
01574             spanCellSpacing += spacingX;
01575           }
01576         }
01577         cellPctWidth += spanCellSpacing; // add it back in since it was subtracted from aBasisIn
01578         if (cellPctWidth <= 0) {
01579           continue;
01580         }
01581         spanTotal = canSkipPctAdj ? spanTotalNoPctAdj: spanTotal; // if we can skip the PCT_ADJ ignore theire width
01582       
01583         colPctWidthTotal = canSkipPctAdj ? colPctAdjTotal: colPctWidthTotal; 
01584         
01585         if ((PR_MAX(colPctWidthTotal, colPctAdjTotal)+ spanCellSpacing) < cellPctWidth) { 
01586           // we have something to distribute ...
01587           // record the percent contributions for the spanned cols
01588           PRInt32 usedColumns = colSpan;
01589           for (spanX = colSpan-1; spanX >= 0; spanX--) {
01590             nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); 
01591             if (!colFrame) continue;
01592             if ((colFrame->GetWidth(PCT) > 0) || (canSkipPctAdj && (colFrame->GetWidth(PCT_ADJ) > 0))) {
01593               // dont use pct cols or if we can skip the pct adj event do not take the PCT_ADJ cols
01594               usedColumns--;
01595               continue;
01596             } // count the pieces 
01597             if (usedColumns == 0)
01598               usedColumns = 1; // avoid division by 0 later
01599             nscoord minWidth = colFrame->GetMinWidth();
01600             nscoord colWidth = PR_MAX(minWidth, colFrame->GetFixWidth());
01601             colWidth = PR_MAX(colWidth, colFrame->GetDesWidth()); // XXX check this
01602             float avail = (float)PR_MAX(cellPctWidth - colPctWidthTotal, 0);
01603             float colPctAdj = (0 == spanTotal) 
01604                               ? avail / ((float) usedColumns) / ((float)basis)
01605                               : (avail / (float)basis) * (((float)colWidth) / (float)spanTotal);
01606             if (colPctAdj > 0) {
01607               nscoord colPctAdjWidth = colFrame->GetWidth(PCT_ADJ);
01608               nscoord newColPctAdjWidth = nsTableFrame::RoundToPixel(NSToCoordRound(colPctAdj * (float)basis), aPixelToTwips);
01609               if (newColPctAdjWidth > colPctAdjWidth) {
01610                 newColPctAdjWidth = PR_MAX(newColPctAdjWidth, minWidth); 
01611                 if (newColPctAdjWidth > colFrame->GetWidth(PCT)) {
01612                   colFrame->SetWidth(PCT_ADJ, newColPctAdjWidth);
01613                   if(0 != basis) { // I am paranoid
01614                     colPctTotal += NSToCoordRound(100.0f *(newColPctAdjWidth-colPctAdjWidth) / (float)basis); 
01615                     // accumulate the new distributed percents
01616                   }
01617                 }
01618               }
01619               else {
01620                 usedColumns--;
01621                 colPctWidthTotal += colPctAdjWidth; // accumulate the already distributed percents
01622               }
01623             }
01624           }
01625         }
01626       }
01627     } // end for (index ..
01628   } // end for (colX ..
01629 
01630   // We are done with our spanlist, get rid of it now
01631   PL_FinishArenaPool(&spanArena);
01632 
01633   // if the percent total went over 100%, adjustments need to be made to right most cols
01634   if (colPctTotal > 100) {
01635     ReduceOverSpecifiedPctCols(nsTableFrame::RoundToPixel(NSToCoordRound(((float)(colPctTotal - 100)) * 0.01f * (float)basis), aPixelToTwips));
01636   }
01637 
01638   // adjust the basis to include table border, padding and cell spacing
01639   basis += borderPadding.left + borderPadding.right + mCellSpacingTotal;
01640   return WrapupAssignPctColumnWidths(mTableFrame, aReflowState, basis); 
01641 }
01642 
01643 
01644 // calculate totals by width type. The logic here is kept in synch with 
01645 // that in CanAllocate. aDupedWidths (duplicatd) are widths that will be 
01646 // allocated in BalanceColumnWidths before aTotalsWidths (e.g. aTotalWidths[PCT] 
01647 // will have aDuplicatedWidths[PCT] consisting of the MIN widths of cols which
01648 // have a PCT width).
01649 void BasicTableLayoutStrategy::CalculateTotals(PRInt32* aTotalCounts,
01650                                                PRInt32* aTotalWidths,
01651                                                PRInt32* aDupedWidths, 
01652                                                PRInt32& a0ProportionalCount)
01653 {
01654   //mTableFrame->Dump(PR_TRUE, PR_FALSE);
01655   for (PRInt32 widthX = 0; widthX < NUM_WIDTHS; widthX++) {
01656     aTotalCounts[widthX]      = 0;
01657     aTotalWidths[widthX]      = 0;
01658     aDupedWidths[widthX]      = 0;
01659   }
01660   a0ProportionalCount = 0;
01661 
01662   PRInt32 numEffCols = mTableFrame->GetEffectiveColCount();
01663   PRInt32 colX;
01664 
01665   for (colX = 0; colX < numEffCols; colX++) { 
01666     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01667     if (!colFrame) continue;
01668     nscoord minCol = colFrame->GetMinWidth();
01669     aTotalCounts[MIN_CON]++;
01670     aTotalWidths[MIN_CON] += minCol;
01671 
01672     if (e0ProportionConstraint == colFrame->GetConstraint()) {
01673       a0ProportionalCount++;
01674     }
01675 
01676     nscoord pct    = colFrame->GetPctWidth();
01677     nscoord fix    = colFrame->GetWidth(FIX);
01678     nscoord fixAdj = colFrame->GetWidth(FIX_ADJ);
01679     // if there is a pct width then no others are considered
01680     if (pct > 0) {
01681       aTotalCounts[PCT]++;
01682       aTotalWidths[PCT] += PR_MAX(pct, minCol);
01683       aDupedWidths[PCT] += minCol;
01684     }
01685     else if ((fix > 0) || (fixAdj > 0)) {
01686       if (fix > 0) {
01687         aTotalCounts[FIX]++;
01688         aTotalWidths[FIX] += PR_MAX(fix, minCol);
01689         aDupedWidths[FIX] += minCol;
01690       }
01691       if (fixAdj > 0) {
01692         if (fixAdj > fix) {
01693           aTotalCounts[FIX_ADJ]++;
01694           aTotalWidths[FIX_ADJ] += PR_MAX(fixAdj, minCol);
01695           if (fix > 0) {
01696             aDupedWidths[FIX_ADJ] += fix;
01697           }
01698           else { // there was no fix
01699             aDupedWidths[FIX_ADJ] += minCol;
01700           }
01701         }
01702       }
01703     }
01704     else if ((eProportionConstraint == colFrame->GetConstraint()) ||
01705              (e0ProportionConstraint == colFrame->GetConstraint())) {
01706       aTotalCounts[MIN_PRO]++;
01707       aTotalWidths[MIN_PRO] += PR_MAX(colFrame->GetWidth(MIN_PRO), minCol);
01708       aDupedWidths[MIN_PRO] += minCol;
01709     }
01710     else {
01711       // desired alone is lowest priority
01712       aTotalCounts[DES_CON]++;
01713       aTotalWidths[DES_CON] += PR_MAX(colFrame->GetDesWidth(), minCol);
01714       aDupedWidths[DES_CON] += minCol;
01715     }
01716   }
01717 }
01718 
01719 
01720 struct ColInfo {
01721   ColInfo(nsTableColFrame* aFrame,
01722           PRInt32          aIndex,
01723           PRInt32          aMinWidth,
01724           PRInt32          aWidth,
01725           PRInt32          aMaxWidth)
01726     : mFrame(aFrame), mIndex(aIndex), mMinWidth(aMinWidth), 
01727       mWidth(aWidth), mMaxWidth(aMaxWidth), mWeight(0)
01728   {}
01729   nsTableColFrame* mFrame;
01730   PRInt32          mIndex;
01731   PRInt32          mMinWidth;
01732   PRInt32          mWidth;
01733   PRInt32          mMaxWidth;
01734   float            mWeight;
01735 };
01736 
01737 void
01738 AC_Wrapup(nsTableFrame* aTableFrame,
01739           PRInt32       aNumItems, 
01740           ColInfo**     aColInfo,
01741           PRBool        aAbort = PR_FALSE)
01742 {
01743   if (aColInfo) {
01744     for (PRInt32 i = 0; i < aNumItems; i++) {
01745       if (aColInfo[i]) {
01746         if (!aAbort) {
01747           aTableFrame->SetColumnWidth(aColInfo[i]->mIndex, aColInfo[i]->mWidth);
01748         }
01749         delete aColInfo[i];
01750       }
01751     }
01752     delete [] aColInfo;
01753   }
01754 }
01755 
01756 void
01757 AC_Increase(PRInt32     aNumAutoCols,
01758             ColInfo**   aColInfo,
01759             PRInt32     aDivisor,
01760             PRInt32&    aAvailWidth,
01761             float       aPixelToTwips)
01762 {
01763   for (PRInt32 i = 0; i < aNumAutoCols; i++) {
01764     if ((aAvailWidth <= 0) || (aDivisor <= 0)) {
01765       break;
01766     }
01767     // aDivisor represents the sum of unallocated space (diff between max and min values)
01768     float percent = ((float)aColInfo[i]->mMaxWidth - (float)aColInfo[i]->mMinWidth) / (float)aDivisor;
01769     aDivisor -= aColInfo[i]->mMaxWidth - aColInfo[i]->mMinWidth;
01770 
01771     nscoord addition = nsTableFrame::RoundToPixel(NSToCoordRound(((float)(aAvailWidth)) * percent), aPixelToTwips);
01772     // if its the last col, try to give what's left to it
01773     if ((i == aNumAutoCols - 1) && (addition < aAvailWidth)) {
01774       addition = aAvailWidth;
01775     }
01776     // don't let the addition exceed what is available to add
01777     addition = PR_MIN(addition, aAvailWidth);
01778     // don't go over the col max
01779     addition = PR_MIN(addition, aColInfo[i]->mMaxWidth - aColInfo[i]->mWidth);
01780     aColInfo[i]->mWidth += addition;
01781     aAvailWidth -= addition;
01782   }
01783 }
01784 
01785 void
01786 AC_Decrease(PRInt32     aNumAutoCols,
01787             ColInfo**   aColInfo,
01788             PRInt32     aDivisor,
01789             PRInt32&    aExcess,
01790             float       aPixelToTwips)
01791 {
01792   for (PRInt32 i = 0; i < aNumAutoCols; i++) {
01793     if ((aExcess <= 0) || (aDivisor <= 0)) {
01794       break;
01795     }
01796     float percent = ((float)aColInfo[i]->mMaxWidth) / (float)aDivisor;
01797     aDivisor -= aColInfo[i]->mMaxWidth;
01798     nscoord reduction = nsTableFrame::RoundToPixel(NSToCoordRound(((float)(aExcess)) * percent), aPixelToTwips);
01799     // if its the last col, try to remove the remaining excess from it
01800     if ((i == aNumAutoCols - 1) && (reduction < aExcess)) {
01801       reduction = aExcess;
01802     }
01803     // don't let the reduction exceed what is available to reduce
01804     reduction = PR_MIN(reduction, aExcess);
01805     // don't go under the col min
01806     reduction = PR_MIN(reduction, aColInfo[i]->mWidth - aColInfo[i]->mMinWidth);
01807     aColInfo[i]->mWidth -= reduction;
01808     aExcess -= reduction;
01809   }
01810 }
01811 
01812 void 
01813 AC_Sort(ColInfo** aColInfo, PRInt32 aNumCols)
01814 {
01815   // sort the cols based on the Weight 
01816   for (PRInt32 j = aNumCols - 1; j > 0; j--) {
01817     for (PRInt32 i = 0; i < j; i++) { 
01818       if (aColInfo[i]->mWeight < aColInfo[i+1]->mWeight) { // swap them
01819         ColInfo* save = aColInfo[i];
01820         aColInfo[i]   = aColInfo[i+1];
01821         aColInfo[i+1] = save;
01822       }
01823     }
01824   }
01825 }
01826 
01827 // this assumes that the table has set the width for each col to be its min
01828 void BasicTableLayoutStrategy::AllocateConstrained(PRInt32  aAvailWidth,
01829                                                    PRInt32  aWidthType,
01830                                                    PRBool   aStartAtMin,        
01831                                                    PRInt32* aAllocTypes,
01832                                                    float    aPixelToTwips)
01833 {
01834   if ((0 == aAvailWidth) || (aWidthType < 0) || (aWidthType >= NUM_WIDTHS)) {
01835     NS_ASSERTION(PR_TRUE, "invalid args to AllocateConstrained");
01836     return;
01837   }
01838 
01839   PRInt32 numCols = mTableFrame->GetColCount();
01840   PRInt32 numConstrainedCols = 0;
01841   nscoord sumMaxConstraints  = 0;
01842   nscoord sumMinConstraints  = 0;
01843   PRInt32 colX;
01844   // find out how many constrained cols there are
01845   for (colX = 0; colX < numCols; colX++) {
01846     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01847     if (!colFrame) continue;
01848     if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
01849       continue;
01850     }
01851     numConstrainedCols++;
01852   }
01853 
01854   // allocate storage for the constrained cols. Only they get adjusted.
01855   ColInfo** colInfo = new ColInfo*[numConstrainedCols];
01856   if (!colInfo) return;
01857   memset(colInfo, 0, numConstrainedCols * sizeof(ColInfo *));
01858 
01859   PRInt32 maxMinDiff = 0;
01860   PRInt32 constrColX = 0;
01861   // set the col info entries for each constrained col
01862   for (colX = 0; colX < numCols; colX++) {
01863     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); 
01864     if (!colFrame) continue;
01865     if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
01866       continue;
01867     }
01868     nscoord minWidth = mTableFrame->GetColumnWidth(colX);
01869     nscoord maxWidth = GetColWidth(colFrame, aWidthType);
01870     // proportional and desired widths are handled together
01871     PRBool haveProWidth = PR_FALSE;
01872     if (DES_CON == aWidthType) {
01873       // Take into acount MIN_adj width as it has been included in totals before
01874       maxWidth = PR_MAX(maxWidth, colFrame->GetWidth(MIN_ADJ));
01875       nscoord proWidth = colFrame->GetWidth(MIN_PRO);
01876       if (proWidth >= 0) {
01877         haveProWidth = PR_TRUE;
01878         maxWidth = proWidth;
01879       }
01880     }
01881 
01882     if (maxWidth <= 0) continue;
01883 
01884     sumMaxConstraints += maxWidth;
01885     sumMinConstraints += minWidth;
01886 
01887     maxWidth = PR_MAX(maxWidth, minWidth);
01888     maxMinDiff += maxWidth - minWidth;
01889     nscoord startWidth = (aStartAtMin) ? minWidth : maxWidth;
01890     colInfo[constrColX] = new ColInfo(colFrame, colX, minWidth, startWidth, maxWidth);
01891     if (!colInfo[constrColX]) {
01892       AC_Wrapup(mTableFrame, numConstrainedCols, colInfo, PR_TRUE);
01893       return;
01894     }
01895     aAllocTypes[colX] = (haveProWidth) ? MIN_PRO : aWidthType;
01896     constrColX++;
01897   }
01898 
01899   if (constrColX < numConstrainedCols) {
01900     // some of the constrainted cols might have been 0 and skipped
01901     numConstrainedCols = constrColX;
01902   }
01903 
01904   PRInt32 i;
01905   if (aStartAtMin) { // allocate extra space 
01906     nscoord availWidth = aAvailWidth; 
01907     for (i = 0; i < numConstrainedCols; i++) {
01908       // the weight here is a relative metric for determining when cols reach their max constraint. 
01909       // A col with a larger weight will reach its max before one with a smaller value.
01910       nscoord delta = colInfo[i]->mMaxWidth - colInfo[i]->mWidth;
01911       colInfo[i]->mWeight = (delta <= 0) 
01912         ? 1000000 // cols which have already reached their max get a large value
01913         : ((float)colInfo[i]->mMaxWidth) / ((float)delta);
01914     }
01915       
01916     // sort the cols based on the weight so that in one pass cols with higher 
01917     // weights will get their max earlier than ones with lower weights
01918     // This is an innefficient bubble sort, but unless there are an unlikely 
01919     // large number of cols, it is not an issue.
01920     AC_Sort(colInfo, numConstrainedCols);
01921    
01922     // compute the proportion to be added to each column, don't go beyond the col's
01923     // max. This algorithm assumes that the Weight works as stated above
01924     AC_Increase(numConstrainedCols, colInfo, sumMaxConstraints - sumMinConstraints, 
01925                 availWidth, aPixelToTwips);
01926   }
01927   else { // reduce each col width 
01928     nscoord reduceWidth = maxMinDiff - aAvailWidth;
01929     if (reduceWidth < 0) {
01930       NS_ASSERTION(PR_TRUE, "AllocateConstrained called incorrectly");
01931       AC_Wrapup(mTableFrame, numConstrainedCols, colInfo);
01932       return;
01933     }
01934     for (i = 0; i < numConstrainedCols; i++) {
01935       // the weight here is a relative metric for determining when cols reach their min. 
01936       // A col with a larger weight will reach its min before one with a smaller value.
01937       nscoord delta = colInfo[i]->mWidth - colInfo[i]->mMinWidth;
01938       colInfo[i]->mWeight = (delta <= 0) 
01939         ? 1000000 // cols which have already reached their min get a large value
01940         : ((float)colInfo[i]->mWidth) / ((float)delta);
01941     }
01942       
01943     // sort the cols based on the Weight 
01944     AC_Sort(colInfo, numConstrainedCols);
01945    
01946     // compute the proportion to be subtracted from each column, don't go beyond 
01947     // the col's min. This algorithm assumes that the Weight works as stated above
01948     AC_Decrease(numConstrainedCols, colInfo, sumMaxConstraints, reduceWidth, aPixelToTwips);
01949   }
01950   AC_Wrapup(mTableFrame, numConstrainedCols, colInfo);
01951 }
01952 
01953 #ifdef DEBUG_TABLE_STRATEGY
01954 void BasicTableLayoutStrategy::Dump(PRInt32 aIndent)
01955 {
01956   char* indent = new char[aIndent + 1];
01957   if (!indent) return;
01958   for (PRInt32 i = 0; i < aIndent + 1; i++) {
01959     indent[i] = ' ';
01960   }
01961   indent[aIndent] = 0;
01962 
01963   printf("%s**START BASIC STRATEGY DUMP** table=%p cols=%X",
01964          indent, mTableFrame, mCols);
01965   printf("\n%s cellSpacing=%d propRatio=%.2f navQuirks=%d",
01966     indent, mCellSpacingTotal, mMinToDesProportionRatio, mIsNavQuirksMode);
01967   printf(" **END BASIC STRATEGY DUMP** \n");
01968   delete [] indent;
01969 }
01970 #endif