Back to index

lightning-sunbird  0.9+nobinonly
FixedTableLayoutStrategy.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 #include "FixedTableLayoutStrategy.h"
00039 #include "nsTableFrame.h"
00040 #include "nsTableCellFrame.h"
00041 #include "nsStyleConsts.h"
00042 #include "nsVoidArray.h"
00043 
00044 FixedTableLayoutStrategy::FixedTableLayoutStrategy(nsTableFrame *aFrame)
00045   : BasicTableLayoutStrategy(aFrame)
00046 {
00047 }
00048 
00049 FixedTableLayoutStrategy::~FixedTableLayoutStrategy()
00050 {
00051 }
00052 
00053 PRBool FixedTableLayoutStrategy::BalanceColumnWidths(const nsHTMLReflowState& aReflowState)
00054 {
00055   return PR_TRUE;
00056 }
00057 
00058 /*
00059  * assign the width of all columns
00060  * if there is a colframe with a width attribute, use it as the column width
00061  * otherwise if there is a cell in the first row and it has a width attribute, use it
00062  *  if this cell includes a colspan, width is divided equally among spanned columns
00063  * otherwise the cell get a proportion of the remaining space 
00064  *  as determined by the table width attribute.  If no table width attribute, it gets 0 width
00065  */
00066 PRBool 
00067 FixedTableLayoutStrategy::AssignNonPctColumnWidths(nscoord                  aComputedWidth,
00068                                                    const nsHTMLReflowState& aReflowState)
00069 {
00070   // NS_ASSERTION(aComputedWidth != NS_UNCONSTRAINEDSIZE, "bad computed width");
00071   const nsStylePosition* tablePosition = mTableFrame->GetStylePosition();
00072   PRBool tableIsFixedWidth = eStyleUnit_Coord   == tablePosition->mWidth.GetUnit() ||
00073                              eStyleUnit_Percent == tablePosition->mWidth.GetUnit();
00074 
00075   PRInt32 numCols = mTableFrame->GetColCount();
00076   PRInt32 colX;
00077   float pixelToTwips = mTableFrame->GetPresContext()->ScaledPixelsToTwips();
00078   // availWidth is used as the basis for percentage width columns. It is aComputedWidth
00079   // minus table border, padding, & cellspacing
00080   nscoord spacingX = mTableFrame->GetCellSpacingX();
00081   mCellSpacingTotal = spacingX;
00082   for (colX = 0; colX < numCols; colX++){
00083     if (mTableFrame->GetNumCellsOriginatingInCol(colX) > 0) {
00084       mCellSpacingTotal += spacingX;
00085     }
00086   }
00087   nscoord availWidth = (NS_UNCONSTRAINEDSIZE == aComputedWidth) 
00088     ? NS_UNCONSTRAINEDSIZE
00089     : aComputedWidth - aReflowState.mComputedBorderPadding.left - 
00090       aReflowState.mComputedBorderPadding.right - 
00091       mCellSpacingTotal;
00092   
00093   PRInt32 specifiedCols = 0;  // the number of columns whose width is given
00094   nscoord totalColWidth = 0;  // the sum of the widths of the columns 
00095 
00096   nscoord* colWidths = new nscoord[numCols];
00097   if (!colWidths) return PR_FALSE;
00098   memset(colWidths, WIDTH_NOT_SET, numCols*sizeof(nscoord));
00099 
00100   nscoord* propInfo = new nscoord[numCols];
00101   if (!propInfo) {
00102     delete [] colWidths;
00103     return PR_FALSE;
00104   }
00105 
00106   memset(propInfo, 0, numCols*sizeof(nscoord));
00107   nscoord propTotal = 0;
00108   nscoord percTotal = 0;
00109   // for every column, determine its specified width
00110   for (colX = 0; colX < numCols; colX++) { 
00111     // Get column information
00112     nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
00113     if (!colFrame) {
00114       NS_ASSERTION(PR_FALSE, "bad col frame");
00115       return PR_FALSE;
00116     }
00117 
00118     // Get the columns's style
00119     const nsStylePosition* colPosition = colFrame->GetStylePosition();
00120 
00121     // get the fixed width if available
00122     if (eStyleUnit_Coord == colPosition->mWidth.GetUnit()) { 
00123       colWidths[colX] = colPosition->mWidth.GetCoordValue();
00124       colFrame->SetWidth(MIN_CON, colWidths[colX]);
00125     } // get the percentage width
00126     else if ((eStyleUnit_Percent == colPosition->mWidth.GetUnit()) &&
00127              (aComputedWidth != NS_UNCONSTRAINEDSIZE)) { 
00128       // Only apply percentages if we're constrained.
00129       float percent = colPosition->mWidth.GetPercentValue();
00130       colWidths[colX] = nsTableFrame::RoundToPixel(NSToCoordRound(percent * (float)availWidth), pixelToTwips); 
00131       colFrame->SetWidth(PCT, colWidths[colX]);
00132       percTotal+=colWidths[colX];
00133     }
00134     else if (eStyleUnit_Proportional == colPosition->mWidth.GetUnit() &&
00135       colPosition->mWidth.GetIntValue() > 0) {
00136       propInfo[colX] = colPosition->mWidth.GetIntValue();
00137       propTotal += propInfo[colX];
00138     }
00139     else { // get width from the cell
00140 
00141       nsTableCellFrame* cellFrame = mTableFrame->GetCellFrameAt(0, colX);
00142       if (nsnull != cellFrame) {
00143         // Get the cell's style
00144         const nsStylePosition* cellPosition = cellFrame->GetStylePosition();
00145 
00146         nscoord cellWidth = 0;
00147         PRInt32 colSpan = mTableFrame->GetEffectiveColSpan(*cellFrame);
00148         // Get fixed cell width if available
00149         if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) {
00150           // need to add border and padding into fixed width
00151           nsMargin borderPadding = nsTableFrame::GetBorderPadding(nsSize(aReflowState.mComputedWidth, 0),
00152                                                                   pixelToTwips, cellFrame);
00153           cellWidth = cellPosition->mWidth.GetCoordValue() + borderPadding.left + borderPadding.right;
00154           colWidths[colX] = nsTableFrame::RoundToPixel(NSToCoordRound(((float) cellWidth) / ((float) colSpan)),
00155                                                                       pixelToTwips);
00156           colFrame->SetWidth(MIN_CON, colWidths[colX]);
00157         }
00158         else if ((eStyleUnit_Percent == cellPosition->mWidth.GetUnit()) &&
00159                  (aComputedWidth != NS_UNCONSTRAINEDSIZE)) {
00160           float percent = cellPosition->mWidth.GetPercentValue();
00161           // need to add border and padding into percent width
00162           nsMargin borderPadding = nsTableFrame::GetBorderPadding(nsSize(aReflowState.mComputedWidth, 0),
00163                                                                   pixelToTwips, cellFrame);
00164           cellWidth = NSToCoordRound(percent * (float) availWidth) + borderPadding.left + borderPadding.right;
00165           colWidths[colX] = nsTableFrame::RoundToPixel(NSToCoordRound(((float) cellWidth) / ((float) colSpan)),
00166                                                                       pixelToTwips); 
00167           colFrame->SetWidth(PCT, colWidths[colX]);
00168           percTotal += colWidths[colX];
00169         }
00170       }
00171     }
00172     if (colWidths[colX] >= 0) {
00173       totalColWidth += colWidths[colX];
00174       specifiedCols++;
00175     }
00176   }
00177  
00178   nscoord lastColAllocated = -1;
00179   nscoord remainingWidth = availWidth - totalColWidth;
00180   if(availWidth == NS_UNCONSTRAINEDSIZE)
00181     remainingWidth = 0; 
00182   if (remainingWidth >= 500000) {
00183     // let's put a cap on the width so that it doesn't become insane.
00184     remainingWidth = 100;
00185   }
00186 
00187   if (0 < remainingWidth) {
00188     if (propTotal > 0) {
00189       nscoord amountToAllocate = 0;
00190       for (colX = 0; colX < numCols; colX++) {
00191         if (propInfo[colX] > 0) {
00192           // We're proportional
00193           float percent = ((float)propInfo[colX])/((float)propTotal);
00194           amountToAllocate += NSToCoordRound(percent * (float)remainingWidth);
00195           colWidths[colX] = (amountToAllocate > 0) ?
00196             nsTableFrame::RoundToPixel(amountToAllocate, pixelToTwips,
00197                                        eRoundUpIfHalfOrMore) : 0;
00198           totalColWidth += colWidths[colX];
00199           amountToAllocate -= colWidths[colX];
00200           lastColAllocated = colX;
00201         }
00202       }  
00203     }
00204     else if (tableIsFixedWidth) {
00205       if (numCols > specifiedCols) {
00206         // allocate the extra space to the columns which have no width specified
00207         nscoord colAlloc =
00208           NSToCoordRound(((float)remainingWidth) /
00209                          (((float)numCols) - ((float)specifiedCols)));
00210         nscoord amountToAllocate = 0;
00211         for (colX = 0; colX < numCols; colX++) {
00212           if (-1 == colWidths[colX]) {
00213             amountToAllocate += colAlloc;
00214             colWidths[colX] = (amountToAllocate > 0) ?
00215               nsTableFrame::RoundToPixel(amountToAllocate,
00216                                          pixelToTwips,
00217                                          eRoundUpIfHalfOrMore) : 0;
00218             totalColWidth += colWidths[colX];
00219             amountToAllocate -= colWidths[colX];
00220             lastColAllocated = colX;
00221           }
00222         }
00223       }
00224       else { // allocate the extra space to the columns which have width specified
00225         float divisor = (float)totalColWidth;
00226         nscoord amountToAllocate = 0;
00227         for (colX = 0; colX < numCols; colX++) {
00228           if (colWidths[colX] > 0) {
00229             amountToAllocate += NSToCoordRound(remainingWidth * colWidths[colX] / divisor);
00230             nscoord colAlloc = (amountToAllocate > 0) ?
00231               nsTableFrame::RoundToPixel(amountToAllocate, pixelToTwips,
00232                                          eRoundUpIfHalfOrMore) : 0;
00233             colWidths[colX] += colAlloc;
00234             totalColWidth += colAlloc;
00235             amountToAllocate -= colAlloc;
00236             lastColAllocated = colX;
00237           }
00238         }
00239       }  
00240     }
00241   }
00242 
00243   nscoord overAllocation = ((availWidth >= 0) && (availWidth != NS_UNCONSTRAINEDSIZE))  
00244     ? totalColWidth - availWidth : 0;
00245   // set the column widths
00246   for (colX = 0; colX < numCols; colX++) {
00247     if (colWidths[colX] < 0) 
00248       colWidths[colX] = 0;
00249     // if there was too much allocated due to rounding, remove it from the last col
00250     if ((colX == lastColAllocated) && (overAllocation != 0)) {
00251       nscoord thisRemoval = nsTableFrame::RoundToPixel(overAllocation, pixelToTwips);
00252       colWidths[colX] -= thisRemoval;
00253       totalColWidth -= thisRemoval;
00254       
00255       totalColWidth -= colWidths[colX] - PR_MAX(0, colWidths[colX]);
00256       colWidths[colX] = PR_MAX(0, colWidths[colX]);
00257     }
00258   }
00259   overAllocation = ((availWidth >= 0) && (availWidth != NS_UNCONSTRAINEDSIZE))  
00260     ? totalColWidth - availWidth : 0;
00261   if(overAllocation > 0){
00262     // reduce over specified percent col
00263     nscoord amountToRemove = 0;
00264     for (colX = 0; colX < numCols; colX++) {
00265       nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
00266       if(( colFrame->GetWidth(PCT) > 0) && ( percTotal > 0)){
00267         amountToRemove += NSToCoordRound(overAllocation* colWidths[colX] / (float) percTotal);
00268         nscoord thisRemoval = (amountToRemove > 0) ?
00269           nsTableFrame::RoundToPixel(amountToRemove, pixelToTwips,
00270                                      eRoundUpIfHalfOrMore) : 0;
00271         colWidths[colX] -= thisRemoval;
00272         amountToRemove -= thisRemoval;
00273         totalColWidth -= thisRemoval;
00274         
00275         totalColWidth -= colWidths[colX] - PR_MAX(0, colWidths[colX]);
00276         colWidths[colX] = PR_MAX(0, colWidths[colX]);
00277         colFrame->SetWidth(PCT, colWidths[colX]);
00278       }
00279     }
00280   }
00281   for (colX = 0; colX < numCols; colX++) {
00282     mTableFrame->SetColumnWidth(colX, colWidths[colX]);
00283   }
00284 
00285   // clean up
00286   if (nsnull != colWidths) {
00287     delete [] colWidths;
00288   }
00289 
00290   if (nsnull != propInfo) {
00291     delete [] propInfo;
00292   }
00293   
00294   return PR_TRUE;
00295 }
00296 
00297 
00298 
00299