OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2002 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 2002 Lars Knoll (knoll@kde.org) |
3 * (C) 2002 Dirk Mueller (mueller@kde.org) | 3 * (C) 2002 Dirk Mueller (mueller@kde.org) |
4 * Copyright (C) 2003, 2006, 2008, 2010 Apple Inc. All rights reserved. | 4 * Copyright (C) 2003, 2006, 2008, 2010 Apple Inc. All rights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License. | 9 * version 2 of the License. |
10 * | 10 * |
(...skipping 28 matching lines...) Expand all Loading... | |
39 | 39 |
40 void TableLayoutAlgorithmAuto::recalcColumn(unsigned effCol) { | 40 void TableLayoutAlgorithmAuto::recalcColumn(unsigned effCol) { |
41 Layout& columnLayout = m_layoutStruct[effCol]; | 41 Layout& columnLayout = m_layoutStruct[effCol]; |
42 | 42 |
43 LayoutTableCell* fixedContributor = nullptr; | 43 LayoutTableCell* fixedContributor = nullptr; |
44 LayoutTableCell* maxContributor = nullptr; | 44 LayoutTableCell* maxContributor = nullptr; |
45 | 45 |
46 for (LayoutObject* child = m_table->children()->firstChild(); child; | 46 for (LayoutObject* child = m_table->children()->firstChild(); child; |
47 child = child->nextSibling()) { | 47 child = child->nextSibling()) { |
48 if (child->isLayoutTableCol()) { | 48 if (child->isLayoutTableCol()) { |
49 // LayoutTableCols don't have the concept of preferred logical width, but we need to clear their dirty bits | 49 // LayoutTableCols don't have the concept of preferred logical width, but |
50 // so that if we call setPreferredWidthsDirty(true) on a col or one of its descendants, we'll mark it's | 50 // we need to clear their dirty bits so that if we call |
51 // ancestors as dirty. | 51 // setPreferredWidthsDirty(true) on a col or one of its descendants, we'll |
52 // mark it's ancestors as dirty. | |
52 toLayoutTableCol(child)->clearPreferredLogicalWidthsDirtyBits(); | 53 toLayoutTableCol(child)->clearPreferredLogicalWidthsDirtyBits(); |
53 } else if (child->isTableSection()) { | 54 } else if (child->isTableSection()) { |
54 LayoutTableSection* section = toLayoutTableSection(child); | 55 LayoutTableSection* section = toLayoutTableSection(child); |
55 unsigned numRows = section->numRows(); | 56 unsigned numRows = section->numRows(); |
56 for (unsigned i = 0; i < numRows; i++) { | 57 for (unsigned i = 0; i < numRows; i++) { |
57 LayoutTableSection::CellStruct current = section->cellAt(i, effCol); | 58 LayoutTableSection::CellStruct current = section->cellAt(i, effCol); |
58 LayoutTableCell* cell = current.primaryCell(); | 59 LayoutTableCell* cell = current.primaryCell(); |
59 | 60 |
60 if (current.inColSpan || !cell) | 61 if (current.inColSpan || !cell) |
61 continue; | 62 continue; |
62 columnLayout.columnHasNoCells = false; | 63 columnLayout.columnHasNoCells = false; |
63 | 64 |
64 if (cell->maxPreferredLogicalWidth()) | 65 if (cell->maxPreferredLogicalWidth()) |
65 columnLayout.emptyCellsOnly = false; | 66 columnLayout.emptyCellsOnly = false; |
66 | 67 |
67 if (cell->colSpan() == 1) { | 68 if (cell->colSpan() == 1) { |
68 columnLayout.minLogicalWidth = | 69 columnLayout.minLogicalWidth = |
69 std::max<int>(cell->minPreferredLogicalWidth().toInt(), | 70 std::max<int>(cell->minPreferredLogicalWidth().toInt(), |
70 columnLayout.minLogicalWidth); | 71 columnLayout.minLogicalWidth); |
71 if (cell->maxPreferredLogicalWidth() > columnLayout.maxLogicalWidth) { | 72 if (cell->maxPreferredLogicalWidth() > columnLayout.maxLogicalWidth) { |
72 columnLayout.maxLogicalWidth = | 73 columnLayout.maxLogicalWidth = |
73 cell->maxPreferredLogicalWidth().toInt(); | 74 cell->maxPreferredLogicalWidth().toInt(); |
74 maxContributor = cell; | 75 maxContributor = cell; |
75 } | 76 } |
76 | 77 |
77 // All browsers implement a size limit on the cell's max width. | 78 // All browsers implement a size limit on the cell's max width. |
78 // Our limit is based on KHTML's representation that used 16 bits widt hs. | 79 // Our limit is based on KHTML's representation that used 16 bits |
80 // widths. | |
79 // FIXME: Other browsers have a lower limit for the cell's max width. | 81 // FIXME: Other browsers have a lower limit for the cell's max width. |
80 const int cCellMaxWidth = 32760; | 82 const int cCellMaxWidth = 32760; |
81 Length cellLogicalWidth = cell->styleOrColLogicalWidth(); | 83 Length cellLogicalWidth = cell->styleOrColLogicalWidth(); |
82 // FIXME: calc() on tables should be handled consistently with other l engths. See bug: https://crbug.com/382725 | 84 // FIXME: calc() on tables should be handled consistently with other |
85 // lengths. See bug: https://crbug.com/382725 | |
83 if (cellLogicalWidth.isCalculated()) | 86 if (cellLogicalWidth.isCalculated()) |
84 cellLogicalWidth = Length(); // Make it Auto | 87 cellLogicalWidth = Length(); // Make it Auto |
85 if (cellLogicalWidth.value() > cCellMaxWidth) | 88 if (cellLogicalWidth.value() > cCellMaxWidth) |
86 cellLogicalWidth.setValue(cCellMaxWidth); | 89 cellLogicalWidth.setValue(cCellMaxWidth); |
87 if (cellLogicalWidth.isNegative()) | 90 if (cellLogicalWidth.isNegative()) |
88 cellLogicalWidth.setValue(0); | 91 cellLogicalWidth.setValue(0); |
89 switch (cellLogicalWidth.type()) { | 92 switch (cellLogicalWidth.type()) { |
90 case Fixed: | 93 case Fixed: |
91 // ignore width=0 | 94 // ignore width=0 |
92 if (cellLogicalWidth.isPositive() && | 95 if (cellLogicalWidth.isPositive() && |
(...skipping 22 matching lines...) Expand all Loading... | |
115 if (cellLogicalWidth.isPositive() && | 118 if (cellLogicalWidth.isPositive() && |
116 (!columnLayout.logicalWidth.isPercentOrCalc() || | 119 (!columnLayout.logicalWidth.isPercentOrCalc() || |
117 cellLogicalWidth.value() > | 120 cellLogicalWidth.value() > |
118 columnLayout.logicalWidth.value())) | 121 columnLayout.logicalWidth.value())) |
119 columnLayout.logicalWidth = cellLogicalWidth; | 122 columnLayout.logicalWidth = cellLogicalWidth; |
120 break; | 123 break; |
121 default: | 124 default: |
122 break; | 125 break; |
123 } | 126 } |
124 } else if (!effCol || section->primaryCellAt(i, effCol - 1) != cell) { | 127 } else if (!effCol || section->primaryCellAt(i, effCol - 1) != cell) { |
125 // If a cell originates in this spanning column ensure we have a min/m ax width of at least 1px for it. | 128 // If a cell originates in this spanning column ensure we have a |
129 // min/max width of at least 1px for it. | |
126 columnLayout.minLogicalWidth = | 130 columnLayout.minLogicalWidth = |
127 std::max<int>(columnLayout.minLogicalWidth, | 131 std::max<int>(columnLayout.minLogicalWidth, |
128 cell->maxPreferredLogicalWidth() ? 1 : 0); | 132 cell->maxPreferredLogicalWidth() ? 1 : 0); |
129 | 133 |
130 // This spanning cell originates in this column. Insert the cell into spanning cells list. | 134 // This spanning cell originates in this column. Insert the cell into |
135 // spanning cells list. | |
131 insertSpanCell(cell); | 136 insertSpanCell(cell); |
132 } | 137 } |
133 } | 138 } |
134 } | 139 } |
135 } | 140 } |
136 | 141 |
137 // Nav/IE weirdness | 142 // Nav/IE weirdness |
138 if (columnLayout.logicalWidth.isFixed()) { | 143 if (columnLayout.logicalWidth.isFixed()) { |
139 if (m_table->document().inQuirksMode() && | 144 if (m_table->document().inQuirksMode() && |
140 columnLayout.maxLogicalWidth > columnLayout.logicalWidth.value() && | 145 columnLayout.maxLogicalWidth > columnLayout.logicalWidth.value() && |
(...skipping 17 matching lines...) Expand all Loading... | |
158 m_spanCells.fill(0); | 163 m_spanCells.fill(0); |
159 | 164 |
160 Length groupLogicalWidth; | 165 Length groupLogicalWidth; |
161 unsigned currentColumn = 0; | 166 unsigned currentColumn = 0; |
162 for (LayoutTableCol* column = m_table->firstColumn(); column; | 167 for (LayoutTableCol* column = m_table->firstColumn(); column; |
163 column = column->nextColumn()) { | 168 column = column->nextColumn()) { |
164 if (column->isTableColumnGroupWithColumnChildren()) { | 169 if (column->isTableColumnGroupWithColumnChildren()) { |
165 groupLogicalWidth = column->style()->logicalWidth(); | 170 groupLogicalWidth = column->style()->logicalWidth(); |
166 } else { | 171 } else { |
167 Length colLogicalWidth = column->style()->logicalWidth(); | 172 Length colLogicalWidth = column->style()->logicalWidth(); |
168 // FIXME: calc() on tables should be handled consistently with other lengt hs. See bug: https://crbug.com/382725 | 173 // FIXME: calc() on tables should be handled consistently with other |
174 // lengths. See bug: https://crbug.com/382725 | |
169 if (colLogicalWidth.isCalculated() || colLogicalWidth.isAuto()) | 175 if (colLogicalWidth.isCalculated() || colLogicalWidth.isAuto()) |
170 colLogicalWidth = groupLogicalWidth; | 176 colLogicalWidth = groupLogicalWidth; |
171 // TODO(alancutter): Make this work correctly for calc lengths. | 177 // TODO(alancutter): Make this work correctly for calc lengths. |
172 if ((colLogicalWidth.isFixed() || colLogicalWidth.isPercentOrCalc()) && | 178 if ((colLogicalWidth.isFixed() || colLogicalWidth.isPercentOrCalc()) && |
173 colLogicalWidth.isZero()) | 179 colLogicalWidth.isZero()) |
174 colLogicalWidth = Length(); | 180 colLogicalWidth = Length(); |
175 unsigned effCol = m_table->absoluteColumnToEffectiveColumn(currentColumn); | 181 unsigned effCol = m_table->absoluteColumnToEffectiveColumn(currentColumn); |
176 unsigned span = column->span(); | 182 unsigned span = column->span(); |
177 if (!colLogicalWidth.isAuto() && span == 1 && effCol < nEffCols && | 183 if (!colLogicalWidth.isAuto() && span == 1 && effCol < nEffCols && |
178 m_table->spanOfEffectiveColumn(effCol) == 1) { | 184 m_table->spanOfEffectiveColumn(effCol) == 1) { |
179 m_layoutStruct[effCol].logicalWidth = colLogicalWidth; | 185 m_layoutStruct[effCol].logicalWidth = colLogicalWidth; |
180 if (colLogicalWidth.isFixed() && | 186 if (colLogicalWidth.isFixed() && |
181 m_layoutStruct[effCol].maxLogicalWidth < colLogicalWidth.value()) | 187 m_layoutStruct[effCol].maxLogicalWidth < colLogicalWidth.value()) |
182 m_layoutStruct[effCol].maxLogicalWidth = colLogicalWidth.value(); | 188 m_layoutStruct[effCol].maxLogicalWidth = colLogicalWidth.value(); |
183 } | 189 } |
184 currentColumn += span; | 190 currentColumn += span; |
185 } | 191 } |
186 | 192 |
187 // For the last column in a column-group, we invalidate our group logical wi dth. | 193 // For the last column in a column-group, we invalidate our group logical |
194 // width. | |
188 if (column->isTableColumn() && !column->nextSibling()) | 195 if (column->isTableColumn() && !column->nextSibling()) |
189 groupLogicalWidth = Length(); | 196 groupLogicalWidth = Length(); |
190 } | 197 } |
191 | 198 |
192 for (unsigned i = 0; i < nEffCols; i++) | 199 for (unsigned i = 0; i < nEffCols; i++) |
193 recalcColumn(i); | 200 recalcColumn(i); |
194 } | 201 } |
195 | 202 |
196 static bool shouldScaleColumnsForParent(LayoutTable* table) { | 203 static bool shouldScaleColumnsForParent(LayoutTable* table) { |
197 LayoutBlock* cb = table->containingBlock(); | 204 LayoutBlock* cb = table->containingBlock(); |
198 while (!cb->isLayoutView()) { | 205 while (!cb->isLayoutView()) { |
199 // It doesn't matter if our table is auto or fixed: auto means we don't | 206 // It doesn't matter if our table is auto or fixed: auto means we don't |
200 // scale. Fixed doesn't care if we do or not because it doesn't depend | 207 // scale. Fixed doesn't care if we do or not because it doesn't depend |
201 // on the cell contents' preferred widths. | 208 // on the cell contents' preferred widths. |
202 if (cb->isTableCell()) | 209 if (cb->isTableCell()) |
203 return false; | 210 return false; |
204 cb = cb->containingBlock(); | 211 cb = cb->containingBlock(); |
205 } | 212 } |
206 return true; | 213 return true; |
207 } | 214 } |
208 | 215 |
209 // FIXME: This needs to be adapted for vertical writing modes. | 216 // FIXME: This needs to be adapted for vertical writing modes. |
210 static bool shouldScaleColumnsForSelf(LayoutTable* table) { | 217 static bool shouldScaleColumnsForSelf(LayoutTable* table) { |
211 // Normally, scale all columns to satisfy this from CSS2.2: | 218 // Normally, scale all columns to satisfy this from CSS2.2: |
212 // "A percentage value for a column width is relative to the table width. | 219 // "A percentage value for a column width is relative to the table width. |
213 // If the table has 'width: auto', a percentage represents a constraint on the column's width" | 220 // If the table has 'width: auto', a percentage represents a constraint on the |
221 // column's width" | |
214 | 222 |
215 // A special case. If this table is not fixed width and contained inside | 223 // A special case. If this table is not fixed width and contained inside |
216 // a cell, then don't bloat the maxwidth by examining percentage growth. | 224 // a cell, then don't bloat the maxwidth by examining percentage growth. |
217 while (true) { | 225 while (true) { |
218 Length tw = table->style()->width(); | 226 Length tw = table->style()->width(); |
219 if ((!tw.isAuto() && !tw.isPercentOrCalc()) || | 227 if ((!tw.isAuto() && !tw.isPercentOrCalc()) || |
220 table->isOutOfFlowPositioned()) | 228 table->isOutOfFlowPositioned()) |
221 return true; | 229 return true; |
222 LayoutBlock* cb = table->containingBlock(); | 230 LayoutBlock* cb = table->containingBlock(); |
223 | 231 |
(...skipping 22 matching lines...) Expand all Loading... | |
246 | 254 |
247 fullRecalc(); | 255 fullRecalc(); |
248 | 256 |
249 int spanMaxLogicalWidth = calcEffectiveLogicalWidth(); | 257 int spanMaxLogicalWidth = calcEffectiveLogicalWidth(); |
250 minWidth = LayoutUnit(); | 258 minWidth = LayoutUnit(); |
251 maxWidth = LayoutUnit(); | 259 maxWidth = LayoutUnit(); |
252 float maxPercent = 0; | 260 float maxPercent = 0; |
253 float maxNonPercent = 0; | 261 float maxNonPercent = 0; |
254 bool scaleColumnsForSelf = shouldScaleColumnsForSelf(m_table); | 262 bool scaleColumnsForSelf = shouldScaleColumnsForSelf(m_table); |
255 | 263 |
256 // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two pl aces below to avoid division by zero. | 264 // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two |
265 // places below to avoid division by zero. | |
257 // FIXME: Handle the 0% cases properly. | 266 // FIXME: Handle the 0% cases properly. |
258 const float epsilon = 1 / 128.0f; | 267 const float epsilon = 1 / 128.0f; |
259 | 268 |
260 float remainingPercent = 100; | 269 float remainingPercent = 100; |
261 for (size_t i = 0; i < m_layoutStruct.size(); ++i) { | 270 for (size_t i = 0; i < m_layoutStruct.size(); ++i) { |
262 minWidth += m_layoutStruct[i].effectiveMinLogicalWidth; | 271 minWidth += m_layoutStruct[i].effectiveMinLogicalWidth; |
263 maxWidth += m_layoutStruct[i].effectiveMaxLogicalWidth; | 272 maxWidth += m_layoutStruct[i].effectiveMaxLogicalWidth; |
264 if (scaleColumnsForSelf) { | 273 if (scaleColumnsForSelf) { |
265 if (m_layoutStruct[i].effectiveLogicalWidth.isPercentOrCalc()) { | 274 if (m_layoutStruct[i].effectiveLogicalWidth.isPercentOrCalc()) { |
266 float percent = | 275 float percent = |
(...skipping 24 matching lines...) Expand all Loading... | |
291 } | 300 } |
292 | 301 |
293 maxWidth = LayoutUnit(std::max(maxWidth.floor(), spanMaxLogicalWidth)); | 302 maxWidth = LayoutUnit(std::max(maxWidth.floor(), spanMaxLogicalWidth)); |
294 } | 303 } |
295 | 304 |
296 void TableLayoutAlgorithmAuto::applyPreferredLogicalWidthQuirks( | 305 void TableLayoutAlgorithmAuto::applyPreferredLogicalWidthQuirks( |
297 LayoutUnit& minWidth, | 306 LayoutUnit& minWidth, |
298 LayoutUnit& maxWidth) const { | 307 LayoutUnit& maxWidth) const { |
299 Length tableLogicalWidth = m_table->style()->logicalWidth(); | 308 Length tableLogicalWidth = m_table->style()->logicalWidth(); |
300 if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive()) { | 309 if (tableLogicalWidth.isFixed() && tableLogicalWidth.isPositive()) { |
301 // |minWidth| is the result of measuring the intrinsic content's size. Keep it to | 310 // |minWidth| is the result of measuring the intrinsic content's size. Keep |
302 // make sure we are *never* smaller than the actual content. | 311 // it to make sure we are *never* smaller than the actual content. |
303 LayoutUnit minContentWidth = minWidth; | 312 LayoutUnit minContentWidth = minWidth; |
304 // FIXME: This line looks REALLY suspicious as it could allow the minimum | 313 // FIXME: This line looks REALLY suspicious as it could allow the minimum |
305 // preferred logical width to be smaller than the table content. This has | 314 // preferred logical width to be smaller than the table content. This has |
306 // to be cross-checked against other browsers. | 315 // to be cross-checked against other browsers. |
307 minWidth = maxWidth = | 316 minWidth = maxWidth = |
308 LayoutUnit(std::max<int>(minWidth.floor(), tableLogicalWidth.value())); | 317 LayoutUnit(std::max<int>(minWidth.floor(), tableLogicalWidth.value())); |
309 | 318 |
310 const Length& styleMaxLogicalWidth = m_table->style()->logicalMaxWidth(); | 319 const Length& styleMaxLogicalWidth = m_table->style()->logicalMaxWidth(); |
311 if (styleMaxLogicalWidth.isFixed() && !styleMaxLogicalWidth.isNegative()) { | 320 if (styleMaxLogicalWidth.isFixed() && !styleMaxLogicalWidth.isNegative()) { |
312 minWidth = LayoutUnit( | 321 minWidth = LayoutUnit( |
313 std::min<int>(minWidth.floor(), styleMaxLogicalWidth.value())); | 322 std::min<int>(minWidth.floor(), styleMaxLogicalWidth.value())); |
314 minWidth = std::max(minWidth, minContentWidth); | 323 minWidth = std::max(minWidth, minContentWidth); |
315 maxWidth = minWidth; | 324 maxWidth = minWidth; |
316 } | 325 } |
317 } | 326 } |
318 } | 327 } |
319 | 328 |
320 /* | 329 /* |
321 This method takes care of colspans. | 330 This method takes care of colspans. |
322 effWidth is the same as width for cells without colspans. If we have colspans, they get modified. | 331 effWidth is the same as width for cells without colspans. If we have colspans, |
332 they get modified. | |
dcheng
2016/10/07 20:42:01
A wild C-style comment!
| |
323 */ | 333 */ |
324 int TableLayoutAlgorithmAuto::calcEffectiveLogicalWidth() { | 334 int TableLayoutAlgorithmAuto::calcEffectiveLogicalWidth() { |
325 int maxLogicalWidth = 0; | 335 int maxLogicalWidth = 0; |
326 | 336 |
327 size_t nEffCols = m_layoutStruct.size(); | 337 size_t nEffCols = m_layoutStruct.size(); |
328 int spacingInRowDirection = m_table->hBorderSpacing(); | 338 int spacingInRowDirection = m_table->hBorderSpacing(); |
329 | 339 |
330 for (size_t i = 0; i < nEffCols; ++i) { | 340 for (size_t i = 0; i < nEffCols; ++i) { |
331 m_layoutStruct[i].effectiveLogicalWidth = m_layoutStruct[i].logicalWidth; | 341 m_layoutStruct[i].effectiveLogicalWidth = m_layoutStruct[i].logicalWidth; |
332 m_layoutStruct[i].effectiveMinLogicalWidth = | 342 m_layoutStruct[i].effectiveMinLogicalWidth = |
333 m_layoutStruct[i].minLogicalWidth; | 343 m_layoutStruct[i].minLogicalWidth; |
334 m_layoutStruct[i].effectiveMaxLogicalWidth = | 344 m_layoutStruct[i].effectiveMaxLogicalWidth = |
335 m_layoutStruct[i].maxLogicalWidth; | 345 m_layoutStruct[i].maxLogicalWidth; |
336 } | 346 } |
337 | 347 |
338 for (size_t i = 0; i < m_spanCells.size(); ++i) { | 348 for (size_t i = 0; i < m_spanCells.size(); ++i) { |
339 LayoutTableCell* cell = m_spanCells[i]; | 349 LayoutTableCell* cell = m_spanCells[i]; |
340 if (!cell) | 350 if (!cell) |
341 break; | 351 break; |
342 | 352 |
343 unsigned span = cell->colSpan(); | 353 unsigned span = cell->colSpan(); |
344 | 354 |
345 Length cellLogicalWidth = cell->styleOrColLogicalWidth(); | 355 Length cellLogicalWidth = cell->styleOrColLogicalWidth(); |
346 // FIXME: calc() on tables should be handled consistently with other lengths . See bug: https://crbug.com/382725 | 356 // FIXME: calc() on tables should be handled consistently with other |
357 // lengths. See bug: https://crbug.com/382725 | |
347 if (cellLogicalWidth.isZero() || cellLogicalWidth.isCalculated()) | 358 if (cellLogicalWidth.isZero() || cellLogicalWidth.isCalculated()) |
348 cellLogicalWidth = Length(); // Make it Auto | 359 cellLogicalWidth = Length(); // Make it Auto |
349 | 360 |
350 unsigned effCol = | 361 unsigned effCol = |
351 m_table->absoluteColumnToEffectiveColumn(cell->absoluteColumnIndex()); | 362 m_table->absoluteColumnToEffectiveColumn(cell->absoluteColumnIndex()); |
352 size_t lastCol = effCol; | 363 size_t lastCol = effCol; |
353 int cellMinLogicalWidth = | 364 int cellMinLogicalWidth = |
354 (cell->minPreferredLogicalWidth() + spacingInRowDirection).toInt(); | 365 (cell->minPreferredLogicalWidth() + spacingInRowDirection).toInt(); |
355 int cellMaxLogicalWidth = | 366 int cellMaxLogicalWidth = |
356 (cell->maxPreferredLogicalWidth() + spacingInRowDirection).toInt(); | 367 (cell->maxPreferredLogicalWidth() + spacingInRowDirection).toInt(); |
357 float totalPercent = 0; | 368 float totalPercent = 0; |
358 int spanMinLogicalWidth = 0; | 369 int spanMinLogicalWidth = 0; |
359 int spanMaxLogicalWidth = 0; | 370 int spanMaxLogicalWidth = 0; |
360 bool allColsArePercent = true; | 371 bool allColsArePercent = true; |
361 bool allColsAreFixed = true; | 372 bool allColsAreFixed = true; |
362 bool haveAuto = false; | 373 bool haveAuto = false; |
363 bool spanHasEmptyCellsOnly = true; | 374 bool spanHasEmptyCellsOnly = true; |
364 int fixedWidth = 0; | 375 int fixedWidth = 0; |
365 while (lastCol < nEffCols && span > 0) { | 376 while (lastCol < nEffCols && span > 0) { |
366 Layout& columnLayout = m_layoutStruct[lastCol]; | 377 Layout& columnLayout = m_layoutStruct[lastCol]; |
367 switch (columnLayout.logicalWidth.type()) { | 378 switch (columnLayout.logicalWidth.type()) { |
368 case Percent: | 379 case Percent: |
369 totalPercent += columnLayout.logicalWidth.percent(); | 380 totalPercent += columnLayout.logicalWidth.percent(); |
370 allColsAreFixed = false; | 381 allColsAreFixed = false; |
371 break; | 382 break; |
372 case Fixed: | 383 case Fixed: |
373 if (columnLayout.logicalWidth.value() > 0) { | 384 if (columnLayout.logicalWidth.value() > 0) { |
374 fixedWidth += columnLayout.logicalWidth.value(); | 385 fixedWidth += columnLayout.logicalWidth.value(); |
375 allColsArePercent = false; | 386 allColsArePercent = false; |
376 // IE resets effWidth to Auto here, but this breaks the konqueror ab out page and seems to be some bad | 387 // IE resets effWidth to Auto here, but this breaks the konqueror |
377 // legacy behaviour anyway. mozilla doesn't do this so I decided we don't neither. | 388 // about page and seems to be some bad legacy behaviour anyway. |
389 // mozilla doesn't do this so I decided we don't neither. | |
378 break; | 390 break; |
379 } | 391 } |
380 // fall through | 392 // fall through |
381 case Auto: | 393 case Auto: |
382 haveAuto = true; | 394 haveAuto = true; |
383 // fall through | 395 // fall through |
384 default: | 396 default: |
385 // If the column is a percentage width, do not let the spanning cell o verwrite the | 397 // If the column is a percentage width, do not let the spanning cell |
386 // width value. This caused a mis-layout on amazon.com. | 398 // overwrite the width value. This caused a mis-layout on amazon.com. |
387 // Sample snippet: | 399 // Sample snippet: |
388 // <table border=2 width=100%>< | 400 // <table border=2 width=100%>< |
389 // <tr><td>1</td><td colspan=2>2-3</tr> | 401 // <tr><td>1</td><td colspan=2>2-3</tr> |
390 // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr> | 402 // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr> |
391 // </table> | 403 // </table> |
392 // TODO(alancutter): Make this work correctly for calc lengths. | 404 // TODO(alancutter): Make this work correctly for calc lengths. |
393 if (!columnLayout.effectiveLogicalWidth.isPercentOrCalc()) { | 405 if (!columnLayout.effectiveLogicalWidth.isPercentOrCalc()) { |
394 columnLayout.effectiveLogicalWidth = Length(); | 406 columnLayout.effectiveLogicalWidth = Length(); |
395 allColsArePercent = false; | 407 allColsArePercent = false; |
396 } else { | 408 } else { |
(...skipping 16 matching lines...) Expand all Loading... | |
413 if (totalPercent > cellLogicalWidth.percent() || allColsArePercent) { | 425 if (totalPercent > cellLogicalWidth.percent() || allColsArePercent) { |
414 // can't satify this condition, treat as variable | 426 // can't satify this condition, treat as variable |
415 cellLogicalWidth = Length(); | 427 cellLogicalWidth = Length(); |
416 } else { | 428 } else { |
417 maxLogicalWidth = | 429 maxLogicalWidth = |
418 std::max(maxLogicalWidth, | 430 std::max(maxLogicalWidth, |
419 static_cast<int>( | 431 static_cast<int>( |
420 std::max(spanMaxLogicalWidth, cellMaxLogicalWidth) * | 432 std::max(spanMaxLogicalWidth, cellMaxLogicalWidth) * |
421 100 / cellLogicalWidth.percent())); | 433 100 / cellLogicalWidth.percent())); |
422 | 434 |
423 // all non percent columns in the span get percent values to sum up corr ectly. | 435 // all non percent columns in the span get percent values to sum up |
436 // correctly. | |
424 float percentMissing = cellLogicalWidth.percent() - totalPercent; | 437 float percentMissing = cellLogicalWidth.percent() - totalPercent; |
425 int totalWidth = 0; | 438 int totalWidth = 0; |
426 for (unsigned pos = effCol; pos < lastCol; ++pos) { | 439 for (unsigned pos = effCol; pos < lastCol; ++pos) { |
427 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercentOrCalc()) | 440 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercentOrCalc()) |
428 totalWidth += m_layoutStruct[pos].clampedEffectiveMaxLogicalWidth(); | 441 totalWidth += m_layoutStruct[pos].clampedEffectiveMaxLogicalWidth(); |
429 } | 442 } |
430 | 443 |
431 for (unsigned pos = effCol; pos < lastCol && totalWidth > 0; ++pos) { | 444 for (unsigned pos = effCol; pos < lastCol && totalWidth > 0; ++pos) { |
432 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercentOrCalc()) { | 445 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercentOrCalc()) { |
433 float percent = percentMissing * | 446 float percent = percentMissing * |
(...skipping 19 matching lines...) Expand all Loading... | |
453 int cellLogicalWidth = std::max( | 466 int cellLogicalWidth = std::max( |
454 m_layoutStruct[pos].effectiveMinLogicalWidth, | 467 m_layoutStruct[pos].effectiveMinLogicalWidth, |
455 static_cast<int>(cellMinLogicalWidth * | 468 static_cast<int>(cellMinLogicalWidth * |
456 m_layoutStruct[pos].logicalWidth.value() / | 469 m_layoutStruct[pos].logicalWidth.value() / |
457 fixedWidth)); | 470 fixedWidth)); |
458 fixedWidth -= m_layoutStruct[pos].logicalWidth.value(); | 471 fixedWidth -= m_layoutStruct[pos].logicalWidth.value(); |
459 cellMinLogicalWidth -= cellLogicalWidth; | 472 cellMinLogicalWidth -= cellLogicalWidth; |
460 m_layoutStruct[pos].effectiveMinLogicalWidth = cellLogicalWidth; | 473 m_layoutStruct[pos].effectiveMinLogicalWidth = cellLogicalWidth; |
461 } | 474 } |
462 } else if (allColsArePercent) { | 475 } else if (allColsArePercent) { |
463 // In this case, we just split the colspan's min amd max widths followin g the percentage. | 476 // In this case, we just split the colspan's min amd max widths |
477 // following the percentage. | |
464 int allocatedMinLogicalWidth = 0; | 478 int allocatedMinLogicalWidth = 0; |
465 int allocatedMaxLogicalWidth = 0; | 479 int allocatedMaxLogicalWidth = 0; |
466 for (unsigned pos = effCol; pos < lastCol; ++pos) { | 480 for (unsigned pos = effCol; pos < lastCol; ++pos) { |
467 // TODO(alancutter): Make this work correctly for calc lengths. | 481 // TODO(alancutter): Make this work correctly for calc lengths. |
468 DCHECK(m_layoutStruct[pos].logicalWidth.isPercentOrCalc() || | 482 DCHECK(m_layoutStruct[pos].logicalWidth.isPercentOrCalc() || |
469 m_layoutStruct[pos].effectiveLogicalWidth.isPercentOrCalc()); | 483 m_layoutStruct[pos].effectiveLogicalWidth.isPercentOrCalc()); |
470 // |allColsArePercent| means that either the logicalWidth *or* the eff ectiveLogicalWidth are percents, handle both of them here. | 484 // |allColsArePercent| means that either the logicalWidth *or* the |
485 // effectiveLogicalWidth are percents, handle both of them here. | |
471 float percent = | 486 float percent = |
472 m_layoutStruct[pos].logicalWidth.isPercentOrCalc() | 487 m_layoutStruct[pos].logicalWidth.isPercentOrCalc() |
473 ? m_layoutStruct[pos].logicalWidth.percent() | 488 ? m_layoutStruct[pos].logicalWidth.percent() |
474 : m_layoutStruct[pos].effectiveLogicalWidth.percent(); | 489 : m_layoutStruct[pos].effectiveLogicalWidth.percent(); |
475 int columnMinLogicalWidth = | 490 int columnMinLogicalWidth = |
476 static_cast<int>(percent * cellMinLogicalWidth / totalPercent); | 491 static_cast<int>(percent * cellMinLogicalWidth / totalPercent); |
477 int columnMaxLogicalWidth = | 492 int columnMaxLogicalWidth = |
478 static_cast<int>(percent * cellMaxLogicalWidth / totalPercent); | 493 static_cast<int>(percent * cellMaxLogicalWidth / totalPercent); |
479 m_layoutStruct[pos].effectiveMinLogicalWidth = | 494 m_layoutStruct[pos].effectiveMinLogicalWidth = |
480 std::max(m_layoutStruct[pos].effectiveMinLogicalWidth, | 495 std::max(m_layoutStruct[pos].effectiveMinLogicalWidth, |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
583 return; | 598 return; |
584 | 599 |
585 unsigned size = m_spanCells.size(); | 600 unsigned size = m_spanCells.size(); |
586 if (!size || m_spanCells[size - 1] != 0) { | 601 if (!size || m_spanCells[size - 1] != 0) { |
587 m_spanCells.grow(size + 10); | 602 m_spanCells.grow(size + 10); |
588 for (unsigned i = 0; i < 10; i++) | 603 for (unsigned i = 0; i < 10; i++) |
589 m_spanCells[size + i] = 0; | 604 m_spanCells[size + i] = 0; |
590 size += 10; | 605 size += 10; |
591 } | 606 } |
592 | 607 |
593 // add them in sort. This is a slow algorithm, and a binary search or a fast s orting after collection would be better | 608 // Add them in sort. This is a slow algorithm, and a binary search or a fast |
609 // sorting after collection would be better. | |
594 unsigned pos = 0; | 610 unsigned pos = 0; |
595 unsigned span = cell->colSpan(); | 611 unsigned span = cell->colSpan(); |
596 while (pos < m_spanCells.size() && m_spanCells[pos] && | 612 while (pos < m_spanCells.size() && m_spanCells[pos] && |
597 span > m_spanCells[pos]->colSpan()) | 613 span > m_spanCells[pos]->colSpan()) |
598 pos++; | 614 pos++; |
599 memmove(m_spanCells.data() + pos + 1, m_spanCells.data() + pos, | 615 memmove(m_spanCells.data() + pos + 1, m_spanCells.data() + pos, |
600 (size - pos - 1) * sizeof(LayoutTableCell*)); | 616 (size - pos - 1) * sizeof(LayoutTableCell*)); |
601 m_spanCells[pos] = cell; | 617 m_spanCells[pos] = cell; |
602 } | 618 } |
603 | 619 |
604 void TableLayoutAlgorithmAuto::layout() { | 620 void TableLayoutAlgorithmAuto::layout() { |
605 // table layout based on the values collected in the layout structure. | 621 // table layout based on the values collected in the layout structure. |
606 int tableLogicalWidth = (m_table->logicalWidth() - | 622 int tableLogicalWidth = (m_table->logicalWidth() - |
607 m_table->bordersPaddingAndSpacingInRowDirection()) | 623 m_table->bordersPaddingAndSpacingInRowDirection()) |
608 .toInt(); | 624 .toInt(); |
609 int available = tableLogicalWidth; | 625 int available = tableLogicalWidth; |
610 size_t nEffCols = m_table->numEffectiveColumns(); | 626 size_t nEffCols = m_table->numEffectiveColumns(); |
611 | 627 |
612 // FIXME: It is possible to be called without having properly updated our inte rnal representation. | 628 // FIXME: It is possible to be called without having properly updated our |
613 // This means that our preferred logical widths were not recomputed as expecte d. | 629 // internal representation. This means that our preferred logical widths were |
dcheng
2016/10/07 20:42:01
I don't feel that strongly about this (but it is i
| |
630 // not recomputed as expected. | |
614 if (nEffCols != m_layoutStruct.size()) { | 631 if (nEffCols != m_layoutStruct.size()) { |
615 fullRecalc(); | 632 fullRecalc(); |
616 // FIXME: Table layout shouldn't modify our table structure (but does due to columns and column-groups). | 633 // FIXME: Table layout shouldn't modify our table structure (but does due to |
634 // columns and column-groups). | |
617 nEffCols = m_table->numEffectiveColumns(); | 635 nEffCols = m_table->numEffectiveColumns(); |
618 } | 636 } |
619 | 637 |
620 if (m_effectiveLogicalWidthDirty) | 638 if (m_effectiveLogicalWidthDirty) |
621 calcEffectiveLogicalWidth(); | 639 calcEffectiveLogicalWidth(); |
622 | 640 |
623 bool havePercent = false; | 641 bool havePercent = false; |
624 int numAuto = 0; | 642 int numAuto = 0; |
625 int numFixed = 0; | 643 int numFixed = 0; |
626 float totalAuto = 0; | 644 float totalAuto = 0; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
674 } | 692 } |
675 } | 693 } |
676 if (totalPercent > 100) { | 694 if (totalPercent > 100) { |
677 // remove overallocated space from the last columns | 695 // remove overallocated space from the last columns |
678 int excess = tableLogicalWidth * (totalPercent - 100) / 100; | 696 int excess = tableLogicalWidth * (totalPercent - 100) / 100; |
679 for (unsigned i = nEffCols; i;) { | 697 for (unsigned i = nEffCols; i;) { |
680 --i; | 698 --i; |
681 if (m_layoutStruct[i].effectiveLogicalWidth.isPercentOrCalc()) { | 699 if (m_layoutStruct[i].effectiveLogicalWidth.isPercentOrCalc()) { |
682 int cellLogicalWidth = m_layoutStruct[i].computedLogicalWidth; | 700 int cellLogicalWidth = m_layoutStruct[i].computedLogicalWidth; |
683 int reduction = std::min(cellLogicalWidth, excess); | 701 int reduction = std::min(cellLogicalWidth, excess); |
684 // the lines below might look inconsistent, but that's the way it's ha ndled in mozilla | 702 // The lines below might look inconsistent, but that's the way it's |
703 // handled in mozilla. | |
685 excess -= reduction; | 704 excess -= reduction; |
686 int newLogicalWidth = | 705 int newLogicalWidth = |
687 std::max<int>(m_layoutStruct[i].effectiveMinLogicalWidth, | 706 std::max<int>(m_layoutStruct[i].effectiveMinLogicalWidth, |
688 cellLogicalWidth - reduction); | 707 cellLogicalWidth - reduction); |
689 available += cellLogicalWidth - newLogicalWidth; | 708 available += cellLogicalWidth - newLogicalWidth; |
690 m_layoutStruct[i].computedLogicalWidth = newLogicalWidth; | 709 m_layoutStruct[i].computedLogicalWidth = newLogicalWidth; |
691 } | 710 } |
692 } | 711 } |
693 } | 712 } |
694 } | 713 } |
695 | 714 |
696 // then allocate width to fixed cols | 715 // then allocate width to fixed cols |
697 if (available > 0) { | 716 if (available > 0) { |
698 for (size_t i = 0; i < nEffCols; ++i) { | 717 for (size_t i = 0; i < nEffCols; ++i) { |
699 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; | 718 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; |
700 if (logicalWidth.isFixed() && | 719 if (logicalWidth.isFixed() && |
701 logicalWidth.value() > m_layoutStruct[i].computedLogicalWidth) { | 720 logicalWidth.value() > m_layoutStruct[i].computedLogicalWidth) { |
702 available += | 721 available += |
703 m_layoutStruct[i].computedLogicalWidth - logicalWidth.value(); | 722 m_layoutStruct[i].computedLogicalWidth - logicalWidth.value(); |
704 m_layoutStruct[i].computedLogicalWidth = logicalWidth.value(); | 723 m_layoutStruct[i].computedLogicalWidth = logicalWidth.value(); |
705 } | 724 } |
706 } | 725 } |
707 } | 726 } |
708 | 727 |
709 // Give each auto width column its share of the available width, non-empty col umns then empty columns. | 728 // Give each auto width column its share of the available width, non-empty |
729 // columns then empty columns. | |
710 if (available > 0 && (numAuto || numAutoEmptyCellsOnly)) { | 730 if (available > 0 && (numAuto || numAutoEmptyCellsOnly)) { |
711 available += allocAuto; | 731 available += allocAuto; |
712 if (numAuto) | 732 if (numAuto) |
713 distributeWidthToColumns<float, Auto, NonEmptyCells, InitialWidth, | 733 distributeWidthToColumns<float, Auto, NonEmptyCells, InitialWidth, |
714 StartToEnd>(available, totalAuto); | 734 StartToEnd>(available, totalAuto); |
715 if (numAutoEmptyCellsOnly) | 735 if (numAutoEmptyCellsOnly) |
716 distributeWidthToColumns<unsigned, Auto, EmptyCells, InitialWidth, | 736 distributeWidthToColumns<unsigned, Auto, EmptyCells, InitialWidth, |
717 StartToEnd>(available, numAutoEmptyCellsOnly); | 737 StartToEnd>(available, numAutoEmptyCellsOnly); |
718 } | 738 } |
719 | 739 |
720 // Any remaining available width expands fixed width, percent width, and non-e mpty auto width columns, in that order. | 740 // Any remaining available width expands fixed width, percent width, and |
741 // non-empty auto width columns, in that order. | |
721 if (available > 0 && numFixed) | 742 if (available > 0 && numFixed) |
722 distributeWidthToColumns<float, Fixed, AllCells, ExtraWidth, StartToEnd>( | 743 distributeWidthToColumns<float, Fixed, AllCells, ExtraWidth, StartToEnd>( |
723 available, totalFixed); | 744 available, totalFixed); |
724 | 745 |
725 if (available > 0 && m_hasPercent && totalPercent < 100) | 746 if (available > 0 && m_hasPercent && totalPercent < 100) |
726 distributeWidthToColumns<float, Percent, AllCells, ExtraWidth, StartToEnd>( | 747 distributeWidthToColumns<float, Percent, AllCells, ExtraWidth, StartToEnd>( |
727 available, totalPercent); | 748 available, totalPercent); |
728 | 749 |
729 if (available > 0 && nEffCols > numAutoEmptyCellsOnly) { | 750 if (available > 0 && nEffCols > numAutoEmptyCellsOnly) { |
730 unsigned total = nEffCols - numAutoEmptyCellsOnly; | 751 unsigned total = nEffCols - numAutoEmptyCellsOnly; |
731 // Starting from the last cell is for compatibility with FF/IE - it isn't sp ecified anywhere. | 752 // Starting from the last cell is for compatibility with FF/IE - it isn't |
753 // specified anywhere. | |
732 distributeWidthToColumns<unsigned, Auto, NonEmptyCells, LeftoverWidth, | 754 distributeWidthToColumns<unsigned, Auto, NonEmptyCells, LeftoverWidth, |
733 EndToStart>(available, total); | 755 EndToStart>(available, total); |
734 } | 756 } |
735 | 757 |
736 // If we have overallocated, reduce every cell according to the difference bet ween desired width and minwidth | 758 // If we have overallocated, reduce every cell according to the difference |
737 // this seems to produce to the pixel exact results with IE. Wonder is some of this also holds for width distributing. | 759 // between desired width and minwidth. This seems to produce to the pixel |
738 // This is basically the reverse of how we grew the cells. | 760 // exact results with IE. Wonder is some of this also holds for width |
761 // distributing. This is basically the reverse of how we grew the cells. | |
739 if (available < 0) | 762 if (available < 0) |
740 shrinkColumnWidth(Auto, available); | 763 shrinkColumnWidth(Auto, available); |
741 if (available < 0) | 764 if (available < 0) |
742 shrinkColumnWidth(Fixed, available); | 765 shrinkColumnWidth(Fixed, available); |
743 if (available < 0) | 766 if (available < 0) |
744 shrinkColumnWidth(Percent, available); | 767 shrinkColumnWidth(Percent, available); |
745 | 768 |
746 ASSERT(m_table->effectiveColumnPositions().size() == nEffCols + 1); | 769 ASSERT(m_table->effectiveColumnPositions().size() == nEffCols + 1); |
747 int pos = 0; | 770 int pos = 0; |
748 for (size_t i = 0; i < nEffCols; ++i) { | 771 for (size_t i = 0; i < nEffCols; ++i) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
828 int reduce = available * minMaxDiff / logicalWidthBeyondMin; | 851 int reduce = available * minMaxDiff / logicalWidthBeyondMin; |
829 m_layoutStruct[i].computedLogicalWidth += reduce; | 852 m_layoutStruct[i].computedLogicalWidth += reduce; |
830 available -= reduce; | 853 available -= reduce; |
831 logicalWidthBeyondMin -= minMaxDiff; | 854 logicalWidthBeyondMin -= minMaxDiff; |
832 if (available >= 0) | 855 if (available >= 0) |
833 break; | 856 break; |
834 } | 857 } |
835 } | 858 } |
836 } | 859 } |
837 } // namespace blink | 860 } // namespace blink |
OLD | NEW |