Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/MultiColumnFragmentainerGroup.h" | 5 #include "core/layout/MultiColumnFragmentainerGroup.h" |
| 6 | 6 |
| 7 #include "core/layout/ColumnBalancer.h" | 7 #include "core/layout/ColumnBalancer.h" |
| 8 #include "core/layout/FragmentationContext.h" | 8 #include "core/layout/FragmentationContext.h" |
| 9 #include "core/layout/LayoutMultiColumnSet.h" | 9 #include "core/layout/LayoutMultiColumnSet.h" |
| 10 | 10 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 91 // columns may have changed as well. | 91 // columns may have changed as well. |
| 92 setAndConstrainColumnHeight(m_columnHeight); | 92 setAndConstrainColumnHeight(m_columnHeight); |
| 93 } | 93 } |
| 94 | 94 |
| 95 if (m_columnHeight == oldColumnHeight) | 95 if (m_columnHeight == oldColumnHeight) |
| 96 return false; // No change. We're done. | 96 return false; // No change. We're done. |
| 97 | 97 |
| 98 return true; // Need another pass. | 98 return true; // Need another pass. |
| 99 } | 99 } |
| 100 | 100 |
| 101 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread, CoordinateSpaceConversion mode) const | 101 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread, LayoutBox::PageBoundaryRule rule, CoordinateSpaceConversi on mode) const |
| 102 { | 102 { |
| 103 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( ); | 103 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( ); |
| 104 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); | 104 |
| 105 // A column out of range doesn't have a flow thread portion, so we need to c lamp to make sure | |
| 106 // that we stay within the actual columns. This means that content in the ov erflow area will be | |
| 107 // mapped to the last actual column, instead of being mapped to an imaginary column further | |
| 108 // ahead. | |
| 109 unsigned columnIndex = offsetInFlowThread >= logicalBottomInFlowThread() ? a ctualColumnCount() - 1 : columnIndexAtOffset(offsetInFlowThread, rule); | |
|
eae
2016/09/14 22:08:47
Maybe add a DCHECK(actualColumnCount() > 0) before
mstensho (USE GERRIT)
2016/09/15 06:37:50
There are already other actualColumnCount() - 1 ex
| |
| 110 | |
| 105 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); | 111 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); |
| 106 flowThread->flipForWritingMode(portionRect); | 112 flowThread->flipForWritingMode(portionRect); |
| 107 LayoutRect columnRect(columnRectAt(columnIndex)); | 113 LayoutRect columnRect(columnRectAt(columnIndex)); |
| 108 m_columnSet.flipForWritingMode(columnRect); | 114 m_columnSet.flipForWritingMode(columnRect); |
| 109 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); | 115 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); |
| 110 LayoutSize translationRelativeToFlowThread = translationRelativeToGroup + of fsetFromColumnSet() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftL ocationOffset(); | 116 LayoutSize translationRelativeToFlowThread = translationRelativeToGroup + of fsetFromColumnSet() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftL ocationOffset(); |
| 111 if (mode == CoordinateSpaceConversion::Containing) | 117 if (mode == CoordinateSpaceConversion::Containing) |
| 112 return translationRelativeToFlowThread; | 118 return translationRelativeToFlowThread; |
| 113 | 119 |
| 114 LayoutSize enclosingTranslation; | 120 LayoutSize enclosingTranslation; |
| 115 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) { | 121 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) { |
| 116 const MultiColumnFragmentainerGroup& firstRow = flowThread->firstMultiCo lumnSet()->firstFragmentainerGroup(); | 122 const MultiColumnFragmentainerGroup& firstRow = flowThread->firstMultiCo lumnSet()->firstFragmentainerGroup(); |
| 117 // Translation that would map points in the coordinate space of the oute rmost flow thread to | 123 // Translation that would map points in the coordinate space of the oute rmost flow thread to |
| 118 // visual points in the first column in the first fragmentainer group (r ow) in our multicol | 124 // visual points in the first column in the first fragmentainer group (r ow) in our multicol |
| 119 // container. | 125 // container. |
| 120 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(firstRow.blockOffsetInEnclosingFragmentationContext(), mode); | 126 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(firstRow.blockOffsetInEnclosingFragmentationContext(), Layout Box::AssociateWithLatterPage, mode); |
| 121 | 127 |
| 122 // Translation that would map points in the coordinate space of the oute rmost flow thread to | 128 // Translation that would map points in the coordinate space of the oute rmost flow thread to |
| 123 // visual points in the first column in this fragmentainer group. | 129 // visual points in the first column in this fragmentainer group. |
| 124 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFragmentationContext(), mode); | 130 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFragmentationContext(), LayoutBox::AssociateWithLatterPa ge, mode); |
| 125 | 131 |
| 126 // What we ultimately return from this method is a translation that maps points in the | 132 // What we ultimately return from this method is a translation that maps points in the |
| 127 // coordinate space of our flow thread to a visual point in a certain co lumn in this | 133 // coordinate space of our flow thread to a visual point in a certain co lumn in this |
| 128 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this | 134 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this |
| 129 // fragmentainer group may be in a different outer column than the first outer column that | 135 // fragmentainer group may be in a different outer column than the first outer column that |
| 130 // this multicol container lives in. It's the visual distance between th e first | 136 // this multicol container lives in. It's the visual distance between th e first |
| 131 // fragmentainer group and this fragmentainer group that we need to add to the translation. | 137 // fragmentainer group and this fragmentainer group that we need to add to the translation. |
| 132 enclosingTranslation -= enclosingTranslationOrigin; | 138 enclosingTranslation -= enclosingTranslationOrigin; |
| 133 } | 139 } |
| 134 | 140 |
| 135 return enclosingTranslation + translationRelativeToFlowThread; | 141 return enclosingTranslation + translationRelativeToFlowThread; |
| 136 } | 142 } |
| 137 | 143 |
| 138 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const | 144 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const |
| 139 { | 145 { |
| 140 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns); | 146 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, LayoutBox::As sociateWithLatterPage); |
| 141 return logicalTopInFlowThreadAt(columnIndex); | 147 return logicalTopInFlowThreadAt(columnIndex); |
| 142 } | 148 } |
| 143 | 149 |
| 144 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const | 150 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const |
| 145 { | 151 { |
| 146 unsigned columnIndex = columnIndexAtVisualPoint(visualPoint); | 152 unsigned columnIndex = columnIndexAtVisualPoint(visualPoint); |
| 147 LayoutRect columnRect = columnRectAt(columnIndex); | 153 LayoutRect columnRect = columnRectAt(columnIndex); |
| 148 LayoutPoint localPoint(visualPoint); | 154 LayoutPoint localPoint(visualPoint); |
| 149 localPoint.moveBy(-columnRect.location()); | 155 localPoint.moveBy(-columnRect.location()); |
| 150 // Before converting to a flow thread position, if the block direction coord inate is outside the | 156 // Before converting to a flow thread position, if the block direction coord inate is outside the |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 180 if (boundingBoxLogicalBottom <= logicalTopInFlowThread() || boundingBoxLogic alTop >= logicalBottomInFlowThread()) | 186 if (boundingBoxLogicalBottom <= logicalTopInFlowThread() || boundingBoxLogic alTop >= logicalBottomInFlowThread()) |
| 181 return LayoutRect(); // The bounding box doesn't intersect this fragment ainer group. | 187 return LayoutRect(); // The bounding box doesn't intersect this fragment ainer group. |
| 182 unsigned startColumn; | 188 unsigned startColumn; |
| 183 unsigned endColumn; | 189 unsigned endColumn; |
| 184 columnIntervalForBlockRangeInFlowThread(boundingBoxLogicalTop, boundingBoxLo gicalBottom, startColumn, endColumn); | 190 columnIntervalForBlockRangeInFlowThread(boundingBoxLogicalTop, boundingBoxLo gicalBottom, startColumn, endColumn); |
| 185 | 191 |
| 186 LayoutRect startColumnFlowThreadOverflowPortion = flowThreadPortionOverflowR ectAt(startColumn); | 192 LayoutRect startColumnFlowThreadOverflowPortion = flowThreadPortionOverflowR ectAt(startColumn); |
| 187 flowThread->flipForWritingMode(startColumnFlowThreadOverflowPortion); | 193 flowThread->flipForWritingMode(startColumnFlowThreadOverflowPortion); |
| 188 LayoutRect startColumnRect(boundingBoxInFlowThread); | 194 LayoutRect startColumnRect(boundingBoxInFlowThread); |
| 189 startColumnRect.intersect(startColumnFlowThreadOverflowPortion); | 195 startColumnRect.intersect(startColumnFlowThreadOverflowPortion); |
| 190 startColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt( startColumn), CoordinateSpaceConversion::Containing)); | 196 startColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt( startColumn), LayoutBox::AssociateWithLatterPage, CoordinateSpaceConversion::Con taining)); |
| 191 if (startColumn == endColumn) | 197 if (startColumn == endColumn) |
| 192 return startColumnRect; // It all takes place in one column. We're done. | 198 return startColumnRect; // It all takes place in one column. We're done. |
| 193 | 199 |
| 194 LayoutRect endColumnFlowThreadOverflowPortion = flowThreadPortionOverflowRec tAt(endColumn); | 200 LayoutRect endColumnFlowThreadOverflowPortion = flowThreadPortionOverflowRec tAt(endColumn); |
| 195 flowThread->flipForWritingMode(endColumnFlowThreadOverflowPortion); | 201 flowThread->flipForWritingMode(endColumnFlowThreadOverflowPortion); |
| 196 LayoutRect endColumnRect(boundingBoxInFlowThread); | 202 LayoutRect endColumnRect(boundingBoxInFlowThread); |
| 197 endColumnRect.intersect(endColumnFlowThreadOverflowPortion); | 203 endColumnRect.intersect(endColumnFlowThreadOverflowPortion); |
| 198 endColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt(en dColumn), CoordinateSpaceConversion::Containing)); | 204 endColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt(en dColumn), LayoutBox::AssociateWithLatterPage, CoordinateSpaceConversion::Contain ing)); |
| 199 return unionRect(startColumnRect, endColumnRect); | 205 return unionRect(startColumnRect, endColumnRect); |
| 200 } | 206 } |
| 201 | 207 |
| 202 LayoutRect MultiColumnFragmentainerGroup::calculateOverflow() const | 208 LayoutRect MultiColumnFragmentainerGroup::calculateOverflow() const |
| 203 { | 209 { |
| 204 // Note that we just return the bounding rectangle of the column boxes here. We currently don't | 210 // Note that we just return the bounding rectangle of the column boxes here. We currently don't |
| 205 // examine overflow caused by the actual content that ends up in each column . | 211 // examine overflow caused by the actual content that ends up in each column . |
| 206 LayoutRect overflowRect; | 212 LayoutRect overflowRect; |
| 207 if (unsigned columnCount = actualColumnCount()) { | 213 if (unsigned columnCount = actualColumnCount()) { |
| 208 overflowRect = columnRectAt(0); | 214 overflowRect = columnRectAt(0); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); | 384 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); |
| 379 } else { | 385 } else { |
| 380 if (!isLeftmostColumn) | 386 if (!isLeftmostColumn) |
| 381 overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2); | 387 overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2); |
| 382 if (!isRightmostColumn) | 388 if (!isRightmostColumn) |
| 383 overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap - column Gap / 2); | 389 overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap - column Gap / 2); |
| 384 } | 390 } |
| 385 return overflowRect; | 391 return overflowRect; |
| 386 } | 392 } |
| 387 | 393 |
| 388 unsigned MultiColumnFragmentainerGroup::columnIndexAtOffset(LayoutUnit offsetInF lowThread, ColumnIndexCalculationMode mode) const | 394 unsigned MultiColumnFragmentainerGroup::columnIndexAtOffset(LayoutUnit offsetInF lowThread, LayoutBox::PageBoundaryRule pageBoundaryRule) const |
| 389 { | 395 { |
| 390 // Handle the offset being out of range. | 396 // Handle the offset being out of range. |
| 391 if (offsetInFlowThread < m_logicalTopInFlowThread) | 397 if (offsetInFlowThread < m_logicalTopInFlowThread) |
| 392 return 0; | 398 return 0; |
| 393 // If we're laying out right now, we cannot constrain against some logical b ottom, since it | 399 |
| 394 // isn't known yet. Otherwise, just return the last column if we're past the logical bottom. | 400 if (!m_columnHeight) |
| 395 if (mode == ClampToExistingColumns) { | 401 return 0; |
| 396 if (offsetInFlowThread >= m_logicalBottomInFlowThread) | 402 unsigned columnIndex = ((offsetInFlowThread - m_logicalTopInFlowThread) / m_ columnHeight).floor(); |
| 397 return actualColumnCount() - 1; | 403 if (pageBoundaryRule == LayoutBox::AssociateWithFormerPage |
| 404 && columnIndex > 0 && logicalTopInFlowThreadAt(columnIndex) == offsetInF lowThread) { | |
| 405 // We are exactly at a column boundary, and we've been told to associate offsets at column | |
| 406 // boundaries with the former column, not the latter. | |
| 407 columnIndex--; | |
| 398 } | 408 } |
| 399 | 409 return columnIndex; |
| 400 if (m_columnHeight) | |
| 401 return ((offsetInFlowThread - m_logicalTopInFlowThread) / m_columnHeight ).floor(); | |
| 402 return 0; | |
| 403 } | 410 } |
| 404 | 411 |
| 405 unsigned MultiColumnFragmentainerGroup::columnIndexAtVisualPoint(const LayoutPoi nt& visualPoint) const | 412 unsigned MultiColumnFragmentainerGroup::columnIndexAtVisualPoint(const LayoutPoi nt& visualPoint) const |
| 406 { | 413 { |
| 407 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline(); | 414 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline(); |
| 408 bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode(); | 415 bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode(); |
| 409 LayoutUnit columnLengthInColumnProgressionDirection = isColumnProgressionInl ine ? m_columnSet.pageLogicalWidth() : logicalHeight(); | 416 LayoutUnit columnLengthInColumnProgressionDirection = isColumnProgressionInl ine ? m_columnSet.pageLogicalWidth() : logicalHeight(); |
| 410 LayoutUnit offsetInColumnProgressionDirection = isHorizontalWritingMode == i sColumnProgressionInline ? visualPoint.x() : visualPoint.y(); | 417 LayoutUnit offsetInColumnProgressionDirection = isHorizontalWritingMode == i sColumnProgressionInline ? visualPoint.x() : visualPoint.y(); |
| 411 if (!m_columnSet.style()->isLeftToRightDirection() && isColumnProgressionInl ine) | 418 if (!m_columnSet.style()->isLeftToRightDirection() && isColumnProgressionInl ine) |
| 412 offsetInColumnProgressionDirection = m_columnSet.logicalWidth() - offset InColumnProgressionDirection; | 419 offsetInColumnProgressionDirection = m_columnSet.logicalWidth() - offset InColumnProgressionDirection; |
| 413 LayoutUnit columnGap = m_columnSet.columnGap(); | 420 LayoutUnit columnGap = m_columnSet.columnGap(); |
| 414 if (columnLengthInColumnProgressionDirection + columnGap <= 0) | 421 if (columnLengthInColumnProgressionDirection + columnGap <= 0) |
| 415 return 0; | 422 return 0; |
| 416 // Column boundaries are in the middle of the column gap. | 423 // Column boundaries are in the middle of the column gap. |
| 417 int index = ((offsetInColumnProgressionDirection + columnGap / 2) / (columnL engthInColumnProgressionDirection + columnGap)).toInt(); | 424 int index = ((offsetInColumnProgressionDirection + columnGap / 2) / (columnL engthInColumnProgressionDirection + columnGap)).toInt(); |
| 418 if (index < 0) | 425 if (index < 0) |
| 419 return 0; | 426 return 0; |
| 420 return std::min(unsigned(index), actualColumnCount() - 1); | 427 return std::min(unsigned(index), actualColumnCount() - 1); |
| 421 } | 428 } |
| 422 | 429 |
| 423 void MultiColumnFragmentainerGroup::columnIntervalForBlockRangeInFlowThread(Layo utUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread, unsigned& f irstColumn, unsigned& lastColumn) const | 430 void MultiColumnFragmentainerGroup::columnIntervalForBlockRangeInFlowThread(Layo utUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread, unsigned& f irstColumn, unsigned& lastColumn) const |
| 424 { | 431 { |
| 432 logicalTopInFlowThread = std::max(logicalTopInFlowThread, this->logicalTopIn FlowThread()); | |
| 433 logicalBottomInFlowThread = std::min(logicalBottomInFlowThread, this->logica lBottomInFlowThread()); | |
| 425 ASSERT(logicalTopInFlowThread <= logicalBottomInFlowThread); | 434 ASSERT(logicalTopInFlowThread <= logicalBottomInFlowThread); |
| 426 firstColumn = columnIndexAtOffset(logicalTopInFlowThread); | 435 firstColumn = columnIndexAtOffset(logicalTopInFlowThread, LayoutBox::Associa teWithLatterPage); |
| 427 lastColumn = columnIndexAtOffset(logicalBottomInFlowThread); | 436 lastColumn = columnIndexAtOffset(logicalBottomInFlowThread, LayoutBox::Assoc iateWithFormerPage); |
| 428 // logicalBottomInFlowThread is an exclusive endpoint, so some additional ad justments may be necessary. | |
| 429 if (lastColumn > firstColumn && logicalTopInFlowThreadAt(lastColumn) == logi calBottomInFlowThread) | |
| 430 lastColumn--; | |
| 431 } | 437 } |
| 432 | 438 |
| 433 void MultiColumnFragmentainerGroup::columnIntervalForVisualRect(const LayoutRect & rect, unsigned& firstColumn, unsigned& lastColumn) const | 439 void MultiColumnFragmentainerGroup::columnIntervalForVisualRect(const LayoutRect & rect, unsigned& firstColumn, unsigned& lastColumn) const |
| 434 { | 440 { |
| 435 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline(); | 441 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline(); |
| 436 bool isFlippedColumnProgression = !m_columnSet.style()->isLeftToRightDirecti on() && isColumnProgressionInline; | 442 bool isFlippedColumnProgression = !m_columnSet.style()->isLeftToRightDirecti on() && isColumnProgressionInline; |
| 437 if (m_columnSet.isHorizontalWritingMode() == isColumnProgressionInline) { | 443 if (m_columnSet.isHorizontalWritingMode() == isColumnProgressionInline) { |
| 438 if (isFlippedColumnProgression) { | 444 if (isFlippedColumnProgression) { |
| 439 firstColumn = columnIndexAtVisualPoint(rect.maxXMinYCorner()); | 445 firstColumn = columnIndexAtVisualPoint(rect.maxXMinYCorner()); |
| 440 lastColumn = columnIndexAtVisualPoint(rect.minXMinYCorner()); | 446 lastColumn = columnIndexAtVisualPoint(rect.minXMinYCorner()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 474 append(MultiColumnFragmentainerGroup(m_columnSet)); | 480 append(MultiColumnFragmentainerGroup(m_columnSet)); |
| 475 return last(); | 481 return last(); |
| 476 } | 482 } |
| 477 | 483 |
| 478 void MultiColumnFragmentainerGroupList::deleteExtraGroups() | 484 void MultiColumnFragmentainerGroupList::deleteExtraGroups() |
| 479 { | 485 { |
| 480 shrink(1); | 486 shrink(1); |
| 481 } | 487 } |
| 482 | 488 |
| 483 } // namespace blink | 489 } // namespace blink |
| OLD | NEW |