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 "config.h" | 5 #include "config.h" |
6 | 6 |
7 #include "core/layout/MultiColumnFragmentainerGroup.h" | 7 #include "core/layout/MultiColumnFragmentainerGroup.h" |
8 | 8 |
9 #include "core/layout/LayoutMultiColumnSet.h" | 9 #include "core/layout/LayoutMultiColumnSet.h" |
10 | 10 |
(...skipping 10 matching lines...) Expand all Loading... | |
21 } | 21 } |
22 | 22 |
23 LayoutSize MultiColumnFragmentainerGroup::offsetFromColumnSet() const | 23 LayoutSize MultiColumnFragmentainerGroup::offsetFromColumnSet() const |
24 { | 24 { |
25 LayoutSize offset(LayoutUnit(), logicalTop()); | 25 LayoutSize offset(LayoutUnit(), logicalTop()); |
26 if (!m_columnSet.flowThread()->isHorizontalWritingMode()) | 26 if (!m_columnSet.flowThread()->isHorizontalWritingMode()) |
27 return offset.transposedSize(); | 27 return offset.transposedSize(); |
28 return offset; | 28 return offset; |
29 } | 29 } |
30 | 30 |
31 LayoutUnit MultiColumnFragmentainerGroup::blockOffsetInEnclosingFlowThread() con st | |
32 { | |
33 return logicalTop() + m_columnSet.logicalTop() + m_columnSet.multiColumnFlow Thread()->blockOffsetInEnclosingFlowThread(); | |
34 } | |
35 | |
31 bool MultiColumnFragmentainerGroup::heightIsAuto() const | 36 bool MultiColumnFragmentainerGroup::heightIsAuto() const |
32 { | 37 { |
33 // Only the last row may have auto height, and thus be balanced. There are n o good reasons to | 38 // Only the last row may have auto height, and thus be balanced. There are n o good reasons to |
34 // balance the preceding rows, and that could potentially lead to an insane number of layout | 39 // balance the preceding rows, and that could potentially lead to an insane number of layout |
35 // passes as well. | 40 // passes as well. |
36 return isLastGroup() && m_columnSet.heightIsAuto(); | 41 return isLastGroup() && m_columnSet.heightIsAuto(); |
37 } | 42 } |
38 | 43 |
39 void MultiColumnFragmentainerGroup::resetColumnHeight() | 44 void MultiColumnFragmentainerGroup::resetColumnHeight() |
40 { | 45 { |
41 // Nuke previously stored minimum column height. Contents may have changed f or all we know. | 46 // Nuke previously stored minimum column height. Contents may have changed f or all we know. |
42 m_minimumColumnHeight = 0; | 47 m_minimumColumnHeight = 0; |
43 | 48 |
44 m_maxColumnHeight = calculateMaxColumnHeight(); | 49 m_maxColumnHeight = calculateMaxColumnHeight(); |
45 | 50 |
46 LayoutUnit oldColumnHeight = m_columnHeight; | 51 LayoutUnit oldColumnHeight = m_columnHeight; |
47 | 52 |
48 if (heightIsAuto()) | 53 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( ); |
54 LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlow Thread(); | |
55 if (enclosingFlowThread && enclosingFlowThread->isPageLogicalHeightKnown()) { | |
56 // TODO(mstensho): Do this better. If height is auto here, we shouldn't set a | |
57 // height, or forced breaks and pagination struts might mess up column b alancing. | |
58 ASSERT(m_maxColumnHeight != LayoutUnit::max()); | |
leviw_travelin_and_unemployed
2015/08/15 00:04:43
Why this ASSERT? What situation are you testing fo
mstensho (USE GERRIT)
2015/08/17 07:43:09
I wanted to make sure that calculateMaxColumnHeigh
| |
59 LayoutUnit columnHeight = heightIsAuto() ? m_maxColumnHeight : heightAdj ustedForRowOffset(flowThread->columnHeightAvailable()); | |
60 setAndConstrainColumnHeight(columnHeight); | |
61 } else if (heightIsAuto()) { | |
49 m_columnHeight = LayoutUnit(); | 62 m_columnHeight = LayoutUnit(); |
50 else | 63 } else { |
51 setAndConstrainColumnHeight(heightAdjustedForRowOffset(m_columnSet.multi ColumnFlowThread()->columnHeightAvailable())); | 64 setAndConstrainColumnHeight(heightAdjustedForRowOffset(flowThread->colum nHeightAvailable())); |
65 } | |
52 | 66 |
53 if (m_columnHeight != oldColumnHeight) | 67 if (m_columnHeight != oldColumnHeight) |
54 m_columnSet.setChildNeedsLayout(MarkOnlyThis); | 68 m_columnSet.setChildNeedsLayout(MarkOnlyThis); |
55 | 69 |
56 // Content runs are only needed in the initial layout pass, in order to find an initial column | 70 // Content runs are only needed in the initial layout pass, in order to find an initial column |
57 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so | 71 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so |
58 // the list needs to be empty. | 72 // the list needs to be empty. |
59 ASSERT(m_contentRuns.isEmpty()); | 73 ASSERT(m_contentRuns.isEmpty()); |
60 } | 74 } |
61 | 75 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 | 126 |
113 if (m_columnHeight == oldColumnHeight) | 127 if (m_columnHeight == oldColumnHeight) |
114 return false; // No change. We're done. | 128 return false; // No change. We're done. |
115 | 129 |
116 m_minSpaceShortage = LayoutUnit::max(); | 130 m_minSpaceShortage = LayoutUnit::max(); |
117 return true; // Need another pass. | 131 return true; // Need another pass. |
118 } | 132 } |
119 | 133 |
120 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const | 134 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const |
121 { | 135 { |
122 LayoutFlowThread* flowThread = m_columnSet.flowThread(); | 136 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( ); |
123 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); | 137 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); |
124 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); | 138 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); |
125 flowThread->flipForWritingMode(portionRect); | 139 flowThread->flipForWritingMode(portionRect); |
126 LayoutRect columnRect(columnRectAt(columnIndex)); | 140 LayoutRect columnRect(columnRectAt(columnIndex)); |
127 m_columnSet.flipForWritingMode(columnRect); | 141 m_columnSet.flipForWritingMode(columnRect); |
128 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); | 142 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); |
129 return translationRelativeToGroup + offsetFromColumnSet() + m_columnSet.topL eftLocationOffset() - flowThread->topLeftLocationOffset(); | 143 |
144 LayoutSize enclosingTranslation; | |
145 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) { | |
146 // Translation that would map points in the coordinate space of the oute rmost flow thread to | |
147 // visual points in the first column in the first fragmentainer group (r ow) in our multicol | |
148 // container. | |
149 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(flowThread->blockOffsetInEnclosingFlowThread()); | |
150 | |
151 // Translation that would map points in the coordinate space of the oute rmost flow thread to | |
152 // visual points in the first column in this fragmentainer group. | |
153 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFlowThread()); | |
154 | |
155 // What we ultimately return from this method is a translation that maps points in the | |
156 // coordinate space of our flow thread to a visual point in a certain co lumn in this | |
157 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this | |
158 // fragmentainer group may be in a different outer column than the first outer column that | |
159 // this multicol container lives in. It's the visual distance between th e first | |
160 // fragmentainer group and this fragmentainer group that we need to add to the translation. | |
161 enclosingTranslation -= enclosingTranslationOrigin; | |
162 } | |
163 | |
164 return enclosingTranslation + translationRelativeToGroup + offsetFromColumnS et() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftLocationOffset() ; | |
130 } | 165 } |
131 | 166 |
132 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const | 167 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const |
133 { | 168 { |
134 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns); | 169 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns); |
135 return logicalTopInFlowThreadAt(columnIndex); | 170 return logicalTopInFlowThreadAt(columnIndex); |
136 } | 171 } |
137 | 172 |
138 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const | 173 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const |
139 { | 174 { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
301 height -= contentLogicalTop; | 336 height -= contentLogicalTop; |
302 } | 337 } |
303 height -= logicalTop(); | 338 height -= logicalTop(); |
304 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created. | 339 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created. |
305 } | 340 } |
306 | 341 |
307 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const | 342 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const |
308 { | 343 { |
309 LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow(); | 344 LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow(); |
310 const ComputedStyle& multicolStyle = multicolBlock->styleRef(); | 345 const ComputedStyle& multicolStyle = multicolBlock->styleRef(); |
311 LayoutUnit availableHeight = m_columnSet.multiColumnFlowThread()->columnHeig htAvailable(); | 346 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( ); |
347 LayoutUnit availableHeight = flowThread->columnHeightAvailable(); | |
312 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit: :max(); | 348 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit: :max(); |
313 if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) { | 349 if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) { |
314 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (MaxSize, multicolStyle.logicalMaxHeight(), -1); | 350 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (MaxSize, multicolStyle.logicalMaxHeight(), -1); |
315 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) | 351 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) |
316 maxColumnHeight = logicalMaxHeight; | 352 maxColumnHeight = logicalMaxHeight; |
317 } | 353 } |
318 return heightAdjustedForRowOffset(maxColumnHeight); | 354 LayoutUnit maxHeight = heightAdjustedForRowOffset(maxColumnHeight); |
355 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) { | |
356 if (enclosingFlowThread->isPageLogicalHeightKnown()) { | |
357 // We're nested inside another fragmentation context whose fragmenta iner heights are | |
358 // known. This constrains the max height. | |
359 LayoutUnit remainingOuterLogicalHeight = enclosingFlowThread->pageRe mainingLogicalHeightForOffset(blockOffsetInEnclosingFlowThread(), LayoutBlock::A ssociateWithLatterPage); | |
360 ASSERT(remainingOuterLogicalHeight > 0); | |
361 if (maxHeight > remainingOuterLogicalHeight) | |
362 maxHeight = remainingOuterLogicalHeight; | |
363 } | |
364 } | |
365 return maxHeight; | |
319 } | 366 } |
320 | 367 |
321 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight) | 368 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight) |
322 { | 369 { |
323 m_columnHeight = newHeight; | 370 m_columnHeight = newHeight; |
324 if (m_columnHeight > m_maxColumnHeight) | 371 if (m_columnHeight > m_maxColumnHeight) |
325 m_columnHeight = m_maxColumnHeight; | 372 m_columnHeight = m_maxColumnHeight; |
326 // FIXME: the height may also be affected by the enclosing pagination contex t, if any. | |
327 } | 373 } |
328 | 374 |
329 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const | 375 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const |
330 { | 376 { |
331 unsigned indexWithLargestHeight = 0; | 377 unsigned indexWithLargestHeight = 0; |
332 LayoutUnit largestHeight; | 378 LayoutUnit largestHeight; |
333 LayoutUnit previousOffset = m_logicalTopInFlowThread; | 379 LayoutUnit previousOffset = m_logicalTopInFlowThread; |
334 size_t runCount = m_contentRuns.size(); | 380 size_t runCount = m_contentRuns.size(); |
335 ASSERT(runCount); | 381 ASSERT(runCount); |
336 for (size_t i = 0; i < runCount; i++) { | 382 for (size_t i = 0; i < runCount; i++) { |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 { | 508 { |
463 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are | 509 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are |
464 // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column | 510 // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column |
465 // gap along interior edges. | 511 // gap along interior edges. |
466 // | 512 // |
467 // In the block direction, we will not clip overflow out of the top of the f irst column, or out of the bottom of | 513 // In the block direction, we will not clip overflow out of the top of the f irst column, or out of the bottom of |
468 // the last column. This applies only to the true first column and last colu mn across all column sets. | 514 // the last column. This applies only to the true first column and last colu mn across all column sets. |
469 // | 515 // |
470 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting | 516 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting |
471 // mode that understands not to paint contents from a previous column in the overflow area of a following column. | 517 // mode that understands not to paint contents from a previous column in the overflow area of a following column. |
472 bool isFirstColumn = !columnIndex; | 518 bool isFirstColumnInRow = !columnIndex; |
473 bool isLastColumn = columnIndex == actualColumnCount() - 1; | 519 bool isLastColumnInRow = columnIndex == actualColumnCount() - 1; |
474 bool isLTR = m_columnSet.style()->isLeftToRightDirection(); | 520 bool isLTR = m_columnSet.style()->isLeftToRightDirection(); |
475 bool isLeftmostColumn = isLTR ? isFirstColumn : isLastColumn; | 521 bool isLeftmostColumn = isLTR ? isFirstColumnInRow : isLastColumnInRow; |
476 bool isRightmostColumn = isLTR ? isLastColumn : isFirstColumn; | 522 bool isRightmostColumn = isLTR ? isLastColumnInRow : isFirstColumnInRow; |
477 | 523 |
478 LayoutRect portionRect = flowThreadPortionRectAt(columnIndex); | 524 LayoutRect portionRect = flowThreadPortionRectAt(columnIndex); |
525 bool isFirstColumnInMulticolContainer = isFirstColumnInRow && this == &m_col umnSet.firstFragmentainerGroup() && !m_columnSet.previousSiblingMultiColumnSet() ; | |
526 bool isLastColumnInMulticolContainer = isLastColumnInRow && this == &m_colum nSet.lastFragmentainerGroup() && !m_columnSet.nextSiblingMultiColumnSet(); | |
479 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical | 527 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical |
480 // top/bottom unless it's the first/last column. | 528 // top/bottom unless it's the first/last column. |
481 LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(porti onRect, isFirstColumn && !m_columnSet.previousSiblingMultiColumnSet(), isLastCol umn && !m_columnSet.nextSiblingMultiColumnSet()); | 529 LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(porti onRect, isFirstColumnInMulticolContainer, isLastColumnInMulticolContainer); |
482 | 530 |
483 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column | 531 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column |
484 // gaps. Also make sure that we avoid rounding errors. | 532 // gaps. Also make sure that we avoid rounding errors. |
485 LayoutUnit columnGap = m_columnSet.columnGap(); | 533 LayoutUnit columnGap = m_columnSet.columnGap(); |
486 if (m_columnSet.isHorizontalWritingMode()) { | 534 if (m_columnSet.isHorizontalWritingMode()) { |
487 if (!isLeftmostColumn) | 535 if (!isLeftmostColumn) |
488 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2); | 536 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2); |
489 if (!isRightmostColumn) | 537 if (!isRightmostColumn) |
490 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); | 538 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); |
491 } else { | 539 } else { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
586 append(MultiColumnFragmentainerGroup(m_columnSet)); | 634 append(MultiColumnFragmentainerGroup(m_columnSet)); |
587 return last(); | 635 return last(); |
588 } | 636 } |
589 | 637 |
590 void MultiColumnFragmentainerGroupList::deleteExtraGroups() | 638 void MultiColumnFragmentainerGroupList::deleteExtraGroups() |
591 { | 639 { |
592 shrink(1); | 640 shrink(1); |
593 } | 641 } |
594 | 642 |
595 } // namespace blink | 643 } // namespace blink |
OLD | NEW |