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.
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.
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.
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.
25 #include "RenderBlockFlow.h"
28 #include "FloatingObjects.h"
30 #include "FrameSelection.h"
31 #include "HTMLElement.h"
32 #include "HitTestLocation.h"
33 #include "InlineTextBox.h"
34 #include "LayoutRepainter.h"
35 #include "RenderCombineText.h"
36 #include "RenderFlowThread.h"
37 #include "RenderInline.h"
38 #include "RenderIterator.h"
39 #include "RenderLayer.h"
40 #include "RenderLineBreak.h"
41 #include "RenderListItem.h"
42 #include "RenderMarquee.h"
43 #include "RenderMultiColumnFlowThread.h"
44 #include "RenderMultiColumnSet.h"
45 #include "RenderNamedFlowFragment.h"
46 #include "RenderTableCell.h"
47 #include "RenderText.h"
48 #include "RenderView.h"
50 #include "SimpleLineLayoutFunctions.h"
51 #include "VerticalPositionCache.h"
52 #include "VisiblePosition.h"
53 #include <wtf/NeverDestroyed.h>
57 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
59 struct SameSizeAsMarginInfo {
60 uint32_t bitfields : 16;
61 LayoutUnit margins[2];
64 COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
65 COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
67 // Our MarginInfo state used when laying out block children.
68 RenderBlockFlow::MarginInfo::MarginInfo(RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
69 : m_atBeforeSideOfBlock(true)
70 , m_atAfterSideOfBlock(false)
71 , m_hasMarginBeforeQuirk(false)
72 , m_hasMarginAfterQuirk(false)
73 , m_determinedMarginBeforeQuirk(false)
74 , m_discardMargin(false)
76 const RenderStyle& blockStyle = block.style();
77 ASSERT(block.isRenderView() || block.parent());
78 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
80 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
82 // If any height other than auto is specified in CSS, then we don't collapse our bottom
83 // margins with our children's margins. To do otherwise would be to risk odd visual
84 // effects when the children overflow out of the parent block and yet still collapse
85 // with it. We also don't collapse if we have any bottom border/padding.
86 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
87 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
89 m_quirkContainer = block.isTableCell() || block.isBody();
91 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
93 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
94 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
97 RenderBlockFlow::RenderBlockFlow(Element& element, Ref<RenderStyle>&& style)
98 : RenderBlock(element, WTF::move(style), RenderBlockFlowFlag)
99 #if ENABLE(IOS_TEXT_AUTOSIZING)
100 , m_widthForTextAutosizing(-1)
101 , m_lineCountForTextAutosizing(NOT_SET)
104 setChildrenInline(true);
107 RenderBlockFlow::RenderBlockFlow(Document& document, Ref<RenderStyle>&& style)
108 : RenderBlock(document, WTF::move(style), RenderBlockFlowFlag)
109 #if ENABLE(IOS_TEXT_AUTOSIZING)
110 , m_widthForTextAutosizing(-1)
111 , m_lineCountForTextAutosizing(NOT_SET)
114 setChildrenInline(true);
117 RenderBlockFlow::~RenderBlockFlow()
121 void RenderBlockFlow::createMultiColumnFlowThread()
123 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
124 flowThread->initializeStyle();
125 setChildrenInline(false); // Do this to avoid wrapping inline children that are just going to move into the flow thread.
127 RenderBlock::addChild(flowThread);
128 flowThread->populate(); // Called after the flow thread is inserted so that we are reachable by the flow thread.
129 setMultiColumnFlowThread(flowThread);
132 void RenderBlockFlow::destroyMultiColumnFlowThread()
134 multiColumnFlowThread()->evacuateAndDestroy();
135 ASSERT(!multiColumnFlowThread());
138 void RenderBlockFlow::insertedIntoTree()
140 RenderBlock::insertedIntoTree();
141 createRenderNamedFlowFragmentIfNeeded();
144 void RenderBlockFlow::willBeDestroyed()
146 if (renderNamedFlowFragment())
147 setRenderNamedFlowFragment(0);
149 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
150 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
151 destroyLeftoverChildren();
153 if (!documentBeingDestroyed()) {
154 if (firstRootBox()) {
155 // We can't wait for RenderBox::destroy to clear the selection,
156 // because by then we will have nuked the line boxes.
157 if (isSelectionBorder())
158 frame().selection().setNeedsSelectionUpdate();
160 // If we are an anonymous block, then our line boxes might have children
161 // that will outlast this block. In the non-anonymous block case those
162 // children will be destroyed by the time we return from this function.
163 if (isAnonymousBlock()) {
164 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
165 while (auto childBox = box->firstChild())
166 childBox->removeFromParent();
170 parent()->dirtyLinesFromChangedChild(*this);
173 m_lineBoxes.deleteLineBoxes();
175 removeFromUpdateScrollInfoAfterLayoutTransaction();
177 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
178 RenderBox::willBeDestroyed();
181 RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
183 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
184 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
186 parentHasFloats = false;
187 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
188 if (is<RenderBlockFlow>(*sibling)) {
189 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
190 if (!siblingBlock.avoidsFloats())
191 return &siblingBlock;
193 if (sibling->isFloating())
194 parentHasFloats = true;
199 void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
201 if (m_floatingObjects)
202 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
204 HashSet<RenderBox*> oldIntrudingFloatSet;
205 if (!childrenInline() && m_floatingObjects) {
206 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
207 auto end = floatingObjectSet.end();
208 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
209 FloatingObject* floatingObject = it->get();
210 if (!floatingObject->isDescendant())
211 oldIntrudingFloatSet.add(&floatingObject->renderer());
215 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
216 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
217 if (m_floatingObjects)
218 m_floatingObjects->clear();
219 if (!oldIntrudingFloatSet.isEmpty())
220 markAllDescendantsWithFloatsForLayout();
224 RendererToFloatInfoMap floatMap;
226 if (m_floatingObjects) {
227 if (childrenInline())
228 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
230 m_floatingObjects->clear();
233 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
234 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
235 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
236 bool isBlockInsideInline = isAnonymousInlineBlock();
237 if (!is<RenderBlockFlow>(parent()) && !isBlockInsideInline)
240 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
241 // them (as opposed to floats they contain themselves) so check for those here too.
242 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(isBlockInsideInline ? *containingBlock() : *parent());
243 bool parentHasFloats = isBlockInsideInline ? parentBlock.containsFloats() : false;
244 RenderBlockFlow* previousBlock = nullptr;
245 if (!isBlockInsideInline)
246 previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
247 LayoutUnit logicalTopOffset = logicalTop();
248 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
249 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
251 LayoutUnit logicalLeftOffset = 0;
253 logicalTopOffset -= previousBlock->logicalTop();
255 previousBlock = &parentBlock;
256 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
259 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
260 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
261 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
263 if (childrenInline()) {
264 LayoutUnit changeLogicalTop = LayoutUnit::max();
265 LayoutUnit changeLogicalBottom = LayoutUnit::min();
266 if (m_floatingObjects) {
267 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
268 auto end = floatingObjectSet.end();
269 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
270 FloatingObject* floatingObject = it->get();
271 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject->renderer());
272 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
273 if (oldFloatingObject) {
274 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
275 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
276 changeLogicalTop = 0;
277 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
279 if (logicalBottom != oldLogicalBottom) {
280 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
281 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
283 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
284 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
285 if (logicalTop != oldLogicalTop) {
286 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
287 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
291 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
292 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
293 oldFloatingObject->originatingLine()->markDirty();
296 changeLogicalTop = 0;
297 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
302 auto end = floatMap.end();
303 for (auto it = floatMap.begin(); it != end; ++it) {
304 FloatingObject* floatingObject = it->value.get();
305 if (!floatingObject->isDescendant()) {
306 changeLogicalTop = 0;
307 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
311 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
312 } else if (!oldIntrudingFloatSet.isEmpty()) {
313 // If there are previously intruding floats that no longer intrude, then children with floats
314 // should also get layout because they might need their floating object lists cleared.
315 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
316 markAllDescendantsWithFloatsForLayout();
318 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
319 auto end = floatingObjectSet.end();
320 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
321 oldIntrudingFloatSet.remove(&(*it)->renderer());
322 if (!oldIntrudingFloatSet.isEmpty())
323 markAllDescendantsWithFloatsForLayout();
328 void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
330 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
331 // The min/max intrinsic widths calculated really tell how much space elements need when
332 // laid out inside the columns. In order to eventually end up with the desired column width,
333 // we need to convert them to values pertaining to the multicol container.
334 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
335 LayoutUnit columnWidth;
336 LayoutUnit colGap = columnGap();
337 LayoutUnit gapExtra = (columnCount - 1) * colGap;
338 if (style().hasAutoColumnWidth())
339 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
341 columnWidth = style().columnWidth();
342 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
344 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
345 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
346 // performing a layout pass, but this is not an appropriate time or place for layout. The
347 // good news is that if height is unconstrained and there are no explicit breaks, the
348 // resolved column-count really should be 1.
349 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
353 void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
355 if (childrenInline())
356 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
358 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
360 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
362 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
364 if (!style().autoWrap() && childrenInline()) {
365 // A horizontal marquee with inline children has no minimum width.
366 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
370 if (is<RenderTableCell>(*this)) {
371 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
372 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
373 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
376 int scrollbarWidth = instrinsicScrollbarLogicalWidth();
377 maxLogicalWidth += scrollbarWidth;
378 minLogicalWidth += scrollbarWidth;
381 bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
383 bool changed = recomputeLogicalWidth();
385 LayoutUnit oldColumnWidth = computedColumnWidth();
386 computeColumnCountAndWidth();
388 return changed || oldColumnWidth != computedColumnWidth();
391 LayoutUnit RenderBlockFlow::columnGap() const
393 if (style().hasNormalColumnGap())
394 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
395 return style().columnGap();
398 void RenderBlockFlow::computeColumnCountAndWidth()
400 // Calculate our column width and column count.
401 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
402 unsigned desiredColumnCount = 1;
403 LayoutUnit desiredColumnWidth = contentLogicalWidth();
405 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
406 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
407 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
411 LayoutUnit availWidth = desiredColumnWidth;
412 LayoutUnit colGap = columnGap();
413 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
414 int colCount = std::max<int>(1, style().columnCount());
416 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
417 desiredColumnCount = colCount;
418 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
419 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
420 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
421 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
423 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
424 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
426 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
429 void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
431 ASSERT(needsLayout());
433 if (!relayoutChildren && simplifiedLayout())
436 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
438 if (recomputeLogicalWidthAndColumnWidth())
439 relayoutChildren = true;
441 rebuildFloatingObjectSetFromIntrudingFloats();
443 LayoutUnit previousHeight = logicalHeight();
444 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
445 // for consistency with other render classes?
448 bool pageLogicalHeightChanged = false;
449 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
451 const RenderStyle& styleToUse = style();
452 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
454 preparePaginationBeforeBlockLayout(relayoutChildren);
455 if (!relayoutChildren)
456 relayoutChildren = namedFlowFragmentNeedsUpdate();
458 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
459 // our current maximal positive and negative margins. These values are used when we
460 // are collapsed with adjacent blocks, so for example, if you have block A and B
461 // collapsing together, then you'd take the maximal positive margin from both A and B
462 // and subtract it from the maximal negative margin from both A and B to get the
463 // true collapsed margin. This algorithm is recursive, so when we finish layout()
464 // our block knows its current maximal positive/negative values.
466 // Start out by setting our margin values to our current margins. Table cells have
467 // no margins, so we don't fill in the values for table cells.
468 bool isCell = isTableCell();
470 initMaxMarginValues();
472 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
473 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
474 setPaginationStrut(0);
477 LayoutUnit repaintLogicalTop = 0;
478 LayoutUnit repaintLogicalBottom = 0;
479 LayoutUnit maxFloatLogicalBottom = 0;
480 if (!firstChild() && !isAnonymousBlock())
481 setChildrenInline(true);
482 if (childrenInline())
483 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
485 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
487 // Expand our intrinsic height to encompass floats.
488 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
489 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
490 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
492 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
493 ASSERT(!shouldBreakAtLineToAvoidWidow());
497 // Calculate our new height.
498 LayoutUnit oldHeight = logicalHeight();
499 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
501 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
502 // This ensures the size information is correctly computed for the last auto-height region receiving content.
503 if (is<RenderFlowThread>(*this))
504 downcast<RenderFlowThread>(*this).applyBreakAfterContent(oldClientAfterEdge);
506 updateLogicalHeight();
507 LayoutUnit newHeight = logicalHeight();
508 if (oldHeight != newHeight) {
509 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
510 // One of our children's floats may have become an overhanging float for us. We need to look for it.
511 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
512 if (blockFlow.isFloatingOrOutOfFlowPositioned())
514 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
515 addOverhangingFloats(blockFlow, false);
520 bool heightChanged = (previousHeight != newHeight);
522 relayoutChildren = true;
524 layoutPositionedObjects(relayoutChildren || isRoot());
526 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
527 computeOverflow(oldClientAfterEdge);
531 fitBorderToLinesIfNeeded();
533 if (view().layoutState()->m_pageLogicalHeight)
534 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
536 updateLayerTransform();
538 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
539 // we overflow or not.
540 updateScrollInfoAfterLayout();
542 // FIXME: This repaint logic should be moved into a separate helper function!
543 // Repaint with our new bounds if they are different from our old bounds.
544 bool didFullRepaint = repainter.repaintAfterLayout();
545 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
546 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
547 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
548 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
549 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
550 if (hasOverflowClip()) {
551 // 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.
552 // 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.
553 // layoutInlineChildren should be patched to compute the entire repaint rect.
554 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
555 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
558 LayoutRect repaintRect;
559 if (isHorizontalWritingMode())
560 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
562 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
564 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
566 if (hasOverflowClip()) {
567 // Adjust repaint rect for scroll offset
568 repaintRect.move(-scrolledContentOffset());
570 // Don't allow this rect to spill out of our overflow box.
571 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
574 // Make sure the rect is still non-empty after intersecting for overflow above
575 if (!repaintRect.isEmpty()) {
576 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
578 repaintRectangle(reflectedRect(repaintRect));
585 void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
587 dirtyForLayoutFromPercentageHeightDescendants();
589 LayoutUnit beforeEdge = borderAndPaddingBefore();
590 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
592 setLogicalHeight(beforeEdge);
594 // Lay out our hypothetical grid line as though it occurs at the top of the block.
595 if (view().layoutState()->lineGrid() == this)
598 // The margin struct caches all our current margin collapsing state.
599 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
601 // Fieldsets need to find their legend and position it inside the border of the object.
602 // The legend then gets skipped during normal layout. The same is true for ruby text.
603 // It doesn't get included in the normal layout process but is instead skipped.
604 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
606 LayoutUnit previousFloatLogicalBottom = 0;
607 maxFloatLogicalBottom = 0;
609 RenderBox* next = firstChildBox();
612 RenderBox& child = *next;
613 next = child.nextSiblingBox();
615 if (childToExclude == &child)
616 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
618 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
620 if (child.isOutOfFlowPositioned()) {
621 child.containingBlock()->insertPositionedObject(child);
622 adjustPositionedBlock(child, marginInfo);
625 if (child.isFloating()) {
626 insertFloatingObject(child);
627 adjustFloatingBlock(marginInfo);
631 // Lay out the child.
632 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
635 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
636 // determining the correct collapsed bottom margin information.
637 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
640 void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
642 if (lineLayoutPath() == UndeterminedPath)
643 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
645 if (lineLayoutPath() == SimpleLinesPath) {
646 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
650 m_simpleLineLayout = nullptr;
651 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
654 void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
656 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
657 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
659 // The child is a normal flow object. Compute the margins we will use for collapsing now.
660 child.computeAndSetBlockDirectionMargins(this);
662 // Try to guess our correct logical top position. In most cases this guess will
663 // be correct. Only if we're wrong (when we compute the real logical top position)
664 // will we have to potentially relayout.
665 LayoutUnit estimateWithoutPagination;
666 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
668 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
669 LayoutRect oldRect = child.frameRect();
670 LayoutUnit oldLogicalTop = logicalTopForChild(child);
673 LayoutSize oldLayoutDelta = view().layoutDelta();
675 // Position the child as though it didn't collapse with the top.
676 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
677 estimateRegionRangeForBoxChild(child);
679 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
680 bool markDescendantsWithFloats = false;
681 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
682 markDescendantsWithFloats = true;
683 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
684 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
685 // very large elements. If it does the comparison with oldLogicalTop might yield a
686 // false negative as adding and removing margins, borders etc from a saturated number
687 // might yield incorrect results. If this is the case always mark for layout.
688 markDescendantsWithFloats = true;
689 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
690 // If an element might be affected by the presence of floats, then always mark it for
692 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
693 if (fb > logicalTopEstimate)
694 markDescendantsWithFloats = true;
697 if (childBlockFlow) {
698 if (markDescendantsWithFloats)
699 childBlockFlow->markAllDescendantsWithFloatsForLayout();
700 if (!child.isWritingModeRoot())
701 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
704 child.markForPaginationRelayoutIfNeeded();
706 bool childHadLayout = child.everHadLayout();
707 bool childNeededLayout = child.needsLayout();
708 if (childNeededLayout)
711 // Cache if we are at the top of the block right now.
712 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
714 // Now determine the correct ypos based off examination of collapsing margin
716 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
718 // Now check for clear.
719 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
721 bool paginated = view().layoutState()->isPaginated();
723 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
725 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
727 // Now we have a final top position. See if it really does end up being different from our estimate.
728 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
729 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
730 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
731 if (child.shrinkToAvoidFloats()) {
732 // The child's width depends on the line width. When the child shifts to clear an item, its width can
733 // change (because it has more available line width). So mark the item as dirty.
734 child.setChildNeedsLayout(MarkOnlyThis);
737 if (childBlockFlow) {
738 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
739 childBlockFlow->markAllDescendantsWithFloatsForLayout();
740 child.markForPaginationRelayoutIfNeeded();
744 if (updateRegionRangeForBoxChild(child))
745 child.setNeedsLayout(MarkOnlyThis);
747 // In case our guess was wrong, relayout the child.
748 child.layoutIfNeeded();
750 // We are no longer at the top of the block if we encounter a non-empty child.
751 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
752 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
753 marginInfo.setAtBeforeSideOfBlock(false);
755 // Now place the child in the correct left position
756 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
758 // Update our height now that the child has been placed in the correct position.
759 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
760 if (mustSeparateMarginAfterForChild(child)) {
761 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
762 marginInfo.clearMargin();
764 // If the child has overhanging floats that intrude into following siblings (or possibly out
765 // of this block), then the parent gets notified of the floats now.
766 if (childBlockFlow && childBlockFlow->containsFloats())
767 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
769 LayoutSize childOffset = child.location() - oldRect.location();
770 if (childOffset.width() || childOffset.height()) {
771 view().addLayoutDelta(childOffset);
773 // If the child moved, we have to repaint it as well as any floating/positioned
774 // descendants. An exception is if we need a layout. In this case, we know we're going to
775 // repaint ourselves (and the child) anyway.
776 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
777 child.repaintDuringLayoutIfMoved(oldRect);
780 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
782 child.repaintOverhangingFloats(true);
786 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
787 flowThread->flowThreadDescendantBoxLaidOut(&child);
788 // Check for an after page/column break.
789 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
790 if (newHeight != height())
791 setLogicalHeight(newHeight);
794 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
797 void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
799 bool isHorizontal = isHorizontalWritingMode();
800 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
802 LayoutUnit logicalTop = logicalHeight();
803 updateStaticInlinePositionForChild(child, logicalTop);
805 if (!marginInfo.canCollapseWithMarginBefore()) {
806 // Positioned blocks don't collapse margins, so add the margin provided by
807 // the container now. The child's own margin is added later when calculating its logical top.
808 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
809 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
810 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
813 RenderLayer* childLayer = child.layer();
814 if (childLayer->staticBlockPosition() != logicalTop) {
815 childLayer->setStaticBlockPosition(logicalTop);
816 if (hasStaticBlockPosition)
817 child.setChildNeedsLayout(MarkOnlyThis);
821 LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
823 ASSERT(isSelfCollapsingBlock());
824 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
825 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
826 return marginValuesForChild(*this).positiveMarginBefore();
830 void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
832 LayoutUnit startPosition = borderStart() + paddingStart();
833 if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
834 startPosition -= verticalScrollbarWidth();
835 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
837 // Add in our start margin.
838 LayoutUnit childMarginStart = marginStartForChild(child);
839 LayoutUnit newPosition = startPosition + childMarginStart;
841 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
842 // to shift over as necessary to dodge any floats that might get in the way.
843 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
844 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
846 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
849 void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
851 // The float should be positioned taking into account the bottom margin
852 // of the previous flow. We add that margin into the height, get the
853 // float positioned properly, and then subtract the margin out of the
854 // height again. In the case of self-collapsing blocks, we always just
855 // use the top margins, since the self-collapsing block collapsed its
856 // own bottom margin into its top margin.
858 // Note also that the previous flow may collapse its margin into the top of
859 // our block. If this is the case, then we do not add the margin in to our
860 // height when computing the position of the float. This condition can be tested
861 // for by simply calling canCollapseWithMarginBefore. See
862 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
863 // an example of this scenario.
864 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
865 setLogicalHeight(logicalHeight() + marginOffset);
867 setLogicalHeight(logicalHeight() - marginOffset);
870 void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop)
872 if (child.style().isOriginalDisplayInlineType())
873 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
875 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
878 void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
880 if (flowThreadContainingBlock()) {
881 // Shift the inline position to exclude the region offset.
882 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
884 child.layer()->setStaticInlinePosition(inlinePosition);
887 RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
889 LayoutUnit childBeforePositive = 0;
890 LayoutUnit childBeforeNegative = 0;
891 LayoutUnit childAfterPositive = 0;
892 LayoutUnit childAfterNegative = 0;
894 LayoutUnit beforeMargin = 0;
895 LayoutUnit afterMargin = 0;
897 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
899 // If the child has the same directionality as we do, then we can just return its
900 // margins in the same direction.
901 if (!child.isWritingModeRoot()) {
902 if (childRenderBlock) {
903 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
904 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
905 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
906 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
908 beforeMargin = child.marginBefore();
909 afterMargin = child.marginAfter();
911 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
912 // The child has a different directionality. If the child is parallel, then it's just
913 // flipped relative to us. We can use the margins for the opposite edges.
914 if (childRenderBlock) {
915 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
916 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
917 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
918 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
920 beforeMargin = child.marginAfter();
921 afterMargin = child.marginBefore();
924 // The child is perpendicular to us, which means its margins don't collapse but are on the
925 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
926 beforeMargin = marginBeforeForChild(child);
927 afterMargin = marginAfterForChild(child);
930 // Resolve uncollapsing margins into their positive/negative buckets.
932 if (beforeMargin > 0)
933 childBeforePositive = beforeMargin;
935 childBeforeNegative = -beforeMargin;
939 childAfterPositive = afterMargin;
941 childAfterNegative = -afterMargin;
944 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
947 LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
949 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
950 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
951 bool childIsSelfCollapsing = child.isSelfCollapsingBlock();
953 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
954 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
956 // Get the four margin values for the child and cache them.
957 const MarginValues childMargins = marginValuesForChild(child);
959 // Get our max pos and neg top margins.
960 LayoutUnit posTop = childMargins.positiveMarginBefore();
961 LayoutUnit negTop = childMargins.negativeMarginBefore();
963 // For self-collapsing blocks, collapse our bottom margins into our
964 // top to get new posTop and negTop values.
965 if (childIsSelfCollapsing) {
966 posTop = std::max(posTop, childMargins.positiveMarginAfter());
967 negTop = std::max(negTop, childMargins.negativeMarginAfter());
970 // See if the top margin is quirky. We only care if this child has
971 // margins that will collapse with us.
972 bool topQuirk = hasMarginBeforeQuirk(child);
974 if (marginInfo.canCollapseWithMarginBefore()) {
975 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
976 // This child is collapsing with the top of the
977 // block. If it has larger margin values, then we need to update
978 // our own maximal values.
979 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
980 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
982 // The minute any of the margins involved isn't a quirk, don't
983 // collapse it away, even if the margin is smaller (www.webreference.com
984 // has an example of this, a <dt> with 0.8em author-specified inside
985 // a <dl> inside a <td>.
986 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
987 setHasMarginBeforeQuirk(false);
988 marginInfo.setDeterminedMarginBeforeQuirk(true);
991 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
992 // We have no top margin and our top child has a quirky margin.
993 // We will pick up this quirky margin and pass it through.
994 // This deals with the <td><div><p> case.
995 // Don't do this for a block that split two inlines though. You do
996 // still apply margins in this case.
997 setHasMarginBeforeQuirk(true);
999 // The before margin of the container will also discard all the margins it is collapsing with.
1000 setMustDiscardMarginBefore();
1003 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1004 if (childDiscardMarginBefore) {
1005 marginInfo.setDiscardMargin(true);
1006 marginInfo.clearMargin();
1009 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1010 marginInfo.setHasMarginBeforeQuirk(topQuirk);
1012 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1013 LayoutUnit logicalTop = beforeCollapseLogicalTop;
1015 LayoutUnit clearanceForSelfCollapsingBlock;
1016 RenderObject* prev = child.previousSibling();
1017 // 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
1018 // 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
1019 // 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.
1020 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prev) && downcast<RenderBlockFlow>(*prev).isSelfCollapsingBlock()) {
1021 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prev).marginOffsetForSelfCollapsingBlock();
1022 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1025 if (childIsSelfCollapsing) {
1026 // 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.
1027 // Also, the child's top position equals the logical height of the container.
1028 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1029 // This child has no height. We need to compute our
1030 // position before we collapse the child's margins together,
1031 // so that we can get an accurate position for the zero-height block.
1032 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1033 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1034 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1036 // Now collapse the child's margins together, which means examining our
1037 // bottom margin values as well.
1038 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1039 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1041 if (!marginInfo.canCollapseWithMarginBefore())
1042 // We need to make sure that the position of the self-collapsing block
1043 // is correct, since it could have overflowing content
1044 // that needs to be positioned correctly (e.g., a block that
1045 // had a specified height of 0 but that actually had subcontent).
1046 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1049 if (mustSeparateMarginBeforeForChild(child)) {
1050 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1051 // If we are at the before side of the block and we collapse, ignore the computed margin
1052 // and just add the child margin to the container height. This will correctly position
1053 // the child inside the container.
1054 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
1055 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
1056 logicalTop = logicalHeight();
1057 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1058 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1059 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1060 // We're collapsing with a previous sibling's margins and not
1061 // with the top of the block.
1062 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
1063 logicalTop = logicalHeight();
1066 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1068 if (!marginInfo.discardMargin()) {
1069 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1070 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1072 marginInfo.clearMargin();
1074 if (marginInfo.margin())
1075 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
1078 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1079 // collapsed into the page edge.
1080 LayoutState* layoutState = view().layoutState();
1081 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1082 && hasNextPage(beforeCollapseLogicalTop)) {
1083 LayoutUnit oldLogicalTop = logicalTop;
1084 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
1085 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1088 if (is<RenderBlockFlow>(prev) && !prev->isFloatingOrOutOfFlowPositioned()) {
1089 // 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
1090 // any floats from the parent will now overhang.
1091 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prev);
1092 LayoutUnit oldLogicalHeight = logicalHeight();
1093 setLogicalHeight(logicalTop);
1094 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
1095 addOverhangingFloats(block, false);
1096 setLogicalHeight(oldLogicalHeight);
1098 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1099 // 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
1100 // floats in the parent that overhang |child|'s new logical top.
1101 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
1102 if (logicalTopIntrudesIntoFloat && containsFloats() && !child.avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1103 child.setNeedsLayout();
1109 LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
1111 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1112 if (!heightIncrease)
1115 if (child.isSelfCollapsingBlock()) {
1116 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1118 // For self-collapsing blocks that clear, they can still collapse their
1119 // margins with following siblings. Reset the current margins to represent
1120 // the self-collapsing block's margins only.
1121 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
1122 MarginValues childMargins = marginValuesForChild(child);
1123 if (!childDiscardMargin) {
1124 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1125 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1127 marginInfo.clearMargin();
1128 marginInfo.setDiscardMargin(childDiscardMargin);
1131 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1132 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1133 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1134 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1135 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
1136 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
1137 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1138 wouldCollapseMarginsWithParent = false;
1140 if (wouldCollapseMarginsWithParent)
1141 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1143 // 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
1144 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1145 // 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
1146 // margins can collapse at the correct vertical position.
1147 // 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
1148 // (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],
1149 // i.e., clearance = [height of float] - margin-top".
1150 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
1152 // Increase our height by the amount we had to clear.
1153 setLogicalHeight(logicalHeight() + heightIncrease);
1155 if (marginInfo.canCollapseWithMarginBefore()) {
1156 // We can no longer collapse with the top of the block since a clear
1157 // occurred. The empty blocks collapse into the cleared block.
1158 // FIXME: This isn't quite correct. Need clarification for what to do
1159 // if the height the cleared block is offset by is smaller than the
1160 // margins involved.
1161 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1162 marginInfo.setAtBeforeSideOfBlock(false);
1164 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
1165 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
1168 return yPos + heightIncrease;
1171 void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
1173 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1174 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1175 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
1176 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
1179 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1180 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
1181 if (child.style().marginBeforeCollapse() == MDISCARD) {
1182 positiveMarginBefore = 0;
1183 negativeMarginBefore = 0;
1184 discardMarginBefore = true;
1188 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
1189 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1190 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
1192 if (!is<RenderBlockFlow>(child))
1195 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
1196 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
1199 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
1200 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1203 RenderBox* grandchildBox = childBlock.firstChildBox();
1204 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
1205 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1209 // Give up if there is clearance on the box, since it probably won't collapse into us.
1210 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
1213 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1214 if (grandchildBox->needsLayout()) {
1215 grandchildBox->computeAndSetBlockDirectionMargins(this);
1216 if (is<RenderBlock>(*grandchildBox)) {
1217 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1218 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1219 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
1223 // Collapse the margin of the grandchild box with our own to produce an estimate.
1224 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1227 LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
1229 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1230 // relayout if there are intruding floats.
1231 LayoutUnit logicalTopEstimate = logicalHeight();
1232 if (!marginInfo.canCollapseWithMarginBefore()) {
1233 LayoutUnit positiveMarginBefore = 0;
1234 LayoutUnit negativeMarginBefore = 0;
1235 bool discardMarginBefore = false;
1236 if (child.selfNeedsLayout()) {
1237 // Try to do a basic estimation of how the collapse is going to go.
1238 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1240 // Use the cached collapsed margin values from a previous layout. Most of the time they
1242 MarginValues marginValues = marginValuesForChild(child);
1243 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1244 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
1245 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1248 // Collapse the result with our current margins.
1249 if (!discardMarginBefore)
1250 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
1253 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1255 LayoutState* layoutState = view().layoutState();
1256 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1257 && hasNextPage(logicalHeight()))
1258 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1260 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1262 estimateWithoutPagination = logicalTopEstimate;
1264 if (layoutState->isPaginated()) {
1265 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1266 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1268 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1269 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1271 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1272 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
1275 return logicalTopEstimate;
1278 void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1280 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1281 // 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.
1282 // Don't update the max margin values because we won't need them anyway.
1283 if (marginInfo.discardMargin()) {
1284 setMustDiscardMarginAfter();
1288 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1289 // with our children.
1290 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1292 if (!marginInfo.hasMarginAfterQuirk())
1293 setHasMarginAfterQuirk(false);
1295 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1296 // We have no bottom margin and our last child has a quirky margin.
1297 // We will pick up this quirky margin and pass it through.
1298 // This deals with the <td><div><p> case.
1299 setHasMarginAfterQuirk(true);
1303 void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1305 marginInfo.setAtAfterSideOfBlock(true);
1307 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1308 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1309 // to perform now is at the child's margin-top - so adjust our height to that position.
1310 RenderObject* lastBlock = lastChild();
1311 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1312 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
1314 // If we can't collapse with children then add in the bottom margin.
1315 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1316 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1317 setLogicalHeight(logicalHeight() + marginInfo.margin());
1319 // Now add in our bottom border/padding.
1320 setLogicalHeight(logicalHeight() + afterSide);
1322 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1323 // If this happens, ensure that the computed height is increased to the minimal height.
1324 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
1326 // Update our bottom collapsed margin info.
1327 setCollapsedBottomMargin(marginInfo);
1330 void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1332 if (!hasRareBlockFlowData()) {
1333 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
1335 materializeRareBlockFlowData();
1338 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1339 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
1342 void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1344 if (!hasRareBlockFlowData()) {
1345 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
1347 materializeRareBlockFlowData();
1350 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1351 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
1354 void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1356 if (style().marginBeforeCollapse() == MDISCARD) {
1361 if (!hasRareBlockFlowData()) {
1364 materializeRareBlockFlowData();
1367 rareBlockFlowData()->m_discardMarginBefore = value;
1370 void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1372 if (style().marginAfterCollapse() == MDISCARD) {
1377 if (!hasRareBlockFlowData()) {
1380 materializeRareBlockFlowData();
1383 rareBlockFlowData()->m_discardMarginAfter = value;
1386 bool RenderBlockFlow::mustDiscardMarginBefore() const
1388 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
1391 bool RenderBlockFlow::mustDiscardMarginAfter() const
1393 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
1396 bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
1398 ASSERT(!child.selfNeedsLayout());
1399 if (!child.isWritingModeRoot())
1400 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
1401 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1402 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
1404 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1405 // In case the boxes are perpendicular we assume the property is not specified.
1409 bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
1411 ASSERT(!child.selfNeedsLayout());
1412 if (!child.isWritingModeRoot())
1413 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
1414 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1415 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
1417 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1421 bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
1423 ASSERT(!child.selfNeedsLayout());
1424 const RenderStyle& childStyle = child.style();
1425 if (!child.isWritingModeRoot())
1426 return childStyle.marginBeforeCollapse() == MSEPARATE;
1427 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1428 return childStyle.marginAfterCollapse() == MSEPARATE;
1430 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1434 bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
1436 ASSERT(!child.selfNeedsLayout());
1437 const RenderStyle& childStyle = child.style();
1438 if (!child.isWritingModeRoot())
1439 return childStyle.marginAfterCollapse() == MSEPARATE;
1440 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
1441 return childStyle.marginBeforeCollapse() == MSEPARATE;
1443 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1447 static bool inNormalFlow(RenderBox& child)
1449 RenderBlock* curr = child.containingBlock();
1450 while (curr && curr != &child.view()) {
1451 if (curr->isRenderFlowThread())
1453 if (curr->isFloatingOrOutOfFlowPositioned())
1455 curr = curr->containingBlock();
1460 LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
1462 // FIXME: Add page break checking here when we support printing.
1463 RenderFlowThread* flowThread = flowThreadContainingBlock();
1464 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
1465 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
1466 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
1467 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
1468 bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
1469 || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
1470 || (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
1471 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1472 if (checkColumnBreaks) {
1473 if (isInsideMulticolFlowThread)
1474 checkRegionBreaks = true;
1476 if (checkRegionBreaks) {
1477 LayoutUnit offsetBreakAdjustment = 0;
1478 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
1479 return logicalOffset + offsetBreakAdjustment;
1481 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1483 return logicalOffset;
1486 LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
1488 // FIXME: Add page break checking here when we support printing.
1489 RenderFlowThread* flowThread = flowThreadContainingBlock();
1490 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
1491 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
1492 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
1493 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
1494 bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
1495 || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
1496 || (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
1497 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1498 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1500 // So our margin doesn't participate in the next collapsing steps.
1501 marginInfo.clearMargin();
1503 if (checkColumnBreaks) {
1504 if (isInsideMulticolFlowThread)
1505 checkRegionBreaks = true;
1507 if (checkRegionBreaks) {
1508 LayoutUnit offsetBreakAdjustment = 0;
1509 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
1510 return logicalOffset + marginOffset + offsetBreakAdjustment;
1512 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1514 return logicalOffset;
1517 LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
1519 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
1521 if (estimateWithoutPagination != logicalTopAfterClear) {
1522 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1524 setLogicalHeight(logicalTopAfterClear);
1525 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1527 if (child.shrinkToAvoidFloats()) {
1528 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1529 // change (because it has more available line width). So mark the item as dirty.
1530 child.setChildNeedsLayout(MarkOnlyThis);
1533 if (childRenderBlock) {
1534 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
1535 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
1536 child.markForPaginationRelayoutIfNeeded();
1539 // Our guess was wrong. Make the child lay itself out again.
1540 child.layoutIfNeeded();
1543 LayoutUnit oldTop = logicalTopAfterClear;
1545 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1546 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1548 if (pageLogicalHeightForOffset(result)) {
1549 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
1550 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
1551 if (spaceShortage > 0) {
1552 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1553 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1554 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1555 // This should be improved, though, because here we just pretend that the child is
1556 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1557 // where there's no child content, border or padding. In other words, we risk stretching more
1559 setPageBreak(result, spaceShortage);
1563 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1564 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1565 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1567 LayoutUnit paginationStrut = 0;
1568 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1569 if (unsplittableAdjustmentDelta)
1570 paginationStrut = unsplittableAdjustmentDelta;
1571 else if (childRenderBlock && childRenderBlock->paginationStrut())
1572 paginationStrut = childRenderBlock->paginationStrut();
1574 if (paginationStrut) {
1575 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1576 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1577 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1578 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1579 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1580 // and pushes to the next page anyway, so not too concerned about it.
1581 setPaginationStrut(result + paginationStrut);
1582 if (childRenderBlock)
1583 childRenderBlock->setPaginationStrut(0);
1585 result += paginationStrut;
1588 // Similar to how we apply clearance. Boost height() to be the place where we're going to position the child.
1589 setLogicalHeight(logicalHeight() + (result - oldTop));
1591 // Return the final adjusted logical top.
1595 static inline LayoutUnit calculateMinimumPageHeight(RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
1597 // We may require a certain minimum number of lines per page in order to satisfy
1598 // orphans and widows, and that may affect the minimum page height.
1599 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
1600 if (lineCount > 1) {
1601 RootInlineBox* line = &lastLine;
1602 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1603 line = line->prevRootBox();
1605 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1606 // adjustLinePositionForPagination() for more details.
1607 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
1608 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
1610 return lineBottom - lineTop;
1613 static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1615 const auto& renderer = lineBox.renderer();
1617 if (!renderer.document().settings())
1620 if (!renderer.document().settings()->appleMailPaginationQuirkEnabled())
1623 if (renderer.element() && renderer.element()->idForStyleResolution() == AtomicString("messageContentContainer", AtomicString::ConstructFromLiteral))
1629 void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
1631 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1632 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1633 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1634 // of the first column.
1636 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1637 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1638 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1639 // for overflow to occur), and then cache visible overflow for each column rect.
1641 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1642 // content that paints in a previous column (and content that paints in the following column).
1644 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1645 // at least make positive leading work in typical cases.
1647 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1648 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1649 // line and all following lines.
1650 overflowsRegion = false;
1651 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
1652 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1653 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
1654 LayoutUnit lineHeight = logicalBottom - logicalOffset;
1655 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
1656 logicalOffset += delta;
1657 lineBox->setPaginationStrut(0);
1658 lineBox->setIsFirstAfterPageBreak(false);
1659 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1660 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1661 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1662 // still going to add a strut, so that the visible overflow fits on a single page.
1663 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
1664 // 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.
1665 // 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.
1669 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1670 // 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
1671 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1672 // 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
1674 // 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
1675 // this will be a real-world issue. For now we don't try to deal with this problem.
1676 logicalOffset = intMaxForLayoutUnit;
1677 logicalBottom = intMinForLayoutUnit;
1678 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1679 lineHeight = logicalBottom - logicalOffset;
1680 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1681 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1682 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1685 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1686 overflowsRegion = (lineHeight > remainingLogicalHeight);
1688 int lineIndex = lineCount(lineBox);
1689 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
1690 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
1691 clearShouldBreakAtLineToAvoidWidow();
1692 setDidBreakAtLineToAvoidWidow();
1694 // If we have a non-uniform page height, then we have to shift further possibly.
1695 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1697 if (lineHeight > pageLogicalHeight) {
1698 // Split the top margin in order to avoid splitting the visible part of the line.
1699 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
1701 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1702 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
1703 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
1704 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1705 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
1706 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
1707 && !isOutOfFlowPositioned() && !isTableCell()) {
1708 auto firstRootBox = this->firstRootBox();
1709 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1710 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
1711 if (needsAppleMailPaginationQuirk(*lineBox))
1713 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1715 delta += remainingLogicalHeight;
1716 lineBox->setPaginationStrut(remainingLogicalHeight);
1717 lineBox->setIsFirstAfterPageBreak(true);
1719 } else if (remainingLogicalHeight == pageLogicalHeight) {
1720 // We're at the very top of a page or column.
1721 if (lineBox != firstRootBox())
1722 lineBox->setIsFirstAfterPageBreak(true);
1723 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1724 setPageBreak(logicalOffset, lineHeight);
1728 void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1730 ASSERT(lineToBreak >= 0);
1731 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1732 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
1735 void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1737 ASSERT(!shouldBreakAtLineToAvoidWidow());
1738 if (!hasRareBlockFlowData())
1741 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
1744 void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1746 if (!hasRareBlockFlowData())
1749 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
1752 void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1754 ASSERT(shouldBreakAtLineToAvoidWidow());
1755 if (!hasRareBlockFlowData())
1758 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
1761 bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1763 if (!shouldBreakAtLineToAvoidWidow())
1767 setEverHadLayout(true);
1772 bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1774 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1776 RenderFlowThread* flowThread = flowThreadContainingBlock();
1778 return true; // Printing and multi-column both make new pages to accommodate content.
1780 // See if we're in the last region.
1781 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
1782 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
1786 if (region->isLastRegion())
1787 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
1788 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
1790 RenderRegion* startRegion = nullptr;
1791 RenderRegion* endRegion = nullptr;
1792 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
1793 return (endRegion && region != endRegion);
1796 LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1798 if (!childBoxIsUnsplittableForFragmentation(child))
1799 return logicalOffset;
1801 RenderFlowThread* flowThread = flowThreadContainingBlock();
1802 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1803 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1804 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1805 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1806 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1807 || !hasNextPage(logicalOffset))
1808 return logicalOffset;
1809 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1810 if (remainingLogicalHeight < childLogicalHeight) {
1811 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1812 return logicalOffset;
1813 return logicalOffset + remainingLogicalHeight;
1815 return logicalOffset;
1818 bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1820 bool checkRegion = false;
1821 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1822 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1823 if (minimumLogicalHeight <= pageLogicalHeight)
1825 if (!hasNextPage(logicalOffset + adjustment))
1827 adjustment += pageLogicalHeight;
1830 return !checkRegion;
1833 void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1835 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1836 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1839 void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1841 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1842 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
1845 LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1847 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1848 if (!pageLogicalHeight)
1849 return logicalOffset;
1851 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1852 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1853 if (pageBoundaryRule == ExcludePageBoundary)
1854 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1855 return logicalOffset + remainingLogicalHeight;
1858 LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1860 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1861 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1862 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1863 if (!pageLogicalHeight)
1866 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1867 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1869 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1870 RenderFlowThread* flowThread = flowThreadContainingBlock();
1872 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
1873 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
1876 LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1878 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1879 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1880 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1881 if (!pageLogicalHeight)
1884 // Now check for a flow thread.
1885 RenderFlowThread* flowThread = flowThreadContainingBlock();
1887 return pageLogicalHeight;
1888 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1891 LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1893 offset += offsetFromLogicalTopOfFirstPage();
1895 RenderFlowThread* flowThread = flowThreadContainingBlock();
1897 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1898 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1899 if (pageBoundaryRule == IncludePageBoundary) {
1900 // If includeBoundaryPoint is true the line exactly on the top edge of a
1901 // column will act as being part of the previous column.
1902 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1904 return remainingHeight;
1907 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1910 LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1912 // This method is required because regions do not fragment monolithic elements but instead
1913 // they let them overflow the region they flow in. This behaviour is different from the
1914 // multicol/printing implementations, which have not yet been updated to correctly handle
1915 // monolithic elements.
1916 // As a result, for the moment, this method will only be used for regions, the multicol and
1917 // printing implementations will stick to the existing behaviour until their fragmentation
1918 // implementation is updated to match the regions implementation.
1919 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1920 return logicalHeightForChild(child);
1922 // For unsplittable elements, this method will just return the height of the element that
1923 // fits into the current region, without the height of the part that overflows the region.
1924 // This is done for all regions, except the last one because in that case, the logical
1925 // height of the flow thread needs to also
1926 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1927 return logicalHeightForChild(child);
1929 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1930 // the entire unsplittable child because any following children will not be moved to the next page
1931 // so they will need to be laid out below the current unsplittable child.
1932 LayoutUnit childLogicalTop = logicalTopForChild(child);
1933 if (!hasNextPage(childLogicalTop))
1934 return logicalHeightForChild(child);
1936 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1937 return std::min(child.logicalHeight(), remainingLogicalHeight);
1940 void RenderBlockFlow::layoutLineGridBox()
1942 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
1949 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
1950 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1951 lineGridBox->setConstructed();
1952 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1953 VerticalPositionCache verticalPositionCache;
1954 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1956 setLineGridBox(WTF::move(lineGridBox));
1958 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1959 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1963 bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
1965 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
1968 void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1970 RenderBlock::styleDidChange(diff, oldStyle);
1972 // After our style changed, if we lose our ability to propagate floats into next sibling
1973 // blocks, then we need to find the top most parent containing that overhanging float and
1974 // then mark its descendants with floats for layout and clear all floats from its next
1975 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1976 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1977 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
1978 RenderBlockFlow* parentBlock = this;
1979 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1981 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
1982 if (ancestor.isRenderView())
1984 if (ancestor.hasOverhangingFloats()) {
1985 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
1986 RenderBox& renderer = (*it)->renderer();
1987 if (ancestor.hasOverhangingFloat(renderer)) {
1988 parentBlock = &ancestor;
1995 parentBlock->markAllDescendantsWithFloatsForLayout();
1996 parentBlock->markSiblingsWithFloatsForLayout();
1999 if (auto fragment = renderNamedFlowFragment())
2000 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
2002 if (diff >= StyleDifferenceRepaint) {
2003 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2004 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2005 invalidateLineLayoutPath();
2008 if (multiColumnFlowThread())
2009 updateStylesForColumnChildren();
2012 void RenderBlockFlow::updateStylesForColumnChildren()
2014 for (auto child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
2015 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
2018 void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
2020 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
2021 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2024 EPosition oldPosition = oldStyle->position();
2025 EPosition newPosition = newStyle.position();
2027 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2028 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2029 markAllDescendantsWithFloatsForLayout();
2033 RenderBlock::styleWillChange(diff, newStyle);
2036 void RenderBlockFlow::deleteLines()
2038 if (containsFloats())
2039 m_floatingObjects->clearLineBoxTreePointers();
2041 if (m_simpleLineLayout) {
2042 ASSERT(!m_lineBoxes.firstLineBox());
2043 m_simpleLineLayout = nullptr;
2045 m_lineBoxes.deleteLineBoxTree();
2047 RenderBlock::deleteLines();
2050 void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
2052 // When a portion of the render tree is being detached, anonymous blocks
2053 // will be combined as their children are deleted. In this process, the
2054 // anonymous block later in the tree is merged into the one preceeding it.
2055 // It can happen that the later block (this) contains floats that the
2056 // previous block (toBlockFlow) did not contain, and thus are not in the
2057 // floating objects list for toBlockFlow. This can result in toBlockFlow
2058 // containing floats that are not in it's floating objects list, but are in
2059 // the floating objects lists of siblings and parents. This can cause
2060 // problems when the float itself is deleted, since the deletion code
2061 // assumes that if a float is not in it's containing block's floating
2062 // objects list, it isn't in any floating objects list. In order to
2063 // preserve this condition (removing it has serious performance
2064 // implications), we need to copy the floating objects from the old block
2065 // (this) to the new block (toBlockFlow). The float's metrics will likely
2066 // all be wrong, but since toBlockFlow is already marked for layout, this
2067 // will get fixed before anything gets displayed.
2068 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2069 if (m_floatingObjects) {
2070 if (!toBlockFlow->m_floatingObjects)
2071 toBlockFlow->createFloatingObjects();
2073 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2074 auto end = fromFloatingObjectSet.end();
2076 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2077 FloatingObject* floatingObject = it->get();
2079 // Don't insert the object again if it's already in the list
2080 if (toBlockFlow->containsFloat(floatingObject->renderer()))
2083 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2088 void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
2090 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2091 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2092 moveFloatsTo(&toBlockFlow);
2095 void RenderBlockFlow::addOverflowFromFloats()
2097 if (!m_floatingObjects)
2100 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2101 auto end = floatingObjectSet.end();
2102 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2103 FloatingObject* r = it->get();
2104 if (r->isDescendant())
2105 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
2109 void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2111 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2113 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
2114 addOverflowFromFloats();
2117 void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2119 // Repaint any overhanging floats (if we know we're the one to paint them).
2120 // Otherwise, bail out.
2121 if (!hasOverhangingFloats())
2124 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2125 // in this block. Better yet would be to push extra state for the containers of other floats.
2126 LayoutStateDisabler layoutStateDisabler(&view());
2127 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2128 auto end = floatingObjectSet.end();
2129 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2130 FloatingObject* floatingObject = it->get();
2131 // Only repaint the object if it is overhanging, is not in its own layer, and
2132 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2133 // condition is replaced with being a descendant of us.
2134 if (logicalBottomForFloat(floatingObject) > logicalHeight()
2135 && !floatingObject->renderer().hasSelfPaintingLayer()
2136 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
2137 floatingObject->renderer().repaint();
2138 floatingObject->renderer().repaintOverhangingFloats(false);
2143 void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
2145 RenderBlock::paintColumnRules(paintInfo, point);
2147 if (!multiColumnFlowThread() || paintInfo.context->paintingDisabled())
2150 // Iterate over our children and paint the column rules as needed.
2151 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2152 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2153 columnSet.paintColumnRules(paintInfo, childPoint);
2157 void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2159 if (!m_floatingObjects)
2162 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2163 auto end = floatingObjectSet.end();
2164 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2165 FloatingObject* r = it->get();
2166 // Only paint the object if our m_shouldPaint flag is set.
2167 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
2168 PaintInfo currentPaintInfo(paintInfo);
2169 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2170 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
2171 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2172 r->renderer().paint(currentPaintInfo, childPoint);
2173 if (!preservePhase) {
2174 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2175 r->renderer().paint(currentPaintInfo, childPoint);
2176 currentPaintInfo.phase = PaintPhaseFloat;
2177 r->renderer().paint(currentPaintInfo, childPoint);
2178 currentPaintInfo.phase = PaintPhaseForeground;
2179 r->renderer().paint(currentPaintInfo, childPoint);
2180 currentPaintInfo.phase = PaintPhaseOutline;
2181 r->renderer().paint(currentPaintInfo, childPoint);
2187 void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
2189 if (m_floatingObjects) {
2190 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2191 auto end = floatingObjectSet.end();
2192 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2193 FloatingObject* floatingObject = it->get();
2194 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2195 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
2196 floatingObject->renderer().width(), floatingObject->renderer().height());
2197 rootBlock.flipForWritingMode(floatBox);
2198 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2199 paintInfo->context->clipOut(snappedIntRect(floatBox));
2204 void RenderBlockFlow::createFloatingObjects()
2206 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
2209 void RenderBlockFlow::removeFloatingObjects()
2211 if (!m_floatingObjects)
2214 markSiblingsWithFloatsForLayout();
2216 m_floatingObjects->clear();
2219 FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
2221 ASSERT(floatBox.isFloating());
2223 // Create the list of special objects if we don't aleady have one
2224 if (!m_floatingObjects)
2225 createFloatingObjects();
2227 // Don't insert the floatingObject again if it's already in the list
2228 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2229 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
2230 if (it != floatingObjectSet.end())
2234 // Create the special floatingObject entry & append it to the list
2236 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
2238 // Our location is irrelevant if we're unsplittable or no pagination is in effect. Just lay out the float.
2239 bool isChildRenderBlock = floatBox.isRenderBlock();
2240 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2241 floatBox.setChildNeedsLayout(MarkOnlyThis);
2243 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2244 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2245 // We are unsplittable if we're a block flow root.
2246 floatBox.layoutIfNeeded();
2247 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2250 floatBox.updateLogicalWidth();
2251 floatBox.computeAndSetBlockDirectionMargins(this);
2254 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
2256 return m_floatingObjects->add(WTF::move(floatingObject));
2259 void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
2261 if (m_floatingObjects) {
2262 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2263 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
2264 if (it != floatingObjectSet.end()) {
2265 FloatingObject* floatingObject = it->get();
2266 if (childrenInline()) {
2267 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2268 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
2270 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2271 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2272 logicalBottom = LayoutUnit::max();
2274 // Special-case zero- and less-than-zero-height floats: those don't touch
2275 // the line that they're on, but it still needs to be dirtied. This is
2276 // accomplished by pretending they have a height of 1.
2277 logicalBottom = std::max(logicalBottom, logicalTop + 1);
2279 if (floatingObject->originatingLine()) {
2280 floatingObject->originatingLine()->removeFloat(floatBox);
2281 if (!selfNeedsLayout()) {
2282 ASSERT(&floatingObject->originatingLine()->renderer() == this);
2283 floatingObject->originatingLine()->markDirty();
2285 #if !ASSERT_DISABLED
2286 floatingObject->setOriginatingLine(0);
2289 markLinesDirtyInBlockRange(0, logicalBottom);
2291 m_floatingObjects->remove(floatingObject);
2296 void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2298 if (!containsFloats())
2301 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2302 FloatingObject* curr = floatingObjectSet.last().get();
2303 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
2304 m_floatingObjects->remove(curr);
2305 if (floatingObjectSet.isEmpty())
2307 curr = floatingObjectSet.last().get();
2311 LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2313 LayoutUnit offset = fixedOffset;
2314 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2315 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2316 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2319 LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2321 LayoutUnit offset = fixedOffset;
2322 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2323 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2324 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2327 LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
2329 RenderBox& childBox = floatingObject->renderer();
2330 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
2331 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2333 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
2335 LayoutUnit floatLogicalLeft;
2337 bool insideFlowThread = flowThreadContainingBlock();
2338 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2340 if (isInitialLetter) {
2341 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2342 if (letterClearance > 0) {
2343 logicalTopOffset += letterClearance;
2344 setLogicalHeight(logicalHeight() + letterClearance);
2348 if (childBox.style().floating() == LeftFloat) {
2349 LayoutUnit heightRemainingLeft = 1;
2350 LayoutUnit heightRemainingRight = 1;
2351 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2352 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
2353 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
2354 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2355 if (insideFlowThread) {
2356 // Have to re-evaluate all of our offsets, since they may have changed.
2357 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2358 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
2359 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
2362 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
2364 LayoutUnit heightRemainingLeft = 1;
2365 LayoutUnit heightRemainingRight = 1;
2366 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2367 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
2368 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
2369 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2370 if (insideFlowThread) {
2371 // Have to re-evaluate all of our offsets, since they may have changed.
2372 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2373 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
2374 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
2377 // Use the original width of the float here, since the local variable
2378 // |floatLogicalWidth| was capped to the available line width. See
2379 // fast/block/float/clamped-right-float.html.
2380 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
2383 if (isInitialLetter) {
2384 const RenderStyle& style = firstLineStyle();
2385 const FontMetrics& fontMetrics = style.fontMetrics();
2386 if (fontMetrics.hasCapHeight()) {
2387 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2388 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2390 // Make an adjustment to align with the cap height of a theoretical block line.
2391 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2392 logicalTopOffset += adjustment;
2394 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2395 // positive for raised and negative for sunken).
2396 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2398 // 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.
2399 if (dropHeightDelta < 0) {
2400 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2401 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2404 // 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
2405 // empty lines beside the first letter.
2406 if (dropHeightDelta > 0)
2407 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2411 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2414 bool RenderBlockFlow::positionNewFloats()
2416 if (!m_floatingObjects)
2419 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2420 if (floatingObjectSet.isEmpty())
2423 // If all floats have already been positioned, then we have no work to do.
2424 if (floatingObjectSet.last()->isPlaced())
2427 // Move backwards through our floating object list until we find a float that has
2428 // already been positioned. Then we'll be able to move forward, positioning all of
2429 // the new floats that need it.
2430 auto it = floatingObjectSet.end();
2431 --it; // Go to last item.
2432 auto begin = floatingObjectSet.begin();
2433 FloatingObject* lastPlacedFloatingObject = 0;
2434 while (it != begin) {
2436 if ((*it)->isPlaced()) {
2437 lastPlacedFloatingObject = it->get();
2443 LayoutUnit logicalTop = logicalHeight();
2445 // The float cannot start above the top position of the last positioned float.
2446 if (lastPlacedFloatingObject)
2447 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
2449 auto end = floatingObjectSet.end();
2450 // Now walk through the set of unpositioned floats and place them.
2451 for (; it != end; ++it) {
2452 FloatingObject* floatingObject = it->get();
2453 // The containing block is responsible for positioning floats, so if we have floats in our
2454 // list that come from somewhere else, do not attempt to position them.
2455 if (floatingObject->renderer().containingBlock() != this)
2458 RenderBox& childBox = floatingObject->renderer();
2460 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
2462 LayoutRect oldRect = childBox.frameRect();
2464 if (childBox.style().clear() & CLEFT)
2465 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
2466 if (childBox.style().clear() & CRIGHT)
2467 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
2469 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2471 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
2473 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2474 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2476 estimateRegionRangeForBoxChild(childBox);
2478 childBox.markForPaginationRelayoutIfNeeded();
2479 childBox.layoutIfNeeded();
2481 LayoutState* layoutState = view().layoutState();
2482 bool isPaginated = layoutState->isPaginated();
2484 // If we are unsplittable and don't fit, then we need to move down.
2485 // We include our margins as part of the unsplittable area.
2486 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2488 // See if we have a pagination strut that is making us move down further.
2489 // Note that an unsplittable child can't also have a pagination strut, so this is
2490 // exclusive with the case above.
2491 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
2492 if (childBlock && childBlock->paginationStrut()) {
2493 newLogicalTop += childBlock->paginationStrut();
2494 childBlock->setPaginationStrut(0);
2497 if (newLogicalTop != floatLogicalLocation.y()) {
2498 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
2500 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
2501 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
2503 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2504 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2507 childBlock->setChildNeedsLayout(MarkOnlyThis);
2508 childBox.layoutIfNeeded();
2511 if (updateRegionRangeForBoxChild(childBox)) {
2512 childBox.setNeedsLayout(MarkOnlyThis);
2513 childBox.layoutIfNeeded();
2517 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
2519 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
2521 m_floatingObjects->addPlacedObject(floatingObject);
2523 #if ENABLE(CSS_SHAPES)
2524 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
2525 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
2527 // If the child moved, we have to repaint it.
2528 if (childBox.checkForRepaintDuringLayout())
2529 childBox.repaintDuringLayoutIfMoved(oldRect);
2534 void RenderBlockFlow::clearFloats(EClear clear)
2536 positionNewFloats();
2538 LayoutUnit newY = 0;
2541 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2544 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2547 newY = lowestFloatLogicalBottom();
2552 if (height() < newY)
2553 setLogicalHeight(newY);
2556 LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
2558 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2559 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
2564 LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
2566 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2567 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
2572 LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
2574 if (!m_floatingObjects)
2575 return logicalHeight;
2577 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2580 LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2582 if (!m_floatingObjects)
2583 return logicalHeight;
2585 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
2588 LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2590 if (!m_floatingObjects)
2592 LayoutUnit lowestFloatBottom = 0;
2593 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2594 auto end = floatingObjectSet.end();
2595 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2596 FloatingObject* floatingObject = it->get();
2597 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
2598 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2600 return lowestFloatBottom;
2603 LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2605 if (!m_floatingObjects)
2607 LayoutUnit lowestFloatBottom = 0;
2608 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2609 auto end = floatingObjectSet.end();
2610 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2611 FloatingObject* floatingObject = it->get();
2612 if (floatingObject->isPlaced() && floatingObject->renderer().style().styleType() == FIRST_LETTER && floatingObject->renderer().style().initialLetterDrop() > 0)
2613 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2615 return lowestFloatBottom;
2618 LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
2620 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
2621 if (!child.containsFloats() || child.createsNewFormattingContext())
2624 LayoutUnit childLogicalTop = child.logicalTop();
2625 LayoutUnit childLogicalLeft = child.logicalLeft();
2626 LayoutUnit lowestFloatLogicalBottom = 0;
2628 // Floats that will remain the child's responsibility to paint should factor into its
2630 auto childEnd = child.m_floatingObjects->set().end();
2631 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
2632 FloatingObject* floatingObject = childIt->get();
2633 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
2634 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
2635 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
2637 if (logicalBottom > logicalHeight()) {
2638 // If the object is not in the list, we add it now.
2639 if (!containsFloat(floatingObject->renderer())) {
2640 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2641 bool shouldPaint = false;
2643 // The nearest enclosing layer always paints the float (so that zindex and stacking
2644 // behaves properly). We always want to propagate the desire to paint the float as
2645 // far out as we can, to the outermost block that overlaps the float, stopping only
2646 // if we hit a self-painting layer boundary.
2647 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2648 floatingObject->setShouldPaint(false);
2651 // We create the floating object list lazily.
2652 if (!m_floatingObjects)
2653 createFloatingObjects();
2655 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2658 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
2659 && floatingObject->renderer().isDescendantOf(&child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
2660 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2661 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2663 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2665 floatingObject->setShouldPaint(true);
2668 // 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.
2669 if (floatingObject->isDescendant())
2670 child.addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
2673 return lowestFloatLogicalBottom;
2676 bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
2678 if (!m_floatingObjects || !parent())
2681 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2682 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
2683 if (it == floatingObjectSet.end())
2686 return logicalBottomForFloat(it->get()) > logicalHeight();
2689 void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
2691 ASSERT(!avoidsFloats());
2693 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2694 if (createsNewFormattingContext())
2697 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2698 if (!prev->m_floatingObjects)
2701 logicalLeftOffset += marginLogicalLeft();
2703 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2704 auto prevEnd = prevSet.end();
2705 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2706 FloatingObject* floatingObject = prevIt->get();
2707 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
2708 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2709 // We create the floating object list lazily.
2710 if (!m_floatingObjects)
2711 createFloatingObjects();
2713 // Applying the child's margin makes no sense in the case where the child was passed in.
2714 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2715 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2716 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2717 // will get applied twice.
2718 LayoutSize offset = isHorizontalWritingMode()
2719 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2720 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
2722 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2728 void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2730 if (!everHadLayout() && !containsFloats())
2733 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2734 setChildNeedsLayout(markParents);
2737 removeFloatingObject(*floatToRemove);
2739 // Iterate over our block children and mark them as needed.
2740 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2741 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2743 if (!is<RenderBlockFlow>(block)) {
2744 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2745 block.setChildNeedsLayout(markParents);
2748 auto& blockFlow = downcast<RenderBlockFlow>(block);
2749 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2750 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
2754 void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2756 if (!m_floatingObjects)
2759 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2760 auto end = floatingObjectSet.end();
2762 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
2763 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned() || downcast<RenderBlockFlow>(*next).avoidsFloats())
2766 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
2767 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2768 RenderBox& floatingBox = (*it)->renderer();
2769 if (floatToRemove && &floatingBox != floatToRemove)
2771 if (nextBlock.containsFloat(floatingBox))
2772 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
2777 LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2779 if (!style().isFlippedBlocksWritingMode())
2782 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2783 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2785 if (isHorizontalWritingMode())
2786 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2787 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2790 LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
2792 // There is no need to compute clearance if we have no floats.
2793 if (!containsFloats())
2796 // At least one float is present. We need to perform the clearance computation.
2797 bool clearSet = child.style().clear() != CNONE;
2798 LayoutUnit logicalBottom = 0;
2799 switch (child.style().clear()) {
2803 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2806 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2809 logicalBottom = lowestFloatLogicalBottom();
2813 // 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).
2814 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
2815 if (!result && child.avoidsFloats()) {
2816 LayoutUnit newLogicalTop = logicalTop;
2818 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2819 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2820 return newLogicalTop - logicalTop;
2822 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
2823 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
2824 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2826 // FIXME: None of this is right for perpendicular writing-mode children.
2827 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2828 LayoutUnit childOldMarginLeft = child.marginLeft();
2829 LayoutUnit childOldMarginRight = child.marginRight();
2830 LayoutUnit childOldLogicalTop = child.logicalTop();
2832 child.setLogicalTop(newLogicalTop);
2833 child.updateLogicalWidth();
2834 region = regionAtBlockOffset(logicalTopForChild(child));
2835 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
2836 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2838 child.setLogicalTop(childOldLogicalTop);
2839 child.setLogicalWidth(childOldLogicalWidth);
2840 child.setMarginLeft(childOldMarginLeft);
2841 child.setMarginRight(childOldMarginRight);
2843 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2844 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2845 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2846 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2847 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
2848 child.setChildNeedsLayout(MarkOnlyThis);
2849 return newLogicalTop - logicalTop;
2852 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
2853 ASSERT(newLogicalTop >= logicalTop);
2854 if (newLogicalTop < logicalTop)
2857 ASSERT_NOT_REACHED();
2862 bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2864 if (!m_floatingObjects)
2867 LayoutPoint adjustedLocation = accumulatedOffset;
2868 if (is<RenderView>(*this))
2869 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
2871 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2872 auto begin = floatingObjectSet.begin();
2873 for (auto it = floatingObjectSet.end(); it != begin;) {
2875 FloatingObject* floatingObject = it->get();
2876 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2877 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2878 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2879 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2880 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2881 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2890 bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2892 ASSERT(childrenInline());
2894 if (auto simpleLineLayout = this->simpleLineLayout())
2895 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2897 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2900 void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2902 if (style().visibility() != VISIBLE)
2905 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2906 // for either overflow or translations via relative positioning.
2907 if (childrenInline()) {
2908 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2910 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
2911 if (box->firstChild())
2912 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
2913 if (box->lastChild())
2914 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
2917 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2918 if (!obj->isFloatingOrOutOfFlowPositioned()) {
2919 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2920 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
2921 else if (obj->style().visibility() == VISIBLE) {
2922 // We are a replaced element or some kind of non-block-flow object.
2923 left = std::min(left, x + obj->x());
2924 right = std::max(right, x + obj->x() + obj->width());
2930 if (m_floatingObjects) {
2931 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2932 auto end = floatingObjectSet.end();
2933 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2934 FloatingObject* r = it->get();
2935 // Only examine the object if our m_shouldPaint flag is set.
2936 if (r->shouldPaint()) {
2937 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2938 LayoutUnit floatRight = floatLeft + r->renderer().width();
2939 left = std::min(left, floatLeft);
2940 right = std::max(right, floatRight);
2946 void RenderBlockFlow::fitBorderToLinesIfNeeded()
2948 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
2951 // Walk any normal flow lines to snugly fit.
2952 LayoutUnit left = LayoutUnit::max();
2953 LayoutUnit right = LayoutUnit::min();
2954 LayoutUnit oldWidth = contentWidth();
2955 adjustForBorderFit(0, left, right);
2957 // Clamp to our existing edges. We can never grow. We only shrink.
2958 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2959 LayoutUnit rightEdge = leftEdge + oldWidth;
2960 left = std::min(rightEdge, std::max(leftEdge, left));
2961 right = std::max(leftEdge, std::min(rightEdge, right));
2963 LayoutUnit newContentWidth = right - left;
2964 if (newContentWidth == oldWidth)
2967 setOverrideLogicalContentWidth(newContentWidth);
2969 clearOverrideLogicalContentWidth();
2972 void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2974 if (logicalTop >= logicalBottom)
2977 // Floats currently affect the choice whether to use simple line layout path.
2978 if (m_simpleLineLayout) {
2979 invalidateLineLayoutPath();
2983 RootInlineBox* lowestDirtyLine = lastRootBox();
2984 RootInlineBox* afterLowest = lowestDirtyLine;
2985 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2986 afterLowest = lowestDirtyLine;
2987 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2990 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2991 afterLowest->markDirty();
2992 afterLowest = afterLowest->prevRootBox();
2996 Optional<int> RenderBlockFlow::firstLineBaseline() const
2998 if (isWritingModeRoot() && !isRubyRun())
2999 return Optional<int>();
3001 if (!childrenInline())
3002 return RenderBlock::firstLineBaseline();
3005 return Optional<int>();
3007 if (auto simpleLineLayout = this->simpleLineLayout())
3008 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
3010 ASSERT(firstRootBox());
3011 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
3014 Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
3016 if (isWritingModeRoot() && !isRubyRun())
3017 return Optional<int>();
3019 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3020 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3022 if (!childrenInline()) {
3023 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3024 if (!inlineBlockBaseline)
3025 return inlineBlockBaseline;
3026 lastBaseline = inlineBlockBaseline.value();
3029 if (!hasLineIfEmpty())
3030 return Optional<int>();
3031 const auto& fontMetrics = firstLineStyle().fontMetrics();
3032 return Optional<int>(fontMetrics.ascent()
3033 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
3034 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
3037 if (auto simpleLineLayout = this->simpleLineLayout())
3038 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3040 bool isFirstLine = lastRootBox() == firstRootBox();
3041 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3042 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3045 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3046 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3047 // enough with the spec to not cause tons of breakages).
3048 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
3051 void RenderBlockFlow::setSelectionState(SelectionState state)
3053 if (state != SelectionNone)
3055 RenderBoxModelObject::setSelectionState(state);
3058 GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3059 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3061 ASSERT(!m_simpleLineLayout);
3065 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3068 if (containsStart) {
3069 // Update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this case.
3070 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3071 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3072 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3077 RootInlineBox* lastSelectedLine = 0;
3078 RootInlineBox* curr;
3079 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3081 // Now paint the gaps for the lines.
3082 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3083 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3084 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3086 if (!containsStart && !lastSelectedLine &&
3087 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
3088 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3090 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3091 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
3092 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3093 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3094 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3095 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3097 lastSelectedLine = curr;
3100 if (containsStart && !lastSelectedLine)
3101 // VisibleSelection must start just after our last line.
3102 lastSelectedLine = lastRootBox();
3104 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3105 // Update our lastY to be the bottom of the last selected line.
3106 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3107 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3108 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3113 void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3115 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
3118 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3119 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
3120 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
3121 flowFragment->initializeStyle();
3122 setRenderNamedFlowFragment(flowFragment);
3123 addChild(renderNamedFlowFragment());
3127 bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3129 // A block without floats or that expands to enclose them won't need a relayout
3130 // after a region range change. There is no overflow content needing relayout
3131 // in the region chain because the region range can only shrink after the estimation.
3132 if (!containsFloats() || createsNewFormattingContext())
3138 bool RenderBlockFlow::canHaveChildren() const
3140 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3143 bool RenderBlockFlow::canHaveGeneratedChildren() const
3145 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3148 bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3150 if (!isRenderNamedFlowFragmentCont