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 MultiColumnFragmentainerGroup& group) | 13 ColumnBalancer::ColumnBalancer(const LayoutMultiColumnSet& columnSet, LayoutUnit
logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread) |
14 : m_group(group) | 14 : m_columnSet(columnSet) |
| 15 , m_logicalTopInFlowThread(logicalTopInFlowThread) |
| 16 , m_logicalBottomInFlowThread(logicalBottomInFlowThread) |
15 , m_previousBreakAfterValue(BreakAuto) | 17 , m_previousBreakAfterValue(BreakAuto) |
16 { | 18 { |
17 } | 19 } |
18 | 20 |
19 void ColumnBalancer::traverse() | 21 void ColumnBalancer::traverse() |
20 { | 22 { |
21 traverseSubtree(*m_group.columnSet().flowThread()); | 23 traverseSubtree(*columnSet().flowThread()); |
22 ASSERT(!flowThreadOffset()); | 24 ASSERT(!flowThreadOffset()); |
23 } | 25 } |
24 | 26 |
25 void ColumnBalancer::traverseSubtree(const LayoutBox& box) | 27 void ColumnBalancer::traverseSubtree(const LayoutBox& box) |
26 { | 28 { |
27 if (box.childrenInline() && box.isLayoutBlockFlow()) { | 29 if (box.childrenInline() && box.isLayoutBlockFlow()) { |
28 // Look for breaks between lines. | 30 // Look for breaks between lines. |
29 for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox();
line; line = line->nextRootBox()) { | 31 for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox();
line; line = line->nextRootBox()) { |
30 LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopW
ithLeading(); | 32 LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopW
ithLeading(); |
31 if (lineTopInFlowThread < group().logicalTopInFlowThread()) | 33 if (lineTopInFlowThread < logicalTopInFlowThread()) |
32 continue; | 34 continue; |
33 if (lineTopInFlowThread >= group().logicalBottomInFlowThread()) | 35 if (lineTopInFlowThread >= logicalBottomInFlowThread()) |
34 break; | 36 break; |
35 examineLine(*line); | 37 examineLine(*line); |
36 } | 38 } |
37 } | 39 } |
38 | 40 |
39 const LayoutFlowThread* flowThread = group().columnSet().flowThread(); | 41 const LayoutFlowThread* flowThread = columnSet().flowThread(); |
40 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); | 42 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); |
41 | 43 |
42 // Look for breaks between and inside block-level children. Even if this is
a block flow with | 44 // Look for breaks between and inside block-level children. Even if this is
a block flow with |
43 // inline children, there may be interesting floats to examine here. | 45 // inline children, there may be interesting floats to examine here. |
44 for (const LayoutObject* child = box.slowFirstChild(); child; child = child-
>nextSibling()) { | 46 for (const LayoutObject* child = box.slowFirstChild(); child; child = child-
>nextSibling()) { |
45 if (!child->isBox() || child->isInline()) | 47 if (!child->isBox() || child->isInline()) |
46 continue; | 48 continue; |
47 const LayoutBox& childBox = toLayoutBox(*child); | 49 const LayoutBox& childBox = toLayoutBox(*child); |
48 LayoutRect overflowRect = childBox.layoutOverflowRect(); | 50 LayoutRect overflowRect = childBox.layoutOverflowRect(); |
49 LayoutUnit childLogicalBottomWithOverflow = childBox.logicalTop() + (isH
orizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); | 51 LayoutUnit childLogicalBottomWithOverflow = childBox.logicalTop() + (isH
orizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); |
50 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= group().logic
alTopInFlowThread()) { | 52 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= logicalTopInF
lowThread()) { |
51 // This child is fully above the fragmentainer group we're examining
. | 53 // This child is fully above the flow thread portion we're examining
. |
52 continue; | 54 continue; |
53 } | 55 } |
54 LayoutUnit childLogicalTopWithOverflow = childBox.logicalTop() + (isHori
zontalWritingMode ? overflowRect.y() : overflowRect.x()); | 56 LayoutUnit childLogicalTopWithOverflow = childBox.logicalTop() + (isHori
zontalWritingMode ? overflowRect.y() : overflowRect.x()); |
55 if (m_flowThreadOffset + childLogicalTopWithOverflow >= group().logicalB
ottomInFlowThread()) { | 57 if (m_flowThreadOffset + childLogicalTopWithOverflow >= logicalBottomInF
lowThread()) { |
56 // This child is fully below the fragmentainer group we're examining
. We cannot just | 58 // This child is fully below the flow thread portion we're examining
. We cannot just |
57 // stop here, though, thanks to negative margins. So keep looking. | 59 // stop here, though, thanks to negative margins. So keep looking. |
58 continue; | 60 continue; |
59 } | 61 } |
60 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) | 62 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) |
61 continue; | 63 continue; |
62 | 64 |
63 // Tables are wicked. Both table rows and table cells are relative to th
eir table section. | 65 // Tables are wicked. Both table rows and table cells are relative to th
eir table section. |
64 LayoutUnit offsetForThisChild = childBox.isTableRow() ? LayoutUnit() : c
hildBox.logicalTop(); | 66 LayoutUnit offsetForThisChild = childBox.isTableRow() ? LayoutUnit() : c
hildBox.logicalTop(); |
65 m_flowThreadOffset += offsetForThisChild; | 67 m_flowThreadOffset += offsetForThisChild; |
66 | 68 |
67 examineBoxAfterEntering(childBox); | 69 examineBoxAfterEntering(childBox); |
68 // Unless the child is unsplittable, or if the child establishes an inne
r multicol | 70 // Unless the child is unsplittable, or if the child establishes an inne
r multicol |
69 // container, we descend into its subtree for further examination. | 71 // container, we descend into its subtree for further examination. |
70 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks | 72 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks |
71 && (!childBox.isLayoutBlockFlow() || !toLayoutBlockFlow(childBox).mu
ltiColumnFlowThread())) | 73 && (!childBox.isLayoutBlockFlow() || !toLayoutBlockFlow(childBox).mu
ltiColumnFlowThread())) |
72 traverseSubtree(childBox); | 74 traverseSubtree(childBox); |
73 m_previousBreakAfterValue = childBox.breakAfter(); | 75 m_previousBreakAfterValue = childBox.breakAfter(); |
74 examineBoxBeforeLeaving(childBox); | 76 examineBoxBeforeLeaving(childBox); |
75 | 77 |
76 m_flowThreadOffset -= offsetForThisChild; | 78 m_flowThreadOffset -= offsetForThisChild; |
77 } | 79 } |
78 } | 80 } |
79 | 81 |
80 InitialColumnHeightFinder::InitialColumnHeightFinder(const MultiColumnFragmentai
nerGroup& group) | 82 InitialColumnHeightFinder::InitialColumnHeightFinder(const LayoutMultiColumnSet&
columnSet, LayoutUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThr
ead) |
81 : ColumnBalancer(group) | 83 : ColumnBalancer(columnSet, logicalTopInFlowThread, logicalBottomInFlowThrea
d) |
82 { | 84 { |
83 m_shortestStruts.resize(group.columnSet().usedColumnCount()); | 85 m_shortestStruts.resize(columnSet.usedColumnCount()); |
84 for (auto& strut : m_shortestStruts) | 86 for (auto& strut : m_shortestStruts) |
85 strut = LayoutUnit::max(); | 87 strut = LayoutUnit::max(); |
86 traverse(); | 88 traverse(); |
87 // We have now found each explicit / forced break, and their location. Now w
e need to figure out | 89 // We have now found each explicit / forced break, and their location. Now w
e need to figure out |
88 // how many additional implicit / soft breaks we need and guess where they w
ill occur, in order | 90 // how many additional implicit / soft breaks we need and guess where they w
ill occur, in order |
89 // to provide an initial column height. | 91 // to provide an initial column height. |
90 distributeImplicitBreaks(); | 92 distributeImplicitBreaks(); |
91 } | 93 } |
92 | 94 |
93 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const | 95 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const |
94 { | 96 { |
95 unsigned index = contentRunIndexWithTallestColumns(); | 97 unsigned index = contentRunIndexWithTallestColumns(); |
96 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
: group().logicalTopInFlowThread(); | 98 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
: logicalTopInFlowThread(); |
97 return m_contentRuns[index].columnLogicalHeight(startOffset); | 99 return m_contentRuns[index].columnLogicalHeight(startOffset); |
98 } | 100 } |
99 | 101 |
100 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box) | 102 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box) |
101 { | 103 { |
102 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { | 104 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { |
103 if (box.needsForcedBreakBefore(previousBreakAfterValue())) { | 105 if (box.needsForcedBreakBefore(previousBreakAfterValue())) { |
104 addContentRun(flowThreadOffset()); | 106 addContentRun(flowThreadOffset()); |
105 } else { | 107 } else { |
106 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut
()); | 108 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut
()); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; | 152 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; |
151 LayoutUnit minimumLogialHeight = columnLogicalHeightRequirementForLine(line.
block().styleRef(), line); | 153 LayoutUnit minimumLogialHeight = columnLogicalHeightRequirementForLine(line.
block().styleRef(), line); |
152 m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeig
ht, minimumLogialHeight); | 154 m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeig
ht, minimumLogialHeight); |
153 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() ||
!isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); | 155 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() ||
!isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); |
154 if (isFirstAfterBreak(lineTopInFlowThread)) | 156 if (isFirstAfterBreak(lineTopInFlowThread)) |
155 recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); | 157 recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); |
156 } | 158 } |
157 | 159 |
158 void InitialColumnHeightFinder::recordStrutBeforeOffset(LayoutUnit offsetInFlowT
hread, LayoutUnit strut) | 160 void InitialColumnHeightFinder::recordStrutBeforeOffset(LayoutUnit offsetInFlowT
hread, LayoutUnit strut) |
159 { | 161 { |
160 const LayoutMultiColumnSet& columnSet = group().columnSet(); | 162 ASSERT(columnSet().usedColumnCount() >= 1); |
161 ASSERT(columnSet.usedColumnCount() >= 1); | 163 unsigned columnCount = columnSet().usedColumnCount(); |
162 unsigned columnCount = columnSet.usedColumnCount(); | |
163 ASSERT(m_shortestStruts.size() == columnCount); | 164 ASSERT(m_shortestStruts.size() == columnCount); |
164 unsigned index = group().columnIndexAtOffset(offsetInFlowThread - strut, Mul
tiColumnFragmentainerGroup::AssumeNewColumns); | 165 unsigned index = groupAtOffset(offsetInFlowThread).columnIndexAtOffset(offse
tInFlowThread - strut, MultiColumnFragmentainerGroup::AssumeNewColumns); |
165 if (index >= columnCount) | 166 if (index >= columnCount) |
166 return; | 167 return; |
167 m_shortestStruts[index] = std::min(m_shortestStruts[index], strut); | 168 m_shortestStruts[index] = std::min(m_shortestStruts[index], strut); |
168 } | 169 } |
169 | 170 |
170 LayoutUnit InitialColumnHeightFinder::spaceUsedByStrutsAt(LayoutUnit offsetInFlo
wThread) const | 171 LayoutUnit InitialColumnHeightFinder::spaceUsedByStrutsAt(LayoutUnit offsetInFlo
wThread) const |
171 { | 172 { |
172 unsigned stopBeforeColumn = group().columnIndexAtOffset(offsetInFlowThread,
MultiColumnFragmentainerGroup::AssumeNewColumns) + 1; | 173 unsigned stopBeforeColumn = groupAtOffset(offsetInFlowThread).columnIndexAtO
ffset(offsetInFlowThread, MultiColumnFragmentainerGroup::AssumeNewColumns) + 1; |
173 stopBeforeColumn = std::min(stopBeforeColumn, group().columnSet().usedColumn
Count()); | 174 stopBeforeColumn = std::min(stopBeforeColumn, columnSet().usedColumnCount())
; |
174 ASSERT(stopBeforeColumn <= m_shortestStruts.size()); | 175 ASSERT(stopBeforeColumn <= m_shortestStruts.size()); |
175 LayoutUnit totalStrutSpace; | 176 LayoutUnit totalStrutSpace; |
176 for (unsigned i = 0; i < stopBeforeColumn; i++) { | 177 for (unsigned i = 0; i < stopBeforeColumn; i++) { |
177 if (m_shortestStruts[i] != LayoutUnit::max()) | 178 if (m_shortestStruts[i] != LayoutUnit::max()) |
178 totalStrutSpace += m_shortestStruts[i]; | 179 totalStrutSpace += m_shortestStruts[i]; |
179 } | 180 } |
180 return totalStrutSpace; | 181 return totalStrutSpace; |
181 } | 182 } |
182 | 183 |
183 void InitialColumnHeightFinder::addContentRun(LayoutUnit endOffsetInFlowThread) | 184 void InitialColumnHeightFinder::addContentRun(LayoutUnit endOffsetInFlowThread) |
184 { | 185 { |
185 endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread); | 186 endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread); |
186 if (!m_contentRuns.isEmpty() && endOffsetInFlowThread <= m_contentRuns.last(
).breakOffset()) | 187 if (!m_contentRuns.isEmpty() && endOffsetInFlowThread <= m_contentRuns.last(
).breakOffset()) |
187 return; | 188 return; |
188 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the | 189 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the |
189 // overflow area shouldn't affect column balancing. | 190 // overflow area shouldn't affect column balancing. |
190 if (m_contentRuns.size() < group().columnSet().usedColumnCount()) | 191 if (m_contentRuns.size() < columnSet().usedColumnCount()) |
191 m_contentRuns.append(ContentRun(endOffsetInFlowThread)); | 192 m_contentRuns.append(ContentRun(endOffsetInFlowThread)); |
192 } | 193 } |
193 | 194 |
194 unsigned InitialColumnHeightFinder::contentRunIndexWithTallestColumns() const | 195 unsigned InitialColumnHeightFinder::contentRunIndexWithTallestColumns() const |
195 { | 196 { |
196 unsigned indexWithLargestHeight = 0; | 197 unsigned indexWithLargestHeight = 0; |
197 LayoutUnit largestHeight; | 198 LayoutUnit largestHeight; |
198 LayoutUnit previousOffset = group().logicalTopInFlowThread(); | 199 LayoutUnit previousOffset = logicalTopInFlowThread(); |
199 size_t runCount = m_contentRuns.size(); | 200 size_t runCount = m_contentRuns.size(); |
200 ASSERT(runCount); | 201 ASSERT(runCount); |
201 for (size_t i = 0; i < runCount; i++) { | 202 for (size_t i = 0; i < runCount; i++) { |
202 const ContentRun& run = m_contentRuns[i]; | 203 const ContentRun& run = m_contentRuns[i]; |
203 LayoutUnit height = run.columnLogicalHeight(previousOffset); | 204 LayoutUnit height = run.columnLogicalHeight(previousOffset); |
204 if (largestHeight < height) { | 205 if (largestHeight < height) { |
205 largestHeight = height; | 206 largestHeight = height; |
206 indexWithLargestHeight = i; | 207 indexWithLargestHeight = i; |
207 } | 208 } |
208 previousOffset = run.breakOffset(); | 209 previousOffset = run.breakOffset(); |
209 } | 210 } |
210 return indexWithLargestHeight; | 211 return indexWithLargestHeight; |
211 } | 212 } |
212 | 213 |
213 void InitialColumnHeightFinder::distributeImplicitBreaks() | 214 void InitialColumnHeightFinder::distributeImplicitBreaks() |
214 { | 215 { |
215 // Insert a final content run to encompass all content. This will include ov
erflow if this is | 216 // Insert a final content run to encompass all content. This will include ov
erflow if we're at |
216 // the last group in the multicol container. | 217 // the end of the multicol container. |
217 addContentRun(group().logicalBottomInFlowThread()); | 218 addContentRun(logicalBottomInFlowThread()); |
218 unsigned columnCount = m_contentRuns.size(); | 219 unsigned columnCount = m_contentRuns.size(); |
219 | 220 |
220 // If there is room for more breaks (to reach the used value of column-count
), imagine that we | 221 // If there is room for more breaks (to reach the used value of column-count
), imagine that we |
221 // insert implicit breaks at suitable locations. At any given time, the cont
ent run with the | 222 // insert implicit breaks at suitable locations. At any given time, the cont
ent run with the |
222 // currently tallest columns will get another implicit break "inserted", whi
ch will increase its | 223 // currently tallest columns will get another implicit break "inserted", whi
ch will increase its |
223 // column count by one and shrink its columns' height. Repeat until we have
the desired total | 224 // column count by one and shrink its columns' height. Repeat until we have
the desired total |
224 // number of breaks. The largest column height among the runs will then be t
he initial column | 225 // number of breaks. The largest column height among the runs will then be t
he initial column |
225 // height for the balancer to use. | 226 // height for the balancer to use. |
226 while (columnCount < group().columnSet().usedColumnCount()) { | 227 while (columnCount < columnSet().usedColumnCount()) { |
227 unsigned index = contentRunIndexWithTallestColumns(); | 228 unsigned index = contentRunIndexWithTallestColumns(); |
228 m_contentRuns[index].assumeAnotherImplicitBreak(); | 229 m_contentRuns[index].assumeAnotherImplicitBreak(); |
229 columnCount++; | 230 columnCount++; |
230 } | 231 } |
231 } | 232 } |
232 | 233 |
233 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder(const MultiColumnFragment
ainerGroup& group) | 234 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder(const LayoutMultiColumnSe
t& columnSet, LayoutUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowT
hread) |
234 : ColumnBalancer(group) | 235 : ColumnBalancer(columnSet, logicalTopInFlowThread, logicalBottomInFlowThrea
d) |
235 , m_minimumSpaceShortage(LayoutUnit::max()) | 236 , m_minimumSpaceShortage(LayoutUnit::max()) |
236 , m_pendingStrut(LayoutUnit::min()) | 237 , m_pendingStrut(LayoutUnit::min()) |
237 , m_forcedBreaksCount(0) | 238 , m_forcedBreaksCount(0) |
238 { | 239 { |
239 traverse(); | 240 traverse(); |
240 } | 241 } |
241 | 242 |
242 void MinimumSpaceShortageFinder::examineBoxAfterEntering(const LayoutBox& box) | 243 void MinimumSpaceShortageFinder::examineBoxAfterEntering(const LayoutBox& box) |
243 { | 244 { |
244 LayoutBox::PaginationBreakability breakability = box.getPaginationBreakabili
ty(); | 245 LayoutBox::PaginationBreakability breakability = box.getPaginationBreakabili
ty(); |
(...skipping 17 matching lines...) Expand all Loading... |
262 // more suitable). | 263 // more suitable). |
263 m_pendingStrut = strut; | 264 m_pendingStrut = strut; |
264 } | 265 } |
265 } | 266 } |
266 } | 267 } |
267 } | 268 } |
268 | 269 |
269 if (breakability != LayoutBox::ForbidBreaks) { | 270 if (breakability != LayoutBox::ForbidBreaks) { |
270 // See if this breakable box crosses column boundaries. | 271 // See if this breakable box crosses column boundaries. |
271 LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight()
; | 272 LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight()
; |
| 273 const MultiColumnFragmentainerGroup& group = groupAtOffset(flowThreadOff
set()); |
272 if (isFirstAfterBreak(flowThreadOffset()) | 274 if (isFirstAfterBreak(flowThreadOffset()) |
273 || group().columnLogicalTopForOffset(flowThreadOffset()) != group().
columnLogicalTopForOffset(bottomInFlowThread)) { | 275 || group.columnLogicalTopForOffset(flowThreadOffset()) != group.colu
mnLogicalTopForOffset(bottomInFlowThread)) { |
274 // If the child crosses a column boundary, record space shortage, in
case nothing | 276 // If the child crosses a column boundary, record space shortage, in
case nothing |
275 // inside it has already done so. The column balancer needs to know
by how much it | 277 // inside it has already done so. The column balancer needs to know
by how much it |
276 // has to stretch the columns to make more content fit. If no breaks
are reported | 278 // has to stretch the columns to make more content fit. If no breaks
are reported |
277 // (but do occur), the balancer will have no clue. Only measure the
space after the | 279 // (but do occur), the balancer will have no clue. Only measure the
space after the |
278 // last column boundary, in case it crosses more than one. | 280 // last column boundary, in case it crosses more than one. |
279 LayoutUnit spaceUsedInLastColumn = bottomInFlowThread - group().colu
mnLogicalTopForOffset(bottomInFlowThread); | 281 LayoutUnit spaceUsedInLastColumn = bottomInFlowThread - group.column
LogicalTopForOffset(bottomInFlowThread); |
280 recordSpaceShortage(spaceUsedInLastColumn); | 282 recordSpaceShortage(spaceUsedInLastColumn); |
281 } | 283 } |
282 } | 284 } |
283 | 285 |
284 // If this is an inner multicol container, look for space shortage inside it
. | 286 // If this is an inner multicol container, look for space shortage inside it
. |
285 if (!box.isLayoutBlockFlow()) | 287 if (!box.isLayoutBlockFlow()) |
286 return; | 288 return; |
287 LayoutMultiColumnFlowThread* flowThread = toLayoutBlockFlow(box).multiColumn
FlowThread(); | 289 LayoutMultiColumnFlowThread* flowThread = toLayoutBlockFlow(box).multiColumn
FlowThread(); |
288 if (!flowThread || flowThread->isLayoutPagedFlowThread()) | 290 if (!flowThread || flowThread->isLayoutPagedFlowThread()) |
289 return; | 291 return; |
290 for (const LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet
(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { | 292 for (const LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet
(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { |
291 for (const MultiColumnFragmentainerGroup& row : columnSet->fragmentainer
Groups()) { | 293 // Establish an inner shortage finder for this column set in the inner m
ulticol |
292 MinimumSpaceShortageFinder innerFinder(row); | 294 // container. We need to let it walk through all fragmentainer groups in
one go, or we'd |
293 recordSpaceShortage(innerFinder.minimumSpaceShortage()); | 295 // miss the column boundaries between each fragmentainer group. We need
to record space |
294 } | 296 // shortage there too. |
| 297 MinimumSpaceShortageFinder innerFinder(*columnSet, columnSet->logicalTop
InFlowThread(), columnSet->logicalBottomInFlowThread()); |
| 298 recordSpaceShortage(innerFinder.minimumSpaceShortage()); |
295 } | 299 } |
296 } | 300 } |
297 | 301 |
298 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) | 302 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) |
299 { | 303 { |
300 if (m_pendingStrut == LayoutUnit::min() || box.getPaginationBreakability() !
= LayoutBox::ForbidBreaks) | 304 if (m_pendingStrut == LayoutUnit::min() || box.getPaginationBreakability() !
= LayoutBox::ForbidBreaks) |
301 return; | 305 return; |
302 | 306 |
303 // The previous break was before a breakable block. Here's the first piece o
f unbreakable | 307 // The previous break was before a breakable block. Here's the first piece o
f unbreakable |
304 // content after / inside that block. We want to record the distance from th
e top of the column | 308 // content after / inside that block. We want to record the distance from th
e top of the column |
305 // to the bottom of this box as space shortage. | 309 // to the bottom of this box as space shortage. |
306 LayoutUnit logicalOffsetFromCurrentColumn = flowThreadOffset() - group().col
umnLogicalTopForOffset(flowThreadOffset()); | 310 LayoutUnit logicalOffsetFromCurrentColumn = offsetFromColumnLogicalTop(flowT
hreadOffset()); |
307 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - m
_pendingStrut); | 311 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - m
_pendingStrut); |
308 m_pendingStrut = LayoutUnit::min(); | 312 m_pendingStrut = LayoutUnit::min(); |
309 } | 313 } |
310 | 314 |
311 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) | 315 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) |
312 { | 316 { |
313 LayoutUnit lineTop = line.lineTopWithLeading(); | 317 LayoutUnit lineTop = line.lineTopWithLeading(); |
314 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; | 318 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; |
315 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; | 319 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; |
316 if (m_pendingStrut != LayoutUnit::min()) { | 320 if (m_pendingStrut != LayoutUnit::min()) { |
317 // The previous break was before a breakable block. Here's the first lin
e after / inside | 321 // The previous break was before a breakable block. Here's the first lin
e after / inside |
318 // that block. We want to record the distance from the top of the column
to the bottom of | 322 // that block. We want to record the distance from the top of the column
to the bottom of |
319 // this box as space shortage. | 323 // this box as space shortage. |
320 LayoutUnit logicalOffsetFromCurrentColumn = lineTopInFlowThread - group(
).columnLogicalTopForOffset(lineTopInFlowThread); | 324 LayoutUnit logicalOffsetFromCurrentColumn = offsetFromColumnLogicalTop(l
ineTopInFlowThread); |
321 recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - m_pend
ingStrut); | 325 recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - m_pend
ingStrut); |
322 m_pendingStrut = LayoutUnit::min(); | 326 m_pendingStrut = LayoutUnit::min(); |
323 return; | 327 return; |
324 } | 328 } |
325 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() ||
!isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); | 329 ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() ||
!isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); |
326 if (isFirstAfterBreak(lineTopInFlowThread)) | 330 if (isFirstAfterBreak(lineTopInFlowThread)) |
327 recordSpaceShortage(lineHeight - line.paginationStrut()); | 331 recordSpaceShortage(lineHeight - line.paginationStrut()); |
328 | 332 |
329 // Even if the line box itself fits fine inside a column, some content may o
verflow the line | 333 // Even if the line box itself fits fine inside a column, some content may o
verflow the line |
330 // box bottom (due to restrictive line-height, for instance). We should chec
k if some portion | 334 // box bottom (due to restrictive line-height, for instance). We should chec
k if some portion |
331 // of said overflow ends up in the next column. That counts as space shortag
e. | 335 // of said overflow ends up in the next column. That counts as space shortag
e. |
| 336 const MultiColumnFragmentainerGroup& group = groupAtOffset(lineTopInFlowThre
ad); |
332 LayoutUnit lineBottomWithOverflow = lineTopInFlowThread + line.lineBottom()
- lineTop; | 337 LayoutUnit lineBottomWithOverflow = lineTopInFlowThread + line.lineBottom()
- lineTop; |
333 if (group().columnLogicalTopForOffset(lineTopInFlowThread) != group().column
LogicalTopForOffset(lineBottomWithOverflow)) { | 338 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != group.columnLogi
calTopForOffset(lineBottomWithOverflow)) { |
334 LayoutUnit shortage = lineBottomWithOverflow - group().columnLogicalTopF
orOffset(lineBottomWithOverflow); | 339 LayoutUnit shortage = lineBottomWithOverflow - group.columnLogicalTopFor
Offset(lineBottomWithOverflow); |
335 recordSpaceShortage(shortage); | 340 recordSpaceShortage(shortage); |
336 } | 341 } |
337 } | 342 } |
338 | 343 |
339 } // namespace blink | 344 } // namespace blink |
OLD | NEW |