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