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