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