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 |
(...skipping 22 matching lines...) Expand all Loading... |
33 continue; | 33 continue; |
34 if (lineTopInFlowThread >= logicalBottomInFlowThread()) | 34 if (lineTopInFlowThread >= logicalBottomInFlowThread()) |
35 break; | 35 break; |
36 examineLine(*line); | 36 examineLine(*line); |
37 } | 37 } |
38 } | 38 } |
39 | 39 |
40 const LayoutFlowThread* flowThread = columnSet().flowThread(); | 40 const LayoutFlowThread* flowThread = columnSet().flowThread(); |
41 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); | 41 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); |
42 | 42 |
43 // The break-after value from the previous in-flow block-level object to be jo
ined with the | 43 // The break-after value from the previous in-flow block-level object to be |
44 // break-before value of the next in-flow block-level sibling. | 44 // joined with the break-before value of the next in-flow block-level sibling. |
45 EBreak previousBreakAfterValue = BreakAuto; | 45 EBreak previousBreakAfterValue = BreakAuto; |
46 | 46 |
47 // 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 |
48 // inline children, there may be interesting floats to examine here. | 48 // block flow with inline children, there may be interesting floats to examine |
| 49 // here. |
49 for (const LayoutObject* child = box.slowFirstChild(); child; | 50 for (const LayoutObject* child = box.slowFirstChild(); child; |
50 child = child->nextSibling()) { | 51 child = child->nextSibling()) { |
51 if (!child->isBox() || child->isInline()) | 52 if (!child->isBox() || child->isInline()) |
52 continue; | 53 continue; |
53 const LayoutBox& childBox = toLayoutBox(*child); | 54 const LayoutBox& childBox = toLayoutBox(*child); |
54 LayoutRect overflowRect = childBox.layoutOverflowRect(); | 55 LayoutRect overflowRect = childBox.layoutOverflowRect(); |
55 LayoutUnit childLogicalBottomWithOverflow = | 56 LayoutUnit childLogicalBottomWithOverflow = |
56 childBox.logicalTop() + | 57 childBox.logicalTop() + |
57 (isHorizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); | 58 (isHorizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); |
58 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= | 59 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= |
59 logicalTopInFlowThread()) { | 60 logicalTopInFlowThread()) { |
60 // This child is fully above the flow thread portion we're examining. | 61 // This child is fully above the flow thread portion we're examining. |
61 continue; | 62 continue; |
62 } | 63 } |
63 LayoutUnit childLogicalTopWithOverflow = | 64 LayoutUnit childLogicalTopWithOverflow = |
64 childBox.logicalTop() + | 65 childBox.logicalTop() + |
65 (isHorizontalWritingMode ? overflowRect.y() : overflowRect.x()); | 66 (isHorizontalWritingMode ? overflowRect.y() : overflowRect.x()); |
66 if (m_flowThreadOffset + childLogicalTopWithOverflow >= | 67 if (m_flowThreadOffset + childLogicalTopWithOverflow >= |
67 logicalBottomInFlowThread()) { | 68 logicalBottomInFlowThread()) { |
68 // This child is fully below the flow thread portion we're examining. We c
annot just | 69 // This child is fully below the flow thread portion we're examining. We |
69 // stop here, though, thanks to negative margins. So keep looking. | 70 // cannot just stop here, though, thanks to negative margins. |
| 71 // So keep looking. |
70 continue; | 72 continue; |
71 } | 73 } |
72 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) | 74 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) |
73 continue; | 75 continue; |
74 | 76 |
75 // Tables are wicked. Both table rows and table cells are relative to their
table section. | 77 // Tables are wicked. Both table rows and table cells are relative to their |
| 78 // table section. |
76 LayoutUnit offsetForThisChild = | 79 LayoutUnit offsetForThisChild = |
77 childBox.isTableRow() ? LayoutUnit() : childBox.logicalTop(); | 80 childBox.isTableRow() ? LayoutUnit() : childBox.logicalTop(); |
78 m_flowThreadOffset += offsetForThisChild; | 81 m_flowThreadOffset += offsetForThisChild; |
79 | 82 |
80 examineBoxAfterEntering(childBox, previousBreakAfterValue); | 83 examineBoxAfterEntering(childBox, previousBreakAfterValue); |
81 // Unless the child is unsplittable, or if the child establishes an inner mu
lticol | 84 // Unless the child is unsplittable, or if the child establishes an inner |
82 // container, we descend into its subtree for further examination. | 85 // multicol container, we descend into its subtree for further examination. |
83 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks && | 86 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks && |
84 (!childBox.isLayoutBlockFlow() || | 87 (!childBox.isLayoutBlockFlow() || |
85 !toLayoutBlockFlow(childBox).multiColumnFlowThread())) | 88 !toLayoutBlockFlow(childBox).multiColumnFlowThread())) |
86 traverseSubtree(childBox); | 89 traverseSubtree(childBox); |
87 previousBreakAfterValue = childBox.breakAfter(); | 90 previousBreakAfterValue = childBox.breakAfter(); |
88 examineBoxBeforeLeaving(childBox); | 91 examineBoxBeforeLeaving(childBox); |
89 | 92 |
90 m_flowThreadOffset -= offsetForThisChild; | 93 m_flowThreadOffset -= offsetForThisChild; |
91 } | 94 } |
92 } | 95 } |
93 | 96 |
94 InitialColumnHeightFinder::InitialColumnHeightFinder( | 97 InitialColumnHeightFinder::InitialColumnHeightFinder( |
95 const LayoutMultiColumnSet& columnSet, | 98 const LayoutMultiColumnSet& columnSet, |
96 LayoutUnit logicalTopInFlowThread, | 99 LayoutUnit logicalTopInFlowThread, |
97 LayoutUnit logicalBottomInFlowThread) | 100 LayoutUnit logicalBottomInFlowThread) |
98 : ColumnBalancer(columnSet, | 101 : ColumnBalancer(columnSet, |
99 logicalTopInFlowThread, | 102 logicalTopInFlowThread, |
100 logicalBottomInFlowThread) { | 103 logicalBottomInFlowThread) { |
101 m_shortestStruts.resize(columnSet.usedColumnCount()); | 104 m_shortestStruts.resize(columnSet.usedColumnCount()); |
102 for (auto& strut : m_shortestStruts) | 105 for (auto& strut : m_shortestStruts) |
103 strut = LayoutUnit::max(); | 106 strut = LayoutUnit::max(); |
104 traverse(); | 107 traverse(); |
105 // We have now found each explicit / forced break, and their location. Now we
need to figure out | 108 // We have now found each explicit / forced break, and their location. Now we |
106 // how many additional implicit / soft breaks we need and guess where they wil
l occur, in order | 109 // need to figure out how many additional implicit / soft breaks we need and |
| 110 // guess where they will occur, in order |
107 // to provide an initial column height. | 111 // to provide an initial column height. |
108 distributeImplicitBreaks(); | 112 distributeImplicitBreaks(); |
109 } | 113 } |
110 | 114 |
111 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const { | 115 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const { |
112 unsigned index = contentRunIndexWithTallestColumns(); | 116 unsigned index = contentRunIndexWithTallestColumns(); |
113 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() | 117 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() |
114 : logicalTopInFlowThread(); | 118 : logicalTopInFlowThread(); |
115 return m_contentRuns[index].columnLogicalHeight(startOffset); | 119 return m_contentRuns[index].columnLogicalHeight(startOffset); |
116 } | 120 } |
(...skipping 14 matching lines...) Expand all Loading... |
131 } | 135 } |
132 | 136 |
133 if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) { | 137 if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) { |
134 LayoutUnit unsplittableLogicalHeight = box.logicalHeight(); | 138 LayoutUnit unsplittableLogicalHeight = box.logicalHeight(); |
135 if (box.isFloating()) | 139 if (box.isFloating()) |
136 unsplittableLogicalHeight += box.marginBefore() + box.marginAfter(); | 140 unsplittableLogicalHeight += box.marginBefore() + box.marginAfter(); |
137 m_tallestUnbreakableLogicalHeight = | 141 m_tallestUnbreakableLogicalHeight = |
138 std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight); | 142 std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight); |
139 return; | 143 return; |
140 } | 144 } |
141 // Need to examine inner multicol containers to find their tallest unbreakable
piece of content. | 145 // Need to examine inner multicol containers to find their tallest unbreakable |
| 146 // piece of content. |
142 if (!box.isLayoutBlockFlow()) | 147 if (!box.isLayoutBlockFlow()) |
143 return; | 148 return; |
144 LayoutMultiColumnFlowThread* innerFlowThread = | 149 LayoutMultiColumnFlowThread* innerFlowThread = |
145 toLayoutBlockFlow(box).multiColumnFlowThread(); | 150 toLayoutBlockFlow(box).multiColumnFlowThread(); |
146 if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread()) | 151 if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread()) |
147 return; | 152 return; |
148 LayoutUnit offsetInInnerFlowThread = | 153 LayoutUnit offsetInInnerFlowThread = |
149 flowThreadOffset() - | 154 flowThreadOffset() - |
150 innerFlowThread->blockOffsetInEnclosingFragmentationContext(); | 155 innerFlowThread->blockOffsetInEnclosingFragmentationContext(); |
151 LayoutUnit innerUnbreakableHeight = | 156 LayoutUnit innerUnbreakableHeight = |
152 innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread); | 157 innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread); |
153 m_tallestUnbreakableLogicalHeight = | 158 m_tallestUnbreakableLogicalHeight = |
154 std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight); | 159 std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight); |
155 } | 160 } |
156 | 161 |
157 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box) {} | 162 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box) {} |
158 | 163 |
159 static inline LayoutUnit columnLogicalHeightRequirementForLine( | 164 static inline LayoutUnit columnLogicalHeightRequirementForLine( |
160 const ComputedStyle& style, | 165 const ComputedStyle& style, |
161 const RootInlineBox& lastLine) { | 166 const RootInlineBox& lastLine) { |
162 // We may require a certain minimum number of lines per page in order to satis
fy | 167 // We may require a certain minimum number of lines per page in order to |
163 // orphans and widows, and that may affect the minimum page height. | 168 // satisfy orphans and widows, and that may affect the minimum page height. |
164 unsigned minimumLineCount = | 169 unsigned minimumLineCount = |
165 std::max<unsigned>(style.orphans(), style.widows()); | 170 std::max<unsigned>(style.orphans(), style.widows()); |
166 const RootInlineBox* firstLine = &lastLine; | 171 const RootInlineBox* firstLine = &lastLine; |
167 for (unsigned i = 1; i < minimumLineCount && firstLine->prevRootBox(); i++) | 172 for (unsigned i = 1; i < minimumLineCount && firstLine->prevRootBox(); i++) |
168 firstLine = firstLine->prevRootBox(); | 173 firstLine = firstLine->prevRootBox(); |
169 return lastLine.lineBottomWithLeading() - firstLine->lineTopWithLeading(); | 174 return lastLine.lineBottomWithLeading() - firstLine->lineTopWithLeading(); |
170 } | 175 } |
171 | 176 |
172 void InitialColumnHeightFinder::examineLine(const RootInlineBox& line) { | 177 void InitialColumnHeightFinder::examineLine(const RootInlineBox& line) { |
173 LayoutUnit lineTop = line.lineTopWithLeading(); | 178 LayoutUnit lineTop = line.lineTopWithLeading(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 } | 218 } |
214 return totalStrutSpace; | 219 return totalStrutSpace; |
215 } | 220 } |
216 | 221 |
217 void InitialColumnHeightFinder::addContentRun( | 222 void InitialColumnHeightFinder::addContentRun( |
218 LayoutUnit endOffsetInFlowThread) { | 223 LayoutUnit endOffsetInFlowThread) { |
219 endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread); | 224 endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread); |
220 if (!m_contentRuns.isEmpty() && | 225 if (!m_contentRuns.isEmpty() && |
221 endOffsetInFlowThread <= m_contentRuns.last().breakOffset()) | 226 endOffsetInFlowThread <= m_contentRuns.last().breakOffset()) |
222 return; | 227 return; |
223 // Append another item as long as we haven't exceeded used column count. What
ends up in the | 228 // Append another item as long as we haven't exceeded used column count. What |
224 // overflow area shouldn't affect column balancing. | 229 // ends up in the overflow area shouldn't affect column balancing. |
225 if (m_contentRuns.size() < columnSet().usedColumnCount()) | 230 if (m_contentRuns.size() < columnSet().usedColumnCount()) |
226 m_contentRuns.append(ContentRun(endOffsetInFlowThread)); | 231 m_contentRuns.append(ContentRun(endOffsetInFlowThread)); |
227 } | 232 } |
228 | 233 |
229 unsigned InitialColumnHeightFinder::contentRunIndexWithTallestColumns() const { | 234 unsigned InitialColumnHeightFinder::contentRunIndexWithTallestColumns() const { |
230 unsigned indexWithLargestHeight = 0; | 235 unsigned indexWithLargestHeight = 0; |
231 LayoutUnit largestHeight; | 236 LayoutUnit largestHeight; |
232 LayoutUnit previousOffset = logicalTopInFlowThread(); | 237 LayoutUnit previousOffset = logicalTopInFlowThread(); |
233 size_t runCount = m_contentRuns.size(); | 238 size_t runCount = m_contentRuns.size(); |
234 ASSERT(runCount); | 239 ASSERT(runCount); |
235 for (size_t i = 0; i < runCount; i++) { | 240 for (size_t i = 0; i < runCount; i++) { |
236 const ContentRun& run = m_contentRuns[i]; | 241 const ContentRun& run = m_contentRuns[i]; |
237 LayoutUnit height = run.columnLogicalHeight(previousOffset); | 242 LayoutUnit height = run.columnLogicalHeight(previousOffset); |
238 if (largestHeight < height) { | 243 if (largestHeight < height) { |
239 largestHeight = height; | 244 largestHeight = height; |
240 indexWithLargestHeight = i; | 245 indexWithLargestHeight = i; |
241 } | 246 } |
242 previousOffset = run.breakOffset(); | 247 previousOffset = run.breakOffset(); |
243 } | 248 } |
244 return indexWithLargestHeight; | 249 return indexWithLargestHeight; |
245 } | 250 } |
246 | 251 |
247 void InitialColumnHeightFinder::distributeImplicitBreaks() { | 252 void InitialColumnHeightFinder::distributeImplicitBreaks() { |
248 // Insert a final content run to encompass all content. This will include over
flow if we're at | 253 // Insert a final content run to encompass all content. This will include |
249 // the end of the multicol container. | 254 // overflow if we're at the end of the multicol container. |
250 addContentRun(logicalBottomInFlowThread()); | 255 addContentRun(logicalBottomInFlowThread()); |
251 unsigned columnCount = m_contentRuns.size(); | 256 unsigned columnCount = m_contentRuns.size(); |
252 | 257 |
253 // If there is room for more breaks (to reach the used value of column-count),
imagine that we | 258 // If there is room for more breaks (to reach the used value of column-count), |
254 // insert implicit breaks at suitable locations. At any given time, the conten
t run with the | 259 // imagine that we insert implicit breaks at suitable locations. At any given |
255 // currently tallest columns will get another implicit break "inserted", which
will increase its | 260 // time, the content run with the currently tallest columns will get another |
256 // column count by one and shrink its columns' height. Repeat until we have th
e desired total | 261 // implicit break "inserted", which will increase its column count by one and |
257 // number of breaks. The largest column height among the runs will then be the
initial column | 262 // shrink its columns' height. Repeat until we have the desired total number |
258 // height for the balancer to use. | 263 // of breaks. The largest column height among the runs will then be the |
| 264 // initial column height for the balancer to use. |
259 while (columnCount < columnSet().usedColumnCount()) { | 265 while (columnCount < columnSet().usedColumnCount()) { |
260 unsigned index = contentRunIndexWithTallestColumns(); | 266 unsigned index = contentRunIndexWithTallestColumns(); |
261 m_contentRuns[index].assumeAnotherImplicitBreak(); | 267 m_contentRuns[index].assumeAnotherImplicitBreak(); |
262 columnCount++; | 268 columnCount++; |
263 } | 269 } |
264 } | 270 } |
265 | 271 |
266 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder( | 272 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder( |
267 const LayoutMultiColumnSet& columnSet, | 273 const LayoutMultiColumnSet& columnSet, |
268 LayoutUnit logicalTopInFlowThread, | 274 LayoutUnit logicalTopInFlowThread, |
(...skipping 15 matching lines...) Expand all Loading... |
284 | 290 |
285 // Look for breaks before the child box. | 291 // Look for breaks before the child box. |
286 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { | 292 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { |
287 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { | 293 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { |
288 m_forcedBreaksCount++; | 294 m_forcedBreaksCount++; |
289 } else { | 295 } else { |
290 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut()); | 296 ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut()); |
291 if (isFirstAfterBreak(flowThreadOffset())) { | 297 if (isFirstAfterBreak(flowThreadOffset())) { |
292 // This box is first after a soft break. | 298 // This box is first after a soft break. |
293 LayoutUnit strut = box.paginationStrut(); | 299 LayoutUnit strut = box.paginationStrut(); |
294 // Figure out how much more space we would need to prevent it from being
pushed to the next column. | 300 // Figure out how much more space we would need to prevent it from being |
| 301 // pushed to the next column. |
295 recordSpaceShortage(box.logicalHeight() - strut); | 302 recordSpaceShortage(box.logicalHeight() - strut); |
296 if (breakability != LayoutBox::ForbidBreaks && | 303 if (breakability != LayoutBox::ForbidBreaks && |
297 m_pendingStrut == LayoutUnit::min()) { | 304 m_pendingStrut == LayoutUnit::min()) { |
298 // We now want to look for the first piece of unbreakable content (e.g
. a line or a | 305 // We now want to look for the first piece of unbreakable content |
299 // block-displayed image) inside this block. That ought to be a good c
andidate for | 306 // (e.g. a line or a block-displayed image) inside this block. That |
300 // minimum space shortage; a much better one than reporting space shor
tage for the | 307 // ought to be a good candidate for minimum space shortage; a much |
301 // entire block (which we'll also do (further down), in case we couldn
't find anything | 308 // better one than reporting space shortage for the entire block |
302 // more suitable). | 309 // (which we'll also do (further down), in case we couldn't find |
| 310 // anything more suitable). |
303 m_pendingStrut = strut; | 311 m_pendingStrut = strut; |
304 } | 312 } |
305 } | 313 } |
306 } | 314 } |
307 } | 315 } |
308 | 316 |
309 if (breakability != LayoutBox::ForbidBreaks) { | 317 if (breakability != LayoutBox::ForbidBreaks) { |
310 // See if this breakable box crosses column boundaries. | 318 // See if this breakable box crosses column boundaries. |
311 LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight(); | 319 LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight(); |
312 const MultiColumnFragmentainerGroup& group = | 320 const MultiColumnFragmentainerGroup& group = |
313 groupAtOffset(flowThreadOffset()); | 321 groupAtOffset(flowThreadOffset()); |
314 if (isFirstAfterBreak(flowThreadOffset()) || | 322 if (isFirstAfterBreak(flowThreadOffset()) || |
315 group.columnLogicalTopForOffset(flowThreadOffset()) != | 323 group.columnLogicalTopForOffset(flowThreadOffset()) != |
316 group.columnLogicalTopForOffset(bottomInFlowThread)) { | 324 group.columnLogicalTopForOffset(bottomInFlowThread)) { |
317 // If the child crosses a column boundary, record space shortage, in case
nothing | 325 // If the child crosses a column boundary, record space shortage, in case |
318 // inside it has already done so. The column balancer needs to know by how
much it | 326 // nothing inside it has already done so. The column balancer needs to |
319 // has to stretch the columns to make more content fit. If no breaks are r
eported | 327 // know by how much it has to stretch the columns to make more content |
320 // (but do occur), the balancer will have no clue. Only measure the space
after the | 328 // fit. If no breaks are reported (but do occur), the balancer will have |
321 // last column boundary, in case it crosses more than one. | 329 // no clue. Only measure the space after the last column boundary, in case |
| 330 // it crosses more than one. |
322 LayoutUnit spaceUsedInLastColumn = | 331 LayoutUnit spaceUsedInLastColumn = |
323 bottomInFlowThread - | 332 bottomInFlowThread - |
324 group.columnLogicalTopForOffset(bottomInFlowThread); | 333 group.columnLogicalTopForOffset(bottomInFlowThread); |
325 recordSpaceShortage(spaceUsedInLastColumn); | 334 recordSpaceShortage(spaceUsedInLastColumn); |
326 } | 335 } |
327 } | 336 } |
328 | 337 |
329 // If this is an inner multicol container, look for space shortage inside it. | 338 // If this is an inner multicol container, look for space shortage inside it. |
330 if (!box.isLayoutBlockFlow()) | 339 if (!box.isLayoutBlockFlow()) |
331 return; | 340 return; |
332 LayoutMultiColumnFlowThread* flowThread = | 341 LayoutMultiColumnFlowThread* flowThread = |
333 toLayoutBlockFlow(box).multiColumnFlowThread(); | 342 toLayoutBlockFlow(box).multiColumnFlowThread(); |
334 if (!flowThread || flowThread->isLayoutPagedFlowThread()) | 343 if (!flowThread || flowThread->isLayoutPagedFlowThread()) |
335 return; | 344 return; |
336 for (const LayoutMultiColumnSet* columnSet = | 345 for (const LayoutMultiColumnSet* columnSet = |
337 flowThread->firstMultiColumnSet(); | 346 flowThread->firstMultiColumnSet(); |
338 columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { | 347 columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { |
339 // Establish an inner shortage finder for this column set in the inner multi
col | 348 // Establish an inner shortage finder for this column set in the inner |
340 // container. We need to let it walk through all fragmentainer groups in one
go, or we'd | 349 // multicol container. We need to let it walk through all fragmentainer |
341 // miss the column boundaries between each fragmentainer group. We need to r
ecord space | 350 // groups in one go, or we'd miss the column boundaries between each |
342 // shortage there too. | 351 // fragmentainer group. We need to record space shortage there too. |
343 MinimumSpaceShortageFinder innerFinder( | 352 MinimumSpaceShortageFinder innerFinder( |
344 *columnSet, columnSet->logicalTopInFlowThread(), | 353 *columnSet, columnSet->logicalTopInFlowThread(), |
345 columnSet->logicalBottomInFlowThread()); | 354 columnSet->logicalBottomInFlowThread()); |
346 recordSpaceShortage(innerFinder.minimumSpaceShortage()); | 355 recordSpaceShortage(innerFinder.minimumSpaceShortage()); |
347 } | 356 } |
348 } | 357 } |
349 | 358 |
350 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) { | 359 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) { |
351 if (m_pendingStrut == LayoutUnit::min() || | 360 if (m_pendingStrut == LayoutUnit::min() || |
352 box.getPaginationBreakability() != LayoutBox::ForbidBreaks) | 361 box.getPaginationBreakability() != LayoutBox::ForbidBreaks) |
353 return; | 362 return; |
354 | 363 |
355 // The previous break was before a breakable block. Here's the first piece of
unbreakable | 364 // The previous break was before a breakable block. Here's the first piece of |
356 // content after / inside that block. We want to record the distance from the
top of the column | 365 // unbreakable content after / inside that block. We want to record the |
357 // to the bottom of this box as space shortage. | 366 // distance from the top of the column to the bottom of this box as space |
| 367 // shortage. |
358 LayoutUnit logicalOffsetFromCurrentColumn = | 368 LayoutUnit logicalOffsetFromCurrentColumn = |
359 offsetFromColumnLogicalTop(flowThreadOffset()); | 369 offsetFromColumnLogicalTop(flowThreadOffset()); |
360 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - | 370 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - |
361 m_pendingStrut); | 371 m_pendingStrut); |
362 m_pendingStrut = LayoutUnit::min(); | 372 m_pendingStrut = LayoutUnit::min(); |
363 } | 373 } |
364 | 374 |
365 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) { | 375 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) { |
366 LayoutUnit lineTop = line.lineTopWithLeading(); | 376 LayoutUnit lineTop = line.lineTopWithLeading(); |
367 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; | 377 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; |
368 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; | 378 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; |
369 if (m_pendingStrut != LayoutUnit::min()) { | 379 if (m_pendingStrut != LayoutUnit::min()) { |
370 // The previous break was before a breakable block. Here's the first line af
ter / inside | 380 // The previous break was before a breakable block. Here's the first line |
371 // that block. We want to record the distance from the top of the column to
the bottom of | 381 // after / inside that block. We want to record the distance from the top of |
372 // this box as space shortage. | 382 // the column to the bottom of this box as space shortage. |
373 LayoutUnit logicalOffsetFromCurrentColumn = | 383 LayoutUnit logicalOffsetFromCurrentColumn = |
374 offsetFromColumnLogicalTop(lineTopInFlowThread); | 384 offsetFromColumnLogicalTop(lineTopInFlowThread); |
375 recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - | 385 recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - |
376 m_pendingStrut); | 386 m_pendingStrut); |
377 m_pendingStrut = LayoutUnit::min(); | 387 m_pendingStrut = LayoutUnit::min(); |
378 return; | 388 return; |
379 } | 389 } |
380 ASSERT( | 390 ASSERT( |
381 isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || | 391 isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || |
382 !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); | 392 !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); |
383 if (isFirstAfterBreak(lineTopInFlowThread)) | 393 if (isFirstAfterBreak(lineTopInFlowThread)) |
384 recordSpaceShortage(lineHeight - line.paginationStrut()); | 394 recordSpaceShortage(lineHeight - line.paginationStrut()); |
385 | 395 |
386 // Even if the line box itself fits fine inside a column, some content may ove
rflow the line | 396 // Even if the line box itself fits fine inside a column, some content may |
387 // box bottom (due to restrictive line-height, for instance). We should check
if some portion | 397 // overflow the line box bottom (due to restrictive line-height, for |
388 // of said overflow ends up in the next column. That counts as space shortage. | 398 // instance). We should check if some portion of said overflow ends up in the |
| 399 // next column. That counts as space shortage. |
389 const MultiColumnFragmentainerGroup& group = | 400 const MultiColumnFragmentainerGroup& group = |
390 groupAtOffset(lineTopInFlowThread); | 401 groupAtOffset(lineTopInFlowThread); |
391 LayoutUnit lineBottomWithOverflow = | 402 LayoutUnit lineBottomWithOverflow = |
392 lineTopInFlowThread + line.lineBottom() - lineTop; | 403 lineTopInFlowThread + line.lineBottom() - lineTop; |
393 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != | 404 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != |
394 group.columnLogicalTopForOffset(lineBottomWithOverflow)) { | 405 group.columnLogicalTopForOffset(lineBottomWithOverflow)) { |
395 LayoutUnit shortage = | 406 LayoutUnit shortage = |
396 lineBottomWithOverflow - | 407 lineBottomWithOverflow - |
397 group.columnLogicalTopForOffset(lineBottomWithOverflow); | 408 group.columnLogicalTopForOffset(lineBottomWithOverflow); |
398 recordSpaceShortage(shortage); | 409 recordSpaceShortage(shortage); |
399 } | 410 } |
400 } | 411 } |
401 | 412 |
402 } // namespace blink | 413 } // namespace blink |
OLD | NEW |