| 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/ColumnBalancer.h" | 5 #include "core/layout/ColumnBalancer.h" |
| 6 | 6 |
| 7 #include "core/layout/LayoutMultiColumnFlowThread.h" | 7 #include "core/layout/LayoutMultiColumnFlowThread.h" |
| 8 #include "core/layout/LayoutMultiColumnSet.h" | 8 #include "core/layout/LayoutMultiColumnSet.h" |
| 9 #include "core/layout/api/LineLayoutBlockFlow.h" | 9 #include "core/layout/api/LineLayoutBlockFlow.h" |
| 10 | 10 |
| 11 namespace blink { | 11 namespace blink { |
| 12 | 12 |
| 13 ColumnBalancer::ColumnBalancer(const LayoutMultiColumnSet& columnSet, LayoutUnit
logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread) | 13 ColumnBalancer::ColumnBalancer(const LayoutMultiColumnSet& columnSet, LayoutUnit
logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread) |
| 14 : m_columnSet(columnSet) | 14 : m_columnSet(columnSet) |
| 15 , m_logicalTopInFlowThread(logicalTopInFlowThread) | 15 , m_logicalTopInFlowThread(logicalTopInFlowThread) |
| 16 , m_logicalBottomInFlowThread(logicalBottomInFlowThread) | 16 , m_logicalBottomInFlowThread(logicalBottomInFlowThread) |
| 17 , m_previousBreakAfterValue(BreakAuto) | |
| 18 { | 17 { |
| 19 } | 18 } |
| 20 | 19 |
| 21 void ColumnBalancer::traverse() | 20 void ColumnBalancer::traverse() |
| 22 { | 21 { |
| 23 traverseSubtree(*columnSet().flowThread()); | 22 traverseSubtree(*columnSet().flowThread()); |
| 24 ASSERT(!flowThreadOffset()); | 23 ASSERT(!flowThreadOffset()); |
| 25 } | 24 } |
| 26 | 25 |
| 27 void ColumnBalancer::traverseSubtree(const LayoutBox& box) | 26 void ColumnBalancer::traverseSubtree(const LayoutBox& box) |
| 28 { | 27 { |
| 29 if (box.childrenInline() && box.isLayoutBlockFlow()) { | 28 if (box.childrenInline() && box.isLayoutBlockFlow()) { |
| 30 // Look for breaks between lines. | 29 // Look for breaks between lines. |
| 31 for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox();
line; line = line->nextRootBox()) { | 30 for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox();
line; line = line->nextRootBox()) { |
| 32 LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopW
ithLeading(); | 31 LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopW
ithLeading(); |
| 33 if (lineTopInFlowThread < logicalTopInFlowThread()) | 32 if (lineTopInFlowThread < logicalTopInFlowThread()) |
| 34 continue; | 33 continue; |
| 35 if (lineTopInFlowThread >= logicalBottomInFlowThread()) | 34 if (lineTopInFlowThread >= logicalBottomInFlowThread()) |
| 36 break; | 35 break; |
| 37 examineLine(*line); | 36 examineLine(*line); |
| 38 } | 37 } |
| 39 } | 38 } |
| 40 | 39 |
| 41 const LayoutFlowThread* flowThread = columnSet().flowThread(); | 40 const LayoutFlowThread* flowThread = columnSet().flowThread(); |
| 42 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); | 41 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); |
| 43 | 42 |
| 43 // The break-after value from the previous in-flow block-level object to be
joined with the |
| 44 // break-before value of the next in-flow block-level sibling. |
| 45 EBreak previousBreakAfterValue = BreakAuto; |
| 46 |
| 44 // Look for breaks between and inside block-level children. Even if this is
a block flow with | 47 // Look for breaks between and inside block-level children. Even if this is
a block flow with |
| 45 // inline children, there may be interesting floats to examine here. | 48 // inline children, there may be interesting floats to examine here. |
| 46 for (const LayoutObject* child = box.slowFirstChild(); child; child = child-
>nextSibling()) { | 49 for (const LayoutObject* child = box.slowFirstChild(); child; child = child-
>nextSibling()) { |
| 47 if (!child->isBox() || child->isInline()) | 50 if (!child->isBox() || child->isInline()) |
| 48 continue; | 51 continue; |
| 49 const LayoutBox& childBox = toLayoutBox(*child); | 52 const LayoutBox& childBox = toLayoutBox(*child); |
| 50 LayoutRect overflowRect = childBox.layoutOverflowRect(); | 53 LayoutRect overflowRect = childBox.layoutOverflowRect(); |
| 51 LayoutUnit childLogicalBottomWithOverflow = childBox.logicalTop() + (isH
orizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); | 54 LayoutUnit childLogicalBottomWithOverflow = childBox.logicalTop() + (isH
orizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); |
| 52 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= logicalTopInF
lowThread()) { | 55 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= logicalTopInF
lowThread()) { |
| 53 // This child is fully above the flow thread portion we're examining
. | 56 // This child is fully above the flow thread portion we're examining
. |
| 54 continue; | 57 continue; |
| 55 } | 58 } |
| 56 LayoutUnit childLogicalTopWithOverflow = childBox.logicalTop() + (isHori
zontalWritingMode ? overflowRect.y() : overflowRect.x()); | 59 LayoutUnit childLogicalTopWithOverflow = childBox.logicalTop() + (isHori
zontalWritingMode ? overflowRect.y() : overflowRect.x()); |
| 57 if (m_flowThreadOffset + childLogicalTopWithOverflow >= logicalBottomInF
lowThread()) { | 60 if (m_flowThreadOffset + childLogicalTopWithOverflow >= logicalBottomInF
lowThread()) { |
| 58 // This child is fully below the flow thread portion we're examining
. We cannot just | 61 // This child is fully below the flow thread portion we're examining
. We cannot just |
| 59 // stop here, though, thanks to negative margins. So keep looking. | 62 // stop here, though, thanks to negative margins. So keep looking. |
| 60 continue; | 63 continue; |
| 61 } | 64 } |
| 62 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) | 65 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) |
| 63 continue; | 66 continue; |
| 64 | 67 |
| 65 // Tables are wicked. Both table rows and table cells are relative to th
eir table section. | 68 // Tables are wicked. Both table rows and table cells are relative to th
eir table section. |
| 66 LayoutUnit offsetForThisChild = childBox.isTableRow() ? LayoutUnit() : c
hildBox.logicalTop(); | 69 LayoutUnit offsetForThisChild = childBox.isTableRow() ? LayoutUnit() : c
hildBox.logicalTop(); |
| 67 m_flowThreadOffset += offsetForThisChild; | 70 m_flowThreadOffset += offsetForThisChild; |
| 68 | 71 |
| 69 examineBoxAfterEntering(childBox); | 72 examineBoxAfterEntering(childBox, previousBreakAfterValue); |
| 70 // Unless the child is unsplittable, or if the child establishes an inne
r multicol | 73 // Unless the child is unsplittable, or if the child establishes an inne
r multicol |
| 71 // container, we descend into its subtree for further examination. | 74 // container, we descend into its subtree for further examination. |
| 72 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks | 75 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks |
| 73 && (!childBox.isLayoutBlockFlow() || !toLayoutBlockFlow(childBox).mu
ltiColumnFlowThread())) | 76 && (!childBox.isLayoutBlockFlow() || !toLayoutBlockFlow(childBox).mu
ltiColumnFlowThread())) |
| 74 traverseSubtree(childBox); | 77 traverseSubtree(childBox); |
| 75 m_previousBreakAfterValue = childBox.breakAfter(); | 78 previousBreakAfterValue = childBox.breakAfter(); |
| 76 examineBoxBeforeLeaving(childBox); | 79 examineBoxBeforeLeaving(childBox); |
| 77 | 80 |
| 78 m_flowThreadOffset -= offsetForThisChild; | 81 m_flowThreadOffset -= offsetForThisChild; |
| 79 } | 82 } |
| 80 } | 83 } |
| 81 | 84 |
| 82 InitialColumnHeightFinder::InitialColumnHeightFinder(const LayoutMultiColumnSet&
columnSet, LayoutUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThr
ead) | 85 InitialColumnHeightFinder::InitialColumnHeightFinder(const LayoutMultiColumnSet&
columnSet, LayoutUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThr
ead) |
| 83 : ColumnBalancer(columnSet, logicalTopInFlowThread, logicalBottomInFlowThrea
d) | 86 : ColumnBalancer(columnSet, logicalTopInFlowThread, logicalBottomInFlowThrea
d) |
| 84 { | 87 { |
| 85 m_shortestStruts.resize(columnSet.usedColumnCount()); | 88 m_shortestStruts.resize(columnSet.usedColumnCount()); |
| 86 for (auto& strut : m_shortestStruts) | 89 for (auto& strut : m_shortestStruts) |
| 87 strut = LayoutUnit::max(); | 90 strut = LayoutUnit::max(); |
| 88 traverse(); | 91 traverse(); |
| 89 // We have now found each explicit / forced break, and their location. Now w
e need to figure out | 92 // We have now found each explicit / forced break, and their location. Now w
e need to figure out |
| 90 // how many additional implicit / soft breaks we need and guess where they w
ill occur, in order | 93 // how many additional implicit / soft breaks we need and guess where they w
ill occur, in order |
| 91 // to provide an initial column height. | 94 // to provide an initial column height. |
| 92 distributeImplicitBreaks(); | 95 distributeImplicitBreaks(); |
| 93 } | 96 } |
| 94 | 97 |
| 95 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const | 98 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const |
| 96 { | 99 { |
| 97 unsigned index = contentRunIndexWithTallestColumns(); | 100 unsigned index = contentRunIndexWithTallestColumns(); |
| 98 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
: logicalTopInFlowThread(); | 101 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
: logicalTopInFlowThread(); |
| 99 return m_contentRuns[index].columnLogicalHeight(startOffset); | 102 return m_contentRuns[index].columnLogicalHeight(startOffset); |
| 100 } | 103 } |
| 101 | 104 |
| 102 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box) | 105 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box, EB
reak previousBreakAfterValue) |
| 103 { | 106 { |
| 104 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { | 107 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { |
| 105 if (box.needsForcedBreakBefore(previousBreakAfterValue())) { | 108 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { |
| 106 addContentRun(flowThreadOffset()); | 109 addContentRun(flowThreadOffset()); |
| 107 } else { | 110 } else { |
| 108 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut
()); | 111 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut
()); |
| 109 if (isFirstAfterBreak(flowThreadOffset())) { | 112 if (isFirstAfterBreak(flowThreadOffset())) { |
| 110 // This box is first after a soft break. | 113 // This box is first after a soft break. |
| 111 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut(
)); | 114 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut(
)); |
| 112 } | 115 } |
| 113 } | 116 } |
| 114 } | 117 } |
| 115 | 118 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 | 236 |
| 234 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder(const LayoutMultiColumnSe
t& columnSet, LayoutUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowT
hread) | 237 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder(const LayoutMultiColumnSe
t& columnSet, LayoutUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowT
hread) |
| 235 : ColumnBalancer(columnSet, logicalTopInFlowThread, logicalBottomInFlowThrea
d) | 238 : ColumnBalancer(columnSet, logicalTopInFlowThread, logicalBottomInFlowThrea
d) |
| 236 , m_minimumSpaceShortage(LayoutUnit::max()) | 239 , m_minimumSpaceShortage(LayoutUnit::max()) |
| 237 , m_pendingStrut(LayoutUnit::min()) | 240 , m_pendingStrut(LayoutUnit::min()) |
| 238 , m_forcedBreaksCount(0) | 241 , m_forcedBreaksCount(0) |
| 239 { | 242 { |
| 240 traverse(); | 243 traverse(); |
| 241 } | 244 } |
| 242 | 245 |
| 243 void MinimumSpaceShortageFinder::examineBoxAfterEntering(const LayoutBox& box) | 246 void MinimumSpaceShortageFinder::examineBoxAfterEntering(const LayoutBox& box, E
Break previousBreakAfterValue) |
| 244 { | 247 { |
| 245 LayoutBox::PaginationBreakability breakability = box.getPaginationBreakabili
ty(); | 248 LayoutBox::PaginationBreakability breakability = box.getPaginationBreakabili
ty(); |
| 246 | 249 |
| 247 // Look for breaks before the child box. | 250 // Look for breaks before the child box. |
| 248 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { | 251 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { |
| 249 if (box.needsForcedBreakBefore(previousBreakAfterValue())) { | 252 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { |
| 250 m_forcedBreaksCount++; | 253 m_forcedBreaksCount++; |
| 251 } else { | 254 } else { |
| 252 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut
()); | 255 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut
()); |
| 253 if (isFirstAfterBreak(flowThreadOffset())) { | 256 if (isFirstAfterBreak(flowThreadOffset())) { |
| 254 // This box is first after a soft break. | 257 // This box is first after a soft break. |
| 255 LayoutUnit strut = box.paginationStrut(); | 258 LayoutUnit strut = box.paginationStrut(); |
| 256 // Figure out how much more space we would need to prevent it fr
om being pushed to the next column. | 259 // Figure out how much more space we would need to prevent it fr
om being pushed to the next column. |
| 257 recordSpaceShortage(box.logicalHeight() - strut); | 260 recordSpaceShortage(box.logicalHeight() - strut); |
| 258 if (breakability != LayoutBox::ForbidBreaks && m_pendingStrut ==
LayoutUnit::min()) { | 261 if (breakability != LayoutBox::ForbidBreaks && m_pendingStrut ==
LayoutUnit::min()) { |
| 259 // We now want to look for the first piece of unbreakable co
ntent (e.g. a line or a | 262 // We now want to look for the first piece of unbreakable co
ntent (e.g. a line or a |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // of said overflow ends up in the next column. That counts as space shortag
e. | 338 // of said overflow ends up in the next column. That counts as space shortag
e. |
| 336 const MultiColumnFragmentainerGroup& group = groupAtOffset(lineTopInFlowThre
ad); | 339 const MultiColumnFragmentainerGroup& group = groupAtOffset(lineTopInFlowThre
ad); |
| 337 LayoutUnit lineBottomWithOverflow = lineTopInFlowThread + line.lineBottom()
- lineTop; | 340 LayoutUnit lineBottomWithOverflow = lineTopInFlowThread + line.lineBottom()
- lineTop; |
| 338 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != group.columnLogi
calTopForOffset(lineBottomWithOverflow)) { | 341 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != group.columnLogi
calTopForOffset(lineBottomWithOverflow)) { |
| 339 LayoutUnit shortage = lineBottomWithOverflow - group.columnLogicalTopFor
Offset(lineBottomWithOverflow); | 342 LayoutUnit shortage = lineBottomWithOverflow - group.columnLogicalTopFor
Offset(lineBottomWithOverflow); |
| 340 recordSpaceShortage(shortage); | 343 recordSpaceShortage(shortage); |
| 341 } | 344 } |
| 342 } | 345 } |
| 343 | 346 |
| 344 } // namespace blink | 347 } // namespace blink |
| OLD | NEW |