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 "config.h" | 5 #include "config.h" |
| 6 | 6 |
| 7 #include "core/layout/ColumnBalancer.h" | 7 #include "core/layout/ColumnBalancer.h" |
| 8 | 8 |
| 9 #include "core/layout/LayoutMultiColumnSet.h" | 9 #include "core/layout/LayoutMultiColumnSet.h" |
| 10 | 10 |
| 11 namespace blink { | 11 namespace blink { |
| 12 | 12 |
| 13 ColumnBalancer::ColumnBalancer(const MultiColumnFragmentainerGroup& group) | 13 ColumnBalancer::ColumnBalancer(const MultiColumnFragmentainerGroup& group) |
| 14 : m_group(group) | 14 : m_group(group) |
| 15 { | 15 { |
| 16 } | 16 } |
| 17 | 17 |
| 18 void ColumnBalancer::traverse() | 18 void ColumnBalancer::traverse() |
| 19 { | 19 { |
| 20 traverseSubtree(*m_group.columnSet().flowThread()); | 20 traverseSubtree(*m_group.columnSet().flowThread()); |
| 21 ASSERT(!flowThreadOffset()); | 21 ASSERT(!flowThreadOffset()); |
| 22 } | 22 } |
| 23 | 23 |
| 24 void ColumnBalancer::traverseSubtree(const LayoutBox& box) | 24 void ColumnBalancer::traverseSubtree(const LayoutBox& box) |
| 25 { | 25 { |
| 26 if (box.childrenInline() && box.isLayoutBlockFlow()) { | 26 if (box.childrenInline() && box.isLayoutBlockFlow()) { |
| 27 // Look for breaks between lines. | 27 // Look for breaks between lines. |
| 28 for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox(); line; line = line->nextRootBox()) { | 28 const LayoutBlockFlow& blockFlow = toLayoutBlockFlow(box); |
| 29 for (const RootInlineBox* line = blockFlow.firstRootBox(); line; line = line->nextRootBox()) { | |
| 29 LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopW ithLeading(); | 30 LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopW ithLeading(); |
| 30 if (lineTopInFlowThread < group().logicalTopInFlowThread()) | 31 if (lineTopInFlowThread < group().logicalTopInFlowThread()) |
| 31 continue; | 32 continue; |
| 32 if (lineTopInFlowThread >= group().logicalBottomInFlowThread()) | 33 if (lineTopInFlowThread >= group().logicalBottomInFlowThread()) |
| 33 break; | 34 break; |
| 34 examineLine(*line); | 35 examineLine(blockFlow, *line); |
| 35 } | 36 } |
| 36 } | 37 } |
| 37 | 38 |
| 38 const LayoutFlowThread* flowThread = group().columnSet().flowThread(); | 39 const LayoutFlowThread* flowThread = group().columnSet().flowThread(); |
| 39 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); | 40 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); |
| 40 | 41 |
| 41 // Look for breaks between and inside block-level children. Even if this is a block flow with | 42 // Look for breaks between and inside block-level children. Even if this is a block flow with |
| 42 // inline children, there may be interesting floats to examine here. | 43 // inline children, there may be interesting floats to examine here. |
| 43 for (const LayoutObject* child = box.slowFirstChild(); child; child = child- >nextSibling()) { | 44 for (const LayoutObject* child = box.slowFirstChild(); child; child = child- >nextSibling()) { |
| 44 if (!child->isBox() || child->isInline()) | 45 if (!child->isBox() || child->isInline()) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 // We have now found each explicit / forced break, and their location. Now w e need to figure out | 86 // We have now found each explicit / forced break, and their location. Now w e need to figure out |
| 86 // how many additional implicit / soft breaks we need and guess where they w ill occur, in order | 87 // how many additional implicit / soft breaks we need and guess where they w ill occur, in order |
| 87 // to provide an initial column height. | 88 // to provide an initial column height. |
| 88 distributeImplicitBreaks(); | 89 distributeImplicitBreaks(); |
| 89 } | 90 } |
| 90 | 91 |
| 91 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const | 92 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const |
| 92 { | 93 { |
| 93 unsigned index = contentRunIndexWithTallestColumns(); | 94 unsigned index = contentRunIndexWithTallestColumns(); |
| 94 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : group().logicalTopInFlowThread(); | 95 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : group().logicalTopInFlowThread(); |
| 95 return m_contentRuns[index].columnLogicalHeight(startOffset); | 96 LayoutUnit logicalHeightEstimate = m_contentRuns[index].columnLogicalHeight( startOffset); |
| 97 return std::max(logicalHeightEstimate, m_minimumColumnLogicalHeight); | |
| 96 } | 98 } |
| 97 | 99 |
| 98 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box) | 100 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box) |
| 99 { | 101 { |
| 100 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut()); | 102 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut()); |
| 101 if (box.hasForcedBreakBefore()) { | 103 if (box.hasForcedBreakBefore()) { |
| 102 addContentRun(flowThreadOffset()); | 104 addContentRun(flowThreadOffset()); |
| 103 } else if (isFirstAfterBreak(flowThreadOffset())) { | 105 } else if (isFirstAfterBreak(flowThreadOffset())) { |
| 104 // This box is first after a soft break. | 106 // This box is first after a soft break. |
| 105 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut()); | 107 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut()); |
| 106 } | 108 } |
| 107 | 109 |
| 108 if (box.hasForcedBreakAfter()) | 110 if (box.hasForcedBreakAfter()) |
| 109 addContentRun(flowThreadOffset() + box.logicalHeight()); | 111 addContentRun(flowThreadOffset() + box.logicalHeight()); |
| 112 | |
| 113 if (box.paginationBreakability() != LayoutBox::AllowAnyBreaks) { | |
|
leviw_travelin_and_unemployed
2015/11/05 18:44:26
This is new code?
mstensho (USE GERRIT)
2015/11/05 19:15:56
This used to be handled in LayoutBlockFlow::adjust
| |
| 114 LayoutUnit unsplittableLogicalHeight = box.logicalHeight(); | |
| 115 if (box.isFloating()) | |
| 116 unsplittableLogicalHeight += box.marginBefore() + box.marginAfter(); | |
| 117 if (m_minimumColumnLogicalHeight < unsplittableLogicalHeight) | |
| 118 m_minimumColumnLogicalHeight = unsplittableLogicalHeight; | |
| 119 } | |
| 110 } | 120 } |
| 111 | 121 |
| 112 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box) | 122 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box) |
| 113 { | 123 { |
| 114 } | 124 } |
| 115 | 125 |
| 116 void InitialColumnHeightFinder::examineLine(const RootInlineBox& line) | 126 static inline LayoutUnit columnLogicalHeightRequirementForLine(const ComputedSty le& style, const RootInlineBox& lastLine) |
| 127 { | |
| 128 // We may require a certain minimum number of lines per page in order to sat isfy | |
| 129 // orphans and widows, and that may affect the minimum page height. | |
| 130 unsigned lineCount = std::max<unsigned>(style.hasAutoOrphans() ? 1 : style.o rphans(), style.widows()); | |
|
leviw_travelin_and_unemployed
2015/11/05 18:44:26
minimumLineCount?
mstensho (USE GERRIT)
2015/11/05 19:15:56
Good idea. This code was just copied from LayoutBl
mstensho (USE GERRIT)
2015/11/05 22:17:10
Done.
| |
| 131 const RootInlineBox* firstLine = &lastLine; | |
| 132 for (unsigned i = 1; i < lineCount && firstLine->prevRootBox(); i++) | |
| 133 firstLine = firstLine->prevRootBox(); | |
| 134 return lastLine.lineBottomWithLeading() - firstLine->lineTopWithLeading(); | |
| 135 } | |
| 136 | |
| 137 void InitialColumnHeightFinder::examineLine(const LayoutBlockFlow& containingBlo ck, const RootInlineBox& line) | |
| 117 { | 138 { |
| 118 LayoutUnit lineTop = line.lineTopWithLeading(); | 139 LayoutUnit lineTop = line.lineTopWithLeading(); |
| 119 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; | 140 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; |
| 141 LayoutUnit minimumLogialHeight = columnLogicalHeightRequirementForLine(conta iningBlock.styleRef(), line); | |
| 142 if (m_minimumColumnLogicalHeight < minimumLogialHeight) | |
| 143 m_minimumColumnLogicalHeight = minimumLogialHeight; | |
| 120 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut()); | 144 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut()); |
| 121 if (isFirstAfterBreak(lineTopInFlowThread)) | 145 if (isFirstAfterBreak(lineTopInFlowThread)) |
| 122 recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); | 146 recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); |
| 123 } | 147 } |
| 124 | 148 |
| 125 void InitialColumnHeightFinder::recordStrutBeforeOffset(LayoutUnit offsetInFlowT hread, LayoutUnit strut) | 149 void InitialColumnHeightFinder::recordStrutBeforeOffset(LayoutUnit offsetInFlowT hread, LayoutUnit strut) |
| 126 { | 150 { |
| 127 const LayoutMultiColumnSet& columnSet = group().columnSet(); | 151 const LayoutMultiColumnSet& columnSet = group().columnSet(); |
| 128 ASSERT(columnSet.usedColumnCount() >= 1); | 152 ASSERT(columnSet.usedColumnCount() >= 1); |
| 129 unsigned columnCount = columnSet.usedColumnCount(); | 153 unsigned columnCount = columnSet.usedColumnCount(); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 return; | 279 return; |
| 256 | 280 |
| 257 // The previous break was before a breakable block. Here's the first piece o f unbreakable | 281 // The previous break was before a breakable block. Here's the first piece o f unbreakable |
| 258 // content after / inside that block. We want to record the distance from th e top of the column | 282 // content after / inside that block. We want to record the distance from th e top of the column |
| 259 // to the bottom of this box as space shortage. | 283 // to the bottom of this box as space shortage. |
| 260 LayoutUnit logicalOffsetFromCurrentColumn = flowThreadOffset() - group().col umnLogicalTopForOffset(flowThreadOffset()); | 284 LayoutUnit logicalOffsetFromCurrentColumn = flowThreadOffset() - group().col umnLogicalTopForOffset(flowThreadOffset()); |
| 261 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - m _pendingStrut); | 285 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - m _pendingStrut); |
| 262 m_pendingStrut = LayoutUnit::min(); | 286 m_pendingStrut = LayoutUnit::min(); |
| 263 } | 287 } |
| 264 | 288 |
| 265 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) | 289 void MinimumSpaceShortageFinder::examineLine(const LayoutBlockFlow& containingBl ock, const RootInlineBox& line) |
| 266 { | 290 { |
| 267 LayoutUnit lineTop = line.lineTopWithLeading(); | 291 LayoutUnit lineTop = line.lineTopWithLeading(); |
| 268 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; | 292 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; |
| 269 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; | 293 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; |
| 270 if (m_pendingStrut != LayoutUnit::min()) { | 294 if (m_pendingStrut != LayoutUnit::min()) { |
| 271 // The previous break was before a breakable block. Here's the first lin e after / inside | 295 // The previous break was before a breakable block. Here's the first lin e after / inside |
| 272 // that block. We want to record the distance from the top of the column to the bottom of | 296 // that block. We want to record the distance from the top of the column to the bottom of |
| 273 // this box as space shortage. | 297 // this box as space shortage. |
| 274 LayoutUnit logicalOffsetFromCurrentColumn = lineTopInFlowThread - group( ).columnLogicalTopForOffset(lineTopInFlowThread); | 298 LayoutUnit logicalOffsetFromCurrentColumn = lineTopInFlowThread - group( ).columnLogicalTopForOffset(lineTopInFlowThread); |
| 275 recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - m_pend ingStrut); | 299 recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - m_pend ingStrut); |
| 276 m_pendingStrut = LayoutUnit::min(); | 300 m_pendingStrut = LayoutUnit::min(); |
| 277 return; | 301 return; |
| 278 } | 302 } |
| 279 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut()); | 303 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut()); |
| 280 if (isFirstAfterBreak(lineTopInFlowThread)) | 304 if (isFirstAfterBreak(lineTopInFlowThread)) |
| 281 recordSpaceShortage(lineHeight - line.paginationStrut()); | 305 recordSpaceShortage(lineHeight - line.paginationStrut()); |
| 282 } | 306 } |
| 283 | 307 |
| 284 } // namespace blink | 308 } // namespace blink |
| OLD | NEW |