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

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

Issue 2493833004: InitialColumnHeightFinder needs to take all expected rows into account. (Closed)
Patch Set: Code review Created 4 years, 1 month 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 LayoutMultiColumnSet& columnSet, 13 ColumnBalancer::ColumnBalancer(const LayoutMultiColumnSet& columnSet,
14 LayoutUnit logicalTopInFlowThread, 14 LayoutUnit logicalTopInFlowThread,
15 LayoutUnit logicalBottomInFlowThread) 15 LayoutUnit logicalBottomInFlowThread)
16 : m_columnSet(columnSet), 16 : m_columnSet(columnSet),
17 m_logicalTopInFlowThread(logicalTopInFlowThread), 17 m_logicalTopInFlowThread(logicalTopInFlowThread),
18 m_logicalBottomInFlowThread(logicalBottomInFlowThread) {} 18 m_logicalBottomInFlowThread(logicalBottomInFlowThread) {
19 DCHECK_GE(columnSet.usedColumnCount(), 1U);
20 }
19 21
20 void ColumnBalancer::traverse() { 22 void ColumnBalancer::traverse() {
21 traverseSubtree(*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 if (box.childrenInline() && box.isLayoutBlockFlow()) { 28 if (box.childrenInline() && box.isLayoutBlockFlow()) {
27 // Look for breaks between lines. 29 // Look for breaks between lines.
28 traverseLines(toLayoutBlockFlow(box)); 30 traverseLines(toLayoutBlockFlow(box));
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 strut = LayoutUnit::max(); 138 strut = LayoutUnit::max();
137 traverse(); 139 traverse();
138 // We have now found each explicit / forced break, and their location. Now we 140 // We have now found each explicit / forced break, and their location. Now we
139 // need to figure out how many additional implicit / soft breaks we need and 141 // need to figure out how many additional implicit / soft breaks we need and
140 // guess where they will occur, in order 142 // guess where they will occur, in order
141 // to provide an initial column height. 143 // to provide an initial column height.
142 distributeImplicitBreaks(); 144 distributeImplicitBreaks();
143 } 145 }
144 146
145 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const { 147 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const {
148 LayoutUnit rowLogicalTop;
149 if (m_contentRuns.size() > columnSet().usedColumnCount()) {
150 // We have not inserted additional fragmentainer groups yet (because we
151 // aren't able to calculate their constraints yet), but we already know for
152 // sure that there'll be more than one of them, due to the number of forced
153 // breaks in a nested multicol container. We will now attempt to take all
154 // the imaginary rows into account and calculate a minimal balanced logical
155 // height for everything.
156 unsigned stride = columnSet().usedColumnCount();
157 LayoutUnit rowStartOffset = logicalTopInFlowThread();
158 for (unsigned i = 0; i < firstContentRunIndexInLastRow(); i += stride) {
159 LayoutUnit rowEndOffset = m_contentRuns[i + stride - 1].breakOffset();
160 float rowHeight = float(rowEndOffset - rowStartOffset) / float(stride);
161 rowLogicalTop += LayoutUnit::fromFloatCeil(rowHeight);
162 rowStartOffset = rowEndOffset;
163 }
164 }
146 unsigned index = contentRunIndexWithTallestColumns(); 165 unsigned index = contentRunIndexWithTallestColumns();
147 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() 166 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
148 : logicalTopInFlowThread(); 167 : logicalTopInFlowThread();
149 return m_contentRuns[index].columnLogicalHeight(startOffset); 168 LayoutUnit height = m_contentRuns[index].columnLogicalHeight(startOffset);
169 return rowLogicalTop + std::max(height, m_tallestUnbreakableLogicalHeight);
150 } 170 }
151 171
152 void InitialColumnHeightFinder::examineBoxAfterEntering( 172 void InitialColumnHeightFinder::examineBoxAfterEntering(
153 const LayoutBox& box, 173 const LayoutBox& box,
154 LayoutUnit childLogicalHeight, 174 LayoutUnit childLogicalHeight,
155 EBreak previousBreakAfterValue) { 175 EBreak previousBreakAfterValue) {
156 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { 176 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
157 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { 177 if (box.needsForcedBreakBefore(previousBreakAfterValue)) {
158 addContentRun(flowThreadOffset()); 178 addContentRun(flowThreadOffset());
159 } else { 179 } else {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 ASSERT( 233 ASSERT(
214 isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || 234 isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() ||
215 !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); 235 !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut()));
216 if (isFirstAfterBreak(lineTopInFlowThread)) 236 if (isFirstAfterBreak(lineTopInFlowThread))
217 recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); 237 recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut());
218 } 238 }
219 239
220 void InitialColumnHeightFinder::recordStrutBeforeOffset( 240 void InitialColumnHeightFinder::recordStrutBeforeOffset(
221 LayoutUnit offsetInFlowThread, 241 LayoutUnit offsetInFlowThread,
222 LayoutUnit strut) { 242 LayoutUnit strut) {
223 ASSERT(columnSet().usedColumnCount() >= 1);
224 unsigned columnCount = columnSet().usedColumnCount(); 243 unsigned columnCount = columnSet().usedColumnCount();
225 ASSERT(m_shortestStruts.size() == columnCount); 244 ASSERT(m_shortestStruts.size() == columnCount);
226 unsigned index = groupAtOffset(offsetInFlowThread) 245 unsigned index = groupAtOffset(offsetInFlowThread)
227 .columnIndexAtOffset(offsetInFlowThread - strut, 246 .columnIndexAtOffset(offsetInFlowThread - strut,
228 LayoutBox::AssociateWithLatterPage); 247 LayoutBox::AssociateWithLatterPage);
229 if (index >= columnCount) 248 if (index >= columnCount)
230 return; 249 return;
231 m_shortestStruts[index] = std::min(m_shortestStruts[index], strut); 250 m_shortestStruts[index] = std::min(m_shortestStruts[index], strut);
232 } 251 }
233 252
(...skipping 14 matching lines...) Expand all
248 return totalStrutSpace; 267 return totalStrutSpace;
249 } 268 }
250 269
251 void InitialColumnHeightFinder::addContentRun( 270 void InitialColumnHeightFinder::addContentRun(
252 LayoutUnit endOffsetInFlowThread) { 271 LayoutUnit endOffsetInFlowThread) {
253 endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread); 272 endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread);
254 if (!m_contentRuns.isEmpty() && 273 if (!m_contentRuns.isEmpty() &&
255 endOffsetInFlowThread <= m_contentRuns.last().breakOffset()) 274 endOffsetInFlowThread <= m_contentRuns.last().breakOffset())
256 return; 275 return;
257 // Append another item as long as we haven't exceeded used column count. What 276 // Append another item as long as we haven't exceeded used column count. What
258 // ends up in the overflow area shouldn't affect column balancing. 277 // ends up in the overflow area shouldn't affect column balancing. However, if
259 if (m_contentRuns.size() < columnSet().usedColumnCount()) 278 // we're in a nested fragmentation context, we may still need to record all
260 m_contentRuns.append(ContentRun(endOffsetInFlowThread)); 279 // runs, since there'll be no overflow area in the inline direction then, but
280 // rather additional rows of columns in multiple outer fragmentainers.
281 if (m_contentRuns.size() >= columnSet().usedColumnCount()) {
282 const auto* flowThread = columnSet().multiColumnFlowThread();
283 if (!flowThread->enclosingFragmentationContext() ||
284 columnSet().newFragmentainerGroupsAllowed())
285 return;
286 }
287 m_contentRuns.append(ContentRun(endOffsetInFlowThread));
261 } 288 }
262 289
263 unsigned InitialColumnHeightFinder::contentRunIndexWithTallestColumns() const { 290 unsigned InitialColumnHeightFinder::contentRunIndexWithTallestColumns() const {
264 unsigned indexWithLargestHeight = 0; 291 unsigned indexWithLargestHeight = 0;
265 LayoutUnit largestHeight; 292 LayoutUnit largestHeight;
266 LayoutUnit previousOffset = logicalTopInFlowThread(); 293 LayoutUnit previousOffset = logicalTopInFlowThread();
267 size_t runCount = m_contentRuns.size(); 294 size_t runCount = m_contentRuns.size();
268 ASSERT(runCount); 295 ASSERT(runCount);
269 for (size_t i = 0; i < runCount; i++) { 296 for (size_t i = firstContentRunIndexInLastRow(); i < runCount; i++) {
270 const ContentRun& run = m_contentRuns[i]; 297 const ContentRun& run = m_contentRuns[i];
271 LayoutUnit height = run.columnLogicalHeight(previousOffset); 298 LayoutUnit height = run.columnLogicalHeight(previousOffset);
272 if (largestHeight < height) { 299 if (largestHeight < height) {
273 largestHeight = height; 300 largestHeight = height;
274 indexWithLargestHeight = i; 301 indexWithLargestHeight = i;
275 } 302 }
276 previousOffset = run.breakOffset(); 303 previousOffset = run.breakOffset();
277 } 304 }
278 return indexWithLargestHeight; 305 return indexWithLargestHeight;
279 } 306 }
280 307
281 void InitialColumnHeightFinder::distributeImplicitBreaks() { 308 void InitialColumnHeightFinder::distributeImplicitBreaks() {
282 // Insert a final content run to encompass all content. This will include 309 // Insert a final content run to encompass all content. This will include
283 // overflow if we're at the end of the multicol container. 310 // overflow if we're at the end of the multicol container.
284 addContentRun(logicalBottomInFlowThread()); 311 addContentRun(logicalBottomInFlowThread());
285 unsigned columnCount = m_contentRuns.size(); 312 unsigned columnCount = m_contentRuns.size();
286 313
287 // If there is room for more breaks (to reach the used value of column-count), 314 // If there is room for more breaks (to reach the used value of column-count),
288 // imagine that we insert implicit breaks at suitable locations. At any given 315 // imagine that we insert implicit breaks at suitable locations. At any given
289 // time, the content run with the currently tallest columns will get another 316 // time, the content run with the currently tallest columns will get another
290 // implicit break "inserted", which will increase its column count by one and 317 // implicit break "inserted", which will increase its column count by one and
291 // shrink its columns' height. Repeat until we have the desired total number 318 // shrink its columns' height. Repeat until we have the desired total number
292 // of breaks. The largest column height among the runs will then be the 319 // of breaks. The largest column height among the runs will then be the
293 // initial column height for the balancer to use. 320 // initial column height for the balancer to use.
321 if (columnCount > columnSet().usedColumnCount()) {
322 // If we exceed used column-count (which we are allowed to do if we're at
323 // the initial balancing pass for a multicol that lives inside another
324 // to-be-balanced outer multicol container), we only care about content that
325 // could end up in the last row. We need to pad up the number of columns, so
326 // that all rows will contain as many columns as used column-count dictates.
327 columnCount %= columnSet().usedColumnCount();
328 // If there are just enough explicit breaks to fill all rows with the right
329 // amount of columns, we won't be needing any implicit breaks.
330 if (!columnCount)
331 return;
332 }
294 while (columnCount < columnSet().usedColumnCount()) { 333 while (columnCount < columnSet().usedColumnCount()) {
295 unsigned index = contentRunIndexWithTallestColumns(); 334 unsigned index = contentRunIndexWithTallestColumns();
296 m_contentRuns[index].assumeAnotherImplicitBreak(); 335 m_contentRuns[index].assumeAnotherImplicitBreak();
297 columnCount++; 336 columnCount++;
298 } 337 }
299 } 338 }
300 339
301 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder( 340 MinimumSpaceShortageFinder::MinimumSpaceShortageFinder(
302 const LayoutMultiColumnSet& columnSet, 341 const LayoutMultiColumnSet& columnSet,
303 LayoutUnit logicalTopInFlowThread, 342 LayoutUnit logicalTopInFlowThread,
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != 474 if (group.columnLogicalTopForOffset(lineTopInFlowThread) !=
436 group.columnLogicalTopForOffset(lineBottomWithOverflow)) { 475 group.columnLogicalTopForOffset(lineBottomWithOverflow)) {
437 LayoutUnit shortage = 476 LayoutUnit shortage =
438 lineBottomWithOverflow - 477 lineBottomWithOverflow -
439 group.columnLogicalTopForOffset(lineBottomWithOverflow); 478 group.columnLogicalTopForOffset(lineBottomWithOverflow);
440 recordSpaceShortage(shortage); 479 recordSpaceShortage(shortage);
441 } 480 }
442 } 481 }
443 482
444 } // namespace blink 483 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698