| 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 |