Chromium Code Reviews| 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 |