1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/tables/BasicTableLayoutStrategy.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1058 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +// vim:cindent:ts=4:et:sw=4: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Web-compatible algorithms that determine column and table widths, 1.12 + * used for CSS2's 'table-layout: auto'. 1.13 + */ 1.14 + 1.15 +#include "BasicTableLayoutStrategy.h" 1.16 +#include "nsTableFrame.h" 1.17 +#include "nsTableCellFrame.h" 1.18 +#include "nsLayoutUtils.h" 1.19 +#include "nsGkAtoms.h" 1.20 +#include "SpanningCellSorter.h" 1.21 +#include <algorithm> 1.22 + 1.23 +using namespace mozilla; 1.24 +using namespace mozilla::layout; 1.25 + 1.26 +namespace css = mozilla::css; 1.27 + 1.28 +#undef DEBUG_TABLE_STRATEGY 1.29 + 1.30 +BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aTableFrame) 1.31 + : nsITableLayoutStrategy(nsITableLayoutStrategy::Auto) 1.32 + , mTableFrame(aTableFrame) 1.33 +{ 1.34 + MarkIntrinsicWidthsDirty(); 1.35 +} 1.36 + 1.37 +/* virtual */ 1.38 +BasicTableLayoutStrategy::~BasicTableLayoutStrategy() 1.39 +{ 1.40 +} 1.41 + 1.42 +/* virtual */ nscoord 1.43 +BasicTableLayoutStrategy::GetMinWidth(nsRenderingContext* aRenderingContext) 1.44 +{ 1.45 + DISPLAY_MIN_WIDTH(mTableFrame, mMinWidth); 1.46 + if (mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) 1.47 + ComputeIntrinsicWidths(aRenderingContext); 1.48 + return mMinWidth; 1.49 +} 1.50 + 1.51 +/* virtual */ nscoord 1.52 +BasicTableLayoutStrategy::GetPrefWidth(nsRenderingContext* aRenderingContext, 1.53 + bool aComputingSize) 1.54 +{ 1.55 + DISPLAY_PREF_WIDTH(mTableFrame, mPrefWidth); 1.56 + NS_ASSERTION((mPrefWidth == NS_INTRINSIC_WIDTH_UNKNOWN) == 1.57 + (mPrefWidthPctExpand == NS_INTRINSIC_WIDTH_UNKNOWN), 1.58 + "dirtyness out of sync"); 1.59 + if (mPrefWidth == NS_INTRINSIC_WIDTH_UNKNOWN) 1.60 + ComputeIntrinsicWidths(aRenderingContext); 1.61 + return aComputingSize ? mPrefWidthPctExpand : mPrefWidth; 1.62 +} 1.63 + 1.64 +struct CellWidthInfo { 1.65 + CellWidthInfo(nscoord aMinCoord, nscoord aPrefCoord, 1.66 + float aPrefPercent, bool aHasSpecifiedWidth) 1.67 + : hasSpecifiedWidth(aHasSpecifiedWidth) 1.68 + , minCoord(aMinCoord) 1.69 + , prefCoord(aPrefCoord) 1.70 + , prefPercent(aPrefPercent) 1.71 + { 1.72 + } 1.73 + 1.74 + bool hasSpecifiedWidth; 1.75 + nscoord minCoord; 1.76 + nscoord prefCoord; 1.77 + float prefPercent; 1.78 +}; 1.79 + 1.80 +// Used for both column and cell calculations. The parts needed only 1.81 +// for cells are skipped when aIsCell is false. 1.82 +static CellWidthInfo 1.83 +GetWidthInfo(nsRenderingContext *aRenderingContext, 1.84 + nsIFrame *aFrame, bool aIsCell) 1.85 +{ 1.86 + nscoord minCoord, prefCoord; 1.87 + const nsStylePosition *stylePos = aFrame->StylePosition(); 1.88 + bool isQuirks = aFrame->PresContext()->CompatibilityMode() == 1.89 + eCompatibility_NavQuirks; 1.90 + nscoord boxSizingToBorderEdge = 0; 1.91 + if (aIsCell) { 1.92 + // If aFrame is a container for font size inflation, then shrink 1.93 + // wrapping inside of it should not apply font size inflation. 1.94 + AutoMaybeDisableFontInflation an(aFrame); 1.95 + 1.96 + minCoord = aFrame->GetMinWidth(aRenderingContext); 1.97 + prefCoord = aFrame->GetPrefWidth(aRenderingContext); 1.98 + // Until almost the end of this function, minCoord and prefCoord 1.99 + // represent the box-sizing based width values (which mean they 1.100 + // should include horizontal padding and border width when 1.101 + // box-sizing is set to border-box). 1.102 + // Note that this function returns border-box width, we add the 1.103 + // outer edges near the end of this function. 1.104 + 1.105 + // XXX Should we ignore percentage padding? 1.106 + nsIFrame::IntrinsicWidthOffsetData offsets = aFrame->IntrinsicWidthOffsets(aRenderingContext); 1.107 + 1.108 + // In quirks mode, table cell width should be content-box, 1.109 + // but height should be border box. 1.110 + // Because of this historic anomaly, we do not use quirk.css. 1.111 + // (We can't specify one value of box-sizing for width and another 1.112 + // for height). 1.113 + // For this reason, we also do not use box-sizing for just one of 1.114 + // them, as this may be confusing. 1.115 + if (isQuirks) { 1.116 + boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder; 1.117 + } 1.118 + else { 1.119 + switch (stylePos->mBoxSizing) { 1.120 + case NS_STYLE_BOX_SIZING_CONTENT: 1.121 + boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder; 1.122 + break; 1.123 + case NS_STYLE_BOX_SIZING_PADDING: 1.124 + minCoord += offsets.hPadding; 1.125 + prefCoord += offsets.hPadding; 1.126 + boxSizingToBorderEdge = offsets.hBorder; 1.127 + break; 1.128 + default: 1.129 + // NS_STYLE_BOX_SIZING_BORDER 1.130 + minCoord += offsets.hPadding + offsets.hBorder; 1.131 + prefCoord += offsets.hPadding + offsets.hBorder; 1.132 + break; 1.133 + } 1.134 + } 1.135 + } else { 1.136 + minCoord = 0; 1.137 + prefCoord = 0; 1.138 + } 1.139 + float prefPercent = 0.0f; 1.140 + bool hasSpecifiedWidth = false; 1.141 + 1.142 + const nsStyleCoord &width = stylePos->mWidth; 1.143 + nsStyleUnit unit = width.GetUnit(); 1.144 + // NOTE: We're ignoring calc() units with percentages here, for lack of a 1.145 + // sensible idea for what to do with them. This means calc() with 1.146 + // percentages is basically handled like 'auto' for table cells and 1.147 + // columns. 1.148 + if (width.ConvertsToLength()) { 1.149 + hasSpecifiedWidth = true; 1.150 + // Note: since ComputeWidthValue was designed to return content-box 1.151 + // width, it will (in some cases) subtract the box-sizing edges. 1.152 + // We prevent this unwanted behavior by calling it with 1.153 + // aContentEdgeToBoxSizing and aBoxSizingToMarginEdge set to 0. 1.154 + nscoord w = nsLayoutUtils::ComputeWidthValue(aRenderingContext, 1.155 + aFrame, 0, 0, 0, width); 1.156 + // Quirk: A cell with "nowrap" set and a coord value for the 1.157 + // width which is bigger than the intrinsic minimum width uses 1.158 + // that coord value as the minimum width. 1.159 + // This is kept up-to-date with dynamic changes to nowrap by code in 1.160 + // nsTableCellFrame::AttributeChanged 1.161 + if (aIsCell && w > minCoord && isQuirks && 1.162 + aFrame->GetContent()->HasAttr(kNameSpaceID_None, 1.163 + nsGkAtoms::nowrap)) { 1.164 + minCoord = w; 1.165 + } 1.166 + prefCoord = std::max(w, minCoord); 1.167 + } else if (unit == eStyleUnit_Percent) { 1.168 + prefPercent = width.GetPercentValue(); 1.169 + } else if (unit == eStyleUnit_Enumerated && aIsCell) { 1.170 + switch (width.GetIntValue()) { 1.171 + case NS_STYLE_WIDTH_MAX_CONTENT: 1.172 + // 'width' only affects pref width, not min 1.173 + // width, so don't change anything 1.174 + break; 1.175 + case NS_STYLE_WIDTH_MIN_CONTENT: 1.176 + prefCoord = minCoord; 1.177 + break; 1.178 + case NS_STYLE_WIDTH_FIT_CONTENT: 1.179 + case NS_STYLE_WIDTH_AVAILABLE: 1.180 + // act just like 'width: auto' 1.181 + break; 1.182 + default: 1.183 + NS_NOTREACHED("unexpected enumerated value"); 1.184 + } 1.185 + } 1.186 + 1.187 + nsStyleCoord maxWidth(stylePos->mMaxWidth); 1.188 + if (maxWidth.GetUnit() == eStyleUnit_Enumerated) { 1.189 + if (!aIsCell || maxWidth.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE) 1.190 + maxWidth.SetNoneValue(); 1.191 + else if (maxWidth.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT) 1.192 + // for 'max-width', '-moz-fit-content' is like 1.193 + // '-moz-max-content' 1.194 + maxWidth.SetIntValue(NS_STYLE_WIDTH_MAX_CONTENT, 1.195 + eStyleUnit_Enumerated); 1.196 + } 1.197 + unit = maxWidth.GetUnit(); 1.198 + // XXX To really implement 'max-width' well, we'd need to store 1.199 + // it separately on the columns. 1.200 + if (maxWidth.ConvertsToLength() || unit == eStyleUnit_Enumerated) { 1.201 + nscoord w = 1.202 + nsLayoutUtils::ComputeWidthValue(aRenderingContext, aFrame, 1.203 + 0, 0, 0, maxWidth); 1.204 + if (w < minCoord) 1.205 + minCoord = w; 1.206 + if (w < prefCoord) 1.207 + prefCoord = w; 1.208 + } else if (unit == eStyleUnit_Percent) { 1.209 + float p = stylePos->mMaxWidth.GetPercentValue(); 1.210 + if (p < prefPercent) 1.211 + prefPercent = p; 1.212 + } 1.213 + // treat calc() with percentages on max-width just like 'none'. 1.214 + 1.215 + nsStyleCoord minWidth(stylePos->mMinWidth); 1.216 + if (minWidth.GetUnit() == eStyleUnit_Enumerated) { 1.217 + if (!aIsCell || minWidth.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE) 1.218 + minWidth.SetCoordValue(0); 1.219 + else if (minWidth.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT) 1.220 + // for 'min-width', '-moz-fit-content' is like 1.221 + // '-moz-min-content' 1.222 + minWidth.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT, 1.223 + eStyleUnit_Enumerated); 1.224 + } 1.225 + unit = minWidth.GetUnit(); 1.226 + if (minWidth.ConvertsToLength() || unit == eStyleUnit_Enumerated) { 1.227 + nscoord w = 1.228 + nsLayoutUtils::ComputeWidthValue(aRenderingContext, aFrame, 1.229 + 0, 0, 0, minWidth); 1.230 + if (w > minCoord) 1.231 + minCoord = w; 1.232 + if (w > prefCoord) 1.233 + prefCoord = w; 1.234 + } else if (unit == eStyleUnit_Percent) { 1.235 + float p = stylePos->mMinWidth.GetPercentValue(); 1.236 + if (p > prefPercent) 1.237 + prefPercent = p; 1.238 + } 1.239 + // treat calc() with percentages on min-width just like '0'. 1.240 + 1.241 + // XXX Should col frame have border/padding considered? 1.242 + if (aIsCell) { 1.243 + minCoord += boxSizingToBorderEdge; 1.244 + prefCoord = NSCoordSaturatingAdd(prefCoord, boxSizingToBorderEdge); 1.245 + } 1.246 + 1.247 + return CellWidthInfo(minCoord, prefCoord, prefPercent, hasSpecifiedWidth); 1.248 +} 1.249 + 1.250 +static inline CellWidthInfo 1.251 +GetCellWidthInfo(nsRenderingContext *aRenderingContext, 1.252 + nsTableCellFrame *aCellFrame) 1.253 +{ 1.254 + return GetWidthInfo(aRenderingContext, aCellFrame, true); 1.255 +} 1.256 + 1.257 +static inline CellWidthInfo 1.258 +GetColWidthInfo(nsRenderingContext *aRenderingContext, 1.259 + nsIFrame *aFrame) 1.260 +{ 1.261 + return GetWidthInfo(aRenderingContext, aFrame, false); 1.262 +} 1.263 + 1.264 + 1.265 +/** 1.266 + * The algorithm in this function, in addition to meeting the 1.267 + * requirements of Web-compatibility, is also invariant under reordering 1.268 + * of the rows within a table (something that most, but not all, other 1.269 + * browsers are). 1.270 + */ 1.271 +void 1.272 +BasicTableLayoutStrategy::ComputeColumnIntrinsicWidths(nsRenderingContext* aRenderingContext) 1.273 +{ 1.274 + nsTableFrame *tableFrame = mTableFrame; 1.275 + nsTableCellMap *cellMap = tableFrame->GetCellMap(); 1.276 + 1.277 + mozilla::AutoStackArena arena; 1.278 + SpanningCellSorter spanningCells; 1.279 + 1.280 + // Loop over the columns to consider the columns and cells *without* 1.281 + // a colspan. 1.282 + int32_t col, col_end; 1.283 + for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) { 1.284 + nsTableColFrame *colFrame = tableFrame->GetColFrame(col); 1.285 + if (!colFrame) { 1.286 + NS_ERROR("column frames out of sync with cell map"); 1.287 + continue; 1.288 + } 1.289 + colFrame->ResetIntrinsics(); 1.290 + colFrame->ResetSpanIntrinsics(); 1.291 + 1.292 + // Consider the widths on the column. 1.293 + CellWidthInfo colInfo = GetColWidthInfo(aRenderingContext, colFrame); 1.294 + colFrame->AddCoords(colInfo.minCoord, colInfo.prefCoord, 1.295 + colInfo.hasSpecifiedWidth); 1.296 + colFrame->AddPrefPercent(colInfo.prefPercent); 1.297 + 1.298 + // Consider the widths on the column-group. Note that we follow 1.299 + // what the HTML spec says here, and make the width apply to 1.300 + // each column in the group, not the group as a whole. 1.301 + 1.302 + // If column has width, column-group doesn't override width. 1.303 + if (colInfo.minCoord == 0 && colInfo.prefCoord == 0 && 1.304 + colInfo.prefPercent == 0.0f) { 1.305 + NS_ASSERTION(colFrame->GetParent()->GetType() == 1.306 + nsGkAtoms::tableColGroupFrame, 1.307 + "expected a column-group"); 1.308 + colInfo = GetColWidthInfo(aRenderingContext, colFrame->GetParent()); 1.309 + colFrame->AddCoords(colInfo.minCoord, colInfo.prefCoord, 1.310 + colInfo.hasSpecifiedWidth); 1.311 + colFrame->AddPrefPercent(colInfo.prefPercent); 1.312 + } 1.313 + 1.314 + // Consider the contents of and the widths on the cells without 1.315 + // colspans. 1.316 + nsCellMapColumnIterator columnIter(cellMap, col); 1.317 + int32_t row, colSpan; 1.318 + nsTableCellFrame* cellFrame; 1.319 + while ((cellFrame = columnIter.GetNextFrame(&row, &colSpan))) { 1.320 + if (colSpan > 1) { 1.321 + spanningCells.AddCell(colSpan, row, col); 1.322 + continue; 1.323 + } 1.324 + 1.325 + CellWidthInfo info = GetCellWidthInfo(aRenderingContext, cellFrame); 1.326 + 1.327 + colFrame->AddCoords(info.minCoord, info.prefCoord, 1.328 + info.hasSpecifiedWidth); 1.329 + colFrame->AddPrefPercent(info.prefPercent); 1.330 + } 1.331 +#ifdef DEBUG_dbaron_off 1.332 + printf("table %p col %d nonspan: min=%d pref=%d spec=%d pct=%f\n", 1.333 + mTableFrame, col, colFrame->GetMinCoord(), 1.334 + colFrame->GetPrefCoord(), colFrame->GetHasSpecifiedCoord(), 1.335 + colFrame->GetPrefPercent()); 1.336 +#endif 1.337 + } 1.338 +#ifdef DEBUG_TABLE_STRATEGY 1.339 + printf("ComputeColumnIntrinsicWidths single\n"); 1.340 + mTableFrame->Dump(false, true, false); 1.341 +#endif 1.342 + 1.343 + // Consider the cells with a colspan that we saved in the loop above 1.344 + // into the spanning cell sorter. We consider these cells by seeing 1.345 + // if they require adding to the widths resulting only from cells 1.346 + // with a smaller colspan, and therefore we must process them sorted 1.347 + // in increasing order by colspan. For each colspan group, we 1.348 + // accumulate new values to accumulate in the column frame's Span* 1.349 + // members. 1.350 + // 1.351 + // Considering things only relative to the widths resulting from 1.352 + // cells with smaller colspans (rather than incrementally including 1.353 + // the results from spanning cells, or doing spanning and 1.354 + // non-spanning cells in a single pass) means that layout remains 1.355 + // row-order-invariant and (except for percentage widths that add to 1.356 + // more than 100%) column-order invariant. 1.357 + // 1.358 + // Starting with smaller colspans makes it more likely that we 1.359 + // satisfy all the constraints given and don't distribute space to 1.360 + // columns where we don't need it. 1.361 + SpanningCellSorter::Item *item; 1.362 + int32_t colSpan; 1.363 + while ((item = spanningCells.GetNext(&colSpan))) { 1.364 + NS_ASSERTION(colSpan > 1, 1.365 + "cell should not have been put in spanning cell sorter"); 1.366 + do { 1.367 + int32_t row = item->row; 1.368 + col = item->col; 1.369 + CellData *cellData = cellMap->GetDataAt(row, col); 1.370 + NS_ASSERTION(cellData && cellData->IsOrig(), 1.371 + "bogus result from spanning cell sorter"); 1.372 + 1.373 + nsTableCellFrame *cellFrame = cellData->GetCellFrame(); 1.374 + NS_ASSERTION(cellFrame, "bogus result from spanning cell sorter"); 1.375 + 1.376 + CellWidthInfo info = GetCellWidthInfo(aRenderingContext, cellFrame); 1.377 + 1.378 + if (info.prefPercent > 0.0f) { 1.379 + DistributePctWidthToColumns(info.prefPercent, 1.380 + col, colSpan); 1.381 + } 1.382 + DistributeWidthToColumns(info.minCoord, col, colSpan, 1.383 + BTLS_MIN_WIDTH, info.hasSpecifiedWidth); 1.384 + DistributeWidthToColumns(info.prefCoord, col, colSpan, 1.385 + BTLS_PREF_WIDTH, info.hasSpecifiedWidth); 1.386 + } while ((item = item->next)); 1.387 + 1.388 + // Combine the results of the span analysis into the main results, 1.389 + // for each increment of colspan. 1.390 + 1.391 + for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) { 1.392 + nsTableColFrame *colFrame = tableFrame->GetColFrame(col); 1.393 + if (!colFrame) { 1.394 + NS_ERROR("column frames out of sync with cell map"); 1.395 + continue; 1.396 + } 1.397 + 1.398 + colFrame->AccumulateSpanIntrinsics(); 1.399 + colFrame->ResetSpanIntrinsics(); 1.400 + 1.401 +#ifdef DEBUG_dbaron_off 1.402 + printf("table %p col %d span %d: min=%d pref=%d spec=%d pct=%f\n", 1.403 + mTableFrame, col, colSpan, colFrame->GetMinCoord(), 1.404 + colFrame->GetPrefCoord(), colFrame->GetHasSpecifiedCoord(), 1.405 + colFrame->GetPrefPercent()); 1.406 +#endif 1.407 + } 1.408 + } 1.409 + 1.410 + // Prevent percentages from adding to more than 100% by (to be 1.411 + // compatible with other browsers) treating any percentages that would 1.412 + // increase the total percentage to more than 100% as the number that 1.413 + // would increase it to only 100% (which is 0% if we've already hit 1.414 + // 100%). This means layout depends on the order of columns. 1.415 + float pct_used = 0.0f; 1.416 + for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) { 1.417 + nsTableColFrame *colFrame = tableFrame->GetColFrame(col); 1.418 + if (!colFrame) { 1.419 + NS_ERROR("column frames out of sync with cell map"); 1.420 + continue; 1.421 + } 1.422 + 1.423 + colFrame->AdjustPrefPercent(&pct_used); 1.424 + } 1.425 + 1.426 +#ifdef DEBUG_TABLE_STRATEGY 1.427 + printf("ComputeColumnIntrinsicWidths spanning\n"); 1.428 + mTableFrame->Dump(false, true, false); 1.429 +#endif 1.430 +} 1.431 + 1.432 +void 1.433 +BasicTableLayoutStrategy::ComputeIntrinsicWidths(nsRenderingContext* aRenderingContext) 1.434 +{ 1.435 + ComputeColumnIntrinsicWidths(aRenderingContext); 1.436 + 1.437 + nsTableCellMap *cellMap = mTableFrame->GetCellMap(); 1.438 + nscoord min = 0, pref = 0, max_small_pct_pref = 0, nonpct_pref_total = 0; 1.439 + float pct_total = 0.0f; // always from 0.0f - 1.0f 1.440 + int32_t colCount = cellMap->GetColCount(); 1.441 + nscoord spacing = mTableFrame->GetCellSpacingX(); 1.442 + nscoord add = spacing; // add (colcount + 1) * spacing for columns 1.443 + // where a cell originates 1.444 + 1.445 + for (int32_t col = 0; col < colCount; ++col) { 1.446 + nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); 1.447 + if (!colFrame) { 1.448 + NS_ERROR("column frames out of sync with cell map"); 1.449 + continue; 1.450 + } 1.451 + if (mTableFrame->ColumnHasCellSpacingBefore(col)) { 1.452 + add += spacing; 1.453 + } 1.454 + min += colFrame->GetMinCoord(); 1.455 + pref = NSCoordSaturatingAdd(pref, colFrame->GetPrefCoord()); 1.456 + 1.457 + // Percentages are of the table, so we have to reverse them for 1.458 + // intrinsic widths. 1.459 + float p = colFrame->GetPrefPercent(); 1.460 + if (p > 0.0f) { 1.461 + nscoord colPref = colFrame->GetPrefCoord(); 1.462 + nscoord new_small_pct_expand = 1.463 + (colPref == nscoord_MAX ? 1.464 + nscoord_MAX : nscoord(float(colPref) / p)); 1.465 + if (new_small_pct_expand > max_small_pct_pref) { 1.466 + max_small_pct_pref = new_small_pct_expand; 1.467 + } 1.468 + pct_total += p; 1.469 + } else { 1.470 + nonpct_pref_total = NSCoordSaturatingAdd(nonpct_pref_total, 1.471 + colFrame->GetPrefCoord()); 1.472 + } 1.473 + } 1.474 + 1.475 + nscoord pref_pct_expand = pref; 1.476 + 1.477 + // Account for small percentages expanding the preferred width of 1.478 + // *other* columns. 1.479 + if (max_small_pct_pref > pref_pct_expand) { 1.480 + pref_pct_expand = max_small_pct_pref; 1.481 + } 1.482 + 1.483 + // Account for large percentages expanding the preferred width of 1.484 + // themselves. There's no need to iterate over the columns multiple 1.485 + // times, since when there is such a need, the small percentage 1.486 + // effect is bigger anyway. (I think!) 1.487 + NS_ASSERTION(0.0f <= pct_total && pct_total <= 1.0f, 1.488 + "column percentage widths not adjusted down to 100%"); 1.489 + if (pct_total == 1.0f) { 1.490 + if (nonpct_pref_total > 0) { 1.491 + pref_pct_expand = nscoord_MAX; 1.492 + // XXX Or should I use some smaller value? (Test this using 1.493 + // nested tables!) 1.494 + } 1.495 + } else { 1.496 + nscoord large_pct_pref = 1.497 + (nonpct_pref_total == nscoord_MAX ? 1.498 + nscoord_MAX : 1.499 + nscoord(float(nonpct_pref_total) / (1.0f - pct_total))); 1.500 + if (large_pct_pref > pref_pct_expand) 1.501 + pref_pct_expand = large_pct_pref; 1.502 + } 1.503 + 1.504 + // border-spacing isn't part of the basis for percentages 1.505 + if (colCount > 0) { 1.506 + min += add; 1.507 + pref = NSCoordSaturatingAdd(pref, add); 1.508 + pref_pct_expand = NSCoordSaturatingAdd(pref_pct_expand, add); 1.509 + } 1.510 + 1.511 + mMinWidth = min; 1.512 + mPrefWidth = pref; 1.513 + mPrefWidthPctExpand = pref_pct_expand; 1.514 +} 1.515 + 1.516 +/* virtual */ void 1.517 +BasicTableLayoutStrategy::MarkIntrinsicWidthsDirty() 1.518 +{ 1.519 + mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN; 1.520 + mPrefWidth = NS_INTRINSIC_WIDTH_UNKNOWN; 1.521 + mPrefWidthPctExpand = NS_INTRINSIC_WIDTH_UNKNOWN; 1.522 + mLastCalcWidth = nscoord_MIN; 1.523 +} 1.524 + 1.525 +/* virtual */ void 1.526 +BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowState) 1.527 +{ 1.528 + nscoord width = aReflowState.ComputedWidth(); 1.529 + 1.530 + if (mLastCalcWidth == width) 1.531 + return; 1.532 + mLastCalcWidth = width; 1.533 + 1.534 + NS_ASSERTION((mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) == 1.535 + (mPrefWidth == NS_INTRINSIC_WIDTH_UNKNOWN), 1.536 + "dirtyness out of sync"); 1.537 + NS_ASSERTION((mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) == 1.538 + (mPrefWidthPctExpand == NS_INTRINSIC_WIDTH_UNKNOWN), 1.539 + "dirtyness out of sync"); 1.540 + // XXX Is this needed? 1.541 + if (mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) 1.542 + ComputeIntrinsicWidths(aReflowState.rendContext); 1.543 + 1.544 + nsTableCellMap *cellMap = mTableFrame->GetCellMap(); 1.545 + int32_t colCount = cellMap->GetColCount(); 1.546 + if (colCount <= 0) 1.547 + return; // nothing to do 1.548 + 1.549 + DistributeWidthToColumns(width, 0, colCount, BTLS_FINAL_WIDTH, false); 1.550 + 1.551 +#ifdef DEBUG_TABLE_STRATEGY 1.552 + printf("ComputeColumnWidths final\n"); 1.553 + mTableFrame->Dump(false, true, false); 1.554 +#endif 1.555 +} 1.556 + 1.557 +void 1.558 +BasicTableLayoutStrategy::DistributePctWidthToColumns(float aSpanPrefPct, 1.559 + int32_t aFirstCol, 1.560 + int32_t aColCount) 1.561 +{ 1.562 + // First loop to determine: 1.563 + int32_t nonPctColCount = 0; // number of spanned columns without % width 1.564 + nscoord nonPctTotalPrefWidth = 0; // total pref width of those columns 1.565 + // and to reduce aSpanPrefPct by columns that already have % width 1.566 + 1.567 + int32_t scol, scol_end; 1.568 + nsTableCellMap *cellMap = mTableFrame->GetCellMap(); 1.569 + for (scol = aFirstCol, scol_end = aFirstCol + aColCount; 1.570 + scol < scol_end; ++scol) { 1.571 + nsTableColFrame *scolFrame = mTableFrame->GetColFrame(scol); 1.572 + if (!scolFrame) { 1.573 + NS_ERROR("column frames out of sync with cell map"); 1.574 + continue; 1.575 + } 1.576 + float scolPct = scolFrame->GetPrefPercent(); 1.577 + if (scolPct == 0.0f) { 1.578 + nonPctTotalPrefWidth += scolFrame->GetPrefCoord(); 1.579 + if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) { 1.580 + ++nonPctColCount; 1.581 + } 1.582 + } else { 1.583 + aSpanPrefPct -= scolPct; 1.584 + } 1.585 + } 1.586 + 1.587 + if (aSpanPrefPct <= 0.0f || nonPctColCount == 0) { 1.588 + // There's no %-width on the colspan left over to distribute, 1.589 + // or there are no columns to which we could distribute %-width 1.590 + return; 1.591 + } 1.592 + 1.593 + // Second loop, to distribute what remains of aSpanPrefPct 1.594 + // between the non-percent-width spanned columns 1.595 + const bool spanHasNonPctPref = nonPctTotalPrefWidth > 0; // Loop invariant 1.596 + for (scol = aFirstCol, scol_end = aFirstCol + aColCount; 1.597 + scol < scol_end; ++scol) { 1.598 + nsTableColFrame *scolFrame = mTableFrame->GetColFrame(scol); 1.599 + if (!scolFrame) { 1.600 + NS_ERROR("column frames out of sync with cell map"); 1.601 + continue; 1.602 + } 1.603 + 1.604 + if (scolFrame->GetPrefPercent() == 0.0f) { 1.605 + NS_ASSERTION((!spanHasNonPctPref || 1.606 + nonPctTotalPrefWidth != 0) && 1.607 + nonPctColCount != 0, 1.608 + "should not be zero if we haven't allocated " 1.609 + "all pref percent"); 1.610 + 1.611 + float allocatedPct; // % width to be given to this column 1.612 + if (spanHasNonPctPref) { 1.613 + // Group so we're multiplying by 1.0f when we need 1.614 + // to use up aSpanPrefPct. 1.615 + allocatedPct = aSpanPrefPct * 1.616 + (float(scolFrame->GetPrefCoord()) / 1.617 + float(nonPctTotalPrefWidth)); 1.618 + } else if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) { 1.619 + // distribute equally when all pref widths are 0 1.620 + allocatedPct = aSpanPrefPct / float(nonPctColCount); 1.621 + } else { 1.622 + allocatedPct = 0.0f; 1.623 + } 1.624 + // Allocate the percent 1.625 + scolFrame->AddSpanPrefPercent(allocatedPct); 1.626 + 1.627 + // To avoid accumulating rounding error from division, 1.628 + // subtract this column's values from the totals. 1.629 + aSpanPrefPct -= allocatedPct; 1.630 + nonPctTotalPrefWidth -= scolFrame->GetPrefCoord(); 1.631 + if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) { 1.632 + --nonPctColCount; 1.633 + } 1.634 + 1.635 + if (!aSpanPrefPct) { 1.636 + // No more span-percent-width to distribute --> we're done. 1.637 + NS_ASSERTION(spanHasNonPctPref ? 1.638 + nonPctTotalPrefWidth == 0 : 1.639 + nonPctColCount == 0, 1.640 + "No more pct width to distribute, but there are " 1.641 + "still cols that need some."); 1.642 + return; 1.643 + } 1.644 + } 1.645 + } 1.646 +} 1.647 + 1.648 +void 1.649 +BasicTableLayoutStrategy::DistributeWidthToColumns(nscoord aWidth, 1.650 + int32_t aFirstCol, 1.651 + int32_t aColCount, 1.652 + BtlsWidthType aWidthType, 1.653 + bool aSpanHasSpecifiedWidth) 1.654 +{ 1.655 + NS_ASSERTION(aWidthType != BTLS_FINAL_WIDTH || 1.656 + (aFirstCol == 0 && 1.657 + aColCount == mTableFrame->GetCellMap()->GetColCount()), 1.658 + "Computing final column widths, but didn't get full column range"); 1.659 + 1.660 + // border-spacing isn't part of the basis for percentages. 1.661 + nscoord spacing = mTableFrame->GetCellSpacingX(); 1.662 + nscoord subtract = 0; 1.663 + // aWidth initially includes border-spacing for the boundaries in between 1.664 + // each of the columns. We start at aFirstCol + 1 because the first 1.665 + // in-between boundary would be at the left edge of column aFirstCol + 1 1.666 + for (int32_t col = aFirstCol + 1; col < aFirstCol + aColCount; ++col) { 1.667 + if (mTableFrame->ColumnHasCellSpacingBefore(col)) { 1.668 + subtract += spacing; 1.669 + } 1.670 + } 1.671 + if (aWidthType == BTLS_FINAL_WIDTH) { 1.672 + // If we're computing final col-width, then aWidth initially includes 1.673 + // border spacing on the table's far left + far right edge, too. Need 1.674 + // to subtract those out, too. 1.675 + subtract += spacing * 2; 1.676 + } 1.677 + aWidth = NSCoordSaturatingSubtract(aWidth, subtract, nscoord_MAX); 1.678 + 1.679 + /* 1.680 + * The goal of this function is to distribute |aWidth| between the 1.681 + * columns by making an appropriate AddSpanCoords or SetFinalWidth 1.682 + * call for each column. (We call AddSpanCoords if we're 1.683 + * distributing a column-spanning cell's minimum or preferred width 1.684 + * to its spanned columns. We call SetFinalWidth if we're 1.685 + * distributing a table's final width to its columns.) 1.686 + * 1.687 + * The idea is to either assign one of the following sets of widths 1.688 + * or a weighted average of two adjacent sets of widths. It is not 1.689 + * possible to assign values smaller than the smallest set of 1.690 + * widths. However, see below for handling the case of assigning 1.691 + * values larger than the largest set of widths. From smallest to 1.692 + * largest, these are: 1.693 + * 1.694 + * 1. [guess_min] Assign all columns their min width. 1.695 + * 1.696 + * 2. [guess_min_pct] Assign all columns with percentage widths 1.697 + * their percentage width, and all other columns their min width. 1.698 + * 1.699 + * 3. [guess_min_spec] Assign all columns with percentage widths 1.700 + * their percentage width, all columns with specified coordinate 1.701 + * widths their pref width (since it doesn't matter whether it's the 1.702 + * largest contributor to the pref width that was the specified 1.703 + * contributor), and all other columns their min width. 1.704 + * 1.705 + * 4. [guess_pref] Assign all columns with percentage widths their 1.706 + * specified width, and all other columns their pref width. 1.707 + * 1.708 + * If |aWidth| is *larger* than what we would assign in (4), then we 1.709 + * expand the columns: 1.710 + * 1.711 + * a. if any columns without a specified coordinate width or 1.712 + * percent width have nonzero pref width, in proportion to pref 1.713 + * width [total_flex_pref] 1.714 + * 1.715 + * b. otherwise, if any columns without a specified coordinate 1.716 + * width or percent width, but with cells originating in them, 1.717 + * have zero pref width, equally between these 1.718 + * [numNonSpecZeroWidthCols] 1.719 + * 1.720 + * c. otherwise, if any columns without percent width have nonzero 1.721 + * pref width, in proportion to pref width [total_fixed_pref] 1.722 + * 1.723 + * d. otherwise, if any columns have nonzero percentage widths, in 1.724 + * proportion to the percentage widths [total_pct] 1.725 + * 1.726 + * e. otherwise, equally. 1.727 + */ 1.728 + 1.729 + // Loop #1 over the columns, to figure out the four values above so 1.730 + // we know which case we're dealing with. 1.731 + 1.732 + nscoord guess_min = 0, 1.733 + guess_min_pct = 0, 1.734 + guess_min_spec = 0, 1.735 + guess_pref = 0, 1.736 + total_flex_pref = 0, 1.737 + total_fixed_pref = 0; 1.738 + float total_pct = 0.0f; // 0.0f to 1.0f 1.739 + int32_t numInfiniteWidthCols = 0; 1.740 + int32_t numNonSpecZeroWidthCols = 0; 1.741 + 1.742 + int32_t col; 1.743 + nsTableCellMap *cellMap = mTableFrame->GetCellMap(); 1.744 + for (col = aFirstCol; col < aFirstCol + aColCount; ++col) { 1.745 + nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); 1.746 + if (!colFrame) { 1.747 + NS_ERROR("column frames out of sync with cell map"); 1.748 + continue; 1.749 + } 1.750 + nscoord min_width = colFrame->GetMinCoord(); 1.751 + guess_min += min_width; 1.752 + if (colFrame->GetPrefPercent() != 0.0f) { 1.753 + float pct = colFrame->GetPrefPercent(); 1.754 + total_pct += pct; 1.755 + nscoord val = nscoord(float(aWidth) * pct); 1.756 + if (val < min_width) 1.757 + val = min_width; 1.758 + guess_min_pct += val; 1.759 + guess_pref = NSCoordSaturatingAdd(guess_pref, val); 1.760 + } else { 1.761 + nscoord pref_width = colFrame->GetPrefCoord(); 1.762 + if (pref_width == nscoord_MAX) { 1.763 + ++numInfiniteWidthCols; 1.764 + } 1.765 + guess_pref = NSCoordSaturatingAdd(guess_pref, pref_width); 1.766 + guess_min_pct += min_width; 1.767 + if (colFrame->GetHasSpecifiedCoord()) { 1.768 + // we'll add on the rest of guess_min_spec outside the 1.769 + // loop 1.770 + nscoord delta = NSCoordSaturatingSubtract(pref_width, 1.771 + min_width, 0); 1.772 + guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, delta); 1.773 + total_fixed_pref = NSCoordSaturatingAdd(total_fixed_pref, 1.774 + pref_width); 1.775 + } else if (pref_width == 0) { 1.776 + if (cellMap->GetNumCellsOriginatingInCol(col) > 0) { 1.777 + ++numNonSpecZeroWidthCols; 1.778 + } 1.779 + } else { 1.780 + total_flex_pref = NSCoordSaturatingAdd(total_flex_pref, 1.781 + pref_width); 1.782 + } 1.783 + } 1.784 + } 1.785 + guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, guess_min_pct); 1.786 + 1.787 + // Determine what we're flexing: 1.788 + enum Loop2Type { 1.789 + FLEX_PCT_SMALL, // between (1) and (2) above 1.790 + FLEX_FIXED_SMALL, // between (2) and (3) above 1.791 + FLEX_FLEX_SMALL, // between (3) and (4) above 1.792 + FLEX_FLEX_LARGE, // greater than (4) above, case (a) 1.793 + FLEX_FLEX_LARGE_ZERO, // greater than (4) above, case (b) 1.794 + FLEX_FIXED_LARGE, // greater than (4) above, case (c) 1.795 + FLEX_PCT_LARGE, // greater than (4) above, case (d) 1.796 + FLEX_ALL_LARGE // greater than (4) above, case (e) 1.797 + }; 1.798 + 1.799 + Loop2Type l2t; 1.800 + // These are constants (over columns) for each case's math. We use 1.801 + // a pair of nscoords rather than a float so that we can subtract 1.802 + // each column's allocation so we avoid accumulating rounding error. 1.803 + nscoord space; // the amount of extra width to allocate 1.804 + union { 1.805 + nscoord c; 1.806 + float f; 1.807 + } basis; // the sum of the statistic over columns to divide it 1.808 + if (aWidth < guess_pref) { 1.809 + if (aWidthType != BTLS_FINAL_WIDTH && aWidth <= guess_min) { 1.810 + // Return early -- we don't have any extra space to distribute. 1.811 + return; 1.812 + } 1.813 + NS_ASSERTION(!(aWidthType == BTLS_FINAL_WIDTH && aWidth < guess_min), 1.814 + "Table width is less than the " 1.815 + "sum of its columns' min widths"); 1.816 + if (aWidth < guess_min_pct) { 1.817 + l2t = FLEX_PCT_SMALL; 1.818 + space = aWidth - guess_min; 1.819 + basis.c = guess_min_pct - guess_min; 1.820 + } else if (aWidth < guess_min_spec) { 1.821 + l2t = FLEX_FIXED_SMALL; 1.822 + space = aWidth - guess_min_pct; 1.823 + basis.c = NSCoordSaturatingSubtract(guess_min_spec, guess_min_pct, 1.824 + nscoord_MAX); 1.825 + } else { 1.826 + l2t = FLEX_FLEX_SMALL; 1.827 + space = aWidth - guess_min_spec; 1.828 + basis.c = NSCoordSaturatingSubtract(guess_pref, guess_min_spec, 1.829 + nscoord_MAX); 1.830 + } 1.831 + } else { 1.832 + space = NSCoordSaturatingSubtract(aWidth, guess_pref, nscoord_MAX); 1.833 + if (total_flex_pref > 0) { 1.834 + l2t = FLEX_FLEX_LARGE; 1.835 + basis.c = total_flex_pref; 1.836 + } else if (numNonSpecZeroWidthCols > 0) { 1.837 + l2t = FLEX_FLEX_LARGE_ZERO; 1.838 + basis.c = numNonSpecZeroWidthCols; 1.839 + } else if (total_fixed_pref > 0) { 1.840 + l2t = FLEX_FIXED_LARGE; 1.841 + basis.c = total_fixed_pref; 1.842 + } else if (total_pct > 0.0f) { 1.843 + l2t = FLEX_PCT_LARGE; 1.844 + basis.f = total_pct; 1.845 + } else { 1.846 + l2t = FLEX_ALL_LARGE; 1.847 + basis.c = aColCount; 1.848 + } 1.849 + } 1.850 + 1.851 +#ifdef DEBUG_dbaron_off 1.852 + printf("ComputeColumnWidths: %d columns in width %d,\n" 1.853 + " guesses=[%d,%d,%d,%d], totals=[%d,%d,%f],\n" 1.854 + " l2t=%d, space=%d, basis.c=%d\n", 1.855 + aColCount, aWidth, 1.856 + guess_min, guess_min_pct, guess_min_spec, guess_pref, 1.857 + total_flex_pref, total_fixed_pref, total_pct, 1.858 + l2t, space, basis.c); 1.859 +#endif 1.860 + 1.861 + for (col = aFirstCol; col < aFirstCol + aColCount; ++col) { 1.862 + nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); 1.863 + if (!colFrame) { 1.864 + NS_ERROR("column frames out of sync with cell map"); 1.865 + continue; 1.866 + } 1.867 + nscoord col_width; 1.868 + 1.869 + float pct = colFrame->GetPrefPercent(); 1.870 + if (pct != 0.0f) { 1.871 + col_width = nscoord(float(aWidth) * pct); 1.872 + nscoord col_min = colFrame->GetMinCoord(); 1.873 + if (col_width < col_min) 1.874 + col_width = col_min; 1.875 + } else { 1.876 + col_width = colFrame->GetPrefCoord(); 1.877 + } 1.878 + 1.879 + nscoord col_width_before_adjust = col_width; 1.880 + 1.881 + switch (l2t) { 1.882 + case FLEX_PCT_SMALL: 1.883 + col_width = col_width_before_adjust = colFrame->GetMinCoord(); 1.884 + if (pct != 0.0f) { 1.885 + nscoord pct_minus_min = 1.886 + nscoord(float(aWidth) * pct) - col_width; 1.887 + if (pct_minus_min > 0) { 1.888 + float c = float(space) / float(basis.c); 1.889 + basis.c -= pct_minus_min; 1.890 + col_width += NSToCoordRound(float(pct_minus_min) * c); 1.891 + } 1.892 + } 1.893 + break; 1.894 + case FLEX_FIXED_SMALL: 1.895 + if (pct == 0.0f) { 1.896 + NS_ASSERTION(col_width == colFrame->GetPrefCoord(), 1.897 + "wrong width assigned"); 1.898 + if (colFrame->GetHasSpecifiedCoord()) { 1.899 + nscoord col_min = colFrame->GetMinCoord(); 1.900 + nscoord pref_minus_min = col_width - col_min; 1.901 + col_width = col_width_before_adjust = col_min; 1.902 + if (pref_minus_min != 0) { 1.903 + float c = float(space) / float(basis.c); 1.904 + basis.c -= pref_minus_min; 1.905 + col_width += NSToCoordRound( 1.906 + float(pref_minus_min) * c); 1.907 + } 1.908 + } else 1.909 + col_width = col_width_before_adjust = 1.910 + colFrame->GetMinCoord(); 1.911 + } 1.912 + break; 1.913 + case FLEX_FLEX_SMALL: 1.914 + if (pct == 0.0f && 1.915 + !colFrame->GetHasSpecifiedCoord()) { 1.916 + NS_ASSERTION(col_width == colFrame->GetPrefCoord(), 1.917 + "wrong width assigned"); 1.918 + nscoord col_min = colFrame->GetMinCoord(); 1.919 + nscoord pref_minus_min = 1.920 + NSCoordSaturatingSubtract(col_width, col_min, 0); 1.921 + col_width = col_width_before_adjust = col_min; 1.922 + if (pref_minus_min != 0) { 1.923 + float c = float(space) / float(basis.c); 1.924 + // If we have infinite-width cols, then the standard 1.925 + // adjustment to col_width using 'c' won't work, 1.926 + // because basis.c and pref_minus_min are both 1.927 + // nscoord_MAX and will cancel each other out in the 1.928 + // col_width adjustment (making us assign all the 1.929 + // space to the first inf-width col). To correct for 1.930 + // this, we'll also divide by numInfiniteWidthCols to 1.931 + // spread the space equally among the inf-width cols. 1.932 + if (numInfiniteWidthCols) { 1.933 + if (colFrame->GetPrefCoord() == nscoord_MAX) { 1.934 + c = c / float(numInfiniteWidthCols); 1.935 + --numInfiniteWidthCols; 1.936 + } else { 1.937 + c = 0.0f; 1.938 + } 1.939 + } 1.940 + basis.c = NSCoordSaturatingSubtract(basis.c, 1.941 + pref_minus_min, 1.942 + nscoord_MAX); 1.943 + col_width += NSToCoordRound( 1.944 + float(pref_minus_min) * c); 1.945 + } 1.946 + } 1.947 + break; 1.948 + case FLEX_FLEX_LARGE: 1.949 + if (pct == 0.0f && 1.950 + !colFrame->GetHasSpecifiedCoord()) { 1.951 + NS_ASSERTION(col_width == colFrame->GetPrefCoord(), 1.952 + "wrong width assigned"); 1.953 + if (col_width != 0) { 1.954 + if (space == nscoord_MAX) { 1.955 + basis.c -= col_width; 1.956 + col_width = nscoord_MAX; 1.957 + } else { 1.958 + float c = float(space) / float(basis.c); 1.959 + basis.c -= col_width; 1.960 + col_width += NSToCoordRound(float(col_width) * c); 1.961 + } 1.962 + } 1.963 + } 1.964 + break; 1.965 + case FLEX_FLEX_LARGE_ZERO: 1.966 + if (pct == 0.0f && 1.967 + !colFrame->GetHasSpecifiedCoord() && 1.968 + cellMap->GetNumCellsOriginatingInCol(col) > 0) { 1.969 + 1.970 + NS_ASSERTION(col_width == 0 && 1.971 + colFrame->GetPrefCoord() == 0, 1.972 + "Since we're in FLEX_FLEX_LARGE_ZERO case, " 1.973 + "all auto-width cols should have zero pref " 1.974 + "width."); 1.975 + float c = float(space) / float(basis.c); 1.976 + col_width += NSToCoordRound(c); 1.977 + --basis.c; 1.978 + } 1.979 + break; 1.980 + case FLEX_FIXED_LARGE: 1.981 + if (pct == 0.0f) { 1.982 + NS_ASSERTION(col_width == colFrame->GetPrefCoord(), 1.983 + "wrong width assigned"); 1.984 + NS_ASSERTION(colFrame->GetHasSpecifiedCoord() || 1.985 + colFrame->GetPrefCoord() == 0, 1.986 + "wrong case"); 1.987 + if (col_width != 0) { 1.988 + float c = float(space) / float(basis.c); 1.989 + basis.c -= col_width; 1.990 + col_width += NSToCoordRound(float(col_width) * c); 1.991 + } 1.992 + } 1.993 + break; 1.994 + case FLEX_PCT_LARGE: 1.995 + NS_ASSERTION(pct != 0.0f || colFrame->GetPrefCoord() == 0, 1.996 + "wrong case"); 1.997 + if (pct != 0.0f) { 1.998 + float c = float(space) / basis.f; 1.999 + col_width += NSToCoordRound(pct * c); 1.1000 + basis.f -= pct; 1.1001 + } 1.1002 + break; 1.1003 + case FLEX_ALL_LARGE: 1.1004 + { 1.1005 + float c = float(space) / float(basis.c); 1.1006 + col_width += NSToCoordRound(c); 1.1007 + --basis.c; 1.1008 + } 1.1009 + break; 1.1010 + } 1.1011 + 1.1012 + // Only subtract from space if it's a real number. 1.1013 + if (space != nscoord_MAX) { 1.1014 + NS_ASSERTION(col_width != nscoord_MAX, 1.1015 + "How is col_width nscoord_MAX if space isn't?"); 1.1016 + NS_ASSERTION(col_width_before_adjust != nscoord_MAX, 1.1017 + "How is col_width_before_adjust nscoord_MAX if space isn't?"); 1.1018 + space -= col_width - col_width_before_adjust; 1.1019 + } 1.1020 + 1.1021 + NS_ASSERTION(col_width >= colFrame->GetMinCoord(), 1.1022 + "assigned width smaller than min"); 1.1023 + 1.1024 + // Apply the new width 1.1025 + switch (aWidthType) { 1.1026 + case BTLS_MIN_WIDTH: 1.1027 + { 1.1028 + // Note: AddSpanCoords requires both a min and pref width. 1.1029 + // For the pref width, we'll just pass in our computed 1.1030 + // min width, because the real pref width will be at least 1.1031 + // as big 1.1032 + colFrame->AddSpanCoords(col_width, col_width, 1.1033 + aSpanHasSpecifiedWidth); 1.1034 + } 1.1035 + break; 1.1036 + case BTLS_PREF_WIDTH: 1.1037 + { 1.1038 + // Note: AddSpanCoords requires both a min and pref width. 1.1039 + // For the min width, we'll just pass in 0, because 1.1040 + // the real min width will be at least 0 1.1041 + colFrame->AddSpanCoords(0, col_width, 1.1042 + aSpanHasSpecifiedWidth); 1.1043 + } 1.1044 + break; 1.1045 + case BTLS_FINAL_WIDTH: 1.1046 + { 1.1047 + nscoord old_final = colFrame->GetFinalWidth(); 1.1048 + colFrame->SetFinalWidth(col_width); 1.1049 + 1.1050 + if (old_final != col_width) 1.1051 + mTableFrame->DidResizeColumns(); 1.1052 + } 1.1053 + break; 1.1054 + } 1.1055 + } 1.1056 + NS_ASSERTION((space == 0 || space == nscoord_MAX) && 1.1057 + ((l2t == FLEX_PCT_LARGE) 1.1058 + ? (-0.001f < basis.f && basis.f < 0.001f) 1.1059 + : (basis.c == 0 || basis.c == nscoord_MAX)), 1.1060 + "didn't subtract all that we added"); 1.1061 +}