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