|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 // vim:cindent:ts=4:et:sw=4: |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /* |
|
8 * Web-compatible algorithms that determine column and table widths, |
|
9 * used for CSS2's 'table-layout: auto'. |
|
10 */ |
|
11 |
|
12 #include "BasicTableLayoutStrategy.h" |
|
13 #include "nsTableFrame.h" |
|
14 #include "nsTableCellFrame.h" |
|
15 #include "nsLayoutUtils.h" |
|
16 #include "nsGkAtoms.h" |
|
17 #include "SpanningCellSorter.h" |
|
18 #include <algorithm> |
|
19 |
|
20 using namespace mozilla; |
|
21 using namespace mozilla::layout; |
|
22 |
|
23 namespace css = mozilla::css; |
|
24 |
|
25 #undef DEBUG_TABLE_STRATEGY |
|
26 |
|
27 BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aTableFrame) |
|
28 : nsITableLayoutStrategy(nsITableLayoutStrategy::Auto) |
|
29 , mTableFrame(aTableFrame) |
|
30 { |
|
31 MarkIntrinsicWidthsDirty(); |
|
32 } |
|
33 |
|
34 /* virtual */ |
|
35 BasicTableLayoutStrategy::~BasicTableLayoutStrategy() |
|
36 { |
|
37 } |
|
38 |
|
39 /* virtual */ nscoord |
|
40 BasicTableLayoutStrategy::GetMinWidth(nsRenderingContext* aRenderingContext) |
|
41 { |
|
42 DISPLAY_MIN_WIDTH(mTableFrame, mMinWidth); |
|
43 if (mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) |
|
44 ComputeIntrinsicWidths(aRenderingContext); |
|
45 return mMinWidth; |
|
46 } |
|
47 |
|
48 /* virtual */ nscoord |
|
49 BasicTableLayoutStrategy::GetPrefWidth(nsRenderingContext* aRenderingContext, |
|
50 bool aComputingSize) |
|
51 { |
|
52 DISPLAY_PREF_WIDTH(mTableFrame, mPrefWidth); |
|
53 NS_ASSERTION((mPrefWidth == NS_INTRINSIC_WIDTH_UNKNOWN) == |
|
54 (mPrefWidthPctExpand == NS_INTRINSIC_WIDTH_UNKNOWN), |
|
55 "dirtyness out of sync"); |
|
56 if (mPrefWidth == NS_INTRINSIC_WIDTH_UNKNOWN) |
|
57 ComputeIntrinsicWidths(aRenderingContext); |
|
58 return aComputingSize ? mPrefWidthPctExpand : mPrefWidth; |
|
59 } |
|
60 |
|
61 struct CellWidthInfo { |
|
62 CellWidthInfo(nscoord aMinCoord, nscoord aPrefCoord, |
|
63 float aPrefPercent, bool aHasSpecifiedWidth) |
|
64 : hasSpecifiedWidth(aHasSpecifiedWidth) |
|
65 , minCoord(aMinCoord) |
|
66 , prefCoord(aPrefCoord) |
|
67 , prefPercent(aPrefPercent) |
|
68 { |
|
69 } |
|
70 |
|
71 bool hasSpecifiedWidth; |
|
72 nscoord minCoord; |
|
73 nscoord prefCoord; |
|
74 float prefPercent; |
|
75 }; |
|
76 |
|
77 // Used for both column and cell calculations. The parts needed only |
|
78 // for cells are skipped when aIsCell is false. |
|
79 static CellWidthInfo |
|
80 GetWidthInfo(nsRenderingContext *aRenderingContext, |
|
81 nsIFrame *aFrame, bool aIsCell) |
|
82 { |
|
83 nscoord minCoord, prefCoord; |
|
84 const nsStylePosition *stylePos = aFrame->StylePosition(); |
|
85 bool isQuirks = aFrame->PresContext()->CompatibilityMode() == |
|
86 eCompatibility_NavQuirks; |
|
87 nscoord boxSizingToBorderEdge = 0; |
|
88 if (aIsCell) { |
|
89 // If aFrame is a container for font size inflation, then shrink |
|
90 // wrapping inside of it should not apply font size inflation. |
|
91 AutoMaybeDisableFontInflation an(aFrame); |
|
92 |
|
93 minCoord = aFrame->GetMinWidth(aRenderingContext); |
|
94 prefCoord = aFrame->GetPrefWidth(aRenderingContext); |
|
95 // Until almost the end of this function, minCoord and prefCoord |
|
96 // represent the box-sizing based width values (which mean they |
|
97 // should include horizontal padding and border width when |
|
98 // box-sizing is set to border-box). |
|
99 // Note that this function returns border-box width, we add the |
|
100 // outer edges near the end of this function. |
|
101 |
|
102 // XXX Should we ignore percentage padding? |
|
103 nsIFrame::IntrinsicWidthOffsetData offsets = aFrame->IntrinsicWidthOffsets(aRenderingContext); |
|
104 |
|
105 // In quirks mode, table cell width should be content-box, |
|
106 // but height should be border box. |
|
107 // Because of this historic anomaly, we do not use quirk.css. |
|
108 // (We can't specify one value of box-sizing for width and another |
|
109 // for height). |
|
110 // For this reason, we also do not use box-sizing for just one of |
|
111 // them, as this may be confusing. |
|
112 if (isQuirks) { |
|
113 boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder; |
|
114 } |
|
115 else { |
|
116 switch (stylePos->mBoxSizing) { |
|
117 case NS_STYLE_BOX_SIZING_CONTENT: |
|
118 boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder; |
|
119 break; |
|
120 case NS_STYLE_BOX_SIZING_PADDING: |
|
121 minCoord += offsets.hPadding; |
|
122 prefCoord += offsets.hPadding; |
|
123 boxSizingToBorderEdge = offsets.hBorder; |
|
124 break; |
|
125 default: |
|
126 // NS_STYLE_BOX_SIZING_BORDER |
|
127 minCoord += offsets.hPadding + offsets.hBorder; |
|
128 prefCoord += offsets.hPadding + offsets.hBorder; |
|
129 break; |
|
130 } |
|
131 } |
|
132 } else { |
|
133 minCoord = 0; |
|
134 prefCoord = 0; |
|
135 } |
|
136 float prefPercent = 0.0f; |
|
137 bool hasSpecifiedWidth = false; |
|
138 |
|
139 const nsStyleCoord &width = stylePos->mWidth; |
|
140 nsStyleUnit unit = width.GetUnit(); |
|
141 // NOTE: We're ignoring calc() units with percentages here, for lack of a |
|
142 // sensible idea for what to do with them. This means calc() with |
|
143 // percentages is basically handled like 'auto' for table cells and |
|
144 // columns. |
|
145 if (width.ConvertsToLength()) { |
|
146 hasSpecifiedWidth = true; |
|
147 // Note: since ComputeWidthValue was designed to return content-box |
|
148 // width, it will (in some cases) subtract the box-sizing edges. |
|
149 // We prevent this unwanted behavior by calling it with |
|
150 // aContentEdgeToBoxSizing and aBoxSizingToMarginEdge set to 0. |
|
151 nscoord w = nsLayoutUtils::ComputeWidthValue(aRenderingContext, |
|
152 aFrame, 0, 0, 0, width); |
|
153 // Quirk: A cell with "nowrap" set and a coord value for the |
|
154 // width which is bigger than the intrinsic minimum width uses |
|
155 // that coord value as the minimum width. |
|
156 // This is kept up-to-date with dynamic changes to nowrap by code in |
|
157 // nsTableCellFrame::AttributeChanged |
|
158 if (aIsCell && w > minCoord && isQuirks && |
|
159 aFrame->GetContent()->HasAttr(kNameSpaceID_None, |
|
160 nsGkAtoms::nowrap)) { |
|
161 minCoord = w; |
|
162 } |
|
163 prefCoord = std::max(w, minCoord); |
|
164 } else if (unit == eStyleUnit_Percent) { |
|
165 prefPercent = width.GetPercentValue(); |
|
166 } else if (unit == eStyleUnit_Enumerated && aIsCell) { |
|
167 switch (width.GetIntValue()) { |
|
168 case NS_STYLE_WIDTH_MAX_CONTENT: |
|
169 // 'width' only affects pref width, not min |
|
170 // width, so don't change anything |
|
171 break; |
|
172 case NS_STYLE_WIDTH_MIN_CONTENT: |
|
173 prefCoord = minCoord; |
|
174 break; |
|
175 case NS_STYLE_WIDTH_FIT_CONTENT: |
|
176 case NS_STYLE_WIDTH_AVAILABLE: |
|
177 // act just like 'width: auto' |
|
178 break; |
|
179 default: |
|
180 NS_NOTREACHED("unexpected enumerated value"); |
|
181 } |
|
182 } |
|
183 |
|
184 nsStyleCoord maxWidth(stylePos->mMaxWidth); |
|
185 if (maxWidth.GetUnit() == eStyleUnit_Enumerated) { |
|
186 if (!aIsCell || maxWidth.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE) |
|
187 maxWidth.SetNoneValue(); |
|
188 else if (maxWidth.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT) |
|
189 // for 'max-width', '-moz-fit-content' is like |
|
190 // '-moz-max-content' |
|
191 maxWidth.SetIntValue(NS_STYLE_WIDTH_MAX_CONTENT, |
|
192 eStyleUnit_Enumerated); |
|
193 } |
|
194 unit = maxWidth.GetUnit(); |
|
195 // XXX To really implement 'max-width' well, we'd need to store |
|
196 // it separately on the columns. |
|
197 if (maxWidth.ConvertsToLength() || unit == eStyleUnit_Enumerated) { |
|
198 nscoord w = |
|
199 nsLayoutUtils::ComputeWidthValue(aRenderingContext, aFrame, |
|
200 0, 0, 0, maxWidth); |
|
201 if (w < minCoord) |
|
202 minCoord = w; |
|
203 if (w < prefCoord) |
|
204 prefCoord = w; |
|
205 } else if (unit == eStyleUnit_Percent) { |
|
206 float p = stylePos->mMaxWidth.GetPercentValue(); |
|
207 if (p < prefPercent) |
|
208 prefPercent = p; |
|
209 } |
|
210 // treat calc() with percentages on max-width just like 'none'. |
|
211 |
|
212 nsStyleCoord minWidth(stylePos->mMinWidth); |
|
213 if (minWidth.GetUnit() == eStyleUnit_Enumerated) { |
|
214 if (!aIsCell || minWidth.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE) |
|
215 minWidth.SetCoordValue(0); |
|
216 else if (minWidth.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT) |
|
217 // for 'min-width', '-moz-fit-content' is like |
|
218 // '-moz-min-content' |
|
219 minWidth.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT, |
|
220 eStyleUnit_Enumerated); |
|
221 } |
|
222 unit = minWidth.GetUnit(); |
|
223 if (minWidth.ConvertsToLength() || unit == eStyleUnit_Enumerated) { |
|
224 nscoord w = |
|
225 nsLayoutUtils::ComputeWidthValue(aRenderingContext, aFrame, |
|
226 0, 0, 0, minWidth); |
|
227 if (w > minCoord) |
|
228 minCoord = w; |
|
229 if (w > prefCoord) |
|
230 prefCoord = w; |
|
231 } else if (unit == eStyleUnit_Percent) { |
|
232 float p = stylePos->mMinWidth.GetPercentValue(); |
|
233 if (p > prefPercent) |
|
234 prefPercent = p; |
|
235 } |
|
236 // treat calc() with percentages on min-width just like '0'. |
|
237 |
|
238 // XXX Should col frame have border/padding considered? |
|
239 if (aIsCell) { |
|
240 minCoord += boxSizingToBorderEdge; |
|
241 prefCoord = NSCoordSaturatingAdd(prefCoord, boxSizingToBorderEdge); |
|
242 } |
|
243 |
|
244 return CellWidthInfo(minCoord, prefCoord, prefPercent, hasSpecifiedWidth); |
|
245 } |
|
246 |
|
247 static inline CellWidthInfo |
|
248 GetCellWidthInfo(nsRenderingContext *aRenderingContext, |
|
249 nsTableCellFrame *aCellFrame) |
|
250 { |
|
251 return GetWidthInfo(aRenderingContext, aCellFrame, true); |
|
252 } |
|
253 |
|
254 static inline CellWidthInfo |
|
255 GetColWidthInfo(nsRenderingContext *aRenderingContext, |
|
256 nsIFrame *aFrame) |
|
257 { |
|
258 return GetWidthInfo(aRenderingContext, aFrame, false); |
|
259 } |
|
260 |
|
261 |
|
262 /** |
|
263 * The algorithm in this function, in addition to meeting the |
|
264 * requirements of Web-compatibility, is also invariant under reordering |
|
265 * of the rows within a table (something that most, but not all, other |
|
266 * browsers are). |
|
267 */ |
|
268 void |
|
269 BasicTableLayoutStrategy::ComputeColumnIntrinsicWidths(nsRenderingContext* aRenderingContext) |
|
270 { |
|
271 nsTableFrame *tableFrame = mTableFrame; |
|
272 nsTableCellMap *cellMap = tableFrame->GetCellMap(); |
|
273 |
|
274 mozilla::AutoStackArena arena; |
|
275 SpanningCellSorter spanningCells; |
|
276 |
|
277 // Loop over the columns to consider the columns and cells *without* |
|
278 // a colspan. |
|
279 int32_t col, col_end; |
|
280 for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) { |
|
281 nsTableColFrame *colFrame = tableFrame->GetColFrame(col); |
|
282 if (!colFrame) { |
|
283 NS_ERROR("column frames out of sync with cell map"); |
|
284 continue; |
|
285 } |
|
286 colFrame->ResetIntrinsics(); |
|
287 colFrame->ResetSpanIntrinsics(); |
|
288 |
|
289 // Consider the widths on the column. |
|
290 CellWidthInfo colInfo = GetColWidthInfo(aRenderingContext, colFrame); |
|
291 colFrame->AddCoords(colInfo.minCoord, colInfo.prefCoord, |
|
292 colInfo.hasSpecifiedWidth); |
|
293 colFrame->AddPrefPercent(colInfo.prefPercent); |
|
294 |
|
295 // Consider the widths on the column-group. Note that we follow |
|
296 // what the HTML spec says here, and make the width apply to |
|
297 // each column in the group, not the group as a whole. |
|
298 |
|
299 // If column has width, column-group doesn't override width. |
|
300 if (colInfo.minCoord == 0 && colInfo.prefCoord == 0 && |
|
301 colInfo.prefPercent == 0.0f) { |
|
302 NS_ASSERTION(colFrame->GetParent()->GetType() == |
|
303 nsGkAtoms::tableColGroupFrame, |
|
304 "expected a column-group"); |
|
305 colInfo = GetColWidthInfo(aRenderingContext, colFrame->GetParent()); |
|
306 colFrame->AddCoords(colInfo.minCoord, colInfo.prefCoord, |
|
307 colInfo.hasSpecifiedWidth); |
|
308 colFrame->AddPrefPercent(colInfo.prefPercent); |
|
309 } |
|
310 |
|
311 // Consider the contents of and the widths on the cells without |
|
312 // colspans. |
|
313 nsCellMapColumnIterator columnIter(cellMap, col); |
|
314 int32_t row, colSpan; |
|
315 nsTableCellFrame* cellFrame; |
|
316 while ((cellFrame = columnIter.GetNextFrame(&row, &colSpan))) { |
|
317 if (colSpan > 1) { |
|
318 spanningCells.AddCell(colSpan, row, col); |
|
319 continue; |
|
320 } |
|
321 |
|
322 CellWidthInfo info = GetCellWidthInfo(aRenderingContext, cellFrame); |
|
323 |
|
324 colFrame->AddCoords(info.minCoord, info.prefCoord, |
|
325 info.hasSpecifiedWidth); |
|
326 colFrame->AddPrefPercent(info.prefPercent); |
|
327 } |
|
328 #ifdef DEBUG_dbaron_off |
|
329 printf("table %p col %d nonspan: min=%d pref=%d spec=%d pct=%f\n", |
|
330 mTableFrame, col, colFrame->GetMinCoord(), |
|
331 colFrame->GetPrefCoord(), colFrame->GetHasSpecifiedCoord(), |
|
332 colFrame->GetPrefPercent()); |
|
333 #endif |
|
334 } |
|
335 #ifdef DEBUG_TABLE_STRATEGY |
|
336 printf("ComputeColumnIntrinsicWidths single\n"); |
|
337 mTableFrame->Dump(false, true, false); |
|
338 #endif |
|
339 |
|
340 // Consider the cells with a colspan that we saved in the loop above |
|
341 // into the spanning cell sorter. We consider these cells by seeing |
|
342 // if they require adding to the widths resulting only from cells |
|
343 // with a smaller colspan, and therefore we must process them sorted |
|
344 // in increasing order by colspan. For each colspan group, we |
|
345 // accumulate new values to accumulate in the column frame's Span* |
|
346 // members. |
|
347 // |
|
348 // Considering things only relative to the widths resulting from |
|
349 // cells with smaller colspans (rather than incrementally including |
|
350 // the results from spanning cells, or doing spanning and |
|
351 // non-spanning cells in a single pass) means that layout remains |
|
352 // row-order-invariant and (except for percentage widths that add to |
|
353 // more than 100%) column-order invariant. |
|
354 // |
|
355 // Starting with smaller colspans makes it more likely that we |
|
356 // satisfy all the constraints given and don't distribute space to |
|
357 // columns where we don't need it. |
|
358 SpanningCellSorter::Item *item; |
|
359 int32_t colSpan; |
|
360 while ((item = spanningCells.GetNext(&colSpan))) { |
|
361 NS_ASSERTION(colSpan > 1, |
|
362 "cell should not have been put in spanning cell sorter"); |
|
363 do { |
|
364 int32_t row = item->row; |
|
365 col = item->col; |
|
366 CellData *cellData = cellMap->GetDataAt(row, col); |
|
367 NS_ASSERTION(cellData && cellData->IsOrig(), |
|
368 "bogus result from spanning cell sorter"); |
|
369 |
|
370 nsTableCellFrame *cellFrame = cellData->GetCellFrame(); |
|
371 NS_ASSERTION(cellFrame, "bogus result from spanning cell sorter"); |
|
372 |
|
373 CellWidthInfo info = GetCellWidthInfo(aRenderingContext, cellFrame); |
|
374 |
|
375 if (info.prefPercent > 0.0f) { |
|
376 DistributePctWidthToColumns(info.prefPercent, |
|
377 col, colSpan); |
|
378 } |
|
379 DistributeWidthToColumns(info.minCoord, col, colSpan, |
|
380 BTLS_MIN_WIDTH, info.hasSpecifiedWidth); |
|
381 DistributeWidthToColumns(info.prefCoord, col, colSpan, |
|
382 BTLS_PREF_WIDTH, info.hasSpecifiedWidth); |
|
383 } while ((item = item->next)); |
|
384 |
|
385 // Combine the results of the span analysis into the main results, |
|
386 // for each increment of colspan. |
|
387 |
|
388 for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) { |
|
389 nsTableColFrame *colFrame = tableFrame->GetColFrame(col); |
|
390 if (!colFrame) { |
|
391 NS_ERROR("column frames out of sync with cell map"); |
|
392 continue; |
|
393 } |
|
394 |
|
395 colFrame->AccumulateSpanIntrinsics(); |
|
396 colFrame->ResetSpanIntrinsics(); |
|
397 |
|
398 #ifdef DEBUG_dbaron_off |
|
399 printf("table %p col %d span %d: min=%d pref=%d spec=%d pct=%f\n", |
|
400 mTableFrame, col, colSpan, colFrame->GetMinCoord(), |
|
401 colFrame->GetPrefCoord(), colFrame->GetHasSpecifiedCoord(), |
|
402 colFrame->GetPrefPercent()); |
|
403 #endif |
|
404 } |
|
405 } |
|
406 |
|
407 // Prevent percentages from adding to more than 100% by (to be |
|
408 // compatible with other browsers) treating any percentages that would |
|
409 // increase the total percentage to more than 100% as the number that |
|
410 // would increase it to only 100% (which is 0% if we've already hit |
|
411 // 100%). This means layout depends on the order of columns. |
|
412 float pct_used = 0.0f; |
|
413 for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) { |
|
414 nsTableColFrame *colFrame = tableFrame->GetColFrame(col); |
|
415 if (!colFrame) { |
|
416 NS_ERROR("column frames out of sync with cell map"); |
|
417 continue; |
|
418 } |
|
419 |
|
420 colFrame->AdjustPrefPercent(&pct_used); |
|
421 } |
|
422 |
|
423 #ifdef DEBUG_TABLE_STRATEGY |
|
424 printf("ComputeColumnIntrinsicWidths spanning\n"); |
|
425 mTableFrame->Dump(false, true, false); |
|
426 #endif |
|
427 } |
|
428 |
|
429 void |
|
430 BasicTableLayoutStrategy::ComputeIntrinsicWidths(nsRenderingContext* aRenderingContext) |
|
431 { |
|
432 ComputeColumnIntrinsicWidths(aRenderingContext); |
|
433 |
|
434 nsTableCellMap *cellMap = mTableFrame->GetCellMap(); |
|
435 nscoord min = 0, pref = 0, max_small_pct_pref = 0, nonpct_pref_total = 0; |
|
436 float pct_total = 0.0f; // always from 0.0f - 1.0f |
|
437 int32_t colCount = cellMap->GetColCount(); |
|
438 nscoord spacing = mTableFrame->GetCellSpacingX(); |
|
439 nscoord add = spacing; // add (colcount + 1) * spacing for columns |
|
440 // where a cell originates |
|
441 |
|
442 for (int32_t col = 0; col < colCount; ++col) { |
|
443 nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
|
444 if (!colFrame) { |
|
445 NS_ERROR("column frames out of sync with cell map"); |
|
446 continue; |
|
447 } |
|
448 if (mTableFrame->ColumnHasCellSpacingBefore(col)) { |
|
449 add += spacing; |
|
450 } |
|
451 min += colFrame->GetMinCoord(); |
|
452 pref = NSCoordSaturatingAdd(pref, colFrame->GetPrefCoord()); |
|
453 |
|
454 // Percentages are of the table, so we have to reverse them for |
|
455 // intrinsic widths. |
|
456 float p = colFrame->GetPrefPercent(); |
|
457 if (p > 0.0f) { |
|
458 nscoord colPref = colFrame->GetPrefCoord(); |
|
459 nscoord new_small_pct_expand = |
|
460 (colPref == nscoord_MAX ? |
|
461 nscoord_MAX : nscoord(float(colPref) / p)); |
|
462 if (new_small_pct_expand > max_small_pct_pref) { |
|
463 max_small_pct_pref = new_small_pct_expand; |
|
464 } |
|
465 pct_total += p; |
|
466 } else { |
|
467 nonpct_pref_total = NSCoordSaturatingAdd(nonpct_pref_total, |
|
468 colFrame->GetPrefCoord()); |
|
469 } |
|
470 } |
|
471 |
|
472 nscoord pref_pct_expand = pref; |
|
473 |
|
474 // Account for small percentages expanding the preferred width of |
|
475 // *other* columns. |
|
476 if (max_small_pct_pref > pref_pct_expand) { |
|
477 pref_pct_expand = max_small_pct_pref; |
|
478 } |
|
479 |
|
480 // Account for large percentages expanding the preferred width of |
|
481 // themselves. There's no need to iterate over the columns multiple |
|
482 // times, since when there is such a need, the small percentage |
|
483 // effect is bigger anyway. (I think!) |
|
484 NS_ASSERTION(0.0f <= pct_total && pct_total <= 1.0f, |
|
485 "column percentage widths not adjusted down to 100%"); |
|
486 if (pct_total == 1.0f) { |
|
487 if (nonpct_pref_total > 0) { |
|
488 pref_pct_expand = nscoord_MAX; |
|
489 // XXX Or should I use some smaller value? (Test this using |
|
490 // nested tables!) |
|
491 } |
|
492 } else { |
|
493 nscoord large_pct_pref = |
|
494 (nonpct_pref_total == nscoord_MAX ? |
|
495 nscoord_MAX : |
|
496 nscoord(float(nonpct_pref_total) / (1.0f - pct_total))); |
|
497 if (large_pct_pref > pref_pct_expand) |
|
498 pref_pct_expand = large_pct_pref; |
|
499 } |
|
500 |
|
501 // border-spacing isn't part of the basis for percentages |
|
502 if (colCount > 0) { |
|
503 min += add; |
|
504 pref = NSCoordSaturatingAdd(pref, add); |
|
505 pref_pct_expand = NSCoordSaturatingAdd(pref_pct_expand, add); |
|
506 } |
|
507 |
|
508 mMinWidth = min; |
|
509 mPrefWidth = pref; |
|
510 mPrefWidthPctExpand = pref_pct_expand; |
|
511 } |
|
512 |
|
513 /* virtual */ void |
|
514 BasicTableLayoutStrategy::MarkIntrinsicWidthsDirty() |
|
515 { |
|
516 mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN; |
|
517 mPrefWidth = NS_INTRINSIC_WIDTH_UNKNOWN; |
|
518 mPrefWidthPctExpand = NS_INTRINSIC_WIDTH_UNKNOWN; |
|
519 mLastCalcWidth = nscoord_MIN; |
|
520 } |
|
521 |
|
522 /* virtual */ void |
|
523 BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowState) |
|
524 { |
|
525 nscoord width = aReflowState.ComputedWidth(); |
|
526 |
|
527 if (mLastCalcWidth == width) |
|
528 return; |
|
529 mLastCalcWidth = width; |
|
530 |
|
531 NS_ASSERTION((mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) == |
|
532 (mPrefWidth == NS_INTRINSIC_WIDTH_UNKNOWN), |
|
533 "dirtyness out of sync"); |
|
534 NS_ASSERTION((mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) == |
|
535 (mPrefWidthPctExpand == NS_INTRINSIC_WIDTH_UNKNOWN), |
|
536 "dirtyness out of sync"); |
|
537 // XXX Is this needed? |
|
538 if (mMinWidth == NS_INTRINSIC_WIDTH_UNKNOWN) |
|
539 ComputeIntrinsicWidths(aReflowState.rendContext); |
|
540 |
|
541 nsTableCellMap *cellMap = mTableFrame->GetCellMap(); |
|
542 int32_t colCount = cellMap->GetColCount(); |
|
543 if (colCount <= 0) |
|
544 return; // nothing to do |
|
545 |
|
546 DistributeWidthToColumns(width, 0, colCount, BTLS_FINAL_WIDTH, false); |
|
547 |
|
548 #ifdef DEBUG_TABLE_STRATEGY |
|
549 printf("ComputeColumnWidths final\n"); |
|
550 mTableFrame->Dump(false, true, false); |
|
551 #endif |
|
552 } |
|
553 |
|
554 void |
|
555 BasicTableLayoutStrategy::DistributePctWidthToColumns(float aSpanPrefPct, |
|
556 int32_t aFirstCol, |
|
557 int32_t aColCount) |
|
558 { |
|
559 // First loop to determine: |
|
560 int32_t nonPctColCount = 0; // number of spanned columns without % width |
|
561 nscoord nonPctTotalPrefWidth = 0; // total pref width of those columns |
|
562 // and to reduce aSpanPrefPct by columns that already have % width |
|
563 |
|
564 int32_t scol, scol_end; |
|
565 nsTableCellMap *cellMap = mTableFrame->GetCellMap(); |
|
566 for (scol = aFirstCol, scol_end = aFirstCol + aColCount; |
|
567 scol < scol_end; ++scol) { |
|
568 nsTableColFrame *scolFrame = mTableFrame->GetColFrame(scol); |
|
569 if (!scolFrame) { |
|
570 NS_ERROR("column frames out of sync with cell map"); |
|
571 continue; |
|
572 } |
|
573 float scolPct = scolFrame->GetPrefPercent(); |
|
574 if (scolPct == 0.0f) { |
|
575 nonPctTotalPrefWidth += scolFrame->GetPrefCoord(); |
|
576 if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) { |
|
577 ++nonPctColCount; |
|
578 } |
|
579 } else { |
|
580 aSpanPrefPct -= scolPct; |
|
581 } |
|
582 } |
|
583 |
|
584 if (aSpanPrefPct <= 0.0f || nonPctColCount == 0) { |
|
585 // There's no %-width on the colspan left over to distribute, |
|
586 // or there are no columns to which we could distribute %-width |
|
587 return; |
|
588 } |
|
589 |
|
590 // Second loop, to distribute what remains of aSpanPrefPct |
|
591 // between the non-percent-width spanned columns |
|
592 const bool spanHasNonPctPref = nonPctTotalPrefWidth > 0; // Loop invariant |
|
593 for (scol = aFirstCol, scol_end = aFirstCol + aColCount; |
|
594 scol < scol_end; ++scol) { |
|
595 nsTableColFrame *scolFrame = mTableFrame->GetColFrame(scol); |
|
596 if (!scolFrame) { |
|
597 NS_ERROR("column frames out of sync with cell map"); |
|
598 continue; |
|
599 } |
|
600 |
|
601 if (scolFrame->GetPrefPercent() == 0.0f) { |
|
602 NS_ASSERTION((!spanHasNonPctPref || |
|
603 nonPctTotalPrefWidth != 0) && |
|
604 nonPctColCount != 0, |
|
605 "should not be zero if we haven't allocated " |
|
606 "all pref percent"); |
|
607 |
|
608 float allocatedPct; // % width to be given to this column |
|
609 if (spanHasNonPctPref) { |
|
610 // Group so we're multiplying by 1.0f when we need |
|
611 // to use up aSpanPrefPct. |
|
612 allocatedPct = aSpanPrefPct * |
|
613 (float(scolFrame->GetPrefCoord()) / |
|
614 float(nonPctTotalPrefWidth)); |
|
615 } else if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) { |
|
616 // distribute equally when all pref widths are 0 |
|
617 allocatedPct = aSpanPrefPct / float(nonPctColCount); |
|
618 } else { |
|
619 allocatedPct = 0.0f; |
|
620 } |
|
621 // Allocate the percent |
|
622 scolFrame->AddSpanPrefPercent(allocatedPct); |
|
623 |
|
624 // To avoid accumulating rounding error from division, |
|
625 // subtract this column's values from the totals. |
|
626 aSpanPrefPct -= allocatedPct; |
|
627 nonPctTotalPrefWidth -= scolFrame->GetPrefCoord(); |
|
628 if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) { |
|
629 --nonPctColCount; |
|
630 } |
|
631 |
|
632 if (!aSpanPrefPct) { |
|
633 // No more span-percent-width to distribute --> we're done. |
|
634 NS_ASSERTION(spanHasNonPctPref ? |
|
635 nonPctTotalPrefWidth == 0 : |
|
636 nonPctColCount == 0, |
|
637 "No more pct width to distribute, but there are " |
|
638 "still cols that need some."); |
|
639 return; |
|
640 } |
|
641 } |
|
642 } |
|
643 } |
|
644 |
|
645 void |
|
646 BasicTableLayoutStrategy::DistributeWidthToColumns(nscoord aWidth, |
|
647 int32_t aFirstCol, |
|
648 int32_t aColCount, |
|
649 BtlsWidthType aWidthType, |
|
650 bool aSpanHasSpecifiedWidth) |
|
651 { |
|
652 NS_ASSERTION(aWidthType != BTLS_FINAL_WIDTH || |
|
653 (aFirstCol == 0 && |
|
654 aColCount == mTableFrame->GetCellMap()->GetColCount()), |
|
655 "Computing final column widths, but didn't get full column range"); |
|
656 |
|
657 // border-spacing isn't part of the basis for percentages. |
|
658 nscoord spacing = mTableFrame->GetCellSpacingX(); |
|
659 nscoord subtract = 0; |
|
660 // aWidth initially includes border-spacing for the boundaries in between |
|
661 // each of the columns. We start at aFirstCol + 1 because the first |
|
662 // in-between boundary would be at the left edge of column aFirstCol + 1 |
|
663 for (int32_t col = aFirstCol + 1; col < aFirstCol + aColCount; ++col) { |
|
664 if (mTableFrame->ColumnHasCellSpacingBefore(col)) { |
|
665 subtract += spacing; |
|
666 } |
|
667 } |
|
668 if (aWidthType == BTLS_FINAL_WIDTH) { |
|
669 // If we're computing final col-width, then aWidth initially includes |
|
670 // border spacing on the table's far left + far right edge, too. Need |
|
671 // to subtract those out, too. |
|
672 subtract += spacing * 2; |
|
673 } |
|
674 aWidth = NSCoordSaturatingSubtract(aWidth, subtract, nscoord_MAX); |
|
675 |
|
676 /* |
|
677 * The goal of this function is to distribute |aWidth| between the |
|
678 * columns by making an appropriate AddSpanCoords or SetFinalWidth |
|
679 * call for each column. (We call AddSpanCoords if we're |
|
680 * distributing a column-spanning cell's minimum or preferred width |
|
681 * to its spanned columns. We call SetFinalWidth if we're |
|
682 * distributing a table's final width to its columns.) |
|
683 * |
|
684 * The idea is to either assign one of the following sets of widths |
|
685 * or a weighted average of two adjacent sets of widths. It is not |
|
686 * possible to assign values smaller than the smallest set of |
|
687 * widths. However, see below for handling the case of assigning |
|
688 * values larger than the largest set of widths. From smallest to |
|
689 * largest, these are: |
|
690 * |
|
691 * 1. [guess_min] Assign all columns their min width. |
|
692 * |
|
693 * 2. [guess_min_pct] Assign all columns with percentage widths |
|
694 * their percentage width, and all other columns their min width. |
|
695 * |
|
696 * 3. [guess_min_spec] Assign all columns with percentage widths |
|
697 * their percentage width, all columns with specified coordinate |
|
698 * widths their pref width (since it doesn't matter whether it's the |
|
699 * largest contributor to the pref width that was the specified |
|
700 * contributor), and all other columns their min width. |
|
701 * |
|
702 * 4. [guess_pref] Assign all columns with percentage widths their |
|
703 * specified width, and all other columns their pref width. |
|
704 * |
|
705 * If |aWidth| is *larger* than what we would assign in (4), then we |
|
706 * expand the columns: |
|
707 * |
|
708 * a. if any columns without a specified coordinate width or |
|
709 * percent width have nonzero pref width, in proportion to pref |
|
710 * width [total_flex_pref] |
|
711 * |
|
712 * b. otherwise, if any columns without a specified coordinate |
|
713 * width or percent width, but with cells originating in them, |
|
714 * have zero pref width, equally between these |
|
715 * [numNonSpecZeroWidthCols] |
|
716 * |
|
717 * c. otherwise, if any columns without percent width have nonzero |
|
718 * pref width, in proportion to pref width [total_fixed_pref] |
|
719 * |
|
720 * d. otherwise, if any columns have nonzero percentage widths, in |
|
721 * proportion to the percentage widths [total_pct] |
|
722 * |
|
723 * e. otherwise, equally. |
|
724 */ |
|
725 |
|
726 // Loop #1 over the columns, to figure out the four values above so |
|
727 // we know which case we're dealing with. |
|
728 |
|
729 nscoord guess_min = 0, |
|
730 guess_min_pct = 0, |
|
731 guess_min_spec = 0, |
|
732 guess_pref = 0, |
|
733 total_flex_pref = 0, |
|
734 total_fixed_pref = 0; |
|
735 float total_pct = 0.0f; // 0.0f to 1.0f |
|
736 int32_t numInfiniteWidthCols = 0; |
|
737 int32_t numNonSpecZeroWidthCols = 0; |
|
738 |
|
739 int32_t col; |
|
740 nsTableCellMap *cellMap = mTableFrame->GetCellMap(); |
|
741 for (col = aFirstCol; col < aFirstCol + aColCount; ++col) { |
|
742 nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
|
743 if (!colFrame) { |
|
744 NS_ERROR("column frames out of sync with cell map"); |
|
745 continue; |
|
746 } |
|
747 nscoord min_width = colFrame->GetMinCoord(); |
|
748 guess_min += min_width; |
|
749 if (colFrame->GetPrefPercent() != 0.0f) { |
|
750 float pct = colFrame->GetPrefPercent(); |
|
751 total_pct += pct; |
|
752 nscoord val = nscoord(float(aWidth) * pct); |
|
753 if (val < min_width) |
|
754 val = min_width; |
|
755 guess_min_pct += val; |
|
756 guess_pref = NSCoordSaturatingAdd(guess_pref, val); |
|
757 } else { |
|
758 nscoord pref_width = colFrame->GetPrefCoord(); |
|
759 if (pref_width == nscoord_MAX) { |
|
760 ++numInfiniteWidthCols; |
|
761 } |
|
762 guess_pref = NSCoordSaturatingAdd(guess_pref, pref_width); |
|
763 guess_min_pct += min_width; |
|
764 if (colFrame->GetHasSpecifiedCoord()) { |
|
765 // we'll add on the rest of guess_min_spec outside the |
|
766 // loop |
|
767 nscoord delta = NSCoordSaturatingSubtract(pref_width, |
|
768 min_width, 0); |
|
769 guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, delta); |
|
770 total_fixed_pref = NSCoordSaturatingAdd(total_fixed_pref, |
|
771 pref_width); |
|
772 } else if (pref_width == 0) { |
|
773 if (cellMap->GetNumCellsOriginatingInCol(col) > 0) { |
|
774 ++numNonSpecZeroWidthCols; |
|
775 } |
|
776 } else { |
|
777 total_flex_pref = NSCoordSaturatingAdd(total_flex_pref, |
|
778 pref_width); |
|
779 } |
|
780 } |
|
781 } |
|
782 guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, guess_min_pct); |
|
783 |
|
784 // Determine what we're flexing: |
|
785 enum Loop2Type { |
|
786 FLEX_PCT_SMALL, // between (1) and (2) above |
|
787 FLEX_FIXED_SMALL, // between (2) and (3) above |
|
788 FLEX_FLEX_SMALL, // between (3) and (4) above |
|
789 FLEX_FLEX_LARGE, // greater than (4) above, case (a) |
|
790 FLEX_FLEX_LARGE_ZERO, // greater than (4) above, case (b) |
|
791 FLEX_FIXED_LARGE, // greater than (4) above, case (c) |
|
792 FLEX_PCT_LARGE, // greater than (4) above, case (d) |
|
793 FLEX_ALL_LARGE // greater than (4) above, case (e) |
|
794 }; |
|
795 |
|
796 Loop2Type l2t; |
|
797 // These are constants (over columns) for each case's math. We use |
|
798 // a pair of nscoords rather than a float so that we can subtract |
|
799 // each column's allocation so we avoid accumulating rounding error. |
|
800 nscoord space; // the amount of extra width to allocate |
|
801 union { |
|
802 nscoord c; |
|
803 float f; |
|
804 } basis; // the sum of the statistic over columns to divide it |
|
805 if (aWidth < guess_pref) { |
|
806 if (aWidthType != BTLS_FINAL_WIDTH && aWidth <= guess_min) { |
|
807 // Return early -- we don't have any extra space to distribute. |
|
808 return; |
|
809 } |
|
810 NS_ASSERTION(!(aWidthType == BTLS_FINAL_WIDTH && aWidth < guess_min), |
|
811 "Table width is less than the " |
|
812 "sum of its columns' min widths"); |
|
813 if (aWidth < guess_min_pct) { |
|
814 l2t = FLEX_PCT_SMALL; |
|
815 space = aWidth - guess_min; |
|
816 basis.c = guess_min_pct - guess_min; |
|
817 } else if (aWidth < guess_min_spec) { |
|
818 l2t = FLEX_FIXED_SMALL; |
|
819 space = aWidth - guess_min_pct; |
|
820 basis.c = NSCoordSaturatingSubtract(guess_min_spec, guess_min_pct, |
|
821 nscoord_MAX); |
|
822 } else { |
|
823 l2t = FLEX_FLEX_SMALL; |
|
824 space = aWidth - guess_min_spec; |
|
825 basis.c = NSCoordSaturatingSubtract(guess_pref, guess_min_spec, |
|
826 nscoord_MAX); |
|
827 } |
|
828 } else { |
|
829 space = NSCoordSaturatingSubtract(aWidth, guess_pref, nscoord_MAX); |
|
830 if (total_flex_pref > 0) { |
|
831 l2t = FLEX_FLEX_LARGE; |
|
832 basis.c = total_flex_pref; |
|
833 } else if (numNonSpecZeroWidthCols > 0) { |
|
834 l2t = FLEX_FLEX_LARGE_ZERO; |
|
835 basis.c = numNonSpecZeroWidthCols; |
|
836 } else if (total_fixed_pref > 0) { |
|
837 l2t = FLEX_FIXED_LARGE; |
|
838 basis.c = total_fixed_pref; |
|
839 } else if (total_pct > 0.0f) { |
|
840 l2t = FLEX_PCT_LARGE; |
|
841 basis.f = total_pct; |
|
842 } else { |
|
843 l2t = FLEX_ALL_LARGE; |
|
844 basis.c = aColCount; |
|
845 } |
|
846 } |
|
847 |
|
848 #ifdef DEBUG_dbaron_off |
|
849 printf("ComputeColumnWidths: %d columns in width %d,\n" |
|
850 " guesses=[%d,%d,%d,%d], totals=[%d,%d,%f],\n" |
|
851 " l2t=%d, space=%d, basis.c=%d\n", |
|
852 aColCount, aWidth, |
|
853 guess_min, guess_min_pct, guess_min_spec, guess_pref, |
|
854 total_flex_pref, total_fixed_pref, total_pct, |
|
855 l2t, space, basis.c); |
|
856 #endif |
|
857 |
|
858 for (col = aFirstCol; col < aFirstCol + aColCount; ++col) { |
|
859 nsTableColFrame *colFrame = mTableFrame->GetColFrame(col); |
|
860 if (!colFrame) { |
|
861 NS_ERROR("column frames out of sync with cell map"); |
|
862 continue; |
|
863 } |
|
864 nscoord col_width; |
|
865 |
|
866 float pct = colFrame->GetPrefPercent(); |
|
867 if (pct != 0.0f) { |
|
868 col_width = nscoord(float(aWidth) * pct); |
|
869 nscoord col_min = colFrame->GetMinCoord(); |
|
870 if (col_width < col_min) |
|
871 col_width = col_min; |
|
872 } else { |
|
873 col_width = colFrame->GetPrefCoord(); |
|
874 } |
|
875 |
|
876 nscoord col_width_before_adjust = col_width; |
|
877 |
|
878 switch (l2t) { |
|
879 case FLEX_PCT_SMALL: |
|
880 col_width = col_width_before_adjust = colFrame->GetMinCoord(); |
|
881 if (pct != 0.0f) { |
|
882 nscoord pct_minus_min = |
|
883 nscoord(float(aWidth) * pct) - col_width; |
|
884 if (pct_minus_min > 0) { |
|
885 float c = float(space) / float(basis.c); |
|
886 basis.c -= pct_minus_min; |
|
887 col_width += NSToCoordRound(float(pct_minus_min) * c); |
|
888 } |
|
889 } |
|
890 break; |
|
891 case FLEX_FIXED_SMALL: |
|
892 if (pct == 0.0f) { |
|
893 NS_ASSERTION(col_width == colFrame->GetPrefCoord(), |
|
894 "wrong width assigned"); |
|
895 if (colFrame->GetHasSpecifiedCoord()) { |
|
896 nscoord col_min = colFrame->GetMinCoord(); |
|
897 nscoord pref_minus_min = col_width - col_min; |
|
898 col_width = col_width_before_adjust = col_min; |
|
899 if (pref_minus_min != 0) { |
|
900 float c = float(space) / float(basis.c); |
|
901 basis.c -= pref_minus_min; |
|
902 col_width += NSToCoordRound( |
|
903 float(pref_minus_min) * c); |
|
904 } |
|
905 } else |
|
906 col_width = col_width_before_adjust = |
|
907 colFrame->GetMinCoord(); |
|
908 } |
|
909 break; |
|
910 case FLEX_FLEX_SMALL: |
|
911 if (pct == 0.0f && |
|
912 !colFrame->GetHasSpecifiedCoord()) { |
|
913 NS_ASSERTION(col_width == colFrame->GetPrefCoord(), |
|
914 "wrong width assigned"); |
|
915 nscoord col_min = colFrame->GetMinCoord(); |
|
916 nscoord pref_minus_min = |
|
917 NSCoordSaturatingSubtract(col_width, col_min, 0); |
|
918 col_width = col_width_before_adjust = col_min; |
|
919 if (pref_minus_min != 0) { |
|
920 float c = float(space) / float(basis.c); |
|
921 // If we have infinite-width cols, then the standard |
|
922 // adjustment to col_width using 'c' won't work, |
|
923 // because basis.c and pref_minus_min are both |
|
924 // nscoord_MAX and will cancel each other out in the |
|
925 // col_width adjustment (making us assign all the |
|
926 // space to the first inf-width col). To correct for |
|
927 // this, we'll also divide by numInfiniteWidthCols to |
|
928 // spread the space equally among the inf-width cols. |
|
929 if (numInfiniteWidthCols) { |
|
930 if (colFrame->GetPrefCoord() == nscoord_MAX) { |
|
931 c = c / float(numInfiniteWidthCols); |
|
932 --numInfiniteWidthCols; |
|
933 } else { |
|
934 c = 0.0f; |
|
935 } |
|
936 } |
|
937 basis.c = NSCoordSaturatingSubtract(basis.c, |
|
938 pref_minus_min, |
|
939 nscoord_MAX); |
|
940 col_width += NSToCoordRound( |
|
941 float(pref_minus_min) * c); |
|
942 } |
|
943 } |
|
944 break; |
|
945 case FLEX_FLEX_LARGE: |
|
946 if (pct == 0.0f && |
|
947 !colFrame->GetHasSpecifiedCoord()) { |
|
948 NS_ASSERTION(col_width == colFrame->GetPrefCoord(), |
|
949 "wrong width assigned"); |
|
950 if (col_width != 0) { |
|
951 if (space == nscoord_MAX) { |
|
952 basis.c -= col_width; |
|
953 col_width = nscoord_MAX; |
|
954 } else { |
|
955 float c = float(space) / float(basis.c); |
|
956 basis.c -= col_width; |
|
957 col_width += NSToCoordRound(float(col_width) * c); |
|
958 } |
|
959 } |
|
960 } |
|
961 break; |
|
962 case FLEX_FLEX_LARGE_ZERO: |
|
963 if (pct == 0.0f && |
|
964 !colFrame->GetHasSpecifiedCoord() && |
|
965 cellMap->GetNumCellsOriginatingInCol(col) > 0) { |
|
966 |
|
967 NS_ASSERTION(col_width == 0 && |
|
968 colFrame->GetPrefCoord() == 0, |
|
969 "Since we're in FLEX_FLEX_LARGE_ZERO case, " |
|
970 "all auto-width cols should have zero pref " |
|
971 "width."); |
|
972 float c = float(space) / float(basis.c); |
|
973 col_width += NSToCoordRound(c); |
|
974 --basis.c; |
|
975 } |
|
976 break; |
|
977 case FLEX_FIXED_LARGE: |
|
978 if (pct == 0.0f) { |
|
979 NS_ASSERTION(col_width == colFrame->GetPrefCoord(), |
|
980 "wrong width assigned"); |
|
981 NS_ASSERTION(colFrame->GetHasSpecifiedCoord() || |
|
982 colFrame->GetPrefCoord() == 0, |
|
983 "wrong case"); |
|
984 if (col_width != 0) { |
|
985 float c = float(space) / float(basis.c); |
|
986 basis.c -= col_width; |
|
987 col_width += NSToCoordRound(float(col_width) * c); |
|
988 } |
|
989 } |
|
990 break; |
|
991 case FLEX_PCT_LARGE: |
|
992 NS_ASSERTION(pct != 0.0f || colFrame->GetPrefCoord() == 0, |
|
993 "wrong case"); |
|
994 if (pct != 0.0f) { |
|
995 float c = float(space) / basis.f; |
|
996 col_width += NSToCoordRound(pct * c); |
|
997 basis.f -= pct; |
|
998 } |
|
999 break; |
|
1000 case FLEX_ALL_LARGE: |
|
1001 { |
|
1002 float c = float(space) / float(basis.c); |
|
1003 col_width += NSToCoordRound(c); |
|
1004 --basis.c; |
|
1005 } |
|
1006 break; |
|
1007 } |
|
1008 |
|
1009 // Only subtract from space if it's a real number. |
|
1010 if (space != nscoord_MAX) { |
|
1011 NS_ASSERTION(col_width != nscoord_MAX, |
|
1012 "How is col_width nscoord_MAX if space isn't?"); |
|
1013 NS_ASSERTION(col_width_before_adjust != nscoord_MAX, |
|
1014 "How is col_width_before_adjust nscoord_MAX if space isn't?"); |
|
1015 space -= col_width - col_width_before_adjust; |
|
1016 } |
|
1017 |
|
1018 NS_ASSERTION(col_width >= colFrame->GetMinCoord(), |
|
1019 "assigned width smaller than min"); |
|
1020 |
|
1021 // Apply the new width |
|
1022 switch (aWidthType) { |
|
1023 case BTLS_MIN_WIDTH: |
|
1024 { |
|
1025 // Note: AddSpanCoords requires both a min and pref width. |
|
1026 // For the pref width, we'll just pass in our computed |
|
1027 // min width, because the real pref width will be at least |
|
1028 // as big |
|
1029 colFrame->AddSpanCoords(col_width, col_width, |
|
1030 aSpanHasSpecifiedWidth); |
|
1031 } |
|
1032 break; |
|
1033 case BTLS_PREF_WIDTH: |
|
1034 { |
|
1035 // Note: AddSpanCoords requires both a min and pref width. |
|
1036 // For the min width, we'll just pass in 0, because |
|
1037 // the real min width will be at least 0 |
|
1038 colFrame->AddSpanCoords(0, col_width, |
|
1039 aSpanHasSpecifiedWidth); |
|
1040 } |
|
1041 break; |
|
1042 case BTLS_FINAL_WIDTH: |
|
1043 { |
|
1044 nscoord old_final = colFrame->GetFinalWidth(); |
|
1045 colFrame->SetFinalWidth(col_width); |
|
1046 |
|
1047 if (old_final != col_width) |
|
1048 mTableFrame->DidResizeColumns(); |
|
1049 } |
|
1050 break; |
|
1051 } |
|
1052 } |
|
1053 NS_ASSERTION((space == 0 || space == nscoord_MAX) && |
|
1054 ((l2t == FLEX_PCT_LARGE) |
|
1055 ? (-0.001f < basis.f && basis.f < 0.001f) |
|
1056 : (basis.c == 0 || basis.c == nscoord_MAX)), |
|
1057 "didn't subtract all that we added"); |
|
1058 } |