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 |