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

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

Issue 2471933002: Reland of Improve how the column balancer handles top margins on floats. (Closed)
Patch Set: 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 borderEdgeOffset;
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.
83 borderEdgeOffset = 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 // We need to get to the border edge before processing content inside
114 // this child. If the child is floated, we're currently at the margin
115 // edge.
116 m_flowThreadOffset += borderEdgeOffset;
102 traverseSubtree(childBox); 117 traverseSubtree(childBox);
118 m_flowThreadOffset -= borderEdgeOffset;
119 }
103 previousBreakAfterValue = childBox.breakAfter(); 120 previousBreakAfterValue = childBox.breakAfter();
104 examineBoxBeforeLeaving(childBox); 121 examineBoxBeforeLeaving(childBox, logicalHeight);
105 122
106 m_flowThreadOffset -= offsetForThisChild; 123 m_flowThreadOffset -= offsetForThisChild;
107 } 124 }
108 } 125 }
109 126
110 InitialColumnHeightFinder::InitialColumnHeightFinder( 127 InitialColumnHeightFinder::InitialColumnHeightFinder(
111 const LayoutMultiColumnSet& columnSet, 128 const LayoutMultiColumnSet& columnSet,
112 LayoutUnit logicalTopInFlowThread, 129 LayoutUnit logicalTopInFlowThread,
113 LayoutUnit logicalBottomInFlowThread) 130 LayoutUnit logicalBottomInFlowThread)
114 : ColumnBalancer(columnSet, 131 : ColumnBalancer(columnSet,
(...skipping 12 matching lines...) Expand all
127 144
128 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const { 145 LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const {
129 unsigned index = contentRunIndexWithTallestColumns(); 146 unsigned index = contentRunIndexWithTallestColumns();
130 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() 147 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
131 : logicalTopInFlowThread(); 148 : logicalTopInFlowThread();
132 return m_contentRuns[index].columnLogicalHeight(startOffset); 149 return m_contentRuns[index].columnLogicalHeight(startOffset);
133 } 150 }
134 151
135 void InitialColumnHeightFinder::examineBoxAfterEntering( 152 void InitialColumnHeightFinder::examineBoxAfterEntering(
136 const LayoutBox& box, 153 const LayoutBox& box,
154 LayoutUnit childLogicalHeight,
137 EBreak previousBreakAfterValue) { 155 EBreak previousBreakAfterValue) {
138 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { 156 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
139 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { 157 if (box.needsForcedBreakBefore(previousBreakAfterValue)) {
140 addContentRun(flowThreadOffset()); 158 addContentRun(flowThreadOffset());
141 } else { 159 } else {
142 if (isFirstAfterBreak(flowThreadOffset())) { 160 if (isFirstAfterBreak(flowThreadOffset())) {
143 // This box is first after a soft break. 161 // This box is first after a soft break.
144 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut()); 162 recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut());
145 } 163 }
146 } 164 }
147 } 165 }
148 166
149 if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) { 167 if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) {
150 LayoutUnit unsplittableLogicalHeight = box.logicalHeight();
151 if (box.isFloating())
152 unsplittableLogicalHeight += box.marginBefore() + box.marginAfter();
153 m_tallestUnbreakableLogicalHeight = 168 m_tallestUnbreakableLogicalHeight =
154 std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight); 169 std::max(m_tallestUnbreakableLogicalHeight, childLogicalHeight);
155 return; 170 return;
156 } 171 }
157 // Need to examine inner multicol containers to find their tallest unbreakable 172 // Need to examine inner multicol containers to find their tallest unbreakable
158 // piece of content. 173 // piece of content.
159 if (!box.isLayoutBlockFlow()) 174 if (!box.isLayoutBlockFlow())
160 return; 175 return;
161 LayoutMultiColumnFlowThread* innerFlowThread = 176 LayoutMultiColumnFlowThread* innerFlowThread =
162 toLayoutBlockFlow(box).multiColumnFlowThread(); 177 toLayoutBlockFlow(box).multiColumnFlowThread();
163 if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread()) 178 if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread())
164 return; 179 return;
165 LayoutUnit offsetInInnerFlowThread = 180 LayoutUnit offsetInInnerFlowThread =
166 flowThreadOffset() - 181 flowThreadOffset() -
167 innerFlowThread->blockOffsetInEnclosingFragmentationContext(); 182 innerFlowThread->blockOffsetInEnclosingFragmentationContext();
168 LayoutUnit innerUnbreakableHeight = 183 LayoutUnit innerUnbreakableHeight =
169 innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread); 184 innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread);
170 m_tallestUnbreakableLogicalHeight = 185 m_tallestUnbreakableLogicalHeight =
171 std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight); 186 std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight);
172 } 187 }
173 188
174 void InitialColumnHeightFinder::examineBoxBeforeLeaving(const LayoutBox& box) {} 189 void InitialColumnHeightFinder::examineBoxBeforeLeaving(
190 const LayoutBox& box,
191 LayoutUnit childLogicalHeight) {}
175 192
176 static inline LayoutUnit columnLogicalHeightRequirementForLine( 193 static inline LayoutUnit columnLogicalHeightRequirementForLine(
177 const ComputedStyle& style, 194 const ComputedStyle& style,
178 const RootInlineBox& lastLine) { 195 const RootInlineBox& lastLine) {
179 // We may require a certain minimum number of lines per page in order to 196 // 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. 197 // satisfy orphans and widows, and that may affect the minimum page height.
181 unsigned minimumLineCount = 198 unsigned minimumLineCount =
182 std::max<unsigned>(style.orphans(), style.widows()); 199 std::max<unsigned>(style.orphans(), style.widows());
183 const RootInlineBox* firstLine = &lastLine; 200 const RootInlineBox* firstLine = &lastLine;
184 for (unsigned i = 1; i < minimumLineCount && firstLine->prevRootBox(); i++) 201 for (unsigned i = 1; i < minimumLineCount && firstLine->prevRootBox(); i++)
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 logicalTopInFlowThread, 306 logicalTopInFlowThread,
290 logicalBottomInFlowThread), 307 logicalBottomInFlowThread),
291 m_minimumSpaceShortage(LayoutUnit::max()), 308 m_minimumSpaceShortage(LayoutUnit::max()),
292 m_pendingStrut(LayoutUnit::min()), 309 m_pendingStrut(LayoutUnit::min()),
293 m_forcedBreaksCount(0) { 310 m_forcedBreaksCount(0) {
294 traverse(); 311 traverse();
295 } 312 }
296 313
297 void MinimumSpaceShortageFinder::examineBoxAfterEntering( 314 void MinimumSpaceShortageFinder::examineBoxAfterEntering(
298 const LayoutBox& box, 315 const LayoutBox& box,
316 LayoutUnit childLogicalHeight,
299 EBreak previousBreakAfterValue) { 317 EBreak previousBreakAfterValue) {
300 LayoutBox::PaginationBreakability breakability = 318 LayoutBox::PaginationBreakability breakability =
301 box.getPaginationBreakability(); 319 box.getPaginationBreakability();
302 320
303 // Look for breaks before the child box. 321 // Look for breaks before the child box.
304 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { 322 if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) {
305 if (box.needsForcedBreakBefore(previousBreakAfterValue)) { 323 if (box.needsForcedBreakBefore(previousBreakAfterValue)) {
306 m_forcedBreaksCount++; 324 m_forcedBreaksCount++;
307 } else { 325 } else {
308 if (isFirstAfterBreak(flowThreadOffset())) { 326 if (isFirstAfterBreak(flowThreadOffset())) {
309 // This box is first after a soft break. 327 // This box is first after a soft break.
310 LayoutUnit strut = box.paginationStrut(); 328 LayoutUnit strut = box.paginationStrut();
311 // Figure out how much more space we would need to prevent it from being 329 // Figure out how much more space we would need to prevent it from being
312 // pushed to the next column. 330 // pushed to the next column.
313 recordSpaceShortage(box.logicalHeight() - strut); 331 recordSpaceShortage(childLogicalHeight - strut);
314 if (breakability != LayoutBox::ForbidBreaks && 332 if (breakability != LayoutBox::ForbidBreaks &&
315 m_pendingStrut == LayoutUnit::min()) { 333 m_pendingStrut == LayoutUnit::min()) {
316 // We now want to look for the first piece of unbreakable content 334 // 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 335 // (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 336 // ought to be a good candidate for minimum space shortage; a much
319 // better one than reporting space shortage for the entire block 337 // better one than reporting space shortage for the entire block
320 // (which we'll also do (further down), in case we couldn't find 338 // (which we'll also do (further down), in case we couldn't find
321 // anything more suitable). 339 // anything more suitable).
322 m_pendingStrut = strut; 340 m_pendingStrut = strut;
323 } 341 }
324 } 342 }
325 } 343 }
326 } 344 }
327 345
328 if (breakability != LayoutBox::ForbidBreaks) { 346 if (breakability != LayoutBox::ForbidBreaks) {
329 // See if this breakable box crosses column boundaries. 347 // See if this breakable box crosses column boundaries.
330 LayoutUnit bottomInFlowThread = flowThreadOffset() + box.logicalHeight(); 348 LayoutUnit bottomInFlowThread = flowThreadOffset() + childLogicalHeight;
331 const MultiColumnFragmentainerGroup& group = 349 const MultiColumnFragmentainerGroup& group =
332 groupAtOffset(flowThreadOffset()); 350 groupAtOffset(flowThreadOffset());
333 if (isFirstAfterBreak(flowThreadOffset()) || 351 if (isFirstAfterBreak(flowThreadOffset()) ||
334 group.columnLogicalTopForOffset(flowThreadOffset()) != 352 group.columnLogicalTopForOffset(flowThreadOffset()) !=
335 group.columnLogicalTopForOffset(bottomInFlowThread)) { 353 group.columnLogicalTopForOffset(bottomInFlowThread)) {
336 // If the child crosses a column boundary, record space shortage, in case 354 // 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 355 // 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 356 // 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 357 // 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 358 // 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 378 // 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 379 // groups in one go, or we'd miss the column boundaries between each
362 // fragmentainer group. We need to record space shortage there too. 380 // fragmentainer group. We need to record space shortage there too.
363 MinimumSpaceShortageFinder innerFinder( 381 MinimumSpaceShortageFinder innerFinder(
364 *columnSet, columnSet->logicalTopInFlowThread(), 382 *columnSet, columnSet->logicalTopInFlowThread(),
365 columnSet->logicalBottomInFlowThread()); 383 columnSet->logicalBottomInFlowThread());
366 recordSpaceShortage(innerFinder.minimumSpaceShortage()); 384 recordSpaceShortage(innerFinder.minimumSpaceShortage());
367 } 385 }
368 } 386 }
369 387
370 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) { 388 void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(
389 const LayoutBox& box,
390 LayoutUnit childLogicalHeight) {
371 if (m_pendingStrut == LayoutUnit::min() || 391 if (m_pendingStrut == LayoutUnit::min() ||
372 box.getPaginationBreakability() != LayoutBox::ForbidBreaks) 392 box.getPaginationBreakability() != LayoutBox::ForbidBreaks)
373 return; 393 return;
374 394
375 // The previous break was before a breakable block. Here's the first piece of 395 // 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 396 // 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 397 // distance from the top of the column to the bottom of this box as space
378 // shortage. 398 // shortage.
379 LayoutUnit logicalOffsetFromCurrentColumn = 399 LayoutUnit logicalOffsetFromCurrentColumn =
380 offsetFromColumnLogicalTop(flowThreadOffset()); 400 offsetFromColumnLogicalTop(flowThreadOffset());
381 recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - 401 recordSpaceShortage(logicalOffsetFromCurrentColumn + childLogicalHeight -
382 m_pendingStrut); 402 m_pendingStrut);
383 m_pendingStrut = LayoutUnit::min(); 403 m_pendingStrut = LayoutUnit::min();
384 } 404 }
385 405
386 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) { 406 void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) {
387 LayoutUnit lineTop = line.lineTopWithLeading(); 407 LayoutUnit lineTop = line.lineTopWithLeading();
388 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; 408 LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop;
389 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; 409 LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop;
390 if (m_pendingStrut != LayoutUnit::min()) { 410 if (m_pendingStrut != LayoutUnit::min()) {
391 // The previous break was before a breakable block. Here's the first line 411 // The previous break was before a breakable block. Here's the first line
(...skipping 23 matching lines...) Expand all
415 if (group.columnLogicalTopForOffset(lineTopInFlowThread) != 435 if (group.columnLogicalTopForOffset(lineTopInFlowThread) !=
416 group.columnLogicalTopForOffset(lineBottomWithOverflow)) { 436 group.columnLogicalTopForOffset(lineBottomWithOverflow)) {
417 LayoutUnit shortage = 437 LayoutUnit shortage =
418 lineBottomWithOverflow - 438 lineBottomWithOverflow -
419 group.columnLogicalTopForOffset(lineBottomWithOverflow); 439 group.columnLogicalTopForOffset(lineBottomWithOverflow);
420 recordSpaceShortage(shortage); 440 recordSpaceShortage(shortage);
421 } 441 }
422 } 442 }
423 443
424 } // namespace blink 444 } // 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