Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: third_party/WebKit/Source/core/layout/ColumnBalancer.cpp

Issue 1891783002: Support multiple fragmentainer groups per ColumnBalancer run. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698