Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | // vim:cindent:ts=4:et:sw=4: |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /* |
michael@0 | 8 | * Algorithms that determine column and table widths used for CSS2's |
michael@0 | 9 | * 'table-layout: fixed'. |
michael@0 | 10 | */ |
michael@0 | 11 | |
michael@0 | 12 | #include "FixedTableLayoutStrategy.h" |
michael@0 | 13 | #include "nsTableFrame.h" |
michael@0 | 14 | #include "nsTableColFrame.h" |
michael@0 | 15 | #include "nsTableCellFrame.h" |
michael@0 | 16 | #include <algorithm> |
michael@0 | 17 | |
michael@0 | 18 | FixedTableLayoutStrategy::FixedTableLayoutStrategy(nsTableFrame *aTableFrame) |
michael@0 | 19 | : nsITableLayoutStrategy(nsITableLayoutStrategy::Fixed) |
michael@0 | 20 | , mTableFrame(aTableFrame) |
michael@0 | 21 | { |
michael@0 | 22 | MarkIntrinsicWidthsDirty(); |
michael@0 | 23 | } |
michael@0 | 24 | |
michael@0 | 25 | /* virtual */ |
michael@0 | 26 | FixedTableLayoutStrategy::~FixedTableLayoutStrategy() |
michael@0 | 27 | { |
michael@0 | 28 | } |
michael@0 | 29 | |
michael@0 | 30 | /* virtual */ nscoord |
michael@0 | 31 | FixedTableLayoutStrategy::GetMinWidth(nsRenderingContext* aRenderingContext) |
michael@0 | 32 | { |
michael@0 | 33 | DISPLAY_MIN_WIDTH(mTableFrame, mMinWidth); |
michael@0 | 34 | if (mMinWidth != NS_INTRINSIC_WIDTH_UNKNOWN) |
michael@0 | 35 | return mMinWidth; |
michael@0 | 36 | |
michael@0 | 37 | // It's theoretically possible to do something much better here that |
michael@0 | 38 | // depends only on the columns and the first row (where we look at |
michael@0 | 39 | // intrinsic widths inside the first row and then reverse the |
michael@0 | 40 | // algorithm to find the narrowest width that would hold all of |
michael@0 | 41 | // those intrinsic widths), but it wouldn't be compatible with other |
michael@0 | 42 | // browsers, or with the use of GetMinWidth by |
michael@0 | 43 | // nsTableFrame::ComputeSize to determine the width of a fixed |
michael@0 | 44 | // layout table, since CSS2.1 says: |
michael@0 | 45 | // The width of the table is then the greater of the value of the |
michael@0 | 46 | // 'width' property for the table element and the sum of the |
michael@0 | 47 | // column widths (plus cell spacing or borders). |
michael@0 | 48 | |
michael@0 | 49 | // XXX Should we really ignore 'min-width' and 'max-width'? |
michael@0 | 50 | // XXX Should we really ignore widths on column groups? |
michael@0 | 51 | |
michael@0 | 52 | nsTableCellMap *cellMap = mTableFrame->GetCellMap(); |
michael@0 | 53 | int32_t colCount = cellMap->GetColCount(); |
michael@0 | 54 | nscoord spacing = mTableFrame->GetCellSpacingX(); |
michael@0 | 55 | |
michael@0 | 56 | nscoord result = 0; |
michael@0 | 57 | |
michael@0 | 58 | if (colCount > 0) { |
michael@0 | 59 | result += spacing * (colCount + 1); |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 63 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 64 | if (!colFrame) { |
michael@0 | 65 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 66 | continue; |
michael@0 | 67 | } |
michael@0 | 68 | const nsStyleCoord *styleWidth = |
michael@0 | 69 | &colFrame->StylePosition()->mWidth; |
michael@0 | 70 | if (styleWidth->ConvertsToLength()) { |
michael@0 | 71 | result += nsLayoutUtils::ComputeWidthValue(aRenderingContext, |
michael@0 | 72 | colFrame, 0, 0, 0, *styleWidth); |
michael@0 | 73 | } else if (styleWidth->GetUnit() == eStyleUnit_Percent) { |
michael@0 | 74 | // do nothing |
michael@0 | 75 | } else { |
michael@0 | 76 | NS_ASSERTION(styleWidth->GetUnit() == eStyleUnit_Auto || |
michael@0 | 77 | styleWidth->GetUnit() == eStyleUnit_Enumerated || |
michael@0 | 78 | (styleWidth->IsCalcUnit() && styleWidth->CalcHasPercent()), |
michael@0 | 79 | "bad width"); |
michael@0 | 80 | |
michael@0 | 81 | // The 'table-layout: fixed' algorithm considers only cells |
michael@0 | 82 | // in the first row. |
michael@0 | 83 | bool originates; |
michael@0 | 84 | int32_t colSpan; |
michael@0 | 85 | nsTableCellFrame *cellFrame = |
michael@0 | 86 | cellMap->GetCellInfoAt(0, col, &originates, &colSpan); |
michael@0 | 87 | if (cellFrame) { |
michael@0 | 88 | styleWidth = &cellFrame->StylePosition()->mWidth; |
michael@0 | 89 | if (styleWidth->ConvertsToLength() || |
michael@0 | 90 | (styleWidth->GetUnit() == eStyleUnit_Enumerated && |
michael@0 | 91 | (styleWidth->GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT || |
michael@0 | 92 | styleWidth->GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT))) { |
michael@0 | 93 | nscoord cellWidth = nsLayoutUtils::IntrinsicForContainer( |
michael@0 | 94 | aRenderingContext, cellFrame, nsLayoutUtils::MIN_WIDTH); |
michael@0 | 95 | if (colSpan > 1) { |
michael@0 | 96 | // If a column-spanning cell is in the first |
michael@0 | 97 | // row, split up the space evenly. (XXX This |
michael@0 | 98 | // isn't quite right if some of the columns it's |
michael@0 | 99 | // in have specified widths. Should we care?) |
michael@0 | 100 | cellWidth = ((cellWidth + spacing) / colSpan) - spacing; |
michael@0 | 101 | } |
michael@0 | 102 | result += cellWidth; |
michael@0 | 103 | } else if (styleWidth->GetUnit() == eStyleUnit_Percent) { |
michael@0 | 104 | if (colSpan > 1) { |
michael@0 | 105 | // XXX Can this force columns to negative |
michael@0 | 106 | // widths? |
michael@0 | 107 | result -= spacing * (colSpan - 1); |
michael@0 | 108 | } |
michael@0 | 109 | } |
michael@0 | 110 | // else, for 'auto', '-moz-available', '-moz-fit-content', |
michael@0 | 111 | // and 'calc()' with percentages, do nothing |
michael@0 | 112 | } |
michael@0 | 113 | } |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | return (mMinWidth = result); |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | /* virtual */ nscoord |
michael@0 | 120 | FixedTableLayoutStrategy::GetPrefWidth(nsRenderingContext* aRenderingContext, |
michael@0 | 121 | bool aComputingSize) |
michael@0 | 122 | { |
michael@0 | 123 | // It's theoretically possible to do something much better here that |
michael@0 | 124 | // depends only on the columns and the first row (where we look at |
michael@0 | 125 | // intrinsic widths inside the first row and then reverse the |
michael@0 | 126 | // algorithm to find the narrowest width that would hold all of |
michael@0 | 127 | // those intrinsic widths), but it wouldn't be compatible with other |
michael@0 | 128 | // browsers. |
michael@0 | 129 | nscoord result = nscoord_MAX; |
michael@0 | 130 | DISPLAY_PREF_WIDTH(mTableFrame, result); |
michael@0 | 131 | return result; |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | /* virtual */ void |
michael@0 | 135 | FixedTableLayoutStrategy::MarkIntrinsicWidthsDirty() |
michael@0 | 136 | { |
michael@0 | 137 | mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN; |
michael@0 | 138 | mLastCalcWidth = nscoord_MIN; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | static inline nscoord |
michael@0 | 142 | AllocateUnassigned(nscoord aUnassignedSpace, float aShare) |
michael@0 | 143 | { |
michael@0 | 144 | if (aShare == 1.0f) { |
michael@0 | 145 | // This happens when the numbers we're dividing to get aShare |
michael@0 | 146 | // are equal. We want to return unassignedSpace exactly, even |
michael@0 | 147 | // if it can't be precisely round-tripped through float. |
michael@0 | 148 | return aUnassignedSpace; |
michael@0 | 149 | } |
michael@0 | 150 | return NSToCoordRound(float(aUnassignedSpace) * aShare); |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | /* virtual */ void |
michael@0 | 154 | FixedTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowState) |
michael@0 | 155 | { |
michael@0 | 156 | nscoord tableWidth = aReflowState.ComputedWidth(); |
michael@0 | 157 | |
michael@0 | 158 | if (mLastCalcWidth == tableWidth) |
michael@0 | 159 | return; |
michael@0 | 160 | mLastCalcWidth = tableWidth; |
michael@0 | 161 | |
michael@0 | 162 | nsTableCellMap *cellMap = mTableFrame->GetCellMap(); |
michael@0 | 163 | int32_t colCount = cellMap->GetColCount(); |
michael@0 | 164 | nscoord spacing = mTableFrame->GetCellSpacingX(); |
michael@0 | 165 | |
michael@0 | 166 | if (colCount == 0) { |
michael@0 | 167 | // No Columns - nothing to compute |
michael@0 | 168 | return; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | // border-spacing isn't part of the basis for percentages. |
michael@0 | 172 | tableWidth -= spacing * (colCount + 1); |
michael@0 | 173 | |
michael@0 | 174 | // store the old column widths. We might call multiple times SetFinalWidth |
michael@0 | 175 | // on the columns, due to this we can't compare at the last call that the |
michael@0 | 176 | // width has changed with the respect to the last call to |
michael@0 | 177 | // ComputeColumnWidths. In order to overcome this we store the old values |
michael@0 | 178 | // in this array. A single call to SetFinalWidth would make it possible to |
michael@0 | 179 | // call GetFinalWidth before and to compare when setting the final width. |
michael@0 | 180 | nsTArray<nscoord> oldColWidths; |
michael@0 | 181 | |
michael@0 | 182 | // XXX This ignores the 'min-width' and 'max-width' properties |
michael@0 | 183 | // throughout. Then again, that's what the CSS spec says to do. |
michael@0 | 184 | |
michael@0 | 185 | // XXX Should we really ignore widths on column groups? |
michael@0 | 186 | |
michael@0 | 187 | uint32_t unassignedCount = 0; |
michael@0 | 188 | nscoord unassignedSpace = tableWidth; |
michael@0 | 189 | const nscoord unassignedMarker = nscoord_MIN; |
michael@0 | 190 | |
michael@0 | 191 | // We use the PrefPercent on the columns to store the percentages |
michael@0 | 192 | // used to compute column widths in case we need to shrink or expand |
michael@0 | 193 | // the columns. |
michael@0 | 194 | float pctTotal = 0.0f; |
michael@0 | 195 | |
michael@0 | 196 | // Accumulate the total specified (non-percent) on the columns for |
michael@0 | 197 | // distributing excess width to the columns. |
michael@0 | 198 | nscoord specTotal = 0; |
michael@0 | 199 | |
michael@0 | 200 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 201 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 202 | if (!colFrame) { |
michael@0 | 203 | oldColWidths.AppendElement(0); |
michael@0 | 204 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 205 | continue; |
michael@0 | 206 | } |
michael@0 | 207 | oldColWidths.AppendElement(colFrame->GetFinalWidth()); |
michael@0 | 208 | colFrame->ResetPrefPercent(); |
michael@0 | 209 | const nsStyleCoord *styleWidth = |
michael@0 | 210 | &colFrame->StylePosition()->mWidth; |
michael@0 | 211 | nscoord colWidth; |
michael@0 | 212 | if (styleWidth->ConvertsToLength()) { |
michael@0 | 213 | colWidth = nsLayoutUtils::ComputeWidthValue( |
michael@0 | 214 | aReflowState.rendContext, |
michael@0 | 215 | colFrame, 0, 0, 0, *styleWidth); |
michael@0 | 216 | specTotal += colWidth; |
michael@0 | 217 | } else if (styleWidth->GetUnit() == eStyleUnit_Percent) { |
michael@0 | 218 | float pct = styleWidth->GetPercentValue(); |
michael@0 | 219 | colWidth = NSToCoordFloor(pct * float(tableWidth)); |
michael@0 | 220 | colFrame->AddPrefPercent(pct); |
michael@0 | 221 | pctTotal += pct; |
michael@0 | 222 | } else { |
michael@0 | 223 | NS_ASSERTION(styleWidth->GetUnit() == eStyleUnit_Auto || |
michael@0 | 224 | styleWidth->GetUnit() == eStyleUnit_Enumerated || |
michael@0 | 225 | (styleWidth->IsCalcUnit() && styleWidth->CalcHasPercent()), |
michael@0 | 226 | "bad width"); |
michael@0 | 227 | |
michael@0 | 228 | // The 'table-layout: fixed' algorithm considers only cells |
michael@0 | 229 | // in the first row. |
michael@0 | 230 | bool originates; |
michael@0 | 231 | int32_t colSpan; |
michael@0 | 232 | nsTableCellFrame *cellFrame = |
michael@0 | 233 | cellMap->GetCellInfoAt(0, col, &originates, &colSpan); |
michael@0 | 234 | if (cellFrame) { |
michael@0 | 235 | styleWidth = &cellFrame->StylePosition()->mWidth; |
michael@0 | 236 | if (styleWidth->ConvertsToLength() || |
michael@0 | 237 | (styleWidth->GetUnit() == eStyleUnit_Enumerated && |
michael@0 | 238 | (styleWidth->GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT || |
michael@0 | 239 | styleWidth->GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT))) { |
michael@0 | 240 | // XXX This should use real percentage padding |
michael@0 | 241 | // Note that the difference between MIN_WIDTH and |
michael@0 | 242 | // PREF_WIDTH shouldn't matter for any of these |
michael@0 | 243 | // values of styleWidth; use MIN_WIDTH for symmetry |
michael@0 | 244 | // with GetMinWidth above, just in case there is a |
michael@0 | 245 | // difference. |
michael@0 | 246 | colWidth = nsLayoutUtils::IntrinsicForContainer( |
michael@0 | 247 | aReflowState.rendContext, |
michael@0 | 248 | cellFrame, nsLayoutUtils::MIN_WIDTH); |
michael@0 | 249 | } else if (styleWidth->GetUnit() == eStyleUnit_Percent) { |
michael@0 | 250 | // XXX This should use real percentage padding |
michael@0 | 251 | nsIFrame::IntrinsicWidthOffsetData offsets = |
michael@0 | 252 | cellFrame->IntrinsicWidthOffsets(aReflowState.rendContext); |
michael@0 | 253 | float pct = styleWidth->GetPercentValue(); |
michael@0 | 254 | colWidth = NSToCoordFloor(pct * float(tableWidth)); |
michael@0 | 255 | |
michael@0 | 256 | nscoord boxSizingAdjust = 0; |
michael@0 | 257 | switch (cellFrame->StylePosition()->mBoxSizing) { |
michael@0 | 258 | case NS_STYLE_BOX_SIZING_CONTENT: |
michael@0 | 259 | boxSizingAdjust += offsets.hPadding; |
michael@0 | 260 | // Fall through |
michael@0 | 261 | case NS_STYLE_BOX_SIZING_PADDING: |
michael@0 | 262 | boxSizingAdjust += offsets.hBorder; |
michael@0 | 263 | // Fall through |
michael@0 | 264 | case NS_STYLE_BOX_SIZING_BORDER: |
michael@0 | 265 | // Don't add anything |
michael@0 | 266 | break; |
michael@0 | 267 | } |
michael@0 | 268 | colWidth += boxSizingAdjust; |
michael@0 | 269 | |
michael@0 | 270 | pct /= float(colSpan); |
michael@0 | 271 | colFrame->AddPrefPercent(pct); |
michael@0 | 272 | pctTotal += pct; |
michael@0 | 273 | } else { |
michael@0 | 274 | // 'auto', '-moz-available', '-moz-fit-content', and |
michael@0 | 275 | // 'calc()' with percentages |
michael@0 | 276 | colWidth = unassignedMarker; |
michael@0 | 277 | } |
michael@0 | 278 | if (colWidth != unassignedMarker) { |
michael@0 | 279 | if (colSpan > 1) { |
michael@0 | 280 | // If a column-spanning cell is in the first |
michael@0 | 281 | // row, split up the space evenly. (XXX This |
michael@0 | 282 | // isn't quite right if some of the columns it's |
michael@0 | 283 | // in have specified widths. Should we care?) |
michael@0 | 284 | colWidth = ((colWidth + spacing) / colSpan) - spacing; |
michael@0 | 285 | if (colWidth < 0) |
michael@0 | 286 | colWidth = 0; |
michael@0 | 287 | } |
michael@0 | 288 | if (styleWidth->GetUnit() != eStyleUnit_Percent) { |
michael@0 | 289 | specTotal += colWidth; |
michael@0 | 290 | } |
michael@0 | 291 | } |
michael@0 | 292 | } else { |
michael@0 | 293 | colWidth = unassignedMarker; |
michael@0 | 294 | } |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | colFrame->SetFinalWidth(colWidth); |
michael@0 | 298 | |
michael@0 | 299 | if (colWidth == unassignedMarker) { |
michael@0 | 300 | ++unassignedCount; |
michael@0 | 301 | } else { |
michael@0 | 302 | unassignedSpace -= colWidth; |
michael@0 | 303 | } |
michael@0 | 304 | } |
michael@0 | 305 | |
michael@0 | 306 | if (unassignedSpace < 0) { |
michael@0 | 307 | if (pctTotal > 0) { |
michael@0 | 308 | // If the columns took up too much space, reduce those that |
michael@0 | 309 | // had percentage widths. The spec doesn't say to do this, |
michael@0 | 310 | // but we've always done it in the past, and so does WinIE6. |
michael@0 | 311 | nscoord pctUsed = NSToCoordFloor(pctTotal * float(tableWidth)); |
michael@0 | 312 | nscoord reduce = std::min(pctUsed, -unassignedSpace); |
michael@0 | 313 | float reduceRatio = float(reduce) / pctTotal; |
michael@0 | 314 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 315 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 316 | if (!colFrame) { |
michael@0 | 317 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 318 | continue; |
michael@0 | 319 | } |
michael@0 | 320 | nscoord colWidth = colFrame->GetFinalWidth(); |
michael@0 | 321 | colWidth -= NSToCoordFloor(colFrame->GetPrefPercent() * |
michael@0 | 322 | reduceRatio); |
michael@0 | 323 | if (colWidth < 0) |
michael@0 | 324 | colWidth = 0; |
michael@0 | 325 | colFrame->SetFinalWidth(colWidth); |
michael@0 | 326 | } |
michael@0 | 327 | } |
michael@0 | 328 | unassignedSpace = 0; |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | if (unassignedCount > 0) { |
michael@0 | 332 | // The spec says to distribute the remaining space evenly among |
michael@0 | 333 | // the columns. |
michael@0 | 334 | nscoord toAssign = unassignedSpace / unassignedCount; |
michael@0 | 335 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 336 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 337 | if (!colFrame) { |
michael@0 | 338 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 339 | continue; |
michael@0 | 340 | } |
michael@0 | 341 | if (colFrame->GetFinalWidth() == unassignedMarker) |
michael@0 | 342 | colFrame->SetFinalWidth(toAssign); |
michael@0 | 343 | } |
michael@0 | 344 | } else if (unassignedSpace > 0) { |
michael@0 | 345 | // The spec doesn't say how to distribute the unassigned space. |
michael@0 | 346 | if (specTotal > 0) { |
michael@0 | 347 | // Distribute proportionally to non-percentage columns. |
michael@0 | 348 | nscoord specUndist = specTotal; |
michael@0 | 349 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 350 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 351 | if (!colFrame) { |
michael@0 | 352 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 353 | continue; |
michael@0 | 354 | } |
michael@0 | 355 | if (colFrame->GetPrefPercent() == 0.0f) { |
michael@0 | 356 | NS_ASSERTION(colFrame->GetFinalWidth() <= specUndist, |
michael@0 | 357 | "widths don't add up"); |
michael@0 | 358 | nscoord toAdd = AllocateUnassigned(unassignedSpace, |
michael@0 | 359 | float(colFrame->GetFinalWidth()) / float(specUndist)); |
michael@0 | 360 | specUndist -= colFrame->GetFinalWidth(); |
michael@0 | 361 | colFrame->SetFinalWidth(colFrame->GetFinalWidth() + toAdd); |
michael@0 | 362 | unassignedSpace -= toAdd; |
michael@0 | 363 | if (specUndist <= 0) { |
michael@0 | 364 | NS_ASSERTION(specUndist == 0, |
michael@0 | 365 | "math should be exact"); |
michael@0 | 366 | break; |
michael@0 | 367 | } |
michael@0 | 368 | } |
michael@0 | 369 | } |
michael@0 | 370 | NS_ASSERTION(unassignedSpace == 0, "failed to redistribute"); |
michael@0 | 371 | } else if (pctTotal > 0) { |
michael@0 | 372 | // Distribute proportionally to percentage columns. |
michael@0 | 373 | float pctUndist = pctTotal; |
michael@0 | 374 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 375 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 376 | if (!colFrame) { |
michael@0 | 377 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 378 | continue; |
michael@0 | 379 | } |
michael@0 | 380 | if (pctUndist < colFrame->GetPrefPercent()) { |
michael@0 | 381 | // This can happen with floating-point math. |
michael@0 | 382 | NS_ASSERTION(colFrame->GetPrefPercent() - pctUndist |
michael@0 | 383 | < 0.0001, |
michael@0 | 384 | "widths don't add up"); |
michael@0 | 385 | pctUndist = colFrame->GetPrefPercent(); |
michael@0 | 386 | } |
michael@0 | 387 | nscoord toAdd = AllocateUnassigned(unassignedSpace, |
michael@0 | 388 | colFrame->GetPrefPercent() / pctUndist); |
michael@0 | 389 | colFrame->SetFinalWidth(colFrame->GetFinalWidth() + toAdd); |
michael@0 | 390 | unassignedSpace -= toAdd; |
michael@0 | 391 | pctUndist -= colFrame->GetPrefPercent(); |
michael@0 | 392 | if (pctUndist <= 0.0f) { |
michael@0 | 393 | break; |
michael@0 | 394 | } |
michael@0 | 395 | } |
michael@0 | 396 | NS_ASSERTION(unassignedSpace == 0, "failed to redistribute"); |
michael@0 | 397 | } else { |
michael@0 | 398 | // Distribute equally to the zero-width columns. |
michael@0 | 399 | int32_t colsLeft = colCount; |
michael@0 | 400 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 401 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 402 | if (!colFrame) { |
michael@0 | 403 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 404 | continue; |
michael@0 | 405 | } |
michael@0 | 406 | NS_ASSERTION(colFrame->GetFinalWidth() == 0, "yikes"); |
michael@0 | 407 | nscoord toAdd = AllocateUnassigned(unassignedSpace, |
michael@0 | 408 | 1.0f / float(colsLeft)); |
michael@0 | 409 | colFrame->SetFinalWidth(toAdd); |
michael@0 | 410 | unassignedSpace -= toAdd; |
michael@0 | 411 | --colsLeft; |
michael@0 | 412 | } |
michael@0 | 413 | NS_ASSERTION(unassignedSpace == 0, "failed to redistribute"); |
michael@0 | 414 | } |
michael@0 | 415 | } |
michael@0 | 416 | for (int32_t col = 0; col < colCount; ++col) { |
michael@0 | 417 | nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
michael@0 | 418 | if (!colFrame) { |
michael@0 | 419 | NS_ERROR("column frames out of sync with cell map"); |
michael@0 | 420 | continue; |
michael@0 | 421 | } |
michael@0 | 422 | if (oldColWidths.ElementAt(col) != colFrame->GetFinalWidth()) { |
michael@0 | 423 | mTableFrame->DidResizeColumns(); |
michael@0 | 424 | break; |
michael@0 | 425 | } |
michael@0 | 426 | } |
michael@0 | 427 | } |