1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003-2015 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "RenderBlockFlow.h"
26
27#include "Editor.h"
28#include "FloatingObjects.h"
29#include "Frame.h"
30#include "FrameSelection.h"
31#include "HTMLElement.h"
32#include "HTMLInputElement.h"
33#include "HTMLParserIdioms.h"
34#include "HTMLTextAreaElement.h"
35#include "HitTestLocation.h"
36#include "InlineTextBox.h"
37#include "LayoutRepainter.h"
38#include "Logging.h"
39#include "RenderCombineText.h"
40#include "RenderFlexibleBox.h"
41#include "RenderInline.h"
42#include "RenderIterator.h"
43#include "RenderLayer.h"
44#include "RenderLayoutState.h"
45#include "RenderLineBreak.h"
46#include "RenderListItem.h"
47#include "RenderMarquee.h"
48#include "RenderMultiColumnFlow.h"
49#include "RenderMultiColumnSet.h"
50#include "RenderTableCell.h"
51#include "RenderText.h"
52#include "RenderTreeBuilder.h"
53#include "RenderView.h"
54#include "Settings.h"
55#include "SimpleLineLayoutFunctions.h"
56#include "SimpleLineLayoutPagination.h"
57#include "SimpleLineLayoutResolver.h"
58#include "TextAutoSizing.h"
59#include "VerticalPositionCache.h"
60#include "VisiblePosition.h"
61#include <wtf/IsoMallocInlines.h>
62
63namespace WebCore {
64
65WTF_MAKE_ISO_ALLOCATED_IMPL(RenderBlockFlow);
66
67bool RenderBlock::s_canPropagateFloatIntoSibling = false;
68
69struct SameSizeAsMarginInfo {
70 uint32_t bitfields : 16;
71 LayoutUnit margins[2];
72};
73
74COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
75COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
76
77// Our MarginInfo state used when laying out block children.
78RenderBlockFlow::MarginInfo::MarginInfo(const RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
79 : m_atBeforeSideOfBlock(true)
80 , m_atAfterSideOfBlock(false)
81 , m_hasMarginBeforeQuirk(false)
82 , m_hasMarginAfterQuirk(false)
83 , m_determinedMarginBeforeQuirk(false)
84 , m_discardMargin(false)
85{
86 const RenderStyle& blockStyle = block.style();
87 ASSERT(block.isRenderView() || block.parent());
88 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
89
90 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MarginCollapse::Separate;
91
92 // If any height other than auto is specified in CSS, then we don't collapse our bottom
93 // margins with our children's margins. To do otherwise would be to risk odd visual
94 // effects when the children overflow out of the parent block and yet still collapse
95 // with it. We also don't collapse if we have any bottom border/padding.
96 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
97 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MarginCollapse::Separate;
98
99 m_quirkContainer = block.isTableCell() || block.isBody();
100
101 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
102
103 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : 0_lu;
104 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : 0_lu;
105}
106
107RenderBlockFlow::RenderBlockFlow(Element& element, RenderStyle&& style)
108 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
109#if ENABLE(TEXT_AUTOSIZING)
110 , m_widthForTextAutosizing(-1)
111 , m_lineCountForTextAutosizing(NOT_SET)
112#endif
113{
114 setChildrenInline(true);
115}
116
117RenderBlockFlow::RenderBlockFlow(Document& document, RenderStyle&& style)
118 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
119#if ENABLE(TEXT_AUTOSIZING)
120 , m_widthForTextAutosizing(-1)
121 , m_lineCountForTextAutosizing(NOT_SET)
122#endif
123{
124 setChildrenInline(true);
125}
126
127RenderBlockFlow::~RenderBlockFlow()
128{
129 // Do not add any code here. Add it to willBeDestroyed() instead.
130}
131
132void RenderBlockFlow::willBeDestroyed()
133{
134 if (!renderTreeBeingDestroyed()) {
135 if (firstRootBox()) {
136 // We can't wait for RenderBox::destroy to clear the selection,
137 // because by then we will have nuked the line boxes.
138 if (isSelectionBorder())
139 frame().selection().setNeedsSelectionUpdate();
140
141 // If we are an anonymous block, then our line boxes might have children
142 // that will outlast this block. In the non-anonymous block case those
143 // children will be destroyed by the time we return from this function.
144 if (isAnonymousBlock()) {
145 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
146 while (auto childBox = box->firstChild())
147 childBox->removeFromParent();
148 }
149 }
150 } else if (parent())
151 parent()->dirtyLinesFromChangedChild(*this);
152 }
153
154 m_lineBoxes.deleteLineBoxes();
155
156 blockWillBeDestroyed();
157
158 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
159 RenderBox::willBeDestroyed();
160}
161
162RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
163{
164 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
165 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
166 // to avoid floats.
167 parentHasFloats = false;
168 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
169 if (is<RenderBlockFlow>(*sibling)) {
170 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
171 if (!siblingBlock.avoidsFloats())
172 return &siblingBlock;
173 }
174 if (sibling->isFloating())
175 parentHasFloats = true;
176 }
177 return nullptr;
178}
179
180void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
181{
182 if (m_floatingObjects)
183 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
184
185 HashSet<RenderBox*> oldIntrudingFloatSet;
186 if (!childrenInline() && m_floatingObjects) {
187 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
188 auto end = floatingObjectSet.end();
189 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
190 FloatingObject* floatingObject = it->get();
191 if (!floatingObject->isDescendant())
192 oldIntrudingFloatSet.add(&floatingObject->renderer());
193 }
194 }
195
196 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
197 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
198 if (m_floatingObjects)
199 m_floatingObjects->clear();
200 if (!oldIntrudingFloatSet.isEmpty())
201 markAllDescendantsWithFloatsForLayout();
202 return;
203 }
204
205 RendererToFloatInfoMap floatMap;
206
207 if (m_floatingObjects) {
208 if (childrenInline())
209 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
210 else
211 m_floatingObjects->clear();
212 }
213
214 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
215 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
216 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
217 if (!is<RenderBlockFlow>(parent()))
218 return;
219
220 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
221 // them (as opposed to floats they contain themselves) so check for those here too.
222 auto& parentBlock = downcast<RenderBlockFlow>(*parent());
223 bool parentHasFloats = false;
224 RenderBlockFlow* previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
225 LayoutUnit logicalTopOffset = logicalTop();
226 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
227 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
228
229 LayoutUnit logicalLeftOffset;
230 if (previousBlock)
231 logicalTopOffset -= previousBlock->logicalTop();
232 else {
233 previousBlock = &parentBlock;
234 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
235 }
236
237 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
238 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
239 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
240
241 if (childrenInline()) {
242 LayoutUnit changeLogicalTop = LayoutUnit::max();
243 LayoutUnit changeLogicalBottom = LayoutUnit::min();
244 if (m_floatingObjects) {
245 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
246 auto end = floatingObjectSet.end();
247 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
248 const auto& floatingObject = *it->get();
249 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
250 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
251 if (oldFloatingObject) {
252 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
253 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
254 changeLogicalTop = 0;
255 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
256 } else {
257 if (logicalBottom != oldLogicalBottom) {
258 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
259 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
260 }
261 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
262 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
263 if (logicalTop != oldLogicalTop) {
264 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
265 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
266 }
267 }
268
269 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
270 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
271 oldFloatingObject->originatingLine()->markDirty();
272 }
273 } else {
274 changeLogicalTop = 0;
275 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
276 }
277 }
278 }
279
280 auto end = floatMap.end();
281 for (auto it = floatMap.begin(); it != end; ++it) {
282 const auto& floatingObject = *it->value.get();
283 if (!floatingObject.isDescendant()) {
284 changeLogicalTop = 0;
285 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
286 }
287 }
288
289 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
290 } else if (!oldIntrudingFloatSet.isEmpty()) {
291 // If there are previously intruding floats that no longer intrude, then children with floats
292 // should also get layout because they might need their floating object lists cleared.
293 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
294 markAllDescendantsWithFloatsForLayout();
295 else {
296 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
297 auto end = floatingObjectSet.end();
298 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
299 oldIntrudingFloatSet.remove(&(*it)->renderer());
300 if (!oldIntrudingFloatSet.isEmpty())
301 markAllDescendantsWithFloatsForLayout();
302 }
303 }
304}
305
306void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
307{
308 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
309 // The min/max intrinsic widths calculated really tell how much space elements need when
310 // laid out inside the columns. In order to eventually end up with the desired column width,
311 // we need to convert them to values pertaining to the multicol container.
312 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
313 LayoutUnit columnWidth;
314 LayoutUnit colGap = columnGap();
315 LayoutUnit gapExtra = (columnCount - 1) * colGap;
316 if (style().hasAutoColumnWidth())
317 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
318 else {
319 columnWidth = style().columnWidth();
320 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
321 }
322 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
323 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
324 // performing a layout pass, but this is not an appropriate time or place for layout. The
325 // good news is that if height is unconstrained and there are no explicit breaks, the
326 // resolved column-count really should be 1.
327 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
328 }
329}
330
331void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
332{
333 if (childrenInline())
334 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
335 else
336 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
337
338 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
339
340 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
341
342 if (!style().autoWrap() && childrenInline()) {
343 // A horizontal marquee with inline children has no minimum width.
344 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
345 minLogicalWidth = 0;
346 }
347
348 if (is<RenderTableCell>(*this)) {
349 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
350 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
351 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
352 }
353
354 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
355 maxLogicalWidth += scrollbarWidth;
356 minLogicalWidth += scrollbarWidth;
357}
358
359bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
360{
361 bool changed = recomputeLogicalWidth();
362
363 LayoutUnit oldColumnWidth = computedColumnWidth();
364 computeColumnCountAndWidth();
365
366 return changed || oldColumnWidth != computedColumnWidth();
367}
368
369LayoutUnit RenderBlockFlow::columnGap() const
370{
371 if (style().columnGap().isNormal())
372 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
373 return valueForLength(style().columnGap().length(), availableLogicalWidth());
374}
375
376void RenderBlockFlow::computeColumnCountAndWidth()
377{
378 // Calculate our column width and column count.
379 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
380 unsigned desiredColumnCount = 1;
381 LayoutUnit desiredColumnWidth = contentLogicalWidth();
382
383 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
384 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
385 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
386 return;
387 }
388
389 LayoutUnit availWidth = desiredColumnWidth;
390 LayoutUnit colGap = columnGap();
391 LayoutUnit colWidth = std::max<LayoutUnit>(1, style().columnWidth());
392 unsigned colCount = std::max<unsigned>(1, style().columnCount());
393
394 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
395 desiredColumnCount = colCount;
396 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
397 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
398 desiredColumnCount = std::max<unsigned>(1, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned());
399 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
400 } else {
401 desiredColumnCount = std::max<unsigned>(std::min(colCount, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned()), 1);
402 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
403 }
404 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
405}
406
407bool RenderBlockFlow::willCreateColumns(Optional<unsigned> desiredColumnCount) const
408{
409 // The following types are not supposed to create multicol context.
410 if (isFileUploadControl() || isTextControl() || isListBox())
411 return false;
412 if (isRenderSVGBlock() || isRubyRun())
413 return false;
414#if ENABLE(MATHML)
415 if (isRenderMathMLBlock())
416 return false;
417#endif // ENABLE(MATHML)
418
419 if (!firstChild())
420 return false;
421
422 if (style().styleType() != PseudoId::None)
423 return false;
424
425 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating in the RenderView instead.
426 if ((style().overflowY() == Overflow::PagedX || style().overflowY() == Overflow::PagedY) && !(isDocumentElementRenderer() || isBody()))
427 return true;
428
429 if (!style().specifiesColumns())
430 return false;
431
432 // column-axis with opposite writing direction initiates MultiColumnFlow.
433 if (!style().hasInlineColumnAxis())
434 return true;
435
436 // Non-auto column-width always initiates MultiColumnFlow.
437 if (!style().hasAutoColumnWidth())
438 return true;
439
440 if (desiredColumnCount)
441 return desiredColumnCount.value() > 1;
442
443 // column-count > 1 always initiates MultiColumnFlow.
444 if (!style().hasAutoColumnCount())
445 return style().columnCount() > 1;
446
447 ASSERT_NOT_REACHED();
448 return false;
449}
450
451void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
452{
453 ASSERT(needsLayout());
454
455 if (!relayoutChildren && simplifiedLayout())
456 return;
457
458 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
459
460 if (recomputeLogicalWidthAndColumnWidth())
461 relayoutChildren = true;
462
463 rebuildFloatingObjectSetFromIntrudingFloats();
464
465 LayoutUnit previousHeight = logicalHeight();
466 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
467 // for consistency with other render classes?
468 setLogicalHeight(0);
469
470 bool pageLogicalHeightChanged = false;
471 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
472
473 LayoutUnit repaintLogicalTop;
474 LayoutUnit repaintLogicalBottom;
475 LayoutUnit maxFloatLogicalBottom;
476 const RenderStyle& styleToUse = style();
477 {
478 LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
479
480 preparePaginationBeforeBlockLayout(relayoutChildren);
481
482 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
483 // our current maximal positive and negative margins. These values are used when we
484 // are collapsed with adjacent blocks, so for example, if you have block A and B
485 // collapsing together, then you'd take the maximal positive margin from both A and B
486 // and subtract it from the maximal negative margin from both A and B to get the
487 // true collapsed margin. This algorithm is recursive, so when we finish layout()
488 // our block knows its current maximal positive/negative values.
489 //
490 // Start out by setting our margin values to our current margins. Table cells have
491 // no margins, so we don't fill in the values for table cells.
492 bool isCell = isTableCell();
493 if (!isCell) {
494 initMaxMarginValues();
495
496 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
497 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
498 setPaginationStrut(0);
499 }
500 if (!firstChild() && !isAnonymousBlock())
501 setChildrenInline(true);
502 if (childrenInline())
503 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
504 else
505 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
506 }
507
508 // Expand our intrinsic height to encompass floats.
509 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
510 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
511 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
512 if (relayoutForPagination() || relayoutToAvoidWidows()) {
513 ASSERT(!shouldBreakAtLineToAvoidWidow());
514 return;
515 }
516
517 // Calculate our new height.
518 LayoutUnit oldHeight = logicalHeight();
519 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
520
521 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
522 // This ensures the size information is correctly computed for the last auto-height fragment receiving content.
523 if (is<RenderFragmentedFlow>(*this))
524 downcast<RenderFragmentedFlow>(*this).applyBreakAfterContent(oldClientAfterEdge);
525
526 updateLogicalHeight();
527 LayoutUnit newHeight = logicalHeight();
528 {
529 // FIXME: This could be removed once relayoutForPagination()/relayoutToAvoidWidows() either stop recursing or we manage to
530 // re-order them.
531 LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
532
533 if (oldHeight != newHeight) {
534 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
535 // One of our children's floats may have become an overhanging float for us. We need to look for it.
536 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
537 if (blockFlow.isFloatingOrOutOfFlowPositioned())
538 continue;
539 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
540 addOverhangingFloats(blockFlow, false);
541 }
542 }
543 }
544
545 bool heightChanged = (previousHeight != newHeight);
546 if (heightChanged)
547 relayoutChildren = true;
548 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
549 }
550 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
551 computeOverflow(oldClientAfterEdge);
552
553 fitBorderToLinesIfNeeded();
554
555 auto* state = view().frameView().layoutContext().layoutState();
556 if (state && state->pageLogicalHeight())
557 setPageLogicalOffset(state->pageLogicalOffset(this, logicalTop()));
558
559 updateLayerTransform();
560
561 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
562 // we overflow or not.
563 updateScrollInfoAfterLayout();
564
565 // FIXME: This repaint logic should be moved into a separate helper function!
566 // Repaint with our new bounds if they are different from our old bounds.
567 bool didFullRepaint = repainter.repaintAfterLayout();
568 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == Visibility::Visible || enclosingLayer()->hasVisibleContent())) {
569 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
570 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
571 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
572 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
573 if (hasOverflowClip()) {
574 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
575 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
576 // layoutInlineChildren should be patched to compute the entire repaint rect.
577 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
578 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
579 }
580
581 LayoutRect repaintRect;
582 if (isHorizontalWritingMode())
583 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
584 else
585 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
586
587 if (hasOverflowClip()) {
588 // Adjust repaint rect for scroll offset
589 repaintRect.moveBy(-scrollPosition());
590
591 // Don't allow this rect to spill out of our overflow box.
592 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
593 }
594
595 // Make sure the rect is still non-empty after intersecting for overflow above
596 if (!repaintRect.isEmpty()) {
597 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
598 if (hasReflection())
599 repaintRectangle(reflectedRect(repaintRect));
600 }
601 }
602
603 clearNeedsLayout();
604}
605
606void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
607{
608 dirtyForLayoutFromPercentageHeightDescendants();
609
610 LayoutUnit beforeEdge = borderAndPaddingBefore();
611 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
612
613 setLogicalHeight(beforeEdge);
614
615 // Lay out our hypothetical grid line as though it occurs at the top of the block.
616 if (view().frameView().layoutContext().layoutState()->lineGrid() == this)
617 layoutLineGridBox();
618
619 // The margin struct caches all our current margin collapsing state.
620 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
621
622 // Fieldsets need to find their legend and position it inside the border of the object.
623 // The legend then gets skipped during normal layout. The same is true for ruby text.
624 // It doesn't get included in the normal layout process but is instead skipped.
625 layoutExcludedChildren(relayoutChildren);
626
627 LayoutUnit previousFloatLogicalBottom;
628 maxFloatLogicalBottom = 0;
629
630 RenderBox* next = firstChildBox();
631
632 while (next) {
633 RenderBox& child = *next;
634 next = child.nextSiblingBox();
635
636 if (child.isExcludedFromNormalLayout())
637 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
638
639 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
640
641 if (child.isOutOfFlowPositioned()) {
642 child.containingBlock()->insertPositionedObject(child);
643 adjustPositionedBlock(child, marginInfo);
644 continue;
645 }
646 if (child.isFloating()) {
647 insertFloatingObject(child);
648 adjustFloatingBlock(marginInfo);
649 continue;
650 }
651
652 // Lay out the child.
653 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
654 }
655
656 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
657 // determining the correct collapsed bottom margin information.
658 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
659}
660
661void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
662{
663 if (lineLayoutPath() == UndeterminedPath)
664 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
665
666 if (lineLayoutPath() == SimpleLinesPath) {
667 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
668 return;
669 }
670
671 m_simpleLineLayout = nullptr;
672 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
673}
674
675void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
676{
677 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
678 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
679
680 // The child is a normal flow object. Compute the margins we will use for collapsing now.
681 child.computeAndSetBlockDirectionMargins(*this);
682
683 // Try to guess our correct logical top position. In most cases this guess will
684 // be correct. Only if we're wrong (when we compute the real logical top position)
685 // will we have to potentially relayout.
686 LayoutUnit estimateWithoutPagination;
687 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
688
689 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
690 LayoutRect oldRect = child.frameRect();
691 LayoutUnit oldLogicalTop = logicalTopForChild(child);
692
693#if !ASSERT_DISABLED
694 LayoutSize oldLayoutDelta = view().frameView().layoutContext().layoutDelta();
695#endif
696 // Position the child as though it didn't collapse with the top.
697 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
698 estimateFragmentRangeForBoxChild(child);
699
700 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
701 bool markDescendantsWithFloats = false;
702 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
703 markDescendantsWithFloats = true;
704 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
705 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
706 // very large elements. If it does the comparison with oldLogicalTop might yield a
707 // false negative as adding and removing margins, borders etc from a saturated number
708 // might yield incorrect results. If this is the case always mark for layout.
709 markDescendantsWithFloats = true;
710 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
711 // If an element might be affected by the presence of floats, then always mark it for
712 // layout.
713 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
714 if (fb > logicalTopEstimate)
715 markDescendantsWithFloats = true;
716 }
717
718 if (childBlockFlow) {
719 if (markDescendantsWithFloats)
720 childBlockFlow->markAllDescendantsWithFloatsForLayout();
721 if (!child.isWritingModeRoot())
722 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
723 }
724
725 child.markForPaginationRelayoutIfNeeded();
726
727 bool childHadLayout = child.everHadLayout();
728 bool childNeededLayout = child.needsLayout();
729 if (childNeededLayout)
730 child.layout();
731
732 // Cache if we are at the top of the block right now.
733 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
734
735 // Now determine the correct ypos based off examination of collapsing margin
736 // values.
737 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
738
739 // Now check for clear.
740 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
741
742 bool paginated = view().frameView().layoutContext().layoutState()->isPaginated();
743 if (paginated)
744 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
745
746 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
747
748 // Now we have a final top position. See if it really does end up being different from our estimate.
749 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
750 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
751 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
752 if (child.shrinkToAvoidFloats()) {
753 // The child's width depends on the line width. When the child shifts to clear an item, its width can
754 // change (because it has more available line width). So mark the item as dirty.
755 child.setChildNeedsLayout(MarkOnlyThis);
756 }
757
758 if (childBlockFlow) {
759 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
760 childBlockFlow->markAllDescendantsWithFloatsForLayout();
761 child.markForPaginationRelayoutIfNeeded();
762 }
763 }
764
765 if (updateFragmentRangeForBoxChild(child))
766 child.setNeedsLayout(MarkOnlyThis);
767
768 // In case our guess was wrong, relayout the child.
769 child.layoutIfNeeded();
770
771 // We are no longer at the top of the block if we encounter a non-empty child.
772 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
773 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
774 marginInfo.setAtBeforeSideOfBlock(false);
775
776 // Now place the child in the correct left position
777 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
778
779 // Update our height now that the child has been placed in the correct position.
780 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
781 if (mustSeparateMarginAfterForChild(child)) {
782 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
783 marginInfo.clearMargin();
784 }
785 // If the child has overhanging floats that intrude into following siblings (or possibly out
786 // of this block), then the parent gets notified of the floats now.
787 if (childBlockFlow && childBlockFlow->containsFloats())
788 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
789
790 LayoutSize childOffset = child.location() - oldRect.location();
791 if (childOffset.width() || childOffset.height()) {
792 view().frameView().layoutContext().addLayoutDelta(childOffset);
793
794 // If the child moved, we have to repaint it as well as any floating/positioned
795 // descendants. An exception is if we need a layout. In this case, we know we're going to
796 // repaint ourselves (and the child) anyway.
797 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
798 child.repaintDuringLayoutIfMoved(oldRect);
799 }
800
801 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
802 child.repaint();
803 child.repaintOverhangingFloats(true);
804 }
805
806 if (paginated) {
807 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
808 fragmentedFlow->fragmentedFlowDescendantBoxLaidOut(&child);
809 // Check for an after page/column break.
810 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
811 if (newHeight != height())
812 setLogicalHeight(newHeight);
813 }
814
815 ASSERT(view().frameView().layoutContext().layoutDeltaMatches(oldLayoutDelta));
816}
817
818void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
819{
820 bool isHorizontal = isHorizontalWritingMode();
821 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
822
823 LayoutUnit logicalTop = logicalHeight();
824 updateStaticInlinePositionForChild(child, logicalTop, DoNotIndentText);
825
826 if (!marginInfo.canCollapseWithMarginBefore()) {
827 // Positioned blocks don't collapse margins, so add the margin provided by
828 // the container now. The child's own margin is added later when calculating its logical top.
829 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
830 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
831 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
832 }
833
834 RenderLayer* childLayer = child.layer();
835 if (childLayer->staticBlockPosition() != logicalTop) {
836 childLayer->setStaticBlockPosition(logicalTop);
837 if (hasStaticBlockPosition)
838 child.setChildNeedsLayout(MarkOnlyThis);
839 }
840}
841
842LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
843{
844 ASSERT(isSelfCollapsingBlock());
845 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
846 if (parentBlock && style().clear() != Clear::None && parentBlock->getClearDelta(*this, logicalHeight()))
847 return marginValuesForChild(*this).positiveMarginBefore();
848 return 0_lu;
849}
850
851void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
852{
853 LayoutUnit startPosition = borderStart() + paddingStart();
854 if (shouldPlaceBlockDirectionScrollbarOnLeft())
855 startPosition += (style().isLeftToRightDirection() ? 1 : -1) * verticalScrollbarWidth();
856 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
857
858 // Add in our start margin.
859 LayoutUnit childMarginStart = marginStartForChild(child);
860 LayoutUnit newPosition = startPosition + childMarginStart;
861
862 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
863 // to shift over as necessary to dodge any floats that might get in the way.
864 if (child.avoidsFloats() && containsFloats())
865 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
866
867 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
868}
869
870void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
871{
872 // The float should be positioned taking into account the bottom margin
873 // of the previous flow. We add that margin into the height, get the
874 // float positioned properly, and then subtract the margin out of the
875 // height again. In the case of self-collapsing blocks, we always just
876 // use the top margins, since the self-collapsing block collapsed its
877 // own bottom margin into its top margin.
878 //
879 // Note also that the previous flow may collapse its margin into the top of
880 // our block. If this is the case, then we do not add the margin in to our
881 // height when computing the position of the float. This condition can be tested
882 // for by simply calling canCollapseWithMarginBefore. See
883 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
884 // an example of this scenario.
885 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0_lu : marginInfo.margin();
886 setLogicalHeight(logicalHeight() + marginOffset);
887 positionNewFloats();
888 setLogicalHeight(logicalHeight() - marginOffset);
889}
890
891void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText)
892{
893 if (child.style().isOriginalDisplayInlineType())
894 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, shouldIndentText));
895 else
896 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
897}
898
899void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
900{
901 if (enclosingFragmentedFlow()) {
902 // Shift the inline position to exclude the fragment offset.
903 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
904 }
905 child.layer()->setStaticInlinePosition(inlinePosition);
906}
907
908RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
909{
910 LayoutUnit childBeforePositive;
911 LayoutUnit childBeforeNegative;
912 LayoutUnit childAfterPositive;
913 LayoutUnit childAfterNegative;
914
915 LayoutUnit beforeMargin;
916 LayoutUnit afterMargin;
917
918 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
919
920 // If the child has the same directionality as we do, then we can just return its
921 // margins in the same direction.
922 if (!child.isWritingModeRoot()) {
923 if (childRenderBlock) {
924 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
925 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
926 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
927 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
928 } else {
929 beforeMargin = child.marginBefore();
930 afterMargin = child.marginAfter();
931 }
932 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
933 // The child has a different directionality. If the child is parallel, then it's just
934 // flipped relative to us. We can use the margins for the opposite edges.
935 if (childRenderBlock) {
936 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
937 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
938 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
939 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
940 } else {
941 beforeMargin = child.marginAfter();
942 afterMargin = child.marginBefore();
943 }
944 } else {
945 // The child is perpendicular to us, which means its margins don't collapse but are on the
946 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
947 beforeMargin = marginBeforeForChild(child);
948 afterMargin = marginAfterForChild(child);
949 }
950
951 // Resolve uncollapsing margins into their positive/negative buckets.
952 if (beforeMargin) {
953 if (beforeMargin > 0)
954 childBeforePositive = beforeMargin;
955 else
956 childBeforeNegative = -beforeMargin;
957 }
958 if (afterMargin) {
959 if (afterMargin > 0)
960 childAfterPositive = afterMargin;
961 else
962 childAfterNegative = -afterMargin;
963 }
964
965 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
966}
967
968bool RenderBlockFlow::childrenPreventSelfCollapsing() const
969{
970 if (!childrenInline())
971 return RenderBlock::childrenPreventSelfCollapsing();
972
973 return hasLines();
974}
975
976LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
977{
978 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
979}
980
981LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
982{
983 bool childDiscardMarginBefore = child ? mustDiscardMarginBeforeForChild(*child) : false;
984 bool childDiscardMarginAfter = child ? mustDiscardMarginAfterForChild(*child) : false;
985 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
986 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
987 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
988
989 // The child discards the before margin when the after margin has discarded in the case of a self collapsing block.
990 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
991
992 // Get the four margin values for the child and cache them.
993 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
994
995 // Get our max pos and neg top margins.
996 LayoutUnit posTop = childMargins.positiveMarginBefore();
997 LayoutUnit negTop = childMargins.negativeMarginBefore();
998
999 // For self-collapsing blocks, collapse our bottom margins into our
1000 // top to get new posTop and negTop values.
1001 if (childIsSelfCollapsing) {
1002 posTop = std::max(posTop, childMargins.positiveMarginAfter());
1003 negTop = std::max(negTop, childMargins.negativeMarginAfter());
1004 }
1005
1006 if (marginInfo.canCollapseWithMarginBefore()) {
1007 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1008 // This child is collapsing with the top of the
1009 // block. If it has larger margin values, then we need to update
1010 // our own maximal values.
1011 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
1012 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
1013
1014 // The minute any of the margins involved isn't a quirk, don't
1015 // collapse it away, even if the margin is smaller (www.webreference.com
1016 // has an example of this, a <dt> with 0.8em author-specified inside
1017 // a <dl> inside a <td>.
1018 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
1019 setHasMarginBeforeQuirk(false);
1020 marginInfo.setDeterminedMarginBeforeQuirk(true);
1021 }
1022
1023 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
1024 // We have no top margin and our top child has a quirky margin.
1025 // We will pick up this quirky margin and pass it through.
1026 // This deals with the <td><div><p> case.
1027 // Don't do this for a block that split two inlines though. You do
1028 // still apply margins in this case.
1029 setHasMarginBeforeQuirk(true);
1030 }
1031 } else
1032 // The before margin of the container will also discard all the margins it is collapsing with.
1033 setMustDiscardMarginBefore();
1034 }
1035
1036 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1037 if (childDiscardMarginBefore) {
1038 marginInfo.setDiscardMargin(true);
1039 marginInfo.clearMargin();
1040 }
1041
1042 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1043 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
1044
1045 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1046 LayoutUnit logicalTop = beforeCollapseLogicalTop;
1047
1048 LayoutUnit clearanceForSelfCollapsingBlock;
1049
1050 // If the child's previous sibling is a self-collapsing block that cleared a float then its top border edge has been set at the bottom border edge
1051 // of the float. Since we want to collapse the child's top margin with the self-collapsing block's top and bottom margins we need to adjust our parent's height to match the
1052 // margin top of the self-collapsing block. If the resulting collapsed margin leaves the child still intruding into the float then we will want to clear it.
1053 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1054 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
1055 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1056 }
1057
1058 if (childIsSelfCollapsing) {
1059 // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
1060 // Also, the child's top position equals the logical height of the container.
1061 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1062 // This child has no height. We need to compute our
1063 // position before we collapse the child's margins together,
1064 // so that we can get an accurate position for the zero-height block.
1065 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1066 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1067 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1068
1069 // Now collapse the child's margins together, which means examining our
1070 // bottom margin values as well.
1071 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1072 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1073
1074 if (!marginInfo.canCollapseWithMarginBefore())
1075 // We need to make sure that the position of the self-collapsing block
1076 // is correct, since it could have overflowing content
1077 // that needs to be positioned correctly (e.g., a block that
1078 // had a specified height of 0 but that actually had subcontent).
1079 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1080 }
1081 } else {
1082 if (child && mustSeparateMarginBeforeForChild(*child)) {
1083 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1084 // If we are at the before side of the block and we collapse, ignore the computed margin
1085 // and just add the child margin to the container height. This will correctly position
1086 // the child inside the container.
1087 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : 0_lu;
1088 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(*child));
1089 logicalTop = logicalHeight();
1090 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1091 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1092 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1093 // We're collapsing with a previous sibling's margins and not
1094 // with the top of the block.
1095 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
1096 logicalTop = logicalHeight();
1097 }
1098
1099 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1100
1101 if (!marginInfo.discardMargin()) {
1102 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1103 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1104 } else
1105 marginInfo.clearMargin();
1106
1107 if (marginInfo.margin())
1108 marginInfo.setHasMarginAfterQuirk(afterQuirk);
1109 }
1110
1111 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1112 // collapsed into the page edge.
1113 auto* layoutState = view().frameView().layoutContext().layoutState();
1114 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1115 && hasNextPage(beforeCollapseLogicalTop)) {
1116 LayoutUnit oldLogicalTop = logicalTop;
1117 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
1118 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1119 }
1120
1121 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
1122 // If |child| is a self-collapsing block it may have collapsed into a previous sibling and although it hasn't reduced the height of the parent yet
1123 // any floats from the parent will now overhang.
1124 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
1125 LayoutUnit oldLogicalHeight = logicalHeight();
1126 setLogicalHeight(logicalTop);
1127 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
1128 addOverhangingFloats(block, false);
1129 setLogicalHeight(oldLogicalHeight);
1130
1131 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1132 // into the margin area of the self-collapsing block then the float it clears is now intruding into |child|. Layout again so that we can look for
1133 // floats in the parent that overhang |child|'s new logical top.
1134 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
1135 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1136 child->setNeedsLayout();
1137 }
1138
1139 return logicalTop;
1140}
1141
1142LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
1143{
1144 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1145 if (!heightIncrease)
1146 return yPos;
1147
1148 if (child.isSelfCollapsingBlock()) {
1149 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1150
1151 // For self-collapsing blocks that clear, they can still collapse their
1152 // margins with following siblings. Reset the current margins to represent
1153 // the self-collapsing block's margins only.
1154 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
1155 MarginValues childMargins = marginValuesForChild(child);
1156 if (!childDiscardMargin) {
1157 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1158 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1159 } else
1160 marginInfo.clearMargin();
1161 marginInfo.setDiscardMargin(childDiscardMargin);
1162
1163 // CSS2.1 states:
1164 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1165 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1166 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1167 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1168 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
1169 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
1170 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1171 wouldCollapseMarginsWithParent = false;
1172 }
1173 if (wouldCollapseMarginsWithParent)
1174 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1175
1176 // For now set the border-top of |child| flush with the bottom border-edge of the float so it can layout any floating or positioned children of
1177 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1178 // adjust the height of the parent to |child|'s margin top (which if it is positive sits up 'inside' the float it's clearing) so that all three
1179 // margins can collapse at the correct vertical position.
1180 // Per CSS2.1 we need to ensure that any negative margin-top clears |child| beyond the bottom border-edge of the float so that the top border edge of the child
1181 // (i.e. its clearance) is at a position that satisfies the equation: "the amount of clearance is set so that clearance + margin-top = [height of float],
1182 // i.e., clearance = [height of float] - margin-top".
1183 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
1184 } else
1185 // Increase our height by the amount we had to clear.
1186 setLogicalHeight(logicalHeight() + heightIncrease);
1187
1188 if (marginInfo.canCollapseWithMarginBefore()) {
1189 // We can no longer collapse with the top of the block since a clear
1190 // occurred. The empty blocks collapse into the cleared block.
1191 // FIXME: This isn't quite correct. Need clarification for what to do
1192 // if the height the cleared block is offset by is smaller than the
1193 // margins involved.
1194 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1195 marginInfo.setAtBeforeSideOfBlock(false);
1196
1197 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
1198 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MarginCollapse::Discard);
1199 }
1200
1201 return yPos + heightIncrease;
1202}
1203
1204void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
1205{
1206 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1207 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1208 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
1209 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MarginCollapse::Separate)
1210 return;
1211
1212 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1213 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
1214 if (child.style().marginBeforeCollapse() == MarginCollapse::Discard) {
1215 positiveMarginBefore = 0;
1216 negativeMarginBefore = 0;
1217 discardMarginBefore = true;
1218 return;
1219 }
1220
1221 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
1222 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1223 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
1224
1225 if (!is<RenderBlockFlow>(child))
1226 return;
1227
1228 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
1229 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
1230 return;
1231
1232 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
1233 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1234 return;
1235
1236 RenderBox* grandchildBox = childBlock.firstChildBox();
1237 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
1238 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1239 break;
1240 }
1241
1242 // Give up if there is clearance on the box, since it probably won't collapse into us.
1243 if (!grandchildBox || grandchildBox->style().clear() != Clear::None)
1244 return;
1245
1246 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1247 if (grandchildBox->needsLayout()) {
1248 grandchildBox->computeAndSetBlockDirectionMargins(*this);
1249 if (is<RenderBlock>(*grandchildBox)) {
1250 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1251 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1252 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
1253 }
1254 }
1255
1256 // Collapse the margin of the grandchild box with our own to produce an estimate.
1257 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1258}
1259
1260LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
1261{
1262 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1263 // relayout if there are intruding floats.
1264 LayoutUnit logicalTopEstimate = logicalHeight();
1265 if (!marginInfo.canCollapseWithMarginBefore()) {
1266 LayoutUnit positiveMarginBefore;
1267 LayoutUnit negativeMarginBefore;
1268 bool discardMarginBefore = false;
1269 if (child.selfNeedsLayout()) {
1270 // Try to do a basic estimation of how the collapse is going to go.
1271 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1272 } else {
1273 // Use the cached collapsed margin values from a previous layout. Most of the time they
1274 // will be right.
1275 MarginValues marginValues = marginValuesForChild(child);
1276 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1277 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
1278 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1279 }
1280
1281 // Collapse the result with our current margins.
1282 if (!discardMarginBefore)
1283 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
1284 }
1285
1286 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1287 // page.
1288 auto* layoutState = view().frameView().layoutContext().layoutState();
1289 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1290 && hasNextPage(logicalHeight()))
1291 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1292
1293 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1294
1295 estimateWithoutPagination = logicalTopEstimate;
1296
1297 if (layoutState->isPaginated()) {
1298 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1299 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1300
1301 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1302 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1303
1304 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1305 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
1306 }
1307
1308 return logicalTopEstimate;
1309}
1310
1311void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1312{
1313 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1314 // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
1315 // Don't update the max margin values because we won't need them anyway.
1316 if (marginInfo.discardMargin()) {
1317 setMustDiscardMarginAfter();
1318 return;
1319 }
1320
1321 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1322 // with our children.
1323 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1324
1325 if (!marginInfo.hasMarginAfterQuirk())
1326 setHasMarginAfterQuirk(false);
1327
1328 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1329 // We have no bottom margin and our last child has a quirky margin.
1330 // We will pick up this quirky margin and pass it through.
1331 // This deals with the <td><div><p> case.
1332 setHasMarginAfterQuirk(true);
1333 }
1334}
1335
1336void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1337{
1338 marginInfo.setAtAfterSideOfBlock(true);
1339
1340 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1341 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1342 // to perform now is at the child's margin-top - so adjust our height to that position.
1343 RenderObject* lastBlock = lastChild();
1344 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1345 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
1346
1347 // If we can't collapse with children then add in the bottom margin.
1348 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1349 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1350 setLogicalHeight(logicalHeight() + marginInfo.margin());
1351
1352 // Now add in our bottom border/padding.
1353 setLogicalHeight(logicalHeight() + afterSide);
1354
1355 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1356 // If this happens, ensure that the computed height is increased to the minimal height.
1357 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
1358
1359 // Update our bottom collapsed margin info.
1360 setCollapsedBottomMargin(marginInfo);
1361}
1362
1363void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1364{
1365 if (!hasRareBlockFlowData()) {
1366 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
1367 return;
1368 materializeRareBlockFlowData();
1369 }
1370
1371 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1372 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
1373}
1374
1375void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1376{
1377 if (!hasRareBlockFlowData()) {
1378 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
1379 return;
1380 materializeRareBlockFlowData();
1381 }
1382
1383 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1384 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
1385}
1386
1387void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1388{
1389 if (style().marginBeforeCollapse() == MarginCollapse::Discard) {
1390 ASSERT(value);
1391 return;
1392 }
1393
1394 if (!hasRareBlockFlowData()) {
1395 if (!value)
1396 return;
1397 materializeRareBlockFlowData();
1398 }
1399
1400 rareBlockFlowData()->m_discardMarginBefore = value;
1401}
1402
1403void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1404{
1405 if (style().marginAfterCollapse() == MarginCollapse::Discard) {
1406 ASSERT(value);
1407 return;
1408 }
1409
1410 if (!hasRareBlockFlowData()) {
1411 if (!value)
1412 return;
1413 materializeRareBlockFlowData();
1414 }
1415
1416 rareBlockFlowData()->m_discardMarginAfter = value;
1417}
1418
1419bool RenderBlockFlow::mustDiscardMarginBefore() const
1420{
1421 return style().marginBeforeCollapse() == MarginCollapse::Discard || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
1422}
1423
1424bool RenderBlockFlow::mustDiscardMarginAfter() const
1425{
1426 return style().marginAfterCollapse() == MarginCollapse::Discard || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
1427}
1428
1429bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
1430{
1431 ASSERT(!child.selfNeedsLayout());
1432 if (!child.isWritingModeRoot())
1433 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MarginCollapse::Discard);
1434 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1435 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MarginCollapse::Discard);
1436
1437 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1438 // In case the boxes are perpendicular we assume the property is not specified.
1439 return false;
1440}
1441
1442bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
1443{
1444 ASSERT(!child.selfNeedsLayout());
1445 if (!child.isWritingModeRoot())
1446 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MarginCollapse::Discard);
1447 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1448 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MarginCollapse::Discard);
1449
1450 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1451 return false;
1452}
1453
1454bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
1455{
1456 ASSERT(!child.selfNeedsLayout());
1457 const RenderStyle& childStyle = child.style();
1458 if (!child.isWritingModeRoot())
1459 return childStyle.marginBeforeCollapse() == MarginCollapse::Separate;
1460 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1461 return childStyle.marginAfterCollapse() == MarginCollapse::Separate;
1462
1463 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1464 return false;
1465}
1466
1467bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
1468{
1469 ASSERT(!child.selfNeedsLayout());
1470 const RenderStyle& childStyle = child.style();
1471 if (!child.isWritingModeRoot())
1472 return childStyle.marginAfterCollapse() == MarginCollapse::Separate;
1473 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1474 return childStyle.marginBeforeCollapse() == MarginCollapse::Separate;
1475
1476 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1477 return false;
1478}
1479
1480static bool inNormalFlow(RenderBox& child)
1481{
1482 RenderBlock* curr = child.containingBlock();
1483 while (curr && curr != &child.view()) {
1484 if (curr->isRenderFragmentedFlow())
1485 return true;
1486 if (curr->isFloatingOrOutOfFlowPositioned())
1487 return false;
1488 curr = curr->containingBlock();
1489 }
1490 return true;
1491}
1492
1493LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
1494{
1495 // FIXME: Add page break checking here when we support printing.
1496 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1497 bool isInsideMulticolFlow = fragmentedFlow;
1498 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
1499 bool checkPageBreaks = !checkColumnBreaks && view().frameView().layoutContext().layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this.
1500 bool checkFragmentBreaks = false;
1501 bool checkBeforeAlways = (checkColumnBreaks && child.style().breakBefore() == BreakBetween::Column)
1502 || (checkPageBreaks && alwaysPageBreak(child.style().breakBefore()));
1503 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1504 if (checkColumnBreaks) {
1505 if (isInsideMulticolFlow)
1506 checkFragmentBreaks = true;
1507 }
1508 if (checkFragmentBreaks) {
1509 LayoutUnit offsetBreakAdjustment;
1510 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
1511 return logicalOffset + offsetBreakAdjustment;
1512 }
1513 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1514 }
1515 return logicalOffset;
1516}
1517
1518LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
1519{
1520 // FIXME: Add page break checking here when we support printing.
1521 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1522 bool isInsideMulticolFlow = fragmentedFlow;
1523 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
1524 bool checkPageBreaks = !checkColumnBreaks && view().frameView().layoutContext().layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this.
1525 bool checkFragmentBreaks = false;
1526 bool checkAfterAlways = (checkColumnBreaks && child.style().breakAfter() == BreakBetween::Column)
1527 || (checkPageBreaks && alwaysPageBreak(child.style().breakAfter()));
1528 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1529 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0_lu : marginInfo.margin();
1530
1531 // So our margin doesn't participate in the next collapsing steps.
1532 marginInfo.clearMargin();
1533
1534 if (checkColumnBreaks) {
1535 if (isInsideMulticolFlow)
1536 checkFragmentBreaks = true;
1537 }
1538 if (checkFragmentBreaks) {
1539 LayoutUnit offsetBreakAdjustment;
1540 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
1541 return logicalOffset + marginOffset + offsetBreakAdjustment;
1542 }
1543 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1544 }
1545 return logicalOffset;
1546}
1547
1548LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
1549{
1550 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
1551
1552 if (estimateWithoutPagination != logicalTopAfterClear) {
1553 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1554 // position.
1555 setLogicalHeight(logicalTopAfterClear);
1556 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1557
1558 if (child.shrinkToAvoidFloats()) {
1559 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1560 // change (because it has more available line width). So mark the item as dirty.
1561 child.setChildNeedsLayout(MarkOnlyThis);
1562 }
1563
1564 if (childRenderBlock) {
1565 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
1566 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
1567 child.markForPaginationRelayoutIfNeeded();
1568 }
1569
1570 // Our guess was wrong. Make the child lay itself out again.
1571 child.layoutIfNeeded();
1572 }
1573
1574 LayoutUnit oldTop = logicalTopAfterClear;
1575
1576 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1577 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1578
1579 if (pageLogicalHeightForOffset(result)) {
1580 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
1581 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
1582 if (spaceShortage > 0) {
1583 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1584 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1585 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1586 // This should be improved, though, because here we just pretend that the child is
1587 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1588 // where there's no child content, border or padding. In other words, we risk stretching more
1589 // than necessary.
1590 setPageBreak(result, spaceShortage);
1591 }
1592 }
1593
1594 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1595 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1596 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1597
1598 LayoutUnit paginationStrut;
1599 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1600 if (unsplittableAdjustmentDelta)
1601 paginationStrut = unsplittableAdjustmentDelta;
1602 else if (childRenderBlock && childRenderBlock->paginationStrut())
1603 paginationStrut = childRenderBlock->paginationStrut();
1604
1605 if (paginationStrut) {
1606 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1607 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1608 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1609 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1610 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1611 // and pushes to the next page anyway, so not too concerned about it.
1612 setPaginationStrut(result + paginationStrut);
1613 if (childRenderBlock)
1614 childRenderBlock->setPaginationStrut(0);
1615 } else
1616 result += paginationStrut;
1617 }
1618
1619 // Similar to how we apply clearance. Boost height() to be the place where we're going to position the child.
1620 setLogicalHeight(logicalHeight() + (result - oldTop));
1621
1622 // Return the final adjusted logical top.
1623 return result;
1624}
1625
1626static inline LayoutUnit calculateMinimumPageHeight(const RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
1627{
1628 // We may require a certain minimum number of lines per page in order to satisfy
1629 // orphans and widows, and that may affect the minimum page height.
1630 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
1631 if (lineCount > 1) {
1632 RootInlineBox* line = &lastLine;
1633 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1634 line = line->prevRootBox();
1635
1636 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1637 // adjustLinePositionForPagination() for more details.
1638 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
1639 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
1640 }
1641 return lineBottom - lineTop;
1642}
1643
1644static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1645{
1646 auto& renderer = lineBox.renderer();
1647
1648 if (!renderer.settings().appleMailPaginationQuirkEnabled())
1649 return false;
1650
1651 if (renderer.element() && renderer.element()->idForStyleResolution() == "messageContentContainer")
1652 return true;
1653
1654 return false;
1655}
1656
1657static void clearShouldBreakAtLineToAvoidWidowIfNeeded(RenderBlockFlow& blockFlow)
1658{
1659 if (!blockFlow.shouldBreakAtLineToAvoidWidow())
1660 return;
1661 blockFlow.clearShouldBreakAtLineToAvoidWidow();
1662 blockFlow.setDidBreakAtLineToAvoidWidow();
1663}
1664
1665void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsFragment, RenderFragmentedFlow* fragmentedFlow)
1666{
1667 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1668 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1669 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1670 // of the first column.
1671 //
1672 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1673 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1674 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1675 // for overflow to occur), and then cache visible overflow for each column rect.
1676 //
1677 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1678 // content that paints in a previous column (and content that paints in the following column).
1679 //
1680 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1681 // at least make positive leading work in typical cases.
1682 //
1683 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1684 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1685 // line and all following lines.
1686 overflowsFragment = false;
1687 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
1688 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1689 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
1690 LayoutUnit lineHeight = logicalBottom - logicalOffset;
1691 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
1692 logicalOffset += delta;
1693 lineBox->setPaginationStrut(0);
1694 lineBox->setIsFirstAfterPageBreak(false);
1695 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1696 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
1697 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1698 // still going to add a strut, so that the visible overflow fits on a single page.
1699 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
1700 // FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page.
1701 // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
1702 return;
1703 }
1704
1705 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1706 // We are so tall that we are bigger than a page. Before we give up and just leave the line where it is, try drilling into the
1707 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1708 // able to fit with the blank space and overflow excluded, we will give the line its own page with the highest non-blank element being aligned with the
1709 // top of the page.
1710 // FIXME: We are still honoring gigantic margins, which does leave open the possibility of blank pages caused by this heuristic. It remains to be seen whether or not
1711 // this will be a real-world issue. For now we don't try to deal with this problem.
1712 logicalOffset = intMaxForLayoutUnit;
1713 logicalBottom = intMinForLayoutUnit;
1714 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1715 lineHeight = logicalBottom - logicalOffset;
1716 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) {
1717 // Give up. We're genuinely too big even after excluding blank space and overflow.
1718 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
1719 return;
1720 }
1721 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1722 }
1723
1724 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1725 overflowsFragment = (lineHeight > remainingLogicalHeight);
1726
1727 int lineIndex = lineCount(lineBox);
1728 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
1729 if (lineBreakToAvoidWidow() == lineIndex)
1730 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
1731 // If we have a non-uniform page height, then we have to shift further possibly.
1732 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1733 return;
1734 if (lineHeight > pageLogicalHeight) {
1735 // Split the top margin in order to avoid splitting the visible part of the line.
1736 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
1737 }
1738 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1739 overflowsFragment = (lineHeight > remainingLogicalHeightAtNewOffset);
1740 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
1741 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1742 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
1743 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
1744 && !isOutOfFlowPositioned() && !isTableCell()) {
1745 auto firstRootBox = this->firstRootBox();
1746 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1747 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), 0_lu);
1748 if (needsAppleMailPaginationQuirk(*lineBox))
1749 return;
1750 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1751 } else {
1752 delta += remainingLogicalHeight;
1753 lineBox->setPaginationStrut(remainingLogicalHeight);
1754 lineBox->setIsFirstAfterPageBreak(true);
1755 }
1756 } else if (remainingLogicalHeight == pageLogicalHeight) {
1757 // We're at the very top of a page or column.
1758 if (lineBox != firstRootBox())
1759 lineBox->setIsFirstAfterPageBreak(true);
1760 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1761 setPageBreak(logicalOffset, lineHeight);
1762 }
1763}
1764
1765void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1766{
1767 ASSERT(lineToBreak >= 0);
1768 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1769 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
1770}
1771
1772void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1773{
1774 ASSERT(!shouldBreakAtLineToAvoidWidow());
1775 if (!hasRareBlockFlowData())
1776 return;
1777
1778 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
1779}
1780
1781void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1782{
1783 if (!hasRareBlockFlowData())
1784 return;
1785
1786 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
1787}
1788
1789void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1790{
1791 ASSERT(shouldBreakAtLineToAvoidWidow());
1792 if (!hasRareBlockFlowData())
1793 return;
1794
1795 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
1796}
1797
1798bool RenderBlockFlow::relayoutToAvoidWidows()
1799{
1800 if (!shouldBreakAtLineToAvoidWidow())
1801 return false;
1802
1803 setEverHadLayout(true);
1804 layoutBlock(false);
1805 return true;
1806}
1807
1808bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1809{
1810 ASSERT(view().frameView().layoutContext().layoutState() && view().frameView().layoutContext().layoutState()->isPaginated());
1811
1812 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1813 if (!fragmentedFlow)
1814 return true; // Printing and multi-column both make new pages to accommodate content.
1815
1816 // See if we're in the last fragment.
1817 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
1818 RenderFragmentContainer* fragment = fragmentedFlow->fragmentAtBlockOffset(this, pageOffset, true);
1819 if (!fragment)
1820 return false;
1821
1822 if (fragment->isLastFragment())
1823 return fragment->isRenderFragmentContainerSet() || (pageBoundaryRule == IncludePageBoundary && pageOffset == fragment->logicalTopForFragmentedFlowContent());
1824
1825 RenderFragmentContainer* startFragment = nullptr;
1826 RenderFragmentContainer* endFragment = nullptr;
1827 fragmentedFlow->getFragmentRangeForBox(this, startFragment, endFragment);
1828 return (endFragment && fragment != endFragment);
1829}
1830
1831LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, LayoutUnit childBeforeMargin, LayoutUnit childAfterMargin)
1832{
1833 // When flexboxes are embedded inside a block flow, they don't perform any adjustments for unsplittable
1834 // children. We'll treat flexboxes themselves as unsplittable just to get them to paginate properly inside
1835 // a block flow.
1836 bool isUnsplittable = childBoxIsUnsplittableForFragmentation(child);
1837 if (!isUnsplittable && !(child.isFlexibleBox() && !downcast<RenderFlexibleBox>(child).isFlexibleBoxImpl()))
1838 return logicalOffset;
1839
1840 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1841 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + childBeforeMargin + childAfterMargin;
1842 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1843 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
1844 if (isUnsplittable)
1845 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1846 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1847 || !hasNextPage(logicalOffset))
1848 return logicalOffset;
1849 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1850 if (remainingLogicalHeight < childLogicalHeight) {
1851 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1852 return logicalOffset;
1853 auto result = logicalOffset + remainingLogicalHeight;
1854 bool isInitialLetter = child.isFloating() && child.style().styleType() == PseudoId::FirstLetter && child.style().initialLetterDrop() > 0;
1855 if (isInitialLetter) {
1856 // Increase our logical height to ensure that lines all get pushed along with the letter.
1857 setLogicalHeight(logicalOffset + remainingLogicalHeight);
1858 }
1859 return result;
1860 }
1861
1862 return logicalOffset;
1863}
1864
1865bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1866{
1867 bool checkFragment = false;
1868 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1869 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1870 if (minimumLogicalHeight <= pageLogicalHeight)
1871 return true;
1872 if (!hasNextPage(logicalOffset + adjustment))
1873 return false;
1874 adjustment += pageLogicalHeight;
1875 checkFragment = true;
1876 }
1877 return !checkFragment;
1878}
1879
1880void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1881{
1882 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1883 fragmentedFlow->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1884}
1885
1886void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1887{
1888 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1889 fragmentedFlow->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
1890}
1891
1892LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1893{
1894 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1895 if (!pageLogicalHeight)
1896 return logicalOffset;
1897
1898 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1899 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1900 if (pageBoundaryRule == ExcludePageBoundary)
1901 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1902 return logicalOffset + remainingLogicalHeight;
1903}
1904
1905LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1906{
1907 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1908 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1909 auto* layoutState = view().frameView().layoutContext().layoutState();
1910 LayoutUnit pageLogicalHeight = layoutState->pageLogicalHeight();
1911 if (!pageLogicalHeight)
1912 return 0;
1913
1914 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? layoutState->pageOffset().height() : layoutState->pageOffset().width();
1915 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width();
1916
1917 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1918 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1919 if (!fragmentedFlow)
1920 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
1921 return firstPageLogicalTop + fragmentedFlow->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
1922}
1923
1924LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1925{
1926 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1927 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1928 LayoutUnit pageLogicalHeight = view().frameView().layoutContext().layoutState()->pageLogicalHeight();
1929 if (!pageLogicalHeight)
1930 return 0;
1931
1932 // Now check for a flow thread.
1933 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1934 if (!fragmentedFlow)
1935 return pageLogicalHeight;
1936 return fragmentedFlow->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1937}
1938
1939LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1940{
1941 offset += offsetFromLogicalTopOfFirstPage();
1942
1943 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1944 if (!fragmentedFlow) {
1945 LayoutUnit pageLogicalHeight = view().frameView().layoutContext().layoutState()->pageLogicalHeight();
1946 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1947 if (pageBoundaryRule == IncludePageBoundary) {
1948 // If includeBoundaryPoint is true the line exactly on the top edge of a
1949 // column will act as being part of the previous column.
1950 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1951 }
1952 return remainingHeight;
1953 }
1954
1955 return fragmentedFlow->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1956}
1957
1958LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1959{
1960 return logicalHeightForChild(child);
1961}
1962
1963void RenderBlockFlow::layoutLineGridBox()
1964{
1965 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
1966 setLineGridBox(0);
1967 return;
1968 }
1969
1970 setLineGridBox(0);
1971
1972 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
1973 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1974 lineGridBox->setConstructed();
1975 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1976 VerticalPositionCache verticalPositionCache;
1977 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1978
1979 setLineGridBox(WTFMove(lineGridBox));
1980
1981 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1982 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1983 // to this grid.
1984}
1985
1986bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
1987{
1988 return m_floatingObjects && m_floatingObjects->set().contains<FloatingObjectHashTranslator>(renderer);
1989}
1990
1991void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1992{
1993 RenderBlock::styleDidChange(diff, oldStyle);
1994
1995 // After our style changed, if we lose our ability to propagate floats into next sibling
1996 // blocks, then we need to find the top most parent containing that overhanging float and
1997 // then mark its descendants with floats for layout and clear all floats from its next
1998 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1999 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
2000 if (diff == StyleDifference::Layout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2001 RenderBlockFlow* parentBlock = this;
2002 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2003
2004 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2005 if (ancestor.isRenderView())
2006 break;
2007 if (ancestor.hasOverhangingFloats()) {
2008 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2009 RenderBox& renderer = (*it)->renderer();
2010 if (ancestor.hasOverhangingFloat(renderer)) {
2011 parentBlock = &ancestor;
2012 break;
2013 }
2014 }
2015 }
2016 }
2017
2018 parentBlock->markAllDescendantsWithFloatsForLayout();
2019 parentBlock->markSiblingsWithFloatsForLayout();
2020 }
2021
2022 if (diff >= StyleDifference::Repaint) {
2023 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2024 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2025 invalidateLineLayoutPath();
2026 }
2027
2028 if (multiColumnFlow())
2029 updateStylesForColumnChildren();
2030}
2031
2032void RenderBlockFlow::updateStylesForColumnChildren()
2033{
2034 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFragmentedFlow() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
2035 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), DisplayType::Block));
2036}
2037
2038void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
2039{
2040 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
2041 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2042
2043 if (oldStyle) {
2044 auto oldPosition = oldStyle->position();
2045 auto newPosition = newStyle.position();
2046
2047 if (parent() && diff == StyleDifference::Layout && oldPosition != newPosition) {
2048 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2049 markAllDescendantsWithFloatsForLayout();
2050 }
2051 }
2052
2053 RenderBlock::styleWillChange(diff, newStyle);
2054}
2055
2056void RenderBlockFlow::deleteLines()
2057{
2058 if (containsFloats())
2059 m_floatingObjects->clearLineBoxTreePointers();
2060
2061 if (m_simpleLineLayout) {
2062 ASSERT(!m_lineBoxes.firstLineBox());
2063 m_simpleLineLayout = nullptr;
2064 } else
2065 m_lineBoxes.deleteLineBoxTree();
2066
2067 RenderBlock::deleteLines();
2068}
2069
2070void RenderBlockFlow::addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const
2071{
2072 // When a portion of the render tree is being detached, anonymous blocks
2073 // will be combined as their children are deleted. In this process, the
2074 // anonymous block later in the tree is merged into the one preceeding it.
2075 // It can happen that the later block (this) contains floats that the
2076 // previous block (toBlockFlow) did not contain, and thus are not in the
2077 // floating objects list for toBlockFlow. This can result in toBlockFlow
2078 // containing floats that are not in it's floating objects list, but are in
2079 // the floating objects lists of siblings and parents. This can cause
2080 // problems when the float itself is deleted, since the deletion code
2081 // assumes that if a float is not in it's containing block's floating
2082 // objects list, it isn't in any floating objects list. In order to
2083 // preserve this condition (removing it has serious performance
2084 // implications), we need to copy the floating objects from the old block
2085 // (this) to the new block (toBlockFlow). The float's metrics will likely
2086 // all be wrong, but since toBlockFlow is already marked for layout, this
2087 // will get fixed before anything gets displayed.
2088 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2089 if (!m_floatingObjects)
2090 return;
2091
2092 if (!toBlockFlow.m_floatingObjects)
2093 toBlockFlow.createFloatingObjects();
2094
2095 for (auto& floatingObject : m_floatingObjects->set()) {
2096 if (toBlockFlow.containsFloat(floatingObject->renderer()))
2097 continue;
2098 toBlockFlow.m_floatingObjects->add(floatingObject->cloneForNewParent());
2099 }
2100}
2101
2102void RenderBlockFlow::addOverflowFromFloats()
2103{
2104 if (!m_floatingObjects)
2105 return;
2106
2107 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2108 auto end = floatingObjectSet.end();
2109 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2110 const auto& floatingObject = *it->get();
2111 if (floatingObject.isDescendant())
2112 addOverflowFromChild(&floatingObject.renderer(), floatingObject.locationOffsetOfBorderBox());
2113 }
2114}
2115
2116void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2117{
2118 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2119
2120 if (!multiColumnFlow() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
2121 addOverflowFromFloats();
2122}
2123
2124void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2125{
2126 // Repaint any overhanging floats (if we know we're the one to paint them).
2127 // Otherwise, bail out.
2128 if (!hasOverhangingFloats())
2129 return;
2130
2131 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2132 // in this block. Better yet would be to push extra state for the containers of other floats.
2133 LayoutStateDisabler layoutStateDisabler(view().frameView().layoutContext());
2134 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2135 auto end = floatingObjectSet.end();
2136 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2137 const auto& floatingObject = *it->get();
2138 // Only repaint the object if it is overhanging, is not in its own layer, and
2139 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2140 // condition is replaced with being a descendant of us.
2141 auto& renderer = floatingObject.renderer();
2142 if (logicalBottomForFloat(floatingObject) > logicalHeight()
2143 && !renderer.hasSelfPaintingLayer()
2144 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2145 renderer.repaint();
2146 renderer.repaintOverhangingFloats(false);
2147 }
2148 }
2149}
2150
2151void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
2152{
2153 RenderBlock::paintColumnRules(paintInfo, point);
2154
2155 if (!multiColumnFlow() || paintInfo.context().paintingDisabled())
2156 return;
2157
2158 // Iterate over our children and paint the column rules as needed.
2159 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2160 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2161 columnSet.paintColumnRules(paintInfo, childPoint);
2162 }
2163}
2164
2165void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2166{
2167 if (!m_floatingObjects)
2168 return;
2169
2170 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2171 auto end = floatingObjectSet.end();
2172 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2173 const auto& floatingObject = *it->get();
2174 auto& renderer = floatingObject.renderer();
2175 // Only paint the object if our m_shouldPaint flag is set.
2176 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
2177 PaintInfo currentPaintInfo(paintInfo);
2178 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhase::BlockBackground;
2179 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, paintOffset + floatingObject.translationOffsetToAncestor());
2180 renderer.paint(currentPaintInfo, childPoint);
2181 if (!preservePhase) {
2182 currentPaintInfo.phase = PaintPhase::ChildBlockBackgrounds;
2183 renderer.paint(currentPaintInfo, childPoint);
2184 currentPaintInfo.phase = PaintPhase::Float;
2185 renderer.paint(currentPaintInfo, childPoint);
2186 currentPaintInfo.phase = PaintPhase::Foreground;
2187 renderer.paint(currentPaintInfo, childPoint);
2188 currentPaintInfo.phase = PaintPhase::Outline;
2189 renderer.paint(currentPaintInfo, childPoint);
2190 }
2191 }
2192 }
2193}
2194
2195void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
2196{
2197 if (m_floatingObjects) {
2198 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2199 auto end = floatingObjectSet.end();
2200 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2201 const auto& floatingObject = *it->get();
2202 LayoutRect floatBox(offsetFromRootBlock.width(), offsetFromRootBlock.height(), floatingObject.renderer().width(), floatingObject.renderer().height());
2203 floatBox.move(floatingObject.locationOffsetOfBorderBox());
2204 rootBlock.flipForWritingMode(floatBox);
2205 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2206 paintInfo->context().clipOut(snappedIntRect(floatBox));
2207 }
2208 }
2209}
2210
2211void RenderBlockFlow::createFloatingObjects()
2212{
2213 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
2214}
2215
2216void RenderBlockFlow::removeFloatingObjects()
2217{
2218 if (!m_floatingObjects)
2219 return;
2220
2221 markSiblingsWithFloatsForLayout();
2222
2223 m_floatingObjects->clear();
2224}
2225
2226FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
2227{
2228 ASSERT(floatBox.isFloating());
2229
2230 // Create the list of special objects if we don't aleady have one
2231 if (!m_floatingObjects)
2232 createFloatingObjects();
2233 else {
2234 // Don't insert the floatingObject again if it's already in the list
2235 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2236 auto it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox);
2237 if (it != floatingObjectSet.end())
2238 return it->get();
2239 }
2240
2241 // Create the special floatingObject entry & append it to the list
2242
2243 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
2244
2245 // Our location is irrelevant if we're unsplittable or no pagination is in effect. Just lay out the float.
2246 bool isChildRenderBlock = floatBox.isRenderBlock();
2247 if (isChildRenderBlock && !floatBox.needsLayout() && view().frameView().layoutContext().layoutState()->pageLogicalHeightChanged())
2248 floatBox.setChildNeedsLayout(MarkOnlyThis);
2249
2250 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().frameView().layoutContext().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2251 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2252 // We are unsplittable if we're a block flow root.
2253 floatBox.layoutIfNeeded();
2254 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2255 }
2256 else {
2257 floatBox.updateLogicalWidth();
2258 floatBox.computeAndSetBlockDirectionMargins(*this);
2259 }
2260
2261 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
2262
2263 return m_floatingObjects->add(WTFMove(floatingObject));
2264}
2265
2266void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
2267{
2268 if (m_floatingObjects) {
2269 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2270 auto it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox);
2271 if (it != floatingObjectSet.end()) {
2272 auto& floatingObject = *it->get();
2273 if (childrenInline()) {
2274 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2275 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
2276
2277 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2278 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2279 logicalBottom = LayoutUnit::max();
2280 else {
2281 // Special-case zero- and less-than-zero-height floats: those don't touch
2282 // the line that they're on, but it still needs to be dirtied. This is
2283 // accomplished by pretending they have a height of 1.
2284 logicalBottom = std::max(logicalBottom, logicalTop + 1);
2285 }
2286 if (floatingObject.originatingLine()) {
2287 floatingObject.originatingLine()->removeFloat(floatBox);
2288 if (!selfNeedsLayout()) {
2289 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2290 floatingObject.originatingLine()->markDirty();
2291 }
2292#if !ASSERT_DISABLED
2293 floatingObject.clearOriginatingLine();
2294#endif
2295 }
2296 markLinesDirtyInBlockRange(0, logicalBottom);
2297 }
2298 m_floatingObjects->remove(&floatingObject);
2299 }
2300 }
2301}
2302
2303void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2304{
2305 if (!containsFloats())
2306 return;
2307
2308 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2309 FloatingObject* curr = floatingObjectSet.last().get();
2310 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
2311 m_floatingObjects->remove(curr);
2312 if (floatingObjectSet.isEmpty())
2313 break;
2314 curr = floatingObjectSet.last().get();
2315 }
2316}
2317
2318LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2319{
2320 LayoutUnit offset = fixedOffset;
2321 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2322 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2323 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2324}
2325
2326LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2327{
2328 LayoutUnit offset = fixedOffset;
2329 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2330 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2331 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2332}
2333
2334void RenderBlockFlow::computeLogicalLocationForFloat(FloatingObject& floatingObject, LayoutUnit& logicalTopOffset)
2335{
2336 auto& childBox = floatingObject.renderer();
2337 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
2338 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2339
2340 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
2341
2342 LayoutUnit floatLogicalLeft;
2343
2344 bool insideFragmentedFlow = enclosingFragmentedFlow();
2345 bool isInitialLetter = childBox.style().styleType() == PseudoId::FirstLetter && childBox.style().initialLetterDrop() > 0;
2346
2347 if (isInitialLetter) {
2348 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2349 if (letterClearance > 0) {
2350 logicalTopOffset += letterClearance;
2351 setLogicalHeight(logicalHeight() + letterClearance);
2352 }
2353 }
2354
2355 if (childBox.style().floating() == Float::Left) {
2356 LayoutUnit heightRemainingLeft = 1_lu;
2357 LayoutUnit heightRemainingRight = 1_lu;
2358 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2359 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
2360 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
2361 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2362 if (insideFragmentedFlow) {
2363 // Have to re-evaluate all of our offsets, since they may have changed.
2364 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2365 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
2366 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
2367 }
2368 }
2369 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
2370 } else {
2371 LayoutUnit heightRemainingLeft = 1_lu;
2372 LayoutUnit heightRemainingRight = 1_lu;
2373 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2374 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
2375 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
2376 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2377 if (insideFragmentedFlow) {
2378 // Have to re-evaluate all of our offsets, since they may have changed.
2379 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2380 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
2381 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
2382 }
2383 }
2384 // Use the original width of the float here, since the local variable
2385 // |floatLogicalWidth| was capped to the available line width. See
2386 // fast/block/float/clamped-right-float.html.
2387 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
2388 }
2389
2390 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
2391 LayoutUnit childBeforeMargin = marginBeforeForChild(childBox);
2392
2393 if (isInitialLetter)
2394 adjustInitialLetterPosition(childBox, logicalTopOffset, childBeforeMargin);
2395
2396 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
2397 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
2398
2399 setLogicalTopForFloat(floatingObject, logicalTopOffset);
2400 setLogicalTopForChild(childBox, logicalTopOffset + childBeforeMargin);
2401
2402 setLogicalMarginsForFloat(floatingObject, childLogicalLeftMargin, childBeforeMargin);
2403}
2404
2405void RenderBlockFlow::adjustInitialLetterPosition(RenderBox& childBox, LayoutUnit& logicalTopOffset, LayoutUnit& marginBeforeOffset)
2406{
2407 const RenderStyle& style = firstLineStyle();
2408 const FontMetrics& fontMetrics = style.fontMetrics();
2409 if (!fontMetrics.hasCapHeight())
2410 return;
2411
2412 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2413 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2414
2415 // Make an adjustment to align with the cap height of a theoretical block line.
2416 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2417 logicalTopOffset += adjustment;
2418
2419 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2420 // positive for raised and negative for sunken).
2421 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2422
2423 // If we're sunken, the float needs to shift down but lines still need to avoid it. In order to do that we increase the float's margin.
2424 if (dropHeightDelta < 0)
2425 marginBeforeOffset += -dropHeightDelta * heightOfLine;
2426
2427 // If we're raised, then we actually have to grow the height of the block, since the lines have to be pushed down as though we're placing
2428 // empty lines beside the first letter.
2429 if (dropHeightDelta > 0)
2430 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2431}
2432
2433bool RenderBlockFlow::positionNewFloats()
2434{
2435 if (!m_floatingObjects)
2436 return false;
2437
2438 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2439 if (floatingObjectSet.isEmpty())
2440 return false;
2441
2442 // If all floats have already been positioned, then we have no work to do.
2443 if (floatingObjectSet.last()->isPlaced())
2444 return false;
2445
2446 // Move backwards through our floating object list until we find a float that has
2447 // already been positioned. Then we'll be able to move forward, positioning all of
2448 // the new floats that need it.
2449 auto it = floatingObjectSet.end();
2450 --it; // Go to last item.
2451 auto begin = floatingObjectSet.begin();
2452 FloatingObject* lastPlacedFloatingObject = 0;
2453 while (it != begin) {
2454 --it;
2455 if ((*it)->isPlaced()) {
2456 lastPlacedFloatingObject = it->get();
2457 ++it;
2458 break;
2459 }
2460 }
2461
2462 LayoutUnit logicalTop = logicalHeight();
2463
2464 // The float cannot start above the top position of the last positioned float.
2465 if (lastPlacedFloatingObject)
2466 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
2467
2468 auto end = floatingObjectSet.end();
2469 // Now walk through the set of unpositioned floats and place them.
2470 for (; it != end; ++it) {
2471 auto& floatingObject = *it->get();
2472 // The containing block is responsible for positioning floats, so if we have floats in our
2473 // list that come from somewhere else, do not attempt to position them.
2474 auto& childBox = floatingObject.renderer();
2475 if (childBox.containingBlock() != this)
2476 continue;
2477
2478 LayoutRect oldRect = childBox.frameRect();
2479
2480 if (childBox.style().clear() == Clear::Left || childBox.style().clear() == Clear::Both)
2481 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
2482 if (childBox.style().clear() == Clear::Right || childBox.style().clear() == Clear::Both)
2483 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
2484
2485 computeLogicalLocationForFloat(floatingObject, logicalTop);
2486 LayoutUnit childLogicalTop = logicalTopForChild(childBox);
2487
2488 estimateFragmentRangeForBoxChild(childBox);
2489
2490 childBox.markForPaginationRelayoutIfNeeded();
2491 childBox.layoutIfNeeded();
2492
2493 auto* layoutState = view().frameView().layoutContext().layoutState();
2494 bool isPaginated = layoutState->isPaginated();
2495 if (isPaginated) {
2496 // If we are unsplittable and don't fit, then we need to move down.
2497 // We include our margins as part of the unsplittable area.
2498 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, childLogicalTop - logicalTop, marginAfterForChild(childBox));
2499
2500 // See if we have a pagination strut that is making us move down further.
2501 // Note that an unsplittable child can't also have a pagination strut, so this
2502 // is exclusive with the case above.
2503 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
2504 if (childBlock && childBlock->paginationStrut()) {
2505 newLogicalTop += childBlock->paginationStrut();
2506 childBlock->setPaginationStrut(0);
2507 }
2508
2509 if (newLogicalTop != logicalTop) {
2510 floatingObject.setPaginationStrut(newLogicalTop - logicalTop);
2511 computeLogicalLocationForFloat(floatingObject, newLogicalTop);
2512 if (childBlock)
2513 childBlock->setChildNeedsLayout(MarkOnlyThis);
2514 childBox.layoutIfNeeded();
2515 logicalTop = newLogicalTop;
2516 }
2517
2518 if (updateFragmentRangeForBoxChild(childBox)) {
2519 childBox.setNeedsLayout(MarkOnlyThis);
2520 childBox.layoutIfNeeded();
2521 }
2522 }
2523
2524 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + (logicalTopForChild(childBox) - logicalTop) + marginAfterForChild(childBox));
2525
2526 m_floatingObjects->addPlacedObject(&floatingObject);
2527
2528 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
2529 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
2530 // If the child moved, we have to repaint it.
2531 if (childBox.checkForRepaintDuringLayout())
2532 childBox.repaintDuringLayoutIfMoved(oldRect);
2533 }
2534 return true;
2535}
2536
2537void RenderBlockFlow::clearFloats(Clear clear)
2538{
2539 positionNewFloats();
2540 // set y position
2541 LayoutUnit newY;
2542 switch (clear) {
2543 case Clear::Left:
2544 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2545 break;
2546 case Clear::Right:
2547 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2548 break;
2549 case Clear::Both:
2550 newY = lowestFloatLogicalBottom();
2551 break;
2552 case Clear::None:
2553 break;
2554 }
2555 if (height() < newY)
2556 setLogicalHeight(newY);
2557}
2558
2559LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
2560{
2561 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2562 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
2563
2564 return fixedOffset;
2565}
2566
2567LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
2568{
2569 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2570 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
2571
2572 return fixedOffset;
2573}
2574
2575LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
2576{
2577 if (!m_floatingObjects)
2578 return logicalHeight;
2579
2580 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2581}
2582
2583LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2584{
2585 if (!m_floatingObjects)
2586 return logicalHeight;
2587
2588 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
2589}
2590
2591LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2592{
2593 if (!m_floatingObjects)
2594 return 0;
2595 LayoutUnit lowestFloatBottom;
2596 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2597 auto end = floatingObjectSet.end();
2598 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2599 const auto& floatingObject = *it->get();
2600 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
2601 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2602 }
2603 return lowestFloatBottom;
2604}
2605
2606LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2607{
2608 if (!m_floatingObjects)
2609 return 0;
2610 LayoutUnit lowestFloatBottom;
2611 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2612 auto end = floatingObjectSet.end();
2613 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2614 const auto& floatingObject = *it->get();
2615 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == PseudoId::FirstLetter && floatingObject.renderer().style().initialLetterDrop() > 0)
2616 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2617 }
2618 return lowestFloatBottom;
2619}
2620
2621LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
2622{
2623 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
2624 if (!child.containsFloats() || child.createsNewFormattingContext())
2625 return 0;
2626
2627 LayoutUnit childLogicalTop = child.logicalTop();
2628 LayoutUnit childLogicalLeft = child.logicalLeft();
2629 LayoutUnit lowestFloatLogicalBottom;
2630
2631 // Floats that will remain the child's responsibility to paint should factor into its
2632 // overflow.
2633 auto childEnd = child.m_floatingObjects->set().end();
2634 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
2635 auto& floatingObject = *childIt->get();
2636 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
2637 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
2638 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
2639
2640 if (logicalBottom > logicalHeight()) {
2641 // If the object is not in the list, we add it now.
2642 if (!containsFloat(floatingObject.renderer())) {
2643 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2644 bool shouldPaint = false;
2645
2646 // The nearest enclosing layer always paints the float (so that zindex and stacking
2647 // behaves properly). We always want to propagate the desire to paint the float as
2648 // far out as we can, to the outermost block that overlaps the float, stopping only
2649 // if we hit a self-painting layer boundary.
2650 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2651 floatingObject.setShouldPaint(false);
2652 shouldPaint = true;
2653 }
2654 // We create the floating object list lazily.
2655 if (!m_floatingObjects)
2656 createFloatingObjects();
2657
2658 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
2659 }
2660 } else {
2661 const auto& renderer = floatingObject.renderer();
2662 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2663 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
2664 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2665 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2666 // layer.
2667 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2668 // it should paint.
2669 floatingObject.setShouldPaint(true);
2670 }
2671
2672 // Since the float doesn't overhang, it didn't get put into our list. We need to add its overflow in to the child now.
2673 if (floatingObject.isDescendant())
2674 child.addOverflowFromChild(&renderer, floatingObject.locationOffsetOfBorderBox());
2675 }
2676 }
2677 return lowestFloatLogicalBottom;
2678}
2679
2680bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
2681{
2682 if (!m_floatingObjects || !parent())
2683 return false;
2684
2685 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2686 const auto it = floatingObjectSet.find<FloatingObjectHashTranslator>(renderer);
2687 if (it == floatingObjectSet.end())
2688 return false;
2689
2690 return logicalBottomForFloat(*it->get()) > logicalHeight();
2691}
2692
2693void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
2694{
2695 ASSERT(!avoidsFloats());
2696
2697 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2698 if (createsNewFormattingContext())
2699 return;
2700
2701 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2702 if (!prev->m_floatingObjects)
2703 return;
2704
2705 logicalLeftOffset += marginLogicalLeft();
2706
2707 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2708 auto prevEnd = prevSet.end();
2709 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2710 auto& floatingObject = *prevIt->get();
2711 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
2712 if (!m_floatingObjects || !m_floatingObjects->set().contains(&floatingObject)) {
2713 // We create the floating object list lazily.
2714 if (!m_floatingObjects)
2715 createFloatingObjects();
2716
2717 // Applying the child's margin makes no sense in the case where the child was passed in.
2718 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2719 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2720 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2721 // will get applied twice.
2722 LayoutSize offset = isHorizontalWritingMode()
2723 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : 0_lu), logicalTopOffset)
2724 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : 0_lu));
2725
2726 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
2727 }
2728 }
2729 }
2730}
2731
2732void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2733{
2734 if (!everHadLayout() && !containsFloats())
2735 return;
2736
2737 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2738 setChildNeedsLayout(markParents);
2739
2740 if (floatToRemove)
2741 removeFloatingObject(*floatToRemove);
2742 else if (childrenInline())
2743 return;
2744
2745 // Iterate over our block children and mark them as needed.
2746 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2747 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2748 continue;
2749 if (!is<RenderBlockFlow>(block)) {
2750 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2751 block.setChildNeedsLayout(markParents);
2752 continue;
2753 }
2754 auto& blockFlow = downcast<RenderBlockFlow>(block);
2755 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2756 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
2757 }
2758}
2759
2760void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2761{
2762 if (!m_floatingObjects)
2763 return;
2764
2765 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2766 auto end = floatingObjectSet.end();
2767
2768 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
2769 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
2770 continue;
2771
2772 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
2773 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2774 RenderBox& floatingBox = (*it)->renderer();
2775 if (floatToRemove && &floatingBox != floatToRemove)
2776 continue;
2777 if (nextBlock.containsFloat(floatingBox))
2778 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
2779 }
2780 }
2781}
2782
2783LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
2784{
2785 if (!style().isFlippedBlocksWritingMode())
2786 return point;
2787
2788 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2789 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2790 // case.
2791 if (isHorizontalWritingMode())
2792 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * child.locationOffsetOfBorderBox().height());
2793 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * child.locationOffsetOfBorderBox().width(), point.y());
2794}
2795
2796LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
2797{
2798 // There is no need to compute clearance if we have no floats.
2799 if (!containsFloats())
2800 return 0;
2801
2802 // At least one float is present. We need to perform the clearance computation.
2803 bool clearSet = child.style().clear() != Clear::None;
2804 LayoutUnit logicalBottom;
2805 switch (child.style().clear()) {
2806 case Clear::None:
2807 break;
2808 case Clear::Left:
2809 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2810 break;
2811 case Clear::Right:
2812 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2813 break;
2814 case Clear::Both:
2815 logicalBottom = lowestFloatLogicalBottom();
2816 break;
2817 }
2818
2819 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
2820 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : 0_lu;
2821 if (!result && child.avoidsFloats()) {
2822 LayoutUnit newLogicalTop = logicalTop;
2823 while (true) {
2824 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
2825 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2826 return newLogicalTop - logicalTop;
2827
2828 RenderFragmentContainer* fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2829 LayoutRect borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
2830 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2831
2832 // FIXME: None of this is right for perpendicular writing-mode children.
2833 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2834 LayoutUnit childOldMarginLeft = child.marginLeft();
2835 LayoutUnit childOldMarginRight = child.marginRight();
2836 LayoutUnit childOldLogicalTop = child.logicalTop();
2837
2838 child.setLogicalTop(newLogicalTop);
2839 child.updateLogicalWidth();
2840 fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2841 borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
2842 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2843
2844 child.setLogicalTop(childOldLogicalTop);
2845 child.setLogicalWidth(childOldLogicalWidth);
2846 child.setMarginLeft(childOldMarginLeft);
2847 child.setMarginRight(childOldMarginRight);
2848
2849 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2850 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2851 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2852 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2853 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
2854 child.setChildNeedsLayout(MarkOnlyThis);
2855 return newLogicalTop - logicalTop;
2856 }
2857
2858 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
2859 ASSERT(newLogicalTop >= logicalTop);
2860 if (newLogicalTop < logicalTop)
2861 break;
2862 }
2863 ASSERT_NOT_REACHED();
2864 }
2865 return result;
2866}
2867
2868bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2869{
2870 if (!m_floatingObjects)
2871 return false;
2872
2873 LayoutPoint adjustedLocation = accumulatedOffset;
2874 if (is<RenderView>(*this))
2875 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
2876
2877 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2878 auto begin = floatingObjectSet.begin();
2879 for (auto it = floatingObjectSet.end(); it != begin;) {
2880 --it;
2881 const auto& floatingObject = *it->get();
2882 auto& renderer = floatingObject.renderer();
2883 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
2884 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + floatingObject.translationOffsetToAncestor());
2885 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
2886 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2887 return true;
2888 }
2889 }
2890 }
2891
2892 return false;
2893}
2894
2895bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2896{
2897 ASSERT(childrenInline());
2898
2899 if (auto simpleLineLayout = this->simpleLineLayout())
2900 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2901
2902 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2903}
2904
2905void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2906{
2907 if (style().visibility() != Visibility::Visible)
2908 return;
2909
2910 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2911 // for either overflow or translations via relative positioning.
2912 if (childrenInline()) {
2913 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2914
2915 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
2916 if (box->firstChild())
2917 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
2918 if (box->lastChild())
2919 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
2920 }
2921 } else {
2922 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2923 if (!obj->isFloatingOrOutOfFlowPositioned()) {
2924 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2925 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
2926 else if (obj->style().visibility() == Visibility::Visible) {
2927 // We are a replaced element or some kind of non-block-flow object.
2928 left = std::min(left, x + obj->x());
2929 right = std::max(right, x + obj->x() + obj->width());
2930 }
2931 }
2932 }
2933 }
2934
2935 if (m_floatingObjects) {
2936 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2937 auto end = floatingObjectSet.end();
2938 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2939 const auto& floatingObject = *it->get();
2940 // Only examine the object if our m_shouldPaint flag is set.
2941 if (floatingObject.shouldPaint()) {
2942 LayoutUnit floatLeft = floatingObject.translationOffsetToAncestor().width();
2943 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
2944 left = std::min(left, floatLeft);
2945 right = std::max(right, floatRight);
2946 }
2947 }
2948 }
2949}
2950
2951void RenderBlockFlow::fitBorderToLinesIfNeeded()
2952{
2953 if (style().borderFit() == BorderFit::Border || hasOverrideContentLogicalWidth())
2954 return;
2955
2956 // Walk any normal flow lines to snugly fit.
2957 LayoutUnit left = LayoutUnit::max();
2958 LayoutUnit right = LayoutUnit::min();
2959 LayoutUnit oldWidth = contentWidth();
2960 adjustForBorderFit(0, left, right);
2961
2962 // Clamp to our existing edges. We can never grow. We only shrink.
2963 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2964 LayoutUnit rightEdge = leftEdge + oldWidth;
2965 left = std::min(rightEdge, std::max(leftEdge, left));
2966 right = std::max(leftEdge, std::min(rightEdge, right));
2967
2968 LayoutUnit newContentWidth = right - left;
2969 if (newContentWidth == oldWidth)
2970 return;
2971
2972 setOverrideContentLogicalWidth(newContentWidth);
2973 layoutBlock(false);
2974 clearOverrideContentLogicalWidth();
2975}
2976
2977void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2978{
2979 if (logicalTop >= logicalBottom)
2980 return;
2981
2982 // Floats currently affect the choice whether to use simple line layout path.
2983 if (m_simpleLineLayout) {
2984 invalidateLineLayoutPath();
2985 return;
2986 }
2987
2988 RootInlineBox* lowestDirtyLine = lastRootBox();
2989 RootInlineBox* afterLowest = lowestDirtyLine;
2990 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2991 afterLowest = lowestDirtyLine;
2992 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2993 }
2994
2995 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2996 afterLowest->markDirty();
2997 afterLowest = afterLowest->prevRootBox();
2998 }
2999}
3000
3001Optional<int> RenderBlockFlow::firstLineBaseline() const
3002{
3003 if (isWritingModeRoot() && !isRubyRun() && !isGridItem())
3004 return WTF::nullopt;
3005
3006 if (!childrenInline())
3007 return RenderBlock::firstLineBaseline();
3008
3009 if (!hasLines())
3010 return WTF::nullopt;
3011
3012 if (auto simpleLineLayout = this->simpleLineLayout())
3013 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
3014
3015 ASSERT(firstRootBox());
3016 if (style().isFlippedLinesWritingMode())
3017 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().descent(firstRootBox()->baselineType());
3018 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
3019}
3020
3021Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
3022{
3023 if (isWritingModeRoot() && !isRubyRun())
3024 return WTF::nullopt;
3025
3026 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3027 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3028 float lastBaseline;
3029 if (!childrenInline()) {
3030 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3031 if (!inlineBlockBaseline)
3032 return inlineBlockBaseline;
3033 lastBaseline = inlineBlockBaseline.value();
3034 } else {
3035 if (!hasLines()) {
3036 if (!hasLineIfEmpty())
3037 return WTF::nullopt;
3038 const auto& fontMetrics = firstLineStyle().fontMetrics();
3039 return Optional<int>(fontMetrics.ascent()
3040 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
3041 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
3042 }
3043
3044 if (auto simpleLineLayout = this->simpleLineLayout())
3045 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3046 else {
3047 bool isFirstLine = lastRootBox() == firstRootBox();
3048 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3049 // InlineFlowBox::placeBoxesInBlockDirection will flip lines in case of verticalLR mode, so we can assume verticalRL for now.
3050 lastBaseline = style.fontMetrics().ascent(lastRootBox()->baselineType())
3051 + (style.isFlippedLinesWritingMode() ? logicalHeight() - lastRootBox()->logicalBottom() : lastRootBox()->logicalTop());
3052 }
3053 }
3054 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3055 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3056 // enough with the spec to not cause tons of breakages).
3057 return style().overflowY() == Overflow::Visible ? lastBaseline : std::min(boxHeight, lastBaseline);
3058}
3059
3060void RenderBlockFlow::setSelectionState(SelectionState state)
3061{
3062 if (state != SelectionNone)
3063 ensureLineBoxes();
3064 RenderBoxModelObject::setSelectionState(state);
3065}
3066
3067GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3068 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3069{
3070 ASSERT(!m_simpleLineLayout);
3071
3072 GapRects result;
3073
3074 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3075
3076 if (!hasLines()) {
3077 if (containsStart) {
3078 // Update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this case.
3079 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3080 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3081 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3082 }
3083 return result;
3084 }
3085
3086 RootInlineBox* lastSelectedLine = 0;
3087 RootInlineBox* curr;
3088 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3089
3090 // Now paint the gaps for the lines.
3091 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3092 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3093 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3094
3095 if (!containsStart && !lastSelectedLine &&
3096 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
3097 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3098
3099 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3100 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
3101 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3102 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3103 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3104 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3105
3106 lastSelectedLine = curr;
3107 }
3108
3109 if (containsStart && !lastSelectedLine)
3110 // VisibleSelection must start just after our last line.
3111 lastSelectedLine = lastRootBox();
3112
3113 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3114 // Update our lastY to be the bottom of the last selected line.
3115 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3116 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3117 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3118 }
3119 return result;
3120}
3121
3122bool RenderBlockFlow::needsLayoutAfterFragmentRangeChange() const
3123{
3124 // A block without floats or that expands to enclose them won't need a relayout
3125 // after a fragment range change. There is no overflow content needing relayout
3126 // in the fragment chain because the fragment range can only shrink after the estimation.
3127 if (!containsFloats() || createsNewFormattingContext())
3128 return false;
3129
3130 return true;
3131}
3132
3133void RenderBlockFlow::setMultiColumnFlow(RenderMultiColumnFlow& fragmentedFlow)
3134{
3135 ASSERT(!hasRareBlockFlowData() || !rareBlockFlowData()->m_multiColumnFlow);
3136 ensureRareBlockFlowData().m_multiColumnFlow = makeWeakPtr(fragmentedFlow);
3137}
3138
3139void RenderBlockFlow::clearMultiColumnFlow()
3140{
3141 ASSERT(hasRareBlockFlowData());
3142 ASSERT(rareBlockFlowData()->m_multiColumnFlow);
3143 rareBlockFlowData()->m_multiColumnFlow.clear();
3144}
3145
3146static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
3147{
3148 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
3149}
3150
3151RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3152{
3153 ASSERT(i >= 0);
3154
3155 if (style().visibility() != Visibility::Visible)
3156 return nullptr;
3157
3158 if (childrenInline()) {
3159 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3160 if (!i--)
3161 return box;
3162 }
3163 return nullptr;
3164 }
3165
3166 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3167 if (!shouldCheckLines(blockFlow))
3168 continue;
3169 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3170 return box;
3171 }
3172
3173 return nullptr;
3174}
3175
3176int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3177{
3178 if (style().visibility() != Visibility::Visible)
3179 return 0;
3180
3181 int count = 0;
3182
3183 if (childrenInline()) {
3184 if (auto simpleLineLayout = this->simpleLineLayout()) {
3185 ASSERT(!stopRootInlineBox);
3186 return simpleLineLayout->lineCount();
3187 }
3188 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3189 ++count;
3190 if (box == stopRootInlineBox) {
3191 if (found)
3192 *found = true;
3193 break;
3194 }
3195 }
3196 return count;
3197 }
3198
3199 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3200 if (!shouldCheckLines(blockFlow))
3201 continue;
3202 bool recursiveFound = false;
3203 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3204 if (recursiveFound) {
3205 if (found)
3206 *found = true;
3207 break;
3208 }
3209 }
3210
3211 return count;
3212}
3213
3214static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3215{
3216 if (block.style().visibility() != Visibility::Visible)
3217 return -1;
3218
3219 if (block.childrenInline()) {
3220 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
3221 if (++count == lineCount)
3222 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : 0_lu);
3223 }
3224 } else {
3225 RenderBox* normalFlowChildWithoutLines = nullptr;
3226 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
3227 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3228 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
3229 if (result != -1)
3230 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : 0_lu);
3231 } else if (!obj->isFloatingOrOutOfFlowPositioned())
3232 normalFlowChildWithoutLines = obj;
3233 }
3234 if (normalFlowChildWithoutLines && !lineCount)
3235 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3236 }
3237
3238 return -1;
3239}
3240
3241int RenderBlockFlow::heightForLineCount(int lineCount)
3242{
3243 int count = 0;
3244 return getHeightForLineCount(*this, lineCount, true, count);
3245}
3246
3247void RenderBlockFlow::clearTruncation()
3248{
3249 if (style().visibility() != Visibility::Visible)
3250 return;
3251
3252 if (childrenInline() && hasMarkupTruncation()) {
3253 ensureLineBoxes();
3254
3255 setHasMarkupTruncation(false);
3256 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
3257 box->clearTruncation();
3258 return;
3259 }
3260
3261 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3262 if (shouldCheckLines(blockFlow))
3263 blockFlow.clearTruncation();
3264 }
3265}
3266
3267bool RenderBlockFlow::containsNonZeroBidiLevel() const
3268{
3269 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3270 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
3271 if (box->bidiLevel())
3272 return true;
3273 }
3274 }
3275 return false;
3276}
3277
3278Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3279{
3280 if (!box)
3281 return Position();
3282
3283 if (!box->renderer().nonPseudoNode())
3284 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3285
3286 if (!is<InlineTextBox>(*box))
3287 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3288
3289 auto& textBox = downcast<InlineTextBox>(*box);
3290 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
3291}
3292
3293RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
3294{
3295 // A light, non-recursive version of RenderBlock::positionForCoordinates that looks at
3296 // whether a point lies within the gaps between its root line boxes, to be called against
3297 // a node returned from elementAtPoint. We make the assumption that either the node or one
3298 // of its immediate children contains the root line boxes in question.
3299 // See <rdar://problem/6824650> for context.
3300
3301 RenderBlock* block = this;
3302
3303 FloatPoint localPoint = block->absoluteToLocal(point);
3304
3305 if (!block->childrenInline()) {
3306 // Look among our immediate children for an alternate box that contains the point.
3307 for (RenderBox* child = block->firstChildBox(); child; child = child->nextSiblingBox()) {
3308 if (!child->height() || child->style().visibility() != WebCore::Visibility::Visible || child->isFloatingOrOutOfFlowPositioned())
3309 continue;
3310 float top = child->y();
3311
3312 RenderBox* nextChild = child->nextSiblingBox();
3313 while (nextChild && nextChild->isFloatingOrOutOfFlowPositioned())
3314 nextChild = nextChild->nextSiblingBox();
3315 if (!nextChild) {
3316 if (localPoint.y() >= top) {
3317 block = downcast<RenderBlock>(child);
3318 break;
3319 }
3320 continue;
3321 }
3322
3323 float bottom = nextChild->y();
3324
3325 if (localPoint.y() >= top && localPoint.y() < bottom && is<RenderBlock>(*child)) {
3326 block = downcast<RenderBlock>(child);
3327 break;
3328 }
3329 }
3330
3331 if (!block->childrenInline())
3332 return nullptr;
3333
3334 localPoint = block->absoluteToLocal(point);
3335 }
3336
3337 RenderBlockFlow& blockFlow = downcast<RenderBlockFlow>(*block);
3338
3339 // Only check the gaps between the root line boxes. We deliberately ignore overflow because
3340 // experience has shown that hit tests on an exploded text node can fail when within the
3341 // overflow fragment.
3342 for (RootInlineBox* current = blockFlow.firstRootBox(); current && current != blockFlow.lastRootBox(); current = current->nextRootBox()) {
3343 float currentBottom = current->y() + current->logicalHeight();
3344 if (localPoint.y() < currentBottom)
3345 return nullptr;
3346
3347 RootInlineBox* next = current->nextRootBox();
3348 float nextTop = next->y();
3349 if (localPoint.y() < nextTop) {
3350 InlineBox* inlineBox = current->closestLeafChildForLogicalLeftPosition(localPoint.x());
3351 if (inlineBox && inlineBox->behavesLikeText() && is<RenderText>(inlineBox->renderer()))
3352 return &downcast<RenderText>(inlineBox->renderer());
3353 }
3354 }
3355 return nullptr;
3356}
3357
3358VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer* fragment)
3359{
3360 ASSERT(childrenInline());
3361
3362 ensureLineBoxes();
3363
3364 if (!firstRootBox())
3365 return createVisiblePosition(0, DOWNSTREAM);
3366
3367 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3368 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
3369
3370 // look for the closest line box in the root box which is at the passed-in y coordinate
3371 InlineBox* closestBox = 0;
3372 RootInlineBox* firstRootBoxWithChildren = 0;
3373 RootInlineBox* lastRootBoxWithChildren = 0;
3374 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
3375 if (fragment && root->containingFragment() != fragment)
3376 continue;
3377
3378 if (!root->firstLeafChild())
3379 continue;
3380 if (!firstRootBoxWithChildren)
3381 firstRootBoxWithChildren = root;
3382
3383 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3384 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3385 break;
3386
3387 lastRootBoxWithChildren = root;
3388
3389 // check if this root line box is located at this y coordinate
3390 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3391 if (linesAreFlipped) {
3392 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3393 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3394 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3395
3396 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3397 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3398 continue;
3399 }
3400 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3401 if (closestBox)
3402 break;
3403 }
3404 }
3405
3406 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3407
3408 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3409 // y coordinate is below last root line box, pretend we hit it
3410 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3411 }
3412
3413 if (closestBox) {
3414 if (moveCaretToBoundary) {
3415 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
3416 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3417 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3418 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3419 if (box->isLineBreak()) {
3420 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3421 box = newBox;
3422 }
3423 // y coordinate is above first root line box, so return the start of the first
3424 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3425 }
3426 }
3427
3428 // pass the box a top position that is inside it
3429 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3430 if (!isHorizontalWritingMode())
3431 point = point.transposedPoint();
3432 if (closestBox->renderer().isReplaced())
3433 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
3434 return closestBox->renderer().positionForPoint(point, nullptr);
3435 }
3436
3437 if (lastRootBoxWithChildren) {
3438 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3439 ASSERT(moveCaretToBoundary);
3440 InlineBox* logicallyLastBox;
3441 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3442 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3443 }
3444
3445 // Can't reach this. We have a root line box, but it has no kids.
3446 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3447 // seems to hit this code path.
3448 return createVisiblePosition(0, DOWNSTREAM);
3449}
3450
3451Position RenderBlockFlow::positionForPoint(const LayoutPoint& point)
3452{
3453 // FIXME: It supports single text child only (which is the majority of simple line layout supported content at this point).
3454 if (!simpleLineLayout() || firstChild() != lastChild() || !is<RenderText>(firstChild()))
3455 return positionForPoint(point, nullptr).deepEquivalent();
3456 return downcast<RenderText>(*firstChild()).positionForPoint(point);
3457}
3458
3459VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer*)
3460{
3461 return RenderBlock::positionForPoint(point, nullptr);
3462}
3463
3464void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3465{
3466 ASSERT(childrenInline());
3467 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
3468 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3469 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
3470 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3471 if (!rect.isEmpty())
3472 rects.append(rect);
3473 }
3474}
3475
3476void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3477{
3478 ASSERT(childrenInline());
3479
3480 if (auto simpleLineLayout = this->simpleLineLayout()) {
3481 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
3482 return;
3483 }
3484 m_lineBoxes.paint(this, paintInfo, paintOffset);
3485}
3486
3487bool RenderBlockFlow::relayoutForPagination()
3488{
3489 if (!multiColumnFlow() || !multiColumnFlow()->shouldRelayoutForPagination())
3490 return false;
3491
3492 multiColumnFlow()->setNeedsHeightsRecalculation(false);
3493 multiColumnFlow()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3494
3495 bool needsRelayout;
3496 bool neededRelayout = false;
3497 bool firstPass = true;
3498 do {
3499 // Column heights may change here because of balancing. We may have to do multiple layout
3500 // passes, depending on how the contents is fitted to the changed column heights. In most
3501 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3502 // passes than that, though, but the number of retries should not exceed the number of
3503 // columns, unless we have a bug.
3504 needsRelayout = false;
3505 for (RenderMultiColumnSet* multicolSet = multiColumnFlow()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3506 if (multicolSet->recalculateColumnHeight(firstPass))
3507 needsRelayout = true;
3508 if (needsRelayout) {
3509 // Once a column set gets a new column height, that column set and all successive column
3510 // sets need to be laid out over again, since their logical top will be affected by
3511 // this, and therefore their column heights may change as well, at least if the multicol
3512 // height is constrained.
3513 multicolSet->setChildNeedsLayout(MarkOnlyThis);
3514 }
3515 }
3516 if (needsRelayout) {
3517 // Layout again. Column balancing resulted in a new height.
3518 neededRelayout = true;
3519 multiColumnFlow()->setChildNeedsLayout(MarkOnlyThis);
3520 setChildNeedsLayout(MarkOnlyThis);
3521 layoutBlock(false);
3522 }
3523 firstPass = false;
3524 } while (needsRelayout);
3525
3526 multiColumnFlow()->setInBalancingPass(false);
3527
3528 return neededRelayout;
3529}
3530
3531bool RenderBlockFlow::hasLines() const
3532{
3533 if (!childrenInline())
3534 return false;
3535
3536 if (auto simpleLineLayout = this->simpleLineLayout())
3537 return simpleLineLayout->lineCount();
3538
3539 return lineBoxes().firstLineBox();
3540}
3541
3542void RenderBlockFlow::invalidateLineLayoutPath()
3543{
3544 switch (lineLayoutPath()) {
3545 case UndeterminedPath:
3546 case ForceLineBoxesPath:
3547 ASSERT(!m_simpleLineLayout);
3548 return;
3549 case LineBoxesPath:
3550 ASSERT(!m_simpleLineLayout);
3551 setLineLayoutPath(UndeterminedPath);
3552 return;
3553 case SimpleLinesPath:
3554 // The simple line layout may have become invalid.
3555 m_simpleLineLayout = nullptr;
3556 setLineLayoutPath(UndeterminedPath);
3557 if (needsLayout())
3558 return;
3559 // FIXME: We should just kick off a subtree layout here (if needed at all) see webkit.org/b/172947.
3560 setNeedsLayout();
3561 return;
3562 }
3563 ASSERT_NOT_REACHED();
3564}
3565
3566void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
3567{
3568 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3569 if (needsLayout) {
3570 deleteLineBoxesBeforeSimpleLineLayout();
3571 m_simpleLineLayout = SimpleLineLayout::create(*this);
3572 }
3573 if (view().frameView().layoutContext().layoutState() && view().frameView().layoutContext().layoutState()->isPaginated()) {
3574 m_simpleLineLayout->setIsPaginated();
3575 SimpleLineLayout::adjustLinePositionsForPagination(*m_simpleLineLayout, *this);
3576 }
3577 for (auto& renderer : childrenOfType<RenderObject>(*this))
3578 renderer.clearNeedsLayout();
3579 ASSERT(!m_lineBoxes.firstLineBox());
3580 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
3581 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
3582 repaintLogicalTop = lineLayoutTop;
3583 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight + borderAndPaddingAfter() : repaintLogicalTop;
3584 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3585}
3586
3587void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3588{
3589 ASSERT(lineLayoutPath() == SimpleLinesPath);
3590 lineBoxes().deleteLineBoxes();
3591 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3592 if (is<RenderText>(renderer))
3593 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3594 else if (is<RenderLineBreak>(renderer))
3595 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3596 else
3597 ASSERT_NOT_REACHED();
3598 }
3599}
3600
3601void RenderBlockFlow::ensureLineBoxes()
3602{
3603 setLineLayoutPath(ForceLineBoxesPath);
3604 if (!m_simpleLineLayout)
3605 return;
3606
3607 if (SimpleLineLayout::canUseForLineBoxTree(*this, *m_simpleLineLayout)) {
3608 SimpleLineLayout::generateLineBoxTree(*this, *m_simpleLineLayout);
3609 m_simpleLineLayout = nullptr;
3610 return;
3611 }
3612 bool isPaginated = m_simpleLineLayout->isPaginated();
3613 m_simpleLineLayout = nullptr;
3614
3615#if !ASSERT_DISABLED
3616 LayoutUnit oldHeight = logicalHeight();
3617#endif
3618 bool didNeedLayout = needsLayout();
3619
3620 bool relayoutChildren = false;
3621 LayoutUnit repaintLogicalTop;
3622 LayoutUnit repaintLogicalBottom;
3623 if (isPaginated) {
3624 PaginatedLayoutStateMaintainer state(*this);
3625 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3626 // This matches relayoutToAvoidWidows.
3627 if (shouldBreakAtLineToAvoidWidow())
3628 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3629 // FIXME: This is needed as long as simple and normal line layout produce different line breakings.
3630 repaint();
3631 } else
3632 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3633
3634 updateLogicalHeight();
3635 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3636
3637 if (!didNeedLayout)
3638 clearNeedsLayout();
3639}
3640
3641#if ENABLE(TREE_DEBUGGING)
3642void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const InlineBox* markedBox, int depth) const
3643{
3644 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
3645 root->outputLineTreeAndMark(stream, markedBox, depth);
3646
3647 if (auto simpleLineLayout = this->simpleLineLayout())
3648 SimpleLineLayout::outputLineLayoutForFlow(stream, *this, *simpleLineLayout, depth);
3649}
3650#endif
3651
3652RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3653{
3654 if (hasRareBlockFlowData())
3655 return *m_rareBlockFlowData;
3656 materializeRareBlockFlowData();
3657 return *m_rareBlockFlowData;
3658}
3659
3660void RenderBlockFlow::materializeRareBlockFlowData()
3661{
3662 ASSERT(!hasRareBlockFlowData());
3663 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3664}
3665
3666#if ENABLE(TEXT_AUTOSIZING)
3667
3668static inline bool isVisibleRenderText(const RenderObject& renderer)
3669{
3670 if (!is<RenderText>(renderer))
3671 return false;
3672
3673 auto& renderText = downcast<RenderText>(renderer);
3674 return !renderText.linesBoundingBox().isEmpty() && !renderText.text().isAllSpecialCharacters<isHTMLSpace>();
3675}
3676
3677static inline bool resizeTextPermitted(const RenderObject& renderer)
3678{
3679 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3680 for (auto* ancestor = renderer.parent(); ancestor; ancestor = ancestor->parent()) {
3681 // Get the first non-shadow HTMLElement and see if it's an input.
3682 if (is<HTMLElement>(ancestor->element()) && !ancestor->element()->isInShadowTree()) {
3683 auto& element = downcast<HTMLElement>(*ancestor->element());
3684 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
3685 }
3686 }
3687 return true;
3688}
3689
3690int RenderBlockFlow::lineCountForTextAutosizing()
3691{
3692 if (style().visibility() != Visibility::Visible)
3693 return 0;
3694 if (childrenInline())
3695 return lineCount();
3696 // Only descend into list items.
3697 int count = 0;
3698 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3699 count += listItem.lineCount();
3700 return count;
3701}
3702
3703static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject& renderer)
3704{
3705 if (!renderer.isRenderBlock())
3706 return true;
3707 if (renderer.isListItem())
3708 return renderer.style().height().type() != Fixed;
3709 return false;
3710}
3711
3712// For now, we auto size single lines of text the same as multiple lines.
3713// We've been experimenting with low values for single lines of text.
3714static inline float oneLineTextMultiplier(RenderObject& renderer, float specifiedSize)
3715{
3716 const float coefficient = renderer.settings().oneLineTextMultiplierCoefficient();
3717 return std::max((1.0f / log10f(specifiedSize) * coefficient), 1.0f);
3718}
3719
3720static inline float textMultiplier(RenderObject& renderer, float specifiedSize)
3721{
3722 const float coefficient = renderer.settings().multiLineTextMultiplierCoefficient();
3723 return std::max((1.0f / log10f(specifiedSize) * coefficient), 1.0f);
3724}
3725
3726static inline float idempotentTextSize(float specifiedSize, float pageScale)
3727{
3728 // This describes a piecewise curve when the page scale is 2/3.
3729 FloatPoint points[] = { {0.0f, 0.0f}, {6.0f, 12.0f}, {12.0f, 18.0f} };
3730
3731 // When the page scale is 1, the curve should be the identity.
3732 // Linearly interpolate between the curve above and identity based on the page scale.
3733 // Beware that depending on the specific values picked in the curve, this interpolation might change the shape of the curve for very small pageScales.
3734 pageScale = std::min(std::max(pageScale, 0.5f), 1.0f);
3735 auto scalePoint = [&](FloatPoint point) {
3736 float fraction = 3.0f - 3.0f * pageScale;
3737 point.setY(point.x() + (point.y() - point.x()) * fraction);
3738 return point;
3739 };
3740
3741 if (specifiedSize <= 0)
3742 return 0;
3743
3744 float result = scalePoint(points[WTF_ARRAY_LENGTH(points) - 1]).y();
3745 for (size_t i = 1; i < WTF_ARRAY_LENGTH(points); ++i) {
3746 if (points[i].x() < specifiedSize)
3747 continue;
3748 auto leftPoint = scalePoint(points[i - 1]);
3749 auto rightPoint = scalePoint(points[i]);
3750 float fraction = (specifiedSize - leftPoint.x()) / (rightPoint.x() - leftPoint.x());
3751 result = leftPoint.y() + fraction * (rightPoint.y() - leftPoint.y());
3752 break;
3753 }
3754
3755 return std::max(result, specifiedSize);
3756}
3757
3758void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode)
3759{
3760 LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
3761
3762 // Don't do any work if the block is smaller than the visible area.
3763 if (!idempotentMode && visibleWidth >= width())
3764 return;
3765
3766 unsigned lineCount;
3767 if (m_lineCountForTextAutosizing == NOT_SET) {
3768 int count = lineCountForTextAutosizing();
3769 if (!count)
3770 lineCount = NO_LINE;
3771 else if (count == 1)
3772 lineCount = ONE_LINE;
3773 else
3774 lineCount = MULTI_LINE;
3775 } else
3776 lineCount = m_lineCountForTextAutosizing;
3777
3778 ASSERT(lineCount != NOT_SET);
3779 if (lineCount == NO_LINE)
3780 return;
3781
3782 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3783 float scale = visibleWidth / actualWidth;
3784 float minFontSize = roundf(size / scale);
3785
3786 for (auto* descendant = RenderObjectTraversal::firstChild(*this); descendant; ) {
3787 if (!isNonBlocksOrNonFixedHeightListItems(*descendant)) {
3788 descendant = RenderObjectTraversal::nextSkippingChildren(*descendant, this);
3789 continue;
3790 }
3791 if (!isVisibleRenderText(*descendant) || !resizeTextPermitted(*descendant)) {
3792 descendant = RenderObjectTraversal::next(*descendant, this);
3793 continue;
3794 }
3795
3796 auto& text = downcast<RenderText>(*descendant);
3797 auto& oldStyle = text.style();
3798 auto& fontDescription = oldStyle.fontDescription();
3799 float specifiedSize = fontDescription.specifiedSize();
3800 float scaledSize = roundf(specifiedSize * scale);
3801 if (idempotentMode || (scaledSize > 0 && scaledSize < minFontSize)) {
3802 // Record the width of the block and the line count the first time we resize text and use it from then on for text resizing.
3803 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3804 if (m_lineCountForTextAutosizing == NOT_SET)
3805 m_lineCountForTextAutosizing = lineCount;
3806 if (m_widthForTextAutosizing == -1)
3807 m_widthForTextAutosizing = actualWidth;
3808
3809 float candidateNewSize;
3810 if (idempotentMode) {
3811 float lineTextSize = idempotentTextSize(specifiedSize, pageScale);
3812 candidateNewSize = roundf(lineTextSize);
3813 } else {
3814 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
3815 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
3816 }
3817
3818 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3819 document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
3820 }
3821
3822 descendant = RenderObjectTraversal::nextSkippingChildren(text, this);
3823 }
3824}
3825
3826#endif // ENABLE(TEXT_AUTOSIZING)
3827
3828void RenderBlockFlow::layoutExcludedChildren(bool relayoutChildren)
3829{
3830 RenderBlock::layoutExcludedChildren(relayoutChildren);
3831
3832 auto* fragmentedFlow = multiColumnFlow();
3833 if (!fragmentedFlow)
3834 return;
3835
3836 fragmentedFlow->setIsExcludedFromNormalLayout(true);
3837
3838 setLogicalTopForChild(*fragmentedFlow, borderAndPaddingBefore());
3839
3840 if (relayoutChildren)
3841 fragmentedFlow->setChildNeedsLayout(MarkOnlyThis);
3842
3843 if (fragmentedFlow->needsLayout()) {
3844 for (RenderMultiColumnSet* columnSet = fragmentedFlow->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3845 columnSet->prepareForLayout(!fragmentedFlow->inBalancingPass());
3846
3847 fragmentedFlow->invalidateFragments(MarkOnlyThis);
3848 fragmentedFlow->setNeedsHeightsRecalculation(true);
3849 fragmentedFlow->layout();
3850 } else {
3851 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3852 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3853 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3854 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3855 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3856 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3857 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3858 // runs get deleted right after every pass.
3859 fragmentedFlow->setNeedsHeightsRecalculation(false);
3860 }
3861 determineLogicalLeftPositionForChild(*fragmentedFlow);
3862}
3863
3864void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
3865{
3866 // If we don't use columns or flow threads, then bail.
3867 if (!isRenderFragmentedFlow() && !multiColumnFlow())
3868 return;
3869
3870 // We don't actually update any of the variables. We just subclassed to adjust our column height.
3871 if (RenderMultiColumnFlow* fragmentedFlow = multiColumnFlow()) {
3872 LayoutUnit newColumnHeight;
3873 if (hasDefiniteLogicalHeight() || view().frameView().pagination().mode != Pagination::Unpaginated) {
3874 auto computedValues = computeLogicalHeight(0_lu, logicalTop());
3875 newColumnHeight = std::max<LayoutUnit>(computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(), 0);
3876 if (fragmentedFlow->columnHeightAvailable() != newColumnHeight)
3877 relayoutChildren = true;
3878 }
3879 fragmentedFlow->setColumnHeightAvailable(newColumnHeight);
3880 } else if (is<RenderFragmentedFlow>(*this)) {
3881 RenderFragmentedFlow& fragmentedFlow = downcast<RenderFragmentedFlow>(*this);
3882
3883 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3884 // is known. The page logical height thing in RenderLayoutState is meaningless for flow
3885 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3886 // thread), but as long as it is used universally as a means to determine whether page
3887 // height is known or not, we need this. Page height is unknown when column balancing is
3888 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3889 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3890 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3891 // hack once the old multicol implementation is gone (see also RenderView::pushLayoutStateForPagination).
3892 pageLogicalHeight = fragmentedFlow.isPageLogicalHeightKnown() ? 1_lu : 0_lu;
3893
3894 pageLogicalHeightChanged = fragmentedFlow.pageLogicalSizeChanged();
3895 }
3896}
3897
3898bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3899{
3900 return willCreateColumns(desiredColumnCount);
3901}
3902
3903void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3904{
3905 ASSERT(!!multiColumnFlow() == requiresColumns(count));
3906 if (!multiColumnFlow())
3907 return;
3908 multiColumnFlow()->setColumnCountAndWidth(count, width);
3909 multiColumnFlow()->setProgressionIsInline(style().hasInlineColumnAxis());
3910 multiColumnFlow()->setProgressionIsReversed(style().columnProgression() == ColumnProgression::Reverse);
3911}
3912
3913void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
3914{
3915 if (!multiColumnFlow())
3916 return;
3917
3918 bool needsLayout = false;
3919 bool oldProgressionIsInline = multiColumnFlow()->progressionIsInline();
3920 bool newProgressionIsInline = style.hasInlineColumnAxis();
3921 if (oldProgressionIsInline != newProgressionIsInline) {
3922 multiColumnFlow()->setProgressionIsInline(newProgressionIsInline);
3923 needsLayout = true;
3924 }
3925
3926 bool oldProgressionIsReversed = multiColumnFlow()->progressionIsReversed();
3927 bool newProgressionIsReversed = style.columnProgression() == ColumnProgression::Reverse;
3928 if (oldProgressionIsReversed != newProgressionIsReversed) {
3929 multiColumnFlow()->setProgressionIsReversed(newProgressionIsReversed);
3930 needsLayout = true;
3931 }
3932
3933 if (needsLayout)
3934 setNeedsLayoutAndPrefWidthsRecalc();
3935}
3936
3937LayoutUnit RenderBlockFlow::computedColumnWidth() const
3938{
3939 if (multiColumnFlow())
3940 return multiColumnFlow()->computedColumnWidth();
3941 return contentLogicalWidth();
3942}
3943
3944unsigned RenderBlockFlow::computedColumnCount() const
3945{
3946 if (multiColumnFlow())
3947 return multiColumnFlow()->computedColumnCount();
3948
3949 return 1;
3950}
3951
3952bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3953{
3954 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3955 if (!multiColumnFlow() || style().columnProgression() == ColumnProgression::Normal)
3956 return hasTopOverflow;
3957
3958 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3959 hasTopOverflow = !hasTopOverflow;
3960
3961 return hasTopOverflow;
3962}
3963
3964bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3965{
3966 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3967 if (!multiColumnFlow() || style().columnProgression() == ColumnProgression::Normal)
3968 return hasLeftOverflow;
3969
3970 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3971 hasLeftOverflow = !hasLeftOverflow;
3972
3973 return hasLeftOverflow;
3974}
3975
3976struct InlineMinMaxIterator {
3977/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3978 inline min/max width calculations. Note the following about the way it walks:
3979 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3980 (2) We do not drill into the children of floats or replaced elements, since you can't break
3981 in the middle of such an element.
3982 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3983 distinct borders/margin/padding that contribute to the min/max width.
3984*/
3985 const RenderBlockFlow& parent;
3986 RenderObject* current;
3987 bool endOfInline;
3988 bool initial;
3989
3990 InlineMinMaxIterator(const RenderBlockFlow& p)
3991 : parent(p)
3992 , current(nullptr)
3993 , endOfInline(false)
3994 , initial(true)
3995 { }
3996
3997 RenderObject* next();
3998};
3999
4000RenderObject* InlineMinMaxIterator::next()
4001{
4002 RenderObject* result = nullptr;
4003 bool oldEndOfInline = endOfInline;
4004 endOfInline = false;
4005 do {
4006 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
4007 result = current->firstChildSlow();
4008 else if (initial) {
4009 result = parent.firstChild();
4010 initial = false;
4011 }
4012
4013 if (!result) {
4014 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4015 if (!oldEndOfInline && current && current->isRenderInline()) {
4016 result = current;
4017 endOfInline = true;
4018 break;
4019 }
4020
4021 while (current && current != &parent) {
4022 result = current->nextSibling();
4023 if (result)
4024 break;
4025 current = current->parent();
4026 if (current && current != &parent && current->isRenderInline()) {
4027 result = current;
4028 endOfInline = true;
4029 break;
4030 }
4031 }
4032 }
4033
4034 if (!result)
4035 break;
4036
4037 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4038 break;
4039
4040 current = result;
4041 result = nullptr;
4042 } while (current || current == &parent);
4043 // Update our position.
4044 current = result;
4045 return result;
4046}
4047
4048static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4049{
4050 if (cssUnit.type() != Auto)
4051 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4052 return 0;
4053}
4054
4055static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4056{
4057 const RenderStyle& childStyle = child.style();
4058 if (endOfInline) {
4059 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4060 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4061 child.borderEnd();
4062 }
4063 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4064 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4065 child.borderStart();
4066}
4067
4068static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4069{
4070 if (is<RenderText>(trailingSpaceChild)) {
4071 // Collapse away the trailing space at the end of a block.
4072 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
4073 const UChar space = ' ';
4074 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
4075 float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, renderText.style()));
4076 inlineMax -= spaceWidth + font.wordSpacing();
4077 if (inlineMin > inlineMax)
4078 inlineMin = inlineMax;
4079 }
4080}
4081
4082static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4083{
4084 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4085}
4086
4087void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4088{
4089 float inlineMax = 0;
4090 float inlineMin = 0;
4091
4092 const RenderStyle& styleToUse = style();
4093 RenderBlock* containingBlock = this->containingBlock();
4094 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : 0_lu;
4095
4096 // If we are at the start of a line, we want to ignore all white-space.
4097 // Also strip spaces if we previously had text that ended in a trailing space.
4098 bool stripFrontSpaces = true;
4099 RenderObject* trailingSpaceChild = nullptr;
4100
4101 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4102 // very specific cirucumstances (in order to match common WinIE renderings).
4103 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4104 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4105
4106 bool oldAutoWrap = styleToUse.autoWrap();
4107
4108 InlineMinMaxIterator childIterator(*this);
4109
4110 // Only gets added to the max preffered width once.
4111 bool addedTextIndent = false;
4112 // Signals the text indent was more negative than the min preferred width
4113 bool hasRemainingNegativeTextIndent = false;
4114
4115 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4116 RenderObject* prevFloat = 0;
4117 bool isPrevChildInlineFlow = false;
4118 bool shouldBreakLineAfterText = false;
4119 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation().contains(HangingPunctuation::First);
4120 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation().contains(HangingPunctuation::Last);
4121 RenderText* lastText = nullptr;
4122
4123 bool addedStartPunctuationHang = false;
4124
4125 while (RenderObject* child = childIterator.next()) {
4126 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
4127 child->style().autoWrap();
4128 if (!child->isBR()) {
4129 // Step One: determine whether or not we need to terminate our current line.
4130 // Each discrete chunk can become the new min-width, if it is the widest chunk
4131 // seen so far, and it can also become the max-width.
4132
4133 // Children fall into three categories:
4134 // (1) An inline flow object. These objects always have a min/max of 0,
4135 // and are included in the iteration solely so that their margins can
4136 // be added in.
4137 //
4138 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4139 // These objects can always be on a line by themselves, so in this situation
4140 // we need to break the current line, and then add in our own margins and min/max
4141 // width on its own line, and then terminate the line.
4142 //
4143 // (3) A text object. Text runs can have breakable characters at the start,
4144 // the middle or the end. They may also lose whitespace off the front if
4145 // we're already ignoring whitespace. In order to compute accurate min-width
4146 // information, we need three pieces of information.
4147 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4148 // starts with whitespace.
4149 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4150 // ends with whitespace.
4151 // (c) the min/max width of the string (trimmed for whitespace).
4152 //
4153 // If the text string starts with whitespace, then we need to terminate our current line
4154 // (unless we're already in a whitespace stripping mode.
4155 //
4156 // If the text string has a breakable character in the middle, but didn't start
4157 // with whitespace, then we add the width of the first non-breakable run and
4158 // then end the current line. We then need to use the intermediate min/max width
4159 // values (if any of them are larger than our current min/max). We then look at
4160 // the width of the last non-breakable run and use that to start a new line
4161 // (unless we end in whitespace).
4162 const RenderStyle& childStyle = child->style();
4163 float childMin = 0;
4164 float childMax = 0;
4165
4166 if (!child->isText()) {
4167 if (child->isLineBreakOpportunity()) {
4168 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4169 inlineMin = 0;
4170 continue;
4171 }
4172 // Case (1) and (2). Inline replaced and inline flow elements.
4173 if (is<RenderInline>(*child)) {
4174 // Add in padding/border/margin from the appropriate side of
4175 // the element.
4176 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
4177 childMin += bpm;
4178 childMax += bpm;
4179
4180 inlineMin += childMin;
4181 inlineMax += childMax;
4182
4183 child->setPreferredLogicalWidthsDirty(false);
4184 } else {
4185 // Inline replaced elts add in their margins to their min/max values.
4186 if (!child->isFloating())
4187 lastText = nullptr;
4188 LayoutUnit margins;
4189 Length startMargin = childStyle.marginStart();
4190 Length endMargin = childStyle.marginEnd();
4191 if (startMargin.isFixed())
4192 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4193 if (endMargin.isFixed())
4194 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4195 childMin += margins.ceilToFloat();
4196 childMax += margins.ceilToFloat();
4197 }
4198 }
4199
4200 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
4201 // Case (2). Inline replaced elements and floats.
4202 // Terminate the current line as far as minwidth is concerned.
4203 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4204 computeChildPreferredLogicalWidths(*child, childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth);
4205 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4206 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
4207
4208 bool clearPreviousFloat;
4209 if (child->isFloating()) {
4210 clearPreviousFloat = (prevFloat
4211 && ((prevFloat->style().floating() == Float::Left && (childStyle.clear() == Clear::Left || childStyle.clear() == Clear::Both))
4212 || (prevFloat->style().floating() == Float::Right && (childStyle.clear() == Clear::Right || childStyle.clear() == Clear::Both))));
4213 prevFloat = child;
4214 } else
4215 clearPreviousFloat = false;
4216
4217 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4218 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat)) {
4219 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4220 inlineMin = 0;
4221 }
4222
4223 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4224 if (clearPreviousFloat) {
4225 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4226 inlineMax = 0;
4227 }
4228
4229 // Add in text-indent. This is added in only once.
4230 if (!addedTextIndent && !child->isFloating()) {
4231 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4232 childMin += ceiledIndent;
4233 childMax += ceiledIndent;
4234
4235 if (childMin < 0)
4236 textIndent = LayoutUnit::fromFloatCeil(childMin);
4237 else
4238 addedTextIndent = true;
4239 }
4240
4241 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating())
4242 addedStartPunctuationHang = true;
4243
4244 // Add our width to the max.
4245 inlineMax += std::max<float>(0, childMax);
4246
4247 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText))) {
4248 if (child->isFloating())
4249 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4250 else
4251 inlineMin += childMin;
4252 } else {
4253 // Now check our line.
4254 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4255
4256 // Now start a new line.
4257 inlineMin = 0;
4258 }
4259
4260 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4261 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4262 inlineMin = 0;
4263 }
4264
4265 // We are no longer stripping whitespace at the start of a line.
4266 if (!child->isFloating()) {
4267 stripFrontSpaces = false;
4268 trailingSpaceChild = nullptr;
4269 lastText = nullptr;
4270 }
4271 } else if (is<RenderText>(*child)) {
4272 // Case (3). Text.
4273 RenderText& renderText = downcast<RenderText>(*child);
4274
4275 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4276 downcast<RenderCombineText>(renderText).combineTextIfNeeded();
4277
4278 // Determine if we have a breakable character. Pass in
4279 // whether or not we should ignore any spaces at the front
4280 // of the string. If those are going to be stripped out,
4281 // then they shouldn't be considered in the breakable char
4282 // check.
4283 bool strippingBeginWS = stripFrontSpaces;
4284 auto widths = renderText.trimmedPreferredWidths(inlineMax, stripFrontSpaces);
4285
4286 childMin = widths.min;
4287 childMax = widths.max;
4288
4289 // This text object will not be rendered, but it may still provide a breaking opportunity.
4290 if (!widths.hasBreak && !childMax) {
4291 if (autoWrap && (widths.beginWS || widths.endWS)) {
4292 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4293 inlineMin = 0;
4294 }
4295 continue;
4296 }
4297
4298 lastText = &renderText;
4299
4300 if (stripFrontSpaces)
4301 trailingSpaceChild = child;
4302 else
4303 trailingSpaceChild = 0;
4304
4305 // Add in text-indent. This is added in only once.
4306 float ti = 0;
4307 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4308 ti = textIndent.ceilToFloat();
4309 childMin += ti;
4310 widths.beginMin += ti;
4311
4312 // It the text indent negative and larger than the child minimum, we re-use the remainder
4313 // in future minimum calculations, but using the negative value again on the maximum
4314 // will lead to under-counting the max pref width.
4315 if (!addedTextIndent) {
4316 childMax += ti;
4317 widths.beginMax += ti;
4318 addedTextIndent = true;
4319 }
4320
4321 if (childMin < 0) {
4322 textIndent = childMin;
4323 hasRemainingNegativeTextIndent = true;
4324 }
4325 }
4326
4327 // See if we have a hanging punctuation situation at the start.
4328 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
4329 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4330 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
4331 childMin -= hangStartWidth;
4332 widths.beginMin -= hangStartWidth;
4333 childMax -= hangStartWidth;
4334 widths.beginMax -= hangStartWidth;
4335 addedStartPunctuationHang = true;
4336 }
4337
4338 // If we have no breakable characters at all,
4339 // then this is the easy case. We add ourselves to the current
4340 // min and max and continue.
4341 if (!widths.hasBreakableChar)
4342 inlineMin += childMin;
4343 else {
4344 // We have a breakable character. Now we need to know if
4345 // we start and end with whitespace.
4346 if (widths.beginWS) {
4347 // End the current line.
4348 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4349 } else {
4350 inlineMin += widths.beginMin;
4351 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4352 childMin -= ti;
4353 }
4354
4355 inlineMin = childMin;
4356
4357 if (widths.endWS) {
4358 // We end in whitespace, which means we can end our current line.
4359 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4360 inlineMin = 0;
4361 shouldBreakLineAfterText = false;
4362 } else {
4363 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4364 inlineMin = widths.endMin;
4365 shouldBreakLineAfterText = true;
4366 }
4367 }
4368
4369 if (widths.hasBreak) {
4370 inlineMax += widths.beginMax;
4371 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4372 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4373 inlineMax = widths.endMax;
4374 addedTextIndent = true;
4375 addedStartPunctuationHang = true;
4376 } else
4377 inlineMax += std::max<float>(0, childMax);
4378 }
4379
4380 // Ignore spaces after a list marker.
4381 if (child->isListMarker())
4382 stripFrontSpaces = true;
4383 } else {
4384 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4385 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4386 inlineMin = inlineMax = 0;
4387 stripFrontSpaces = true;
4388 trailingSpaceChild = 0;
4389 addedTextIndent = true;
4390 addedStartPunctuationHang = true;
4391 }
4392
4393 if (!child->isText() && child->isRenderInline())
4394 isPrevChildInlineFlow = true;
4395 else
4396 isPrevChildInlineFlow = false;
4397
4398 oldAutoWrap = autoWrap;
4399 }
4400
4401 if (styleToUse.collapseWhiteSpace())
4402 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4403
4404 if (canHangPunctuationAtEnd && lastText && lastText->text().length() > 0) {
4405 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->text().length() - 1;
4406 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4407 inlineMin -= endHangWidth;
4408 inlineMax -= endHangWidth;
4409 }
4410
4411 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4412 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4413}
4414
4415}
4416// namespace WebCore
4417