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 |