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