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

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

Issue 2465363003: Improve how the column balancer handles top margins on floats. (Closed)
Patch Set: Back out some unnecessary changes that caused assertion failures in a test. 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
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 break; 45 break;
46 examineLine(*line); 46 examineLine(*line);
47 } 47 }
48 } 48 }
49 49
50 void ColumnBalancer::traverseChildren(const LayoutObject& object) { 50 void ColumnBalancer::traverseChildren(const LayoutObject& object) {
51 // The break-after value from the previous in-flow block-level object to be 51 // The break-after value from the previous in-flow block-level object to be
52 // joined with the break-before value of the next in-flow block-level sibling. 52 // joined with the break-before value of the next in-flow block-level sibling.
53 EBreak previousBreakAfterValue = BreakAuto; 53 EBreak previousBreakAfterValue = BreakAuto;
54 54
55 const LayoutFlowThread* flowThread = columnSet().flowThread();
56 bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode();
57
58 for (const LayoutObject* child = object.slowFirstChild(); child; 55 for (const LayoutObject* child = object.slowFirstChild(); child;
59 child = child->nextSibling()) { 56 child = child->nextSibling()) {
60 if (!child->isBox()) { 57 if (!child->isBox()) {
61 // Keep traversing inside inlines. There may be floats there. 58 // Keep traversing inside inlines. There may be floats there.
62 if (child->isLayoutInline()) 59 if (child->isLayoutInline())
63 traverseChildren(*child); 60 traverseChildren(*child);
64 continue; 61 continue;
65 } 62 }
66 63
67 const LayoutBox& childBox = toLayoutBox(*child); 64 const LayoutBox& childBox = toLayoutBox(*child);
68 LayoutRect overflowRect = childBox.layoutOverflowRect(); 65
69 LayoutUnit childLogicalBottomWithOverflow = 66 LayoutUnit borderBoxOffset;
70 childBox.logicalTop() + 67 LayoutUnit logicalTop = childBox.logicalTop();
71 (isHorizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); 68 LayoutUnit logicalHeight = childBox.logicalHeightWithVisibleOverflow();
72 if (m_flowThreadOffset + childLogicalBottomWithOverflow <= 69 // Floats' margins don't collapse with column boundaries, and we don't want
70 // to break inside them, or separate them from the float's border box. Set
71 // the offset to the margin-before edge (rather than border-before edge),
72 // and include the block direction margins in the child height.
73 if (childBox.isFloating()) {
74 LayoutUnit marginBefore = childBox.marginBefore(object.style());
75 LayoutUnit marginAfter = childBox.marginAfter(object.style());
76 logicalHeight =
77 std::max(logicalHeight, childBox.logicalHeight() + marginAfter);
78 logicalTop -= marginBefore;
79 logicalHeight += marginBefore;
80
81 // As soon as we want to process content inside this child, though, we
82 // need to get to its border-before edge, though.
83 borderBoxOffset = marginBefore;
84 }
85
86 if (m_flowThreadOffset + logicalTop + logicalHeight <=
73 logicalTopInFlowThread()) { 87 logicalTopInFlowThread()) {
74 // This child is fully above the flow thread portion we're examining. 88 // This child is fully above the flow thread portion we're examining.
75 continue; 89 continue;
76 } 90 }
77 LayoutUnit childLogicalTopWithOverflow = 91 if (m_flowThreadOffset + logicalTop >= logicalBottomInFlowThread()) {
78 childBox.logicalTop() +
79 (isHorizontalWritingMode ? overflowRect.y() : overflowRect.x());
80 if (m_flowThreadOffset + childLogicalTopWithOverflow >=
81 logicalBottomInFlowThread()) {
82 // This child is fully below the flow thread portion we're examining. We 92 // This child is fully below the flow thread portion we're examining. We
83 // cannot just stop here, though, thanks to negative margins. 93 // cannot just stop here, though, thanks to negative margins.
84 // So keep looking. 94 // So keep looking.
85 continue; 95 continue;
86 } 96 }
87 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) 97 if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll())
88 continue; 98 continue;
89 99
90 // Tables are wicked. Both table rows and table cells are relative to their 100 // Tables are wicked. Both table rows and table cells are relative to their
91 // table section. 101 // table section.
92 LayoutUnit offsetForThisChild = 102 LayoutUnit offsetForThisChild =
93 childBox.isTableRow() ? LayoutUnit() : childBox.logicalTop(); 103 childBox.isTableRow() ? LayoutUnit() : logicalTop;
104
94 m_flowThreadOffset += offsetForThisChild; 105 m_flowThreadOffset += offsetForThisChild;
95 106
96 examineBoxAfterEntering(childBox, previousBreakAfterValue); 107 examineBoxAfterEntering(childBox, logicalHeight, previousBreakAfterValue);
97 // Unless the child is unsplittable, or if the child establishes an inner 108 // Unless the child is unsplittable, or if the child establishes an inner
98 // multicol container, we descend into its subtree for further examination. 109 // multicol container, we descend into its subtree for further examination.
99 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks && 110 if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks &&
100 (!childBox.isLayoutBlockFlow() || 111 (!childBox.isLayoutBlockFlow() ||
101 !toLayoutBlockFlow(childBox).multiColumnFlowThread())) 112 !toLayoutBlockFlow(childBox).multiColumnFlowThread())) {
113 m_flowThreadOffset += borderBoxOffset;
eae 2016/11/01 21:46:30 This looks a little fishy, instead of inflating th
mstensho (USE GERRIT) 2016/11/01 22:09:38 I'm not sure if that would be cleaner, since we al
102 traverseSubtree(childBox); 114 traverseSubtree(childBox);
115 m_flowThreadOffset -= borderBoxOffset;
116 }
103 previousBreakAfterValue = childBox.breakAfter(); 117 previousBreakAfterValue = childBox.breakAfter();
104 examineBoxBeforeLeaving(childBox); 118 examineBoxBeforeLeaving(childBox, logicalHeight);
105 119
106 m_flowThreadOffset -= offsetForThisChild; 120 m_flowThreadOffset -= offsetForThisChild;
107 } 121 }
108 } 122 }
109 123
110 InitialColumnHeightFinder::InitialColumnHeightFinder( 124 InitialColumnHeightFinder::InitialColumnHeightFinder(
111 const LayoutMultiColumnSet& columnSet, 125 const LayoutMultiColumnSet& columnSet,
112 LayoutUnit logicalTopInFlowThread, 126 LayoutUnit logicalTopInFlowThread,
113 LayoutUnit logicalBottomInFlowThread) 127 LayoutUnit logicalBottomInFlowThread)
114 : ColumnBalancer(columnSet, 128 : ColumnBalancer(columnSet,
(...skipping 12 matching lines...) Expand all
127 141
128 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const { 142 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const {
129 unsigned index = contentRunIndexWithTallestColumns(); 143 unsigned index = contentRunIndexWithTallestColumns();
130 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() 144 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
131 : logicalTopInFlowThread(); 145 : logicalTopInFlowThread();
132 return m_contentRuns[index].columnLogicalHeight(startOffset); 146 return m_contentRuns[index].columnLogicalHeight(startOffset);
133 } 147 }
134 148
135 void InitialColumnHeightFinder::examineBoxAfterEntering( 149 void InitialColumnHeightFinder::examineBoxAfterEntering(
136 const LayoutBox& box, 150 const LayoutBox& box,
151 LayoutUnit childLogicalHeight,
137 EBreak previousBreakAfterValue) { 152 EBreak previousBreakAfterValue) {
138 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { 153 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
139 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { 154 if (box.needsForcedBreakBefore(previousBreakAfterValue)) {
140 addContentRun(flowThreadOffset()); 155 addContentRun(flowThreadOffset());
141 } else { 156 } else {
142 if (isFirstAfterBreak(flowThreadOffset())) { 157 if (isFirstAfterBreak(flowThreadOffset())) {
143 // This box is first after a soft break. 158 // This box is first after a soft break.
144 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut()); 159 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut());
145 } 160 }
146 } 161 }
147 } 162 }
148 163
149 if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) { 164 if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) {
150 LayoutUnit unsplittableLogicalHeight = box.logicalHeight();
151 if (box.isFloating())
152 unsplittableLogicalHeight += box.marginBefore() + box.marginAfter();
153 m_tallestUnbreakableLogicalHeight = 165 m_tallestUnbreakableLogicalHeight =
154 std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight); 166 std::max(m_tallestUnbreakableLogicalHeight, childLogicalHeight);
155 return; 167 return;
156 } 168 }
157 // Need to examine inner multicol containers to find their tallest unbreakable 169 // Need to examine inner multicol containers to find their tallest unbreakable
158 // piece of content. 170 // piece of content.
159 if (!box.isLayoutBlockFlow()) 171 if (!box.isLayoutBlockFlow())
160 return; 172 return;
161 LayoutMultiColumnFlowThread* innerFlowThread = 173 LayoutMultiColumnFlowThread* innerFlowThread =
162 toLayoutBlockFlow(box).multiColumnFlowThread(); 174 toLayoutBlockFlow(box).multiColumnFlowThread();
163 if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread()) 175 if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread())
164 return; 176 return;
165 LayoutUnit offsetInInnerFlowThread = 177 LayoutUnit offsetInInnerFlowThread =
166 flowThreadOffset() - 178 flowThreadOffset() -
167 innerFlowThread->blockOffsetInEnclosingFragmentationContext(); 179 innerFlowThread->blockOffsetInEnclosingFragmentationContext();
168 LayoutUnit innerUnbreakableHeight = 180 LayoutUnit innerUnbreakableHeight =
169 innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread); 181 innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread);
170 m_tallestUnbreakableLogicalHeight = 182 m_tallestUnbreakableLogicalHeight =
171 std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight); 183 std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight);
172 } 184 }
173 185
174 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box) {} 186 void InitialColumnHeightFinder::examineBoxBeforeLeaving(
187 const LayoutBox& box,
188 LayoutUnit childLogicalHeight) {}
175 189
176 static inline LayoutUnit columnLogicalHeightRequirementForLine( 190 static inline LayoutUnit columnLogicalHeightRequirementForLine(
177 const ComputedStyle& style, 191 const ComputedStyle& style,
178 const RootInlineBox& lastLine) { 192 const RootInlineBox& lastLine) {
179 // We may require a certain minimum number of lines per page in order to 193 // We may require a certain minimum number of lines per page in order to
180 // satisfy orphans and widows, and that may affect the minimum page height. 194 // satisfy orphans and widows, and that may affect the minimum page height.
181 unsigned minimumLineCount = 195 unsigned minimumLineCount =
182 std::max<unsigned>(style.orphans(), style.widows()); 196 std::max<unsigned>(style.orphans(), style.widows());
183 const RootInlineBox* firstLine = &lastLine; 197 const RootInlineBox* firstLine = &lastLine;
184 for (unsigned i = 1; i < minimumLineCount && firstLine->prevRootBox(); i++) 198 for (unsigned i = 1; i < minimumLineCount && firstLine->prevRootBox(); i++)
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 logicalTopInFlowThread, 303 logicalTopInFlowThread,
290 logicalBottomInFlowThread), 304 logicalBottomInFlowThread),
291 m_minimumSpaceShortage(LayoutUnit::max()), 305 m_minimumSpaceShortage(LayoutUnit::max()),
292 m_pendingStrut(LayoutUnit::min()), 306 m_pendingStrut(LayoutUnit::min()),
293 m_forcedBreaksCount(0) { 307 m_forcedBreaksCount(0) {
294 traverse(); 308 traverse();
295 } 309 }
296 310
297 void MinimumSpaceShortageFinder::examineBoxAfterEntering( 311 void MinimumSpaceShortageFinder::examineBoxAfterEntering(
298 const LayoutBox& box, 312 const LayoutBox& box,
313 LayoutUnit childLogicalHeight,
299 EBreak previousBreakAfterValue) { 314 EBreak previousBreakAfterValue) {
300 LayoutBox::PaginationBreakability breakability = 315 LayoutBox::PaginationBreakability breakability =
301 box.getPaginationBreakability(); 316 box.getPaginationBreakability();
302 317
303 // Look for breaks before the child box. 318 // Look for breaks before the child box.
304 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { 319 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
305 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { 320 if (box.needsForcedBreakBefore(previousBreakAfterValue)) {
306 m_forcedBreaksCount++; 321 m_forcedBreaksCount++;
307 } else { 322 } else {
308 if (isFirstAfterBreak(flowThreadOffset())) { 323 if (isFirstAfterBreak(flowThreadOffset())) {
309 // This box is first after a soft break. 324 // This box is first after a soft break.
310 LayoutUnit strut = box.paginationStrut(); 325 LayoutUnit strut = box.paginationStrut();
311 // Figure out how much more space we would need to prevent it from being 326 // Figure out how much more space we would need to prevent it from being
312 // pushed to the next column. 327 // pushed to the next column.
313 recordSpaceShortage(box.logicalHeight() - strut); 328 recordSpaceShortage(childLogicalHeight - strut);
314 if (breakability != LayoutBox::ForbidBreaks && 329 if (breakability != LayoutBox::ForbidBreaks &&
315 m_pendingStrut == LayoutUnit::min()) { 330 m_pendingStrut == LayoutUnit::min()) {
316 // We now want to look for the first piece of unbreakable content 331 // We now want to look for the first piece of unbreakable content
317 // (e.g. a line or a block-displayed image) inside this block. That 332 // (e.g. a line or a block-displayed image) inside this block. That
318 // ought to be a good candidate for minimum space shortage; a much 333 // ought to be a good candidate for minimum space shortage; a much
319 // better one than reporting space shortage for the entire block 334 // better one than reporting space shortage for the entire block
320 // (which we'll also do (further down), in case we couldn't find 335 // (which we'll also do (further down), in case we couldn't find
321 // anything more suitable). 336 // anything more suitable).
322 m_pendingStrut = strut; 337 m_pendingStrut = strut;
323 } 338 }
324 } 339 }
325 } 340 }
326 } 341 }
327 342
328 if (breakability != LayoutBox::ForbidBreaks) { 343 if (breakability != LayoutBox::ForbidBreaks) {
329 // See if this breakable box crosses column boundaries. 344 // See if this breakable box crosses column boundaries.
330 LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight(); 345 LayoutUnit bottomInFlowThread = flowThreadOffset() + childLogicalHeight;
331 const MultiColumnFragmentainerGroup& group = 346 const MultiColumnFragmentainerGroup& group =
332 groupAtOffset(flowThreadOffset()); 347 groupAtOffset(flowThreadOffset());
333 if (isFirstAfterBreak(flowThreadOffset()) || 348 if (isFirstAfterBreak(flowThreadOffset()) ||
334 group.columnLogicalTopForOffset(flowThreadOffset()) != 349 group.columnLogicalTopForOffset(flowThreadOffset()) !=
335 group.columnLogicalTopForOffset(bottomInFlowThread)) { 350 group.columnLogicalTopForOffset(bottomInFlowThread)) {
336 // If the child crosses a column boundary, record space shortage, in case 351 // If the child crosses a column boundary, record space shortage, in case
337 // nothing inside it has already done so. The column balancer needs to 352 // nothing inside it has already done so. The column balancer needs to
338 // know by how much it has to stretch the columns to make more content 353 // know by how much it has to stretch the columns to make more content
339 // fit. If no breaks are reported (but do occur), the balancer will have 354 // fit. If no breaks are reported (but do occur), the balancer will have
340 // no clue. Only measure the space after the last column boundary, in case 355 // no clue. Only measure the space after the last column boundary, in case
(...skipping 19 matching lines...) Expand all
360 // multicol container. We need to let it walk through all fragmentainer 375 // multicol container. We need to let it walk through all fragmentainer
361 // groups in one go, or we'd miss the column boundaries between each 376 // groups in one go, or we'd miss the column boundaries between each
362 // fragmentainer group. We need to record space shortage there too. 377 // fragmentainer group. We need to record space shortage there too.
363 MinimumSpaceShortageFinder innerFinder( 378 MinimumSpaceShortageFinder innerFinder(
364 *columnSet, columnSet->logicalTopInFlowThread(), 379 *columnSet, columnSet->logicalTopInFlowThread(),
365 columnSet->logicalBottomInFlowThread()); 380 columnSet->logicalBottomInFlowThread());
366 recordSpaceShortage(innerFinder.minimumSpaceShortage()); 381 recordSpaceShortage(innerFinder.minimumSpaceShortage());
367 } 382 }
368 } 383 }
369 384
370 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) { 385 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(
386 const LayoutBox& box,
387 LayoutUnit childLogicalHeight) {
371 if (m_pendingStrut == LayoutUnit::min() || 388 if (m_pendingStrut == LayoutUnit::min() ||
372 box.getPaginationBreakability() != LayoutBox::ForbidBreaks) 389 box.getPaginationBreakability() != LayoutBox::ForbidBreaks)
373 return; 390 return;
374 391
375 // The previous break was before a breakable block. Here's the first piece of 392 // The previous break was before a breakable block. Here's the first piece of
376 // unbreakable content after / inside that block. We want to record the 393 // unbreakable content after / inside that block. We want to record the
377 // distance from the top of the column to the bottom of this box as space 394 // distance from the top of the column to the bottom of this box as space
378 // shortage. 395 // shortage.
379 LayoutUnit logicalOffsetFromCurrentColumn = 396 LayoutUnit logicalOffsetFromCurrentColumn =
380 offsetFromColumnLogicalTop(flowThreadOffset()); 397 offsetFromColumnLogicalTop(flowThreadOffset());
381 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - 398 recordSpaceShortage(logicalOffsetFromCurrentColumn + childLogicalHeight -
382 m_pendingStrut); 399 m_pendingStrut);
383 m_pendingStrut = LayoutUnit::min(); 400 m_pendingStrut = LayoutUnit::min();
384 } 401 }
385 402
386 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) { 403 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) {
387 LayoutUnit lineTop = line.lineTopWithLeading(); 404 LayoutUnit lineTop = line.lineTopWithLeading();
388 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; 405 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop;
389 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; 406 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop;
390 if (m_pendingStrut != LayoutUnit::min()) { 407 if (m_pendingStrut != LayoutUnit::min()) {
391 // The previous break was before a breakable block. Here's the first line 408 // The previous break was before a breakable block. Here's the first line
(...skipping 23 matching lines...) Expand all
415 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != 432 if (group.columnLogicalTopForOffset(lineTopInFlowThread) !=
416 group.columnLogicalTopForOffset(lineBottomWithOverflow)) { 433 group.columnLogicalTopForOffset(lineBottomWithOverflow)) {
417 LayoutUnit shortage = 434 LayoutUnit shortage =
418 lineBottomWithOverflow - 435 lineBottomWithOverflow -
419 group.columnLogicalTopForOffset(lineBottomWithOverflow); 436 group.columnLogicalTopForOffset(lineBottomWithOverflow);
420 recordSpaceShortage(shortage); 437 recordSpaceShortage(shortage);
421 } 438 }
422 } 439 }
423 440
424 } // namespace blink 441 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/layout/ColumnBalancer.h ('k') | third_party/WebKit/Source/core/layout/LayoutBox.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698