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 * |
| 11 * This library is distributed in the hope that it will be useful, | 11 * This library is distributed in the hope that it will be useful, |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 * Library General Public License for more details. | 14 * Library General Public License for more details. |
| 15 * | 15 * |
| 16 * You should have received a copy of the GNU Library General Public License | 16 * You should have received a copy of the GNU Library General Public License |
| 17 * along with this library; see the file COPYING.LIB. If not, write to | 17 * along with this library; see the file COPYING.LIB. If not, write to |
| 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 19 * Boston, MA 02110-1301, USA. | 19 * Boston, MA 02110-1301, USA. |
| 20 */ | 20 */ |
| 21 | 21 |
| 22 #include "config.h" | 22 #include "config.h" |
| 23 #include "core/layout/TableLayoutAlgorithmAuto.h" | 23 #include "core/layout/TableLayoutAlgorithmAuto.h" |
| 24 | 24 |
| 25 #include "core/layout/LayoutTable.h" | 25 #include "core/layout/LayoutTable.h" |
| 26 #include "core/layout/LayoutTableCell.h" | 26 #include "core/layout/LayoutTableCell.h" |
| 27 #include "core/layout/LayoutTableCol.h" | 27 #include "core/layout/LayoutTableCol.h" |
| 28 #include "core/layout/LayoutTableSection.h" | 28 #include "core/layout/LayoutTableSection.h" |
| 29 #include "core/layout/LayoutText.h" | |
| 29 #include "core/layout/TextAutosizer.h" | 30 #include "core/layout/TextAutosizer.h" |
| 30 | 31 |
| 31 namespace blink { | 32 namespace blink { |
| 32 | 33 |
| 33 TableLayoutAlgorithmAuto::TableLayoutAlgorithmAuto(LayoutTable* table) | 34 TableLayoutAlgorithmAuto::TableLayoutAlgorithmAuto(LayoutTable* table) |
| 34 : TableLayoutAlgorithm(table) | 35 : TableLayoutAlgorithm(table) |
| 35 , m_hasPercent(false) | 36 , m_hasPercent(false) |
| 36 , m_effectiveLogicalWidthDirty(true) | 37 , m_effectiveLogicalWidthDirty(true) |
| 37 { | 38 { |
| 38 } | 39 } |
| 39 | 40 |
| 40 TableLayoutAlgorithmAuto::~TableLayoutAlgorithmAuto() | 41 TableLayoutAlgorithmAuto::~TableLayoutAlgorithmAuto() |
| 41 { | 42 { |
| 42 } | 43 } |
| 43 | 44 |
| 45 static bool isEmptyCell(LayoutObject* object) | |
| 46 { | |
| 47 for (LayoutObject* curr = object; curr; curr = curr->nextSibling()) { | |
| 48 if (curr->isText() && toLayoutText(curr)->isAllCollapsibleWhitespace()) | |
| 49 continue; | |
| 50 return false; | |
| 51 } | |
| 52 return true; | |
| 53 } | |
| 54 | |
| 44 void TableLayoutAlgorithmAuto::recalcColumn(unsigned effCol) | 55 void TableLayoutAlgorithmAuto::recalcColumn(unsigned effCol) |
| 45 { | 56 { |
| 46 Layout& columnLayout = m_layoutStruct[effCol]; | 57 Layout& columnLayout = m_layoutStruct[effCol]; |
| 47 | 58 |
| 48 LayoutTableCell* fixedContributor = 0; | 59 LayoutTableCell* fixedContributor = 0; |
| 49 LayoutTableCell* maxContributor = 0; | 60 LayoutTableCell* maxContributor = 0; |
| 50 | 61 |
| 51 for (LayoutObject* child = m_table->children()->firstChild(); child; child = child->nextSibling()) { | 62 for (LayoutObject* child = m_table->children()->firstChild(); child; child = child->nextSibling()) { |
| 52 if (child->isLayoutTableCol()) { | 63 if (child->isLayoutTableCol()) { |
| 53 // LayoutTableCols don't have the concept of preferred logical width , but we need to clear their dirty bits | 64 // LayoutTableCols don't have the concept of preferred logical width , but we need to clear their dirty bits |
| 54 // so that if we call setPreferredWidthsDirty(true) on a col or one of its descendants, we'll mark it's | 65 // so that if we call setPreferredWidthsDirty(true) on a col or one of its descendants, we'll mark it's |
| 55 // ancestors as dirty. | 66 // ancestors as dirty. |
| 56 toLayoutTableCol(child)->clearPreferredLogicalWidthsDirtyBits(); | 67 toLayoutTableCol(child)->clearPreferredLogicalWidthsDirtyBits(); |
| 57 } else if (child->isTableSection()) { | 68 } else if (child->isTableSection()) { |
| 58 LayoutTableSection* section = toLayoutTableSection(child); | 69 LayoutTableSection* section = toLayoutTableSection(child); |
| 59 unsigned numRows = section->numRows(); | 70 unsigned numRows = section->numRows(); |
| 60 for (unsigned i = 0; i < numRows; i++) { | 71 for (unsigned i = 0; i < numRows; i++) { |
| 61 LayoutTableSection::CellStruct current = section->cellAt(i, effC ol); | 72 LayoutTableSection::CellStruct current = section->cellAt(i, effC ol); |
| 62 LayoutTableCell* cell = current.primaryCell(); | 73 LayoutTableCell* cell = current.primaryCell(); |
| 63 | 74 |
| 64 if (current.inColSpan || !cell) | 75 if (current.inColSpan || !cell) |
| 65 continue; | 76 continue; |
| 66 | 77 |
| 67 bool cellHasContent = cell->children()->firstChild() || cell->st yle()->hasBorder() || cell->style()->hasPadding() || cell->style()->hasBackgroun d(); | 78 bool cellHasContent = !isEmptyCell(cell->firstChild()) || cell-> style()->hasBorder() || cell->style()->hasPadding() || cell->style()->hasBackgro und(); |
| 68 if (cellHasContent) | 79 if (cellHasContent) |
| 69 columnLayout.emptyCellsOnly = false; | 80 columnLayout.emptyCellsOnly = false; |
| 70 | 81 |
| 71 // A cell originates in this column. Ensure we have | 82 // A cell originates in this column. Ensure we have |
| 72 // a min/max width of at least 1px for this column now. | 83 // a min/max width of at least 1px for this column now. |
| 73 columnLayout.minLogicalWidth = std::max<int>(columnLayout.minLog icalWidth, cellHasContent ? 1 : 0); | 84 columnLayout.minLogicalWidth = std::max<int>(columnLayout.minLog icalWidth, cellHasContent ? 1 : 0); |
| 74 columnLayout.maxLogicalWidth = std::max<int>(columnLayout.maxLog icalWidth, 1); | |
| 75 | 85 |
| 76 if (cell->colSpan() == 1) { | 86 if (cell->colSpan() == 1) { |
| 77 columnLayout.minLogicalWidth = std::max<int>(cell->minPrefer redLogicalWidth(), columnLayout.minLogicalWidth); | 87 columnLayout.minLogicalWidth = std::max<int>(cell->minPrefer redLogicalWidth(), columnLayout.minLogicalWidth); |
| 78 if (cell->maxPreferredLogicalWidth() > columnLayout.maxLogic alWidth) { | 88 if (cell->maxPreferredLogicalWidth() > columnLayout.maxLogic alWidth) { |
| 79 columnLayout.maxLogicalWidth = cell->maxPreferredLogical Width(); | 89 columnLayout.maxLogicalWidth = cell->maxPreferredLogical Width(); |
| 80 maxContributor = cell; | 90 maxContributor = cell; |
| 81 } | 91 } |
| 82 | 92 |
| 83 // All browsers implement a size limit on the cell's max wid th. | 93 // All browsers implement a size limit on the cell's max wid th. |
| 84 // Our limit is based on KHTML's representation that used 16 bits widths. | 94 // Our limit is based on KHTML's representation that used 16 bits widths. |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 367 // all non percent columns in the span get percent values to sum up correctly. | 377 // all non percent columns in the span get percent values to sum up correctly. |
| 368 float percentMissing = cellLogicalWidth.percent() - totalPercent ; | 378 float percentMissing = cellLogicalWidth.percent() - totalPercent ; |
| 369 int totalWidth = 0; | 379 int totalWidth = 0; |
| 370 for (unsigned pos = effCol; pos < lastCol; ++pos) { | 380 for (unsigned pos = effCol; pos < lastCol; ++pos) { |
| 371 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) | 381 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) |
| 372 totalWidth += m_layoutStruct[pos].effectiveMaxLogicalWid th; | 382 totalWidth += m_layoutStruct[pos].effectiveMaxLogicalWid th; |
| 373 } | 383 } |
| 374 | 384 |
| 375 for (unsigned pos = effCol; pos < lastCol && totalWidth > 0; ++p os) { | 385 for (unsigned pos = effCol; pos < lastCol && totalWidth > 0; ++p os) { |
| 376 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) { | 386 if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) { |
| 377 float percent = percentMissing * static_cast<float>(m_la youtStruct[pos].effectiveMaxLogicalWidth) / totalWidth; | 387 float percent = percentMissing * static_cast<float>(std: :max<int>(1, m_layoutStruct[pos].effectiveMaxLogicalWidth)) / totalWidth; |
| 378 totalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWid th; | 388 totalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWid th; |
| 379 percentMissing -= percent; | 389 percentMissing -= percent; |
| 380 if (percent > 0) | 390 if (percent > 0) |
| 381 m_layoutStruct[pos].effectiveLogicalWidth.setValue(P ercent, percent); | 391 m_layoutStruct[pos].effectiveLogicalWidth.setValue(P ercent, percent); |
| 382 else | 392 else |
| 383 m_layoutStruct[pos].effectiveLogicalWidth = Length() ; | 393 m_layoutStruct[pos].effectiveLogicalWidth = Length() ; |
| 384 } | 394 } |
| 385 } | 395 } |
| 386 } | 396 } |
| 387 } | 397 } |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; | 536 m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; |
| 527 available -= cellLogicalWidth; | 537 available -= cellLogicalWidth; |
| 528 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; | 538 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; |
| 529 switch (logicalWidth.type()) { | 539 switch (logicalWidth.type()) { |
| 530 case Percent: | 540 case Percent: |
| 531 havePercent = true; | 541 havePercent = true; |
| 532 totalPercent += logicalWidth.percent(); | 542 totalPercent += logicalWidth.percent(); |
| 533 break; | 543 break; |
| 534 case Fixed: | 544 case Fixed: |
| 535 numFixed++; | 545 numFixed++; |
| 536 totalFixed += m_layoutStruct[i].effectiveMaxLogicalWidth; | 546 totalFixed += std::max<int>(1, m_layoutStruct[i].effectiveMaxLogical Width); |
|
dsinclair
2015/03/24 00:03:48
We do this a bunch of times, would it be better to
mstensho (USE GERRIT)
2015/03/24 08:36:37
I don't think I understand why it's still necessar
rhogan
2015/03/24 20:06:11
It uses the clamped value when deciding what propo
mstensho (USE GERRIT)
2015/03/25 10:10:52
I think that it's the width distribution algorithm
| |
| 537 // fall through | 547 // fall through |
| 538 break; | 548 break; |
| 539 case Auto: | 549 case Auto: |
| 540 if (m_layoutStruct[i].emptyCellsOnly) { | 550 if (m_layoutStruct[i].emptyCellsOnly) { |
| 541 numAutoEmptyCellsOnly++; | 551 numAutoEmptyCellsOnly++; |
| 542 } else { | 552 } else { |
| 543 numAuto++; | 553 numAuto++; |
| 544 totalAuto += m_layoutStruct[i].effectiveMaxLogicalWidth; | 554 totalAuto += std::max<int>(1, m_layoutStruct[i].effectiveMaxLogi calWidth); |
| 545 allocAuto += cellLogicalWidth; | 555 allocAuto += cellLogicalWidth; |
| 546 } | 556 } |
| 547 break; | 557 break; |
| 548 default: | 558 default: |
| 549 break; | 559 break; |
| 550 } | 560 } |
| 551 } | 561 } |
| 552 | 562 |
| 553 // allocate width to percent cols | 563 // allocate width to percent cols |
| 554 if (available > 0 && havePercent) { | 564 if (available > 0 && havePercent) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 } | 598 } |
| 589 } | 599 } |
| 590 } | 600 } |
| 591 | 601 |
| 592 // now satisfy variable | 602 // now satisfy variable |
| 593 if (available > 0 && numAuto) { | 603 if (available > 0 && numAuto) { |
| 594 available += allocAuto; // this gets redistributed | 604 available += allocAuto; // this gets redistributed |
| 595 for (size_t i = 0; i < nEffCols; ++i) { | 605 for (size_t i = 0; i < nEffCols; ++i) { |
| 596 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; | 606 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; |
| 597 if (logicalWidth.isAuto() && totalAuto && !m_layoutStruct[i].emptyCe llsOnly) { | 607 if (logicalWidth.isAuto() && totalAuto && !m_layoutStruct[i].emptyCe llsOnly) { |
| 598 int cellLogicalWidth = std::max<int>(m_layoutStruct[i].computedL ogicalWidth, static_cast<int>(available * static_cast<float>(m_layoutStruct[i].e ffectiveMaxLogicalWidth) / totalAuto)); | 608 int cellLogicalWidth = std::max<int>(m_layoutStruct[i].computedL ogicalWidth, static_cast<int>(available * static_cast<float>(std::max<int>(1, m_ layoutStruct[i].effectiveMaxLogicalWidth)) / totalAuto)); |
| 599 available -= cellLogicalWidth; | 609 available -= cellLogicalWidth; |
| 600 totalAuto -= m_layoutStruct[i].effectiveMaxLogicalWidth; | 610 totalAuto -= std::max<int>(1, m_layoutStruct[i].effectiveMaxLogi calWidth); |
| 601 m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; | 611 m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; |
| 602 } | 612 } |
| 603 } | 613 } |
| 604 } | 614 } |
| 605 | 615 |
| 606 // spread over fixed columns | 616 // spread over fixed columns |
| 607 if (available > 0 && numFixed) { | 617 if (available > 0 && numFixed) { |
| 608 for (size_t i = 0; i < nEffCols; ++i) { | 618 for (size_t i = 0; i < nEffCols; ++i) { |
| 609 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; | 619 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; |
| 610 if (logicalWidth.isFixed()) { | 620 if (logicalWidth.isFixed()) { |
| 611 int cellLogicalWidth = static_cast<int>(available * static_cast< float>(m_layoutStruct[i].effectiveMaxLogicalWidth) / totalFixed); | 621 int cellLogicalWidth = static_cast<int>(available * static_cast< float>(std::max<int>(1, m_layoutStruct[i].effectiveMaxLogicalWidth)) / totalFixe d); |
| 612 available -= cellLogicalWidth; | 622 available -= cellLogicalWidth; |
| 613 totalFixed -= m_layoutStruct[i].effectiveMaxLogicalWidth; | 623 totalFixed -= std::max<int>(1, m_layoutStruct[i].effectiveMaxLog icalWidth); |
| 614 m_layoutStruct[i].computedLogicalWidth += cellLogicalWidth; | 624 m_layoutStruct[i].computedLogicalWidth += cellLogicalWidth; |
| 615 } | 625 } |
| 616 } | 626 } |
| 617 } | 627 } |
| 618 | 628 |
| 619 // spread over percent colums | 629 // spread over percent colums |
| 620 if (available > 0 && m_hasPercent && totalPercent < 100) { | 630 if (available > 0 && m_hasPercent && totalPercent < 100) { |
| 621 for (size_t i = 0; i < nEffCols; ++i) { | 631 for (size_t i = 0; i < nEffCols; ++i) { |
| 622 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; | 632 Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; |
| 623 if (logicalWidth.isPercent()) { | 633 if (logicalWidth.isPercent()) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 730 | 740 |
| 731 int pos = 0; | 741 int pos = 0; |
| 732 for (size_t i = 0; i < nEffCols; ++i) { | 742 for (size_t i = 0; i < nEffCols; ++i) { |
| 733 m_table->setColumnPosition(i, pos); | 743 m_table->setColumnPosition(i, pos); |
| 734 pos += m_layoutStruct[i].computedLogicalWidth + m_table->hBorderSpacing( ); | 744 pos += m_layoutStruct[i].computedLogicalWidth + m_table->hBorderSpacing( ); |
| 735 } | 745 } |
| 736 m_table->setColumnPosition(m_table->columnPositions().size() - 1, pos); | 746 m_table->setColumnPosition(m_table->columnPositions().size() - 1, pos); |
| 737 } | 747 } |
| 738 | 748 |
| 739 } | 749 } |
| OLD | NEW |