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, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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 "RenderBlock.h"
27 #include "AXObjectCache.h"
28 #include "ColumnInfo.h"
32 #include "FloatQuad.h"
34 #include "FrameSelection.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "HTMLInputElement.h"
38 #include "HTMLNames.h"
39 #include "HitTestLocation.h"
40 #include "HitTestResult.h"
41 #include "InlineIterator.h"
42 #include "InlineTextBox.h"
43 #include "LayoutRepainter.h"
44 #include "LogicalSelectionOffsetCaches.h"
45 #include "OverflowEvent.h"
47 #include "PaintInfo.h"
48 #include "RenderBoxRegionInfo.h"
49 #include "RenderCombineText.h"
50 #include "RenderDeprecatedFlexibleBox.h"
51 #include "RenderFlexibleBox.h"
52 #include "RenderInline.h"
53 #include "RenderLayer.h"
54 #include "RenderMarquee.h"
55 #include "RenderNamedFlowThread.h"
56 #include "RenderRegion.h"
57 #include "RenderTableCell.h"
58 #include "RenderTextFragment.h"
59 #include "RenderTheme.h"
60 #include "RenderView.h"
61 #include "SVGTextRunRenderingContext.h"
63 #include "ShadowRoot.h"
64 #include "TransformState.h"
65 #include <wtf/StackStats.h>
66 #include <wtf/TemporaryChange.h>
68 #if ENABLE(CSS_SHAPES)
69 #include "ShapeInsideInfo.h"
70 #include "ShapeOutsideInfo.h"
73 #if ENABLE(IOS_TEXT_AUTOSIZING)
74 #include "HTMLElement.h"
79 using namespace Unicode;
83 using namespace HTMLNames;
85 struct SameSizeAsRenderBlock : public RenderBox {
87 RenderLineBoxList lineBoxes;
91 COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small);
93 typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap;
94 static ColumnInfoMap* gColumnInfoMap = 0;
96 static TrackedDescendantsMap* gPositionedDescendantsMap = 0;
97 static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0;
99 static TrackedContainerMap* gPositionedContainerMap = 0;
100 static TrackedContainerMap* gPercentHeightContainerMap = 0;
102 typedef WTF::HashMap<RenderBlock*, OwnPtr<ListHashSet<RenderInline*> > > ContinuationOutlineTableMap;
104 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
105 static int gDelayUpdateScrollInfo = 0;
106 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
108 static bool gColumnFlowSplitEnabled = true;
110 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
112 // This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
113 // only works on RenderBlocks. If this change, this class should be shared with other RenderBoxes.
114 class OverflowEventDispatcher {
115 WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher);
117 OverflowEventDispatcher(const RenderBlock* block)
119 , m_hadHorizontalLayoutOverflow(false)
120 , m_hadVerticalLayoutOverflow(false)
122 m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document().hasListenerType(Document::OVERFLOWCHANGED_LISTENER);
123 if (m_shouldDispatchEvent) {
124 m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
125 m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
129 ~OverflowEventDispatcher()
131 if (!m_shouldDispatchEvent)
134 bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
135 bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
137 bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow;
138 bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow;
139 if (horizontalLayoutOverflowChanged || verticalLayoutOverflowChanged)
140 m_block->view().frameView().scheduleEvent(OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow), m_block->element());
144 const RenderBlock* m_block;
145 bool m_shouldDispatchEvent;
146 bool m_hadHorizontalLayoutOverflow;
147 bool m_hadVerticalLayoutOverflow;
150 // -------------------------------------------------------------------------------------------------------
152 RenderBlock::RenderBlock(Element* element, unsigned baseTypeFlags)
153 : RenderBox(element, baseTypeFlags | RenderBlockFlag)
155 , m_hasMarginBeforeQuirk(false)
156 , m_hasMarginAfterQuirk(false)
157 , m_beingDestroyed(false)
158 , m_hasMarkupTruncation(false)
159 , m_hasBorderOrPaddingLogicalWidthChanged(false)
160 #if ENABLE(IOS_TEXT_AUTOSIZING)
161 , m_widthForTextAutosizing(-1)
162 , m_lineCountForTextAutosizing(NOT_SET)
165 setChildrenInline(true);
168 static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
170 if (OwnPtr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) {
171 TrackedRendererListHashSet::iterator end = descendantSet->end();
172 for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
173 TrackedContainerMap::iterator it = containerMap->find(*descendant);
174 ASSERT(it != containerMap->end());
175 if (it == containerMap->end())
177 HashSet<RenderBlock*>* containerSet = it->value.get();
178 ASSERT(containerSet->contains(block));
179 containerSet->remove(block);
180 if (containerSet->isEmpty())
181 containerMap->remove(it);
186 RenderBlock::~RenderBlock()
189 gColumnInfoMap->take(this);
190 if (gPercentHeightDescendantsMap)
191 removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
192 if (gPositionedDescendantsMap)
193 removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
196 RenderBlock* RenderBlock::createAnonymous(Document& document)
198 RenderBlock* renderer = new (*document.renderArena()) RenderBlockFlow(0);
199 renderer->setDocumentForAnonymous(document);
203 void RenderBlock::willBeDestroyed()
205 // Mark as being destroyed to avoid trouble with merges in removeChild().
206 m_beingDestroyed = true;
208 if (!documentBeingDestroyed()) {
209 if (firstChild() && firstChild()->isRunIn())
210 moveRunInToOriginalPosition(firstChild());
213 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
214 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
215 destroyLeftoverChildren();
217 // Destroy our continuation before anything other than anonymous children.
218 // The reason we don't destroy it before anonymous children is that they may
219 // have continuations of their own that are anonymous children of our continuation.
220 RenderBoxModelObject* continuation = this->continuation();
222 continuation->destroy();
226 if (!documentBeingDestroyed()) {
227 if (firstLineBox()) {
228 // We can't wait for RenderBox::destroy to clear the selection,
229 // because by then we will have nuked the line boxes.
230 // FIXME: The FrameSelection should be responsible for this when it
231 // is notified of DOM mutations.
232 if (isSelectionBorder())
233 view().clearSelection();
235 // If we are an anonymous block, then our line boxes might have children
236 // that will outlast this block. In the non-anonymous block case those
237 // children will be destroyed by the time we return from this function.
238 if (isAnonymousBlock()) {
239 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
240 while (InlineBox* childBox = box->firstChild())
245 parent()->dirtyLinesFromChangedChild(this);
248 m_lineBoxes.deleteLineBoxes(renderArena());
250 if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
251 gDelayedUpdateScrollInfoSet->remove(this);
253 RenderBox::willBeDestroyed();
256 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
258 RenderStyle* oldStyle = style();
259 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
261 setReplaced(newStyle->isDisplayInlineType());
263 if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
264 if (newStyle->position() == StaticPosition)
265 // Clear our positioned objects list. Our absolutely positioned descendants will be
266 // inserted into our containing block's positioned objects list during layout.
267 removePositionedObjects(0, NewContainingBlock);
268 else if (oldStyle->position() == StaticPosition) {
269 // Remove our absolutely positioned descendants from their current containing block.
270 // They will be inserted into our positioned objects list during layout.
271 RenderObject* cb = parent();
272 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
273 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
274 cb = cb->containingBlock();
280 if (cb->isRenderBlock())
281 toRenderBlock(cb)->removePositionedObjects(this, NewContainingBlock);
284 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
285 markAllDescendantsWithFloatsForLayout();
288 RenderBox::styleWillChange(diff, newStyle);
291 static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
293 if (newStyle->isHorizontalWritingMode())
294 return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
295 || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
296 || oldStyle->paddingLeft() != newStyle->paddingLeft()
297 || oldStyle->paddingRight() != newStyle->paddingRight();
299 return oldStyle->borderTopWidth() != newStyle->borderTopWidth()
300 || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth()
301 || oldStyle->paddingTop() != newStyle->paddingTop()
302 || oldStyle->paddingBottom() != newStyle->paddingBottom();
305 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
307 RenderBox::styleDidChange(diff, oldStyle);
309 RenderStyle* newStyle = style();
311 #if ENABLE(CSS_SHAPES)
312 updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : 0);
315 if (!isAnonymousBlock()) {
316 // Ensure that all of our continuation blocks pick up the new style.
317 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
318 RenderBoxModelObject* nextCont = currCont->continuation();
319 currCont->setContinuation(0);
320 currCont->setStyle(newStyle);
321 currCont->setContinuation(nextCont);
325 propagateStyleToAnonymousChildren(PropagateToBlockChildrenOnly);
328 // After our style changed, if we lose our ability to propagate floats into next sibling
329 // blocks, then we need to find the top most parent containing that overhanging float and
330 // then mark its descendants with floats for layout and clear all floats from its next
331 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
332 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
333 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
334 RenderBlock* parentBlock = this;
335 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
336 auto end = floatingObjectSet.end();
338 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
339 if (curr->isRenderBlock()) {
340 RenderBlock* currBlock = toRenderBlock(curr);
342 if (currBlock->hasOverhangingFloats()) {
343 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
344 RenderBox& renderer = (*it)->renderer();
345 if (currBlock->hasOverhangingFloat(&renderer)) {
346 parentBlock = currBlock;
354 parentBlock->markAllDescendantsWithFloatsForLayout();
355 parentBlock->markSiblingsWithFloatsForLayout();
358 // It's possible for our border/padding to change, but for the overall logical width of the block to
359 // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true.
360 m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle);
363 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
365 if (beforeChild && beforeChild->parent() == this)
368 RenderBlock* curr = toRenderBlock(continuation());
369 RenderBlock* nextToLast = this;
370 RenderBlock* last = this;
372 if (beforeChild && beforeChild->parent() == curr) {
373 if (curr->firstChild() == beforeChild)
380 curr = toRenderBlock(curr->continuation());
383 if (!beforeChild && !last->firstChild())
388 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
390 RenderBlock* flow = continuationBefore(beforeChild);
391 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
392 RenderBoxModelObject* beforeChildParent = 0;
394 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
396 RenderBoxModelObject* cont = flow->continuation();
398 beforeChildParent = cont;
400 beforeChildParent = flow;
403 if (newChild->isFloatingOrOutOfFlowPositioned()) {
404 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
408 // A continuation always consists of two potential candidates: a block or an anonymous
409 // column span box holding column span children.
410 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
411 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
412 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
414 if (flow == beforeChildParent) {
415 flow->addChildIgnoringContinuation(newChild, beforeChild);
419 // The goal here is to match up if we can, so that we can coalesce and create the
420 // minimal # of continuations needed for the inline.
421 if (childIsNormal == bcpIsNormal) {
422 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
425 if (flowIsNormal == childIsNormal) {
426 flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
429 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
433 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
435 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
437 // The goal is to locate a suitable box in which to place our child.
438 RenderBlock* beforeChildParent = 0;
440 RenderObject* curr = beforeChild;
441 while (curr && curr->parent() != this)
442 curr = curr->parent();
443 beforeChildParent = toRenderBlock(curr);
444 ASSERT(beforeChildParent);
445 ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock());
447 beforeChildParent = toRenderBlock(lastChild());
449 // If the new child is floating or positioned it can just go in that block.
450 if (newChild->isFloatingOrOutOfFlowPositioned()) {
451 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
455 // See if the child can be placed in the box.
456 bool newChildHasColumnSpan = !newChild->isInline() && newChild->style()->columnSpan();
457 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
459 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
460 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
465 // Create a new block of the correct type.
466 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
467 insertChildInternal(newBox, nullptr, NotifyChildren);
468 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
472 RenderObject* immediateChild = beforeChild;
473 bool isPreviousBlockViable = true;
474 while (immediateChild->parent() != this) {
475 if (isPreviousBlockViable)
476 isPreviousBlockViable = !immediateChild->previousSibling();
477 immediateChild = immediateChild->parent();
479 if (isPreviousBlockViable && immediateChild->previousSibling()) {
480 toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
484 // Split our anonymous blocks.
485 RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild);
488 // Create a new anonymous box of the appropriate type.
489 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
490 insertChildInternal(newBox, newBeforeChild, NotifyChildren);
491 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
495 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
497 RenderBlock* firstChildIgnoringAnonymousWrappers = 0;
498 for (RenderObject* curr = this; curr; curr = curr->parent()) {
499 if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
500 || curr->isInlineBlockOrInlineTable())
503 // FIXME: Tables, RenderButtons, and RenderListItems all do special management
504 // of their children that breaks when the flow is split through them. Disabling
505 // multi-column for them to avoid this problem.
506 if (curr->isTable() || curr->isRenderButton() || curr->isListItem())
509 RenderBlock* currBlock = toRenderBlock(curr);
510 if (!currBlock->createsAnonymousWrapper())
511 firstChildIgnoringAnonymousWrappers = currBlock;
513 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
514 return firstChildIgnoringAnonymousWrappers;
516 if (currBlock->isAnonymousColumnSpanBlock())
522 RenderBlock* RenderBlock::clone() const
524 RenderBlock* cloneBlock;
525 if (isAnonymousBlock()) {
526 cloneBlock = createAnonymousBlock();
527 cloneBlock->setChildrenInline(childrenInline());
529 RenderObject* cloneRenderer = element()->createRenderer(renderArena(), *style());
530 cloneBlock = toRenderBlock(cloneRenderer);
531 cloneBlock->setStyle(style());
533 // This takes care of setting the right value of childrenInline in case
534 // generated content is added to cloneBlock and 'this' does not have
535 // generated content added yet.
536 cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
538 cloneBlock->setFlowThreadState(flowThreadState());
542 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
543 RenderBlock* middleBlock,
544 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
546 // Create a clone of this inline.
547 RenderBlock* cloneBlock = clone();
548 if (!isAnonymousBlock())
549 cloneBlock->setContinuation(oldCont);
551 if (!beforeChild && isAfterContent(lastChild()))
552 beforeChild = lastChild();
554 // If we are moving inline children from |this| to cloneBlock, then we need
555 // to clear our line box tree.
556 if (beforeChild && childrenInline())
559 // Now take all of the children from beforeChild to the end and remove
560 // them from |this| and place them in the clone.
561 moveChildrenTo(cloneBlock, beforeChild, 0, true);
563 // Hook |clone| up as the continuation of the middle block.
564 if (!cloneBlock->isAnonymousBlock())
565 middleBlock->setContinuation(cloneBlock);
567 // We have been reparented and are now under the fromBlock. We need
568 // to walk up our block parent chain until we hit the containing anonymous columns block.
569 // Once we hit the anonymous columns block we're done.
570 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
571 RenderBoxModelObject* currChild = this;
572 RenderObject* currChildNextSibling = currChild->nextSibling();
574 while (curr && curr != fromBlock) {
575 ASSERT_WITH_SECURITY_IMPLICATION(curr->isRenderBlock());
577 RenderBlock* blockCurr = toRenderBlock(curr);
579 // Create a new clone.
580 RenderBlock* cloneChild = cloneBlock;
581 cloneBlock = blockCurr->clone();
583 // Insert our child clone as the first child.
584 cloneBlock->addChildIgnoringContinuation(cloneChild, 0);
586 // Hook the clone up as a continuation of |curr|. Note we do encounter
587 // anonymous blocks possibly as we walk up the block chain. When we split an
588 // anonymous block, there's no need to do any continuation hookup, since we haven't
589 // actually split a real element.
590 if (!blockCurr->isAnonymousBlock()) {
591 oldCont = blockCurr->continuation();
592 blockCurr->setContinuation(cloneBlock);
593 cloneBlock->setContinuation(oldCont);
596 // Now we need to take all of the children starting from the first child
597 // *after* currChild and append them all to the clone.
598 blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
600 // Keep walking up the chain.
602 currChildNextSibling = currChild->nextSibling();
603 curr = toRenderBoxModelObject(curr->parent());
606 // Now we are at the columns block level. We need to put the clone into the toBlock.
607 toBlock->insertChildInternal(cloneBlock, nullptr, NotifyChildren);
609 // Now take all the children after currChild and remove them from the fromBlock
610 // and put them in the toBlock.
611 fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true);
614 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
615 RenderObject* newChild, RenderBoxModelObject* oldCont)
617 RenderBlock* pre = 0;
618 RenderBlock* block = containingColumnsBlock();
620 // Delete our line boxes before we do the inline split into continuations.
621 block->deleteLineBoxTree();
623 bool madeNewBeforeBlock = false;
624 if (block->isAnonymousColumnsBlock()) {
625 // We can reuse this block and make it the preBlock of the next continuation.
627 pre->removePositionedObjects(0);
628 pre->removeFloatingObjects();
629 block = toRenderBlock(block->parent());
631 // No anonymous block available for use. Make one.
632 pre = block->createAnonymousColumnsBlock();
633 pre->setChildrenInline(false);
634 madeNewBeforeBlock = true;
637 RenderBlock* post = block->createAnonymousColumnsBlock();
638 post->setChildrenInline(false);
640 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
641 if (madeNewBeforeBlock)
642 block->insertChildInternal(pre, boxFirst, NotifyChildren);
643 block->insertChildInternal(newBlockBox, boxFirst, NotifyChildren);
644 block->insertChildInternal(post, boxFirst, NotifyChildren);
645 block->setChildrenInline(false);
647 if (madeNewBeforeBlock)
648 block->moveChildrenTo(pre, boxFirst, 0, true);
650 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
652 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
653 // time in makeChildrenNonInline by just setting this explicitly up front.
654 newBlockBox->setChildrenInline(false);
656 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
657 // connected, thus allowing newChild access to a renderArena should it need
658 // to wrap itself in additional boxes (e.g., table construction).
659 newBlockBox->addChild(newChild);
661 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
662 // get deleted properly. Because objects moves from the pre block into the post block, we want to
663 // make new line boxes instead of leaving the old line boxes around.
664 pre->setNeedsLayoutAndPrefWidthsRecalc();
665 block->setNeedsLayoutAndPrefWidthsRecalc();
666 post->setNeedsLayoutAndPrefWidthsRecalc();
669 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
671 RenderBlock* pre = 0;
672 RenderBlock* post = 0;
673 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
674 // so that we don't have to patch all of the rest of the code later on.
676 // Delete the block's line boxes before we do the split.
677 block->deleteLineBoxTree();
679 if (beforeChild && beforeChild->parent() != this)
680 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
682 if (beforeChild != firstChild()) {
683 pre = block->createAnonymousColumnsBlock();
684 pre->setChildrenInline(block->childrenInline());
688 post = block->createAnonymousColumnsBlock();
689 post->setChildrenInline(block->childrenInline());
692 RenderObject* boxFirst = block->firstChild();
694 block->insertChildInternal(pre, boxFirst, NotifyChildren);
695 block->insertChildInternal(newBlockBox, boxFirst, NotifyChildren);
697 block->insertChildInternal(post, boxFirst, NotifyChildren);
698 block->setChildrenInline(false);
700 // The pre/post blocks always have layers, so we know to always do a full insert/remove (so we pass true as the last argument).
701 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
702 block->moveChildrenTo(post, beforeChild, 0, true);
704 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
705 // time in makeChildrenNonInline by just setting this explicitly up front.
706 newBlockBox->setChildrenInline(false);
708 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
709 // connected, thus allowing newChild access to a renderArena should it need
710 // to wrap itself in additional boxes (e.g., table construction).
711 newBlockBox->addChild(newChild);
713 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
714 // get deleted properly. Because objects moved from the pre block into the post block, we want to
715 // make new line boxes instead of leaving the old line boxes around.
717 pre->setNeedsLayoutAndPrefWidthsRecalc();
718 block->setNeedsLayoutAndPrefWidthsRecalc();
720 post->setNeedsLayoutAndPrefWidthsRecalc();
723 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
725 // FIXME: This function is the gateway for the addition of column-span support. It will
726 // be added to in three stages:
727 // (1) Immediate children of a multi-column block can span.
728 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
729 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
730 // cross the streams and have to cope with both types of continuations mixed together).
731 // This function currently supports (1) and (2).
732 RenderBlock* columnsBlockAncestor = 0;
733 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent()
734 && !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
735 columnsBlockAncestor = containingColumnsBlock(false);
736 if (columnsBlockAncestor) {
737 // Make sure that none of the parent ancestors have a continuation.
738 // If yes, we do not want split the block into continuations.
739 RenderObject* curr = this;
740 while (curr && curr != columnsBlockAncestor) {
741 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
742 columnsBlockAncestor = 0;
745 curr = curr->parent();
749 return columnsBlockAncestor;
752 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
754 if (beforeChild && beforeChild->parent() != this) {
755 RenderElement* beforeChildContainer = beforeChild->parent();
756 while (beforeChildContainer->parent() != this)
757 beforeChildContainer = beforeChildContainer->parent();
758 ASSERT(beforeChildContainer);
760 if (beforeChildContainer->isAnonymous()) {
761 // If the requested beforeChild is not one of our children, then this is because
762 // there is an anonymous container within this object that contains the beforeChild.
763 RenderElement* beforeChildAnonymousContainer = beforeChildContainer;
764 if (beforeChildAnonymousContainer->isAnonymousBlock()
765 #if ENABLE(FULLSCREEN_API)
766 // Full screen renderers and full screen placeholders act as anonymous blocks, not tables:
767 || beforeChildAnonymousContainer->isRenderFullScreen()
768 || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder()
771 // Insert the child into the anonymous block box instead of here.
772 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
773 beforeChild->parent()->addChild(newChild, beforeChild);
775 addChild(newChild, beforeChild->parent());
779 ASSERT(beforeChildAnonymousContainer->isTable());
780 if (newChild->isTablePart()) {
781 // Insert into the anonymous table.
782 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
786 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
788 ASSERT(beforeChild->parent() == this);
789 if (beforeChild->parent() != this) {
790 // We should never reach here. If we do, we need to use the
791 // safe fallback to use the topmost beforeChild container.
792 beforeChild = beforeChildContainer;
795 // We will reach here when beforeChild is a run-in element.
796 // If run-in element precedes a block-level element, it becomes the
797 // the first inline child of that block level element. The insertion
798 // point will be before that block-level element.
799 ASSERT(beforeChild->isRunIn());
800 beforeChild = beforeChildContainer;
804 // Nothing goes before the intruded run-in.
805 if (beforeChild && beforeChild->isRunIn() && runInIsPlacedIntoSiblingBlock(beforeChild))
806 beforeChild = beforeChild->nextSibling();
808 // Check for a spanning element in columns.
809 if (gColumnFlowSplitEnabled) {
810 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
811 if (columnsBlockAncestor) {
812 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
813 // We are placing a column-span element inside a block.
814 RenderBlock* newBox = createAnonymousColumnSpanBlock();
816 if (columnsBlockAncestor != this && !isRenderFlowThread()) {
817 // We are nested inside a multi-column element and are being split by the span. We have to break up
818 // our block into continuations.
819 RenderBoxModelObject* oldContinuation = continuation();
821 // When we split an anonymous block, there's no need to do any continuation hookup,
822 // since we haven't actually split a real element.
823 if (!isAnonymousBlock())
824 setContinuation(newBox);
826 splitFlow(beforeChild, newBox, newChild, oldContinuation);
830 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
831 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
832 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
833 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
838 bool madeBoxesNonInline = false;
840 // A block has to either have all of its children inline, or all of its children as blocks.
841 // So, if our children are currently inline and a block child has to be inserted, we move all our
842 // inline children into anonymous block boxes.
843 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
844 // This is a block with inline content. Wrap the inline content in anonymous blocks.
845 makeChildrenNonInline(beforeChild);
846 madeBoxesNonInline = true;
848 if (beforeChild && beforeChild->parent() != this) {
849 beforeChild = beforeChild->parent();
850 ASSERT(beforeChild->isAnonymousBlock());
851 ASSERT(beforeChild->parent() == this);
853 } else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) {
854 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
855 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
856 // a new one is created and inserted into our list of children in the appropriate position.
857 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
859 if (afterChild && afterChild->isAnonymousBlock()) {
860 toRenderBlock(afterChild)->addChild(newChild);
864 if (newChild->isInline()) {
865 // No suitable existing anonymous box - create a new one.
866 RenderBlock* newBox = createAnonymousBlock();
867 RenderBox::addChild(newBox, beforeChild);
868 newBox->addChild(newChild);
873 RenderBox::addChild(newChild, beforeChild);
875 // Handle placement of run-ins.
876 placeRunInIfNeeded(newChild);
878 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
879 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
880 // this object may be dead here
883 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
885 if (continuation() && !isAnonymousBlock())
886 addChildToContinuation(newChild, beforeChild);
888 addChildIgnoringContinuation(newChild, beforeChild);
891 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
893 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
894 addChildToAnonymousColumnBlocks(newChild, beforeChild);
896 addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
899 static void getInlineRun(RenderObject* start, RenderObject* boundary,
900 RenderObject*& inlineRunStart,
901 RenderObject*& inlineRunEnd)
903 // Beginning at |start| we find the largest contiguous run of inlines that
904 // we can. We denote the run with start and end points, |inlineRunStart|
905 // and |inlineRunEnd|. Note that these two values may be the same if
906 // we encounter only one inline.
908 // We skip any non-inlines we encounter as long as we haven't found any
911 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
912 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
915 // Start by skipping as many non-inlines as we can.
916 RenderObject * curr = start;
919 while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()))
920 curr = curr->nextSibling();
922 inlineRunStart = inlineRunEnd = curr;
925 return; // No more inline children to be found.
927 sawInline = curr->isInline();
929 curr = curr->nextSibling();
930 while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) {
932 if (curr->isInline())
934 curr = curr->nextSibling();
936 } while (!sawInline);
939 void RenderBlock::deleteLineBoxTree()
941 if (containsFloats())
942 m_floatingObjects->clearLineBoxTreePointers();
943 m_lineBoxes.deleteLineBoxTree(renderArena());
945 if (AXObjectCache* cache = document().existingAXObjectCache())
946 cache->recomputeIsIgnored(this);
949 RootInlineBox* RenderBlock::createRootInlineBox()
951 return new (renderArena()) RootInlineBox(*this);
954 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
956 RootInlineBox* rootBox = createRootInlineBox();
957 m_lineBoxes.appendLineBox(rootBox);
959 if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) {
960 if (AXObjectCache* cache = document().existingAXObjectCache())
961 cache->recomputeIsIgnored(this);
967 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
969 // makeChildrenNonInline takes a block whose children are *all* inline and it
970 // makes sure that inline children are coalesced under anonymous
971 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
972 // the new block child that is causing us to have to wrap all the inlines. This
973 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
974 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
976 ASSERT(isInlineBlockOrInlineTable() || !isInline());
977 ASSERT(!insertionPoint || insertionPoint->parent() == this);
979 setChildrenInline(false);
981 RenderObject *child = firstChild();
987 // Since we are going to have block children, we have to move
988 // back the run-in to its original place.
989 if (child->isRunIn()) {
990 moveRunInToOriginalPosition(child);
991 child = firstChild();
995 RenderObject *inlineRunStart, *inlineRunEnd;
996 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
1001 child = inlineRunEnd->nextSibling();
1003 RenderBlock* block = createAnonymousBlock();
1004 insertChildInternal(block, inlineRunStart, NotifyChildren);
1005 moveChildrenTo(block, inlineRunStart, child);
1009 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
1010 ASSERT(!c->isInline());
1016 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
1018 ASSERT(child->isAnonymousBlock());
1019 ASSERT(!child->childrenInline());
1021 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
1024 RenderObject* firstAnChild = child->firstChild();
1025 RenderObject* lastAnChild = child->lastChild();
1027 RenderObject* o = firstAnChild;
1030 o = o->nextSibling();
1032 firstAnChild->setPreviousSibling(child->previousSibling());
1033 lastAnChild->setNextSibling(child->nextSibling());
1034 if (child->previousSibling())
1035 child->previousSibling()->setNextSibling(firstAnChild);
1036 if (child->nextSibling())
1037 child->nextSibling()->setPreviousSibling(lastAnChild);
1039 if (child == firstChild())
1040 setFirstChild(firstAnChild);
1041 if (child == lastChild())
1042 setLastChild(lastAnChild);
1044 if (child == firstChild())
1045 setFirstChild(child->nextSibling());
1046 if (child == lastChild())
1047 setLastChild(child->previousSibling());
1049 if (child->previousSibling())
1050 child->previousSibling()->setNextSibling(child->nextSibling());
1051 if (child->nextSibling())
1052 child->nextSibling()->setPreviousSibling(child->previousSibling());
1055 child->setFirstChild(0);
1058 // Remove all the information in the flow thread associated with the leftover anonymous block.
1059 child->removeFromRenderFlowThread();
1061 child->setParent(0);
1062 child->setPreviousSibling(0);
1063 child->setNextSibling(0);
1068 static bool canMergeAnonymousBlock(RenderBlock* anonymousBlock)
1070 if (anonymousBlock->beingDestroyed() || anonymousBlock->continuation())
1072 if (anonymousBlock->isRubyRun() || anonymousBlock->isRubyBase())
1077 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* previous, RenderObject* next)
1079 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
1083 if (!previous->isAnonymousBlock())
1085 RenderBlock* previousAnonymousBlock = toRenderBlock(previous);
1086 if (!canMergeAnonymousBlock(previousAnonymousBlock))
1088 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
1089 RenderObject* child = previousAnonymousBlock->firstChild();
1090 if (child && child->isInline() && child->isRunIn())
1094 if (!next->isAnonymousBlock())
1096 RenderBlock* nextAnonymousBlock = toRenderBlock(next);
1097 if (!canMergeAnonymousBlock(nextAnonymousBlock))
1100 if (!previous || !next)
1103 // Make sure the types of the anonymous blocks match up.
1104 return previous->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1105 && previous->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1108 void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderBlock* child)
1110 parent->setNeedsLayoutAndPrefWidthsRecalc();
1111 parent->setChildrenInline(child->childrenInline());
1112 RenderObject* nextSibling = child->nextSibling();
1114 RenderFlowThread* childFlowThread = child->flowThreadContainingBlock();
1115 CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread);
1117 parent->removeChildInternal(child, child->hasLayer() ? NotifyChildren : DontNotifyChildren);
1118 child->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
1119 // Delete the now-empty block's lines and nuke it.
1120 child->deleteLineBoxTree();
1121 if (childFlowThread && childFlowThread->isRenderNamedFlowThread())
1122 toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child);
1126 void RenderBlock::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert)
1128 moveAllChildrenTo(toBlock, fullRemoveInsert);
1130 // When a portion of the render tree is being detached, anonymous blocks
1131 // will be combined as their children are deleted. In this process, the
1132 // anonymous block later in the tree is merged into the one preceeding it.
1133 // It can happen that the later block (this) contains floats that the
1134 // previous block (toBlock) did not contain, and thus are not in the
1135 // floating objects list for toBlock. This can result in toBlock containing
1136 // floats that are not in it's floating objects list, but are in the
1137 // floating objects lists of siblings and parents. This can cause problems
1138 // when the float itself is deleted, since the deletion code assumes that
1139 // if a float is not in it's containing block's floating objects list, it
1140 // isn't in any floating objects list. In order to preserve this condition
1141 // (removing it has serious performance implications), we need to copy the
1142 // floating objects from the old block (this) to the new block (toBlock).
1143 // The float's metrics will likely all be wrong, but since toBlock is
1144 // already marked for layout, this will get fixed before anything gets
1146 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
1147 if (m_floatingObjects) {
1148 if (!toBlock->m_floatingObjects)
1149 toBlock->createFloatingObjects();
1151 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
1152 auto end = fromFloatingObjectSet.end();
1154 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
1155 FloatingObject* floatingObject = it->get();
1157 // Don't insert the object again if it's already in the list
1158 if (toBlock->containsFloat(&floatingObject->renderer()))
1161 toBlock->m_floatingObjects->add(floatingObject->unsafeClone());
1166 void RenderBlock::removeChild(RenderObject* oldChild)
1168 // No need to waste time in merging or removing empty anonymous blocks.
1169 // We can just bail out if our document is getting destroyed.
1170 if (documentBeingDestroyed()) {
1171 RenderBox::removeChild(oldChild);
1175 // This protects against column split flows when anonymous blocks are getting merged.
1176 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
1178 // If this child is a block, and if our previous and next siblings are
1179 // both anonymous blocks with inline content, then we can go ahead and
1180 // fold the inline content back together.
1181 RenderObject* prev = oldChild->previousSibling();
1182 RenderObject* next = oldChild->nextSibling();
1183 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1184 if (canMergeAnonymousBlocks && prev && next) {
1185 prev->setNeedsLayoutAndPrefWidthsRecalc();
1186 RenderBlock* nextBlock = toRenderBlock(next);
1187 RenderBlock* prevBlock = toRenderBlock(prev);
1189 if (prev->childrenInline() != next->childrenInline()) {
1190 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1191 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1193 // Place the inline children block inside of the block children block instead of deleting it.
1194 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1195 // to clear out inherited column properties by just making a new style, and to also clear the
1196 // column span flag if it is set.
1197 ASSERT(!inlineChildrenBlock->continuation());
1198 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
1199 // Cache this value as it might get changed in setStyle() call.
1200 bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer();
1201 inlineChildrenBlock->setStyle(newStyle);
1202 removeChildInternal(inlineChildrenBlock, inlineChildrenBlockHasLayer ? NotifyChildren : DontNotifyChildren);
1204 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1205 RenderObject* beforeChild = prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : nullptr;
1206 blockChildrenBlock->insertChildInternal(inlineChildrenBlock, beforeChild,
1207 (inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer()) ? NotifyChildren : DontNotifyChildren);
1208 next->setNeedsLayoutAndPrefWidthsRecalc();
1210 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1211 // of "this". we null out prev or next so that is not used later in the function.
1212 if (inlineChildrenBlock == prevBlock)
1217 // Take all the children out of the |next| block and put them in
1218 // the |prev| block.
1219 nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1221 // Delete the now-empty block's lines and nuke it.
1222 nextBlock->deleteLineBoxTree();
1223 nextBlock->destroy();
1228 RenderBox::removeChild(oldChild);
1230 RenderObject* child = prev ? prev : next;
1231 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) {
1232 // The removal has knocked us down to containing only a single anonymous
1233 // box. We can go ahead and pull the content right back up into our
1235 collapseAnonymousBoxChild(this, toRenderBlock(child));
1236 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
1237 // It's possible that the removal has knocked us down to a single anonymous
1238 // block with pseudo-style element siblings (e.g. first-letter). If these
1239 // are floating, then we need to pull the content up also.
1240 RenderBlock* anonBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1241 if ((anonBlock->previousSibling() || anonBlock->nextSibling())
1242 && (!anonBlock->previousSibling() || (anonBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonBlock->previousSibling()->isFloating() && !anonBlock->previousSibling()->previousSibling()))
1243 && (!anonBlock->nextSibling() || (anonBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonBlock->nextSibling()->isFloating() && !anonBlock->nextSibling()->nextSibling()))) {
1244 collapseAnonymousBoxChild(this, anonBlock);
1248 if (!firstChild()) {
1249 // If this was our last child be sure to clear out our line boxes.
1250 if (childrenInline())
1251 deleteLineBoxTree();
1253 // If we are an empty anonymous block in the continuation chain,
1254 // we need to remove ourself and fix the continuation chain.
1255 if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) {
1256 RenderObject* containingBlockIgnoringAnonymous = containingBlock();
1257 while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock())
1258 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
1259 for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
1260 if (curr->virtualContinuation() != this)
1263 // Found our previous continuation. We just need to point it to
1264 // |this|'s next continuation.
1265 RenderBoxModelObject* nextContinuation = continuation();
1266 if (curr->isRenderInline())
1267 toRenderInline(curr)->setContinuation(nextContinuation);
1268 else if (curr->isRenderBlock())
1269 toRenderBlock(curr)->setContinuation(nextContinuation);
1271 ASSERT_NOT_REACHED();
1281 bool RenderBlock::isSelfCollapsingBlock() const
1283 // We are not self-collapsing if we
1284 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1286 // (c) have border/padding,
1287 // (d) have a min-height
1288 // (e) have specified that one of our margins can't collapse using a CSS extension
1289 if (logicalHeight() > 0
1290 || isTable() || borderAndPaddingLogicalHeight()
1291 || style()->logicalMinHeight().isPositive()
1292 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1295 Length logicalHeightLength = style()->logicalHeight();
1296 bool hasAutoHeight = logicalHeightLength.isAuto();
1297 if (logicalHeightLength.isPercent() && !document().inQuirksMode()) {
1298 hasAutoHeight = true;
1299 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1300 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1301 hasAutoHeight = false;
1305 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1306 // on whether we have content that is all self-collapsing or not.
1307 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1308 // If the block has inline children, see if we generated any line boxes. If we have any
1309 // line boxes, then we can't be self-collapsing, since we have content.
1310 if (childrenInline())
1311 return !firstLineBox();
1313 // Whether or not we collapse is dependent on whether all our normal flow children
1314 // are also self-collapsing.
1315 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1316 if (child->isFloatingOrOutOfFlowPositioned())
1318 if (!child->isSelfCollapsingBlock())
1326 void RenderBlock::startDelayUpdateScrollInfo()
1328 if (gDelayUpdateScrollInfo == 0) {
1329 ASSERT(!gDelayedUpdateScrollInfoSet);
1330 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1332 ASSERT(gDelayedUpdateScrollInfoSet);
1333 ++gDelayUpdateScrollInfo;
1336 void RenderBlock::finishDelayUpdateScrollInfo()
1338 --gDelayUpdateScrollInfo;
1339 ASSERT(gDelayUpdateScrollInfo >= 0);
1340 if (gDelayUpdateScrollInfo == 0) {
1341 ASSERT(gDelayedUpdateScrollInfoSet);
1343 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1344 gDelayedUpdateScrollInfoSet = 0;
1346 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1347 RenderBlock* block = *it;
1348 if (block->hasOverflowClip()) {
1349 block->layer()->updateScrollInfoAfterLayout();
1350 block->clearLayoutOverflow();
1356 void RenderBlock::updateScrollInfoAfterLayout()
1358 if (hasOverflowClip()) {
1359 if (style()->isFlippedBlocksWritingMode()) {
1360 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
1361 // Workaround for now. We cannot delay the scroll info for overflow
1362 // for items with opposite writing directions, as the contents needs
1363 // to overflow in that direction
1364 layer()->updateScrollInfoAfterLayout();
1368 if (gDelayUpdateScrollInfo)
1369 gDelayedUpdateScrollInfoSet->add(this);
1371 layer()->updateScrollInfoAfterLayout();
1375 void RenderBlock::layout()
1377 StackStats::LayoutCheckPoint layoutCheckPoint;
1378 OverflowEventDispatcher dispatcher(this);
1380 // Update our first letter info now.
1381 updateFirstLetter();
1383 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1387 // It's safe to check for control clip here, since controls can never be table cells.
1388 // If we have a lightweight clip, there can never be any overflow from children.
1389 if (hasControlClip() && m_overflow && !gDelayUpdateScrollInfo)
1390 clearLayoutOverflow();
1392 invalidateBackgroundObscurationStatus();
1395 #if ENABLE(CSS_SHAPES)
1396 void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset)
1398 LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height();
1399 if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo())
1401 // Propagate layout markers only up to the child, as we are still in the middle
1403 child->setNormalChildNeedsLayout(true);
1404 child->markShapeInsideDescendantsForLayout();
1405 child->layoutIfNeeded();
1408 LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const
1410 const RenderBlock* currentBlock = this;
1411 LayoutRect blockRect(currentBlock->borderBoxRect());
1412 while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) {
1413 RenderBlock* containerBlock = currentBlock->containingBlock();
1414 ASSERT(containerBlock);
1415 if (!containerBlock)
1416 return LayoutSize();
1418 if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
1419 // We have to put the block rect in container coordinates
1420 // and we have to take into account both the container and current block flipping modes
1421 // Bug 118073: Flipping inline and block directions at the same time will not work,
1422 // as one of the flipped dimensions will not yet have been set to its final size
1423 if (containerBlock->style()->isFlippedBlocksWritingMode()) {
1424 if (containerBlock->isHorizontalWritingMode())
1425 blockRect.setY(currentBlock->height() - blockRect.maxY());
1427 blockRect.setX(currentBlock->width() - blockRect.maxX());
1429 currentBlock->flipForWritingMode(blockRect);
1432 blockRect.moveBy(currentBlock->location());
1433 currentBlock = containerBlock;
1436 LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x());
1440 void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*)
1442 RenderBox::imageChanged(image);
1447 ShapeValue* shapeValue = style()->shapeInside();
1448 if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) {
1449 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1450 shapeInsideInfo->dirtyShapeSize();
1451 markShapeInsideDescendantsForLayout();
1455 void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
1457 // FIXME: A future optimization would do a deep comparison for equality.
1458 if (shapeInside == oldShapeInside)
1462 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1463 shapeInsideInfo->dirtyShapeSize();
1465 setShapeInsideInfo(nullptr);
1466 markShapeInsideDescendantsForLayout();
1470 void RenderBlock::markShapeInsideDescendantsForLayout()
1472 if (!everHadLayout())
1474 if (childrenInline()) {
1475 setNeedsLayout(true);
1478 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1479 if (!child->isRenderBlock())
1481 RenderBlock* childBlock = toRenderBlock(child);
1482 childBlock->markShapeInsideDescendantsForLayout();
1487 #if ENABLE(CSS_SHAPES)
1488 static inline bool shapeInfoRequiresRelayout(const RenderBlock* block)
1490 ShapeInsideInfo* info = block->shapeInsideInfo();
1492 info->setNeedsLayout(info->shapeSizeDirty());
1494 info = block->layoutShapeInsideInfo();
1495 return info && info->needsLayout();
1499 bool RenderBlock::updateShapesBeforeBlockLayout()
1501 #if ENABLE(CSS_SHAPES)
1502 if (!flowThreadContainingBlock() && !shapeInsideInfo())
1503 return shapeInfoRequiresRelayout(this);
1505 LayoutUnit oldHeight = logicalHeight();
1506 LayoutUnit oldTop = logicalTop();
1508 // Compute the maximum logical height content may cause this block to expand to
1509 // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
1510 setLogicalHeight(RenderFlowThread::maxLogicalHeight());
1511 updateLogicalHeight();
1515 setLogicalHeight(oldHeight);
1516 setLogicalTop(oldTop);
1518 return shapeInfoRequiresRelayout(this);
1524 #if ENABLE(CSS_SHAPES)
1525 void RenderBlock::computeShapeSize()
1527 ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
1528 if (shapeInsideInfo) {
1529 bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
1530 shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
1535 void RenderBlock::updateShapesAfterBlockLayout(bool heightChanged)
1537 #if ENABLE(CSS_SHAPES)
1538 // A previous sibling has changed dimension, so we need to relayout the shape with the content
1539 ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
1540 if (heightChanged && shapeInsideInfo)
1541 shapeInsideInfo->dirtyShapeSize();
1543 UNUSED_PARAM(heightChanged);
1547 bool RenderBlock::updateLogicalWidthAndColumnWidth()
1549 LayoutUnit oldWidth = logicalWidth();
1550 LayoutUnit oldColumnWidth = desiredColumnWidth();
1552 updateLogicalWidth();
1555 bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged;
1556 m_hasBorderOrPaddingLogicalWidthChanged = false;
1558 return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
1561 void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
1563 ColumnInfo* colInfo = columnInfo();
1565 if (!pageLogicalHeight) {
1566 // We need to go ahead and set our explicit page height if one exists, so that we can
1567 // avoid doing two layout passes.
1568 updateLogicalHeight();
1569 LayoutUnit columnHeight = isRenderView() ? view().pageOrViewLogicalHeight() : contentLogicalHeight();
1570 if (columnHeight > 0) {
1571 pageLogicalHeight = columnHeight;
1572 hasSpecifiedPageLogicalHeight = true;
1574 setLogicalHeight(0);
1577 if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout())
1578 pageLogicalHeightChanged = true;
1580 colInfo->setColumnHeight(pageLogicalHeight);
1582 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1583 colInfo->clearForcedBreaks();
1585 colInfo->setPaginationUnit(paginationUnit());
1586 } else if (isRenderFlowThread()) {
1587 pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
1588 pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged();
1592 void RenderBlock::layoutBlock(bool, LayoutUnit)
1594 ASSERT_NOT_REACHED();
1595 setNeedsLayout(false);
1598 void RenderBlock::addOverflowFromChildren()
1600 if (!hasColumns()) {
1601 if (childrenInline())
1602 addOverflowFromInlineChildren();
1604 addOverflowFromBlockChildren();
1606 ColumnInfo* colInfo = columnInfo();
1607 if (columnCount(colInfo)) {
1608 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1609 addLayoutOverflow(lastRect);
1610 if (!hasOverflowClip())
1611 addVisualOverflow(lastRect);
1616 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
1620 // Add overflow from children.
1621 addOverflowFromChildren();
1623 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1624 addOverflowFromFloats();
1626 // Add in the overflow from positioned objects.
1627 addOverflowFromPositionedObjects();
1629 if (hasOverflowClip()) {
1630 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1631 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1632 // be considered reachable.
1633 LayoutRect clientRect(clientBoxRect());
1634 LayoutRect rectToApply;
1635 if (isHorizontalWritingMode())
1636 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1638 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1639 addLayoutOverflow(rectToApply);
1640 if (hasRenderOverflow())
1641 m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
1644 // Add visual overflow from box-shadow and border-image-outset.
1645 addVisualEffectOverflow();
1647 // Add visual overflow from theme.
1648 addVisualOverflowFromTheme();
1650 if (isRenderNamedFlowThread())
1651 toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge);
1654 void RenderBlock::clearLayoutOverflow()
1659 if (visualOverflowRect() == borderBoxRect()) {
1660 // FIXME: Implement complete solution for regions overflow.
1665 m_overflow->setLayoutOverflow(borderBoxRect());
1668 void RenderBlock::addOverflowFromBlockChildren()
1670 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1671 if (!child->isFloatingOrOutOfFlowPositioned())
1672 addOverflowFromChild(child);
1676 void RenderBlock::addOverflowFromFloats()
1678 if (!m_floatingObjects)
1681 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1682 auto end = floatingObjectSet.end();
1683 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
1684 FloatingObject* r = it->get();
1685 if (r->isDescendant())
1686 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1690 void RenderBlock::addOverflowFromPositionedObjects()
1692 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1693 if (!positionedDescendants)
1696 RenderBox* positionedObject;
1697 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1698 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1699 positionedObject = *it;
1701 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1702 if (positionedObject->style()->position() != FixedPosition) {
1703 LayoutUnit x = positionedObject->x();
1704 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1705 x -= verticalScrollbarWidth();
1706 addOverflowFromChild(positionedObject, LayoutSize(x, positionedObject->y()));
1711 void RenderBlock::addVisualOverflowFromTheme()
1713 if (!style()->hasAppearance())
1716 IntRect inflatedRect = pixelSnappedBorderBoxRect();
1717 theme()->adjustRepaintRect(this, inflatedRect);
1718 addVisualOverflow(inflatedRect);
1720 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1721 flowThread->addRegionsVisualOverflowFromTheme(this);
1724 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1726 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
1727 || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
1730 static void destroyRunIn(RenderBoxModelObject* runIn)
1732 ASSERT(runIn->isRunIn());
1733 ASSERT(!runIn->firstChild());
1735 // Delete our line box tree. This is needed as our children got moved
1736 // and our line box tree is no longer valid.
1737 if (runIn->isRenderBlock())
1738 toRenderBlock(runIn)->deleteLineBoxTree();
1739 else if (runIn->isRenderInline())
1740 toRenderInline(runIn)->deleteLineBoxTree();
1742 ASSERT_NOT_REACHED();
1747 void RenderBlock::placeRunInIfNeeded(RenderObject* newChild)
1749 if (newChild->isRunIn())
1750 moveRunInUnderSiblingBlockIfNeeded(newChild);
1751 else if (RenderObject* prevSibling = newChild->previousSibling()) {
1752 if (prevSibling->isRunIn())
1753 moveRunInUnderSiblingBlockIfNeeded(prevSibling);
1757 RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn)
1759 ASSERT(runIn->isRunIn());
1760 ASSERT(runIn->element());
1762 RenderBoxModelObject* newRunIn = 0;
1763 if (!runIn->isRenderBlockFlow())
1764 newRunIn = new (renderArena()) RenderBlockFlow(runIn->element());
1766 newRunIn = new (renderArena()) RenderInline(runIn->element());
1768 runIn->element()->setRenderer(newRunIn);
1769 newRunIn->setStyle(runIn->style());
1771 runIn->moveAllChildrenTo(newRunIn, true);
1776 void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn)
1778 ASSERT(runIn->isRunIn());
1780 // See if we have inline children. If the children aren't inline,
1781 // then just treat the run-in as a normal block.
1782 if (!runIn->childrenInline())
1785 // FIXME: We don't handle non-block elements with run-in for now.
1786 if (!runIn->isRenderBlockFlow())
1789 // FIXME: We don't support run-ins with or as part of a continuation
1790 // as it makes the back-and-forth placing complex.
1791 if (runIn->isElementContinuation() || runIn->virtualContinuation())
1794 // Check if this node is allowed to run-in. E.g. <select> expects its renderer to
1795 // be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in.
1796 if (!runIn->canBeReplacedWithInlineRunIn())
1799 RenderObject* curr = runIn->nextSibling();
1800 if (!curr || !curr->isRenderBlock() || !curr->childrenInline())
1803 RenderBlock& nextSiblingBlock = toRenderBlock(*curr);
1804 if (nextSiblingBlock.beingDestroyed())
1807 // Per CSS3, "A run-in cannot run in to a block that already starts with a
1808 // run-in or that itself is a run-in".
1809 if (nextSiblingBlock.isRunIn() || (nextSiblingBlock.firstChild() && nextSiblingBlock.firstChild()->isRunIn()))
1812 if (nextSiblingBlock.isAnonymous() || nextSiblingBlock.isFloatingOrOutOfFlowPositioned())
1815 RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn);
1816 RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn);
1817 destroyRunIn(oldRunIn);
1819 // Now insert the new child under |curr| block. Use addChild instead of insertChildNode
1820 // since it handles correct placement of the children, especially where we cannot insert
1821 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1822 nextSiblingBlock.addChild(newRunIn, nextSiblingBlock.firstChild());
1824 // Make sure that |this| get a layout since its run-in child moved.
1825 nextSiblingBlock.setNeedsLayoutAndPrefWidthsRecalc();
1828 bool RenderBlock::runInIsPlacedIntoSiblingBlock(RenderObject* runIn)
1830 ASSERT(runIn->isRunIn());
1832 // If we don't have a parent, we can't be moved into our sibling block.
1836 // An intruded run-in needs to be an inline.
1837 if (!runIn->isRenderInline())
1843 void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn)
1845 ASSERT(runIn->isRunIn());
1847 if (!runInIsPlacedIntoSiblingBlock(runIn))
1850 // FIXME: Run-in that are now placed in sibling block can break up into continuation
1851 // chains when new children are added to it. We cannot easily send them back to their
1852 // original place since that requires writing integration logic with RenderInline::addChild
1853 // and all other places that might cause continuations to be created (without blowing away
1854 // |this|). Disabling this feature for now to prevent crashes.
1855 if (runIn->isElementContinuation() || runIn->virtualContinuation())
1858 RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn);
1859 RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn);
1860 destroyRunIn(oldRunIn);
1862 // Add the run-in block as our previous sibling.
1863 parent()->addChild(newRunIn, this);
1865 // Make sure that the parent holding the new run-in gets layout.
1866 parent()->setNeedsLayoutAndPrefWidthsRecalc();
1869 LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* region)
1871 LayoutUnit startPosition = startOffsetForContent(region);
1873 // Add in our start margin.
1874 LayoutUnit oldPosition = startPosition + childMarginStart;
1875 LayoutUnit newPosition = oldPosition;
1877 LayoutUnit blockOffset = logicalTopForChild(child);
1879 blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage()));
1881 LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, logicalHeightForChild(child));
1883 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1884 if (childMarginStart < 0)
1885 startOff += childMarginStart;
1886 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1887 } else if (startOff != startPosition)
1888 newPosition = startOff + childMarginStart;
1890 return newPosition - oldPosition;
1893 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
1895 LayoutUnit startPosition = borderStart() + paddingStart();
1896 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1897 startPosition -= verticalScrollbarWidth();
1898 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1900 // Add in our start margin.
1901 LayoutUnit childMarginStart = marginStartForChild(child);
1902 LayoutUnit newPosition = startPosition + childMarginStart;
1904 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1905 // to shift over as necessary to dodge any floats that might get in the way.
1906 if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
1907 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
1909 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
1912 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
1914 if (isHorizontalWritingMode()) {
1915 if (applyDelta == ApplyLayoutDelta)
1916 view().addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
1917 child->setX(logicalLeft);
1919 if (applyDelta == ApplyLayoutDelta)
1920 view().addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
1921 child->setY(logicalLeft);
1925 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
1927 if (isHorizontalWritingMode()) {
1928 if (applyDelta == ApplyLayoutDelta)
1929 view().addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
1930 child->setY(logicalTop);
1932 if (applyDelta == ApplyLayoutDelta)
1933 view().addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
1934 child->setX(logicalTop);
1938 void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child)
1940 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1941 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1942 if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()) || child->hasViewportPercentageLogicalHeight())
1943 child->setChildNeedsLayout(true, MarkOnlyThis);
1945 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1946 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
1947 child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
1950 void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants()
1952 if (!gPercentHeightDescendantsMap)
1955 TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
1959 TrackedRendererListHashSet::iterator end = descendants->end();
1960 for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
1961 RenderBox* box = *it;
1962 while (box != this) {
1963 if (box->normalChildNeedsLayout())
1965 box->setChildNeedsLayout(true, MarkOnlyThis);
1967 // If the width of an image is affected by the height of a child (e.g., an image with an aspect ratio),
1968 // then we have to dirty preferred widths, since even enclosing blocks can become dirty as a result.
1969 // (A horizontal flexbox that contains an inline image wrapped in an anonymous block for example.)
1970 if (box->hasAspectRatio())
1971 box->setPreferredLogicalWidthsDirty(true);
1973 box = box->containingBlock();
1981 void RenderBlock::simplifiedNormalFlowLayout()
1983 if (childrenInline()) {
1984 ListHashSet<RootInlineBox*> lineBoxes;
1985 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1986 RenderObject* o = walker.current();
1987 if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
1988 o->layoutIfNeeded();
1989 if (toRenderBox(o)->inlineBoxWrapper())
1990 lineBoxes.add(&toRenderBox(o)->inlineBoxWrapper()->root());
1991 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline()))
1992 o->setNeedsLayout(false);
1995 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
1996 // FIXME: Find a way to invalidate the knownToHaveNoOverflow flag on the InlineBoxes.
1997 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1998 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
1999 RootInlineBox* box = *it;
2000 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2003 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2004 if (!box->isOutOfFlowPositioned())
2005 box->layoutIfNeeded();
2010 bool RenderBlock::simplifiedLayout()
2012 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2015 LayoutStateMaintainer statePusher(&view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2017 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2020 // Lay out positioned descendants or objects that just need to recompute overflow.
2021 if (needsSimplifiedNormalFlowLayout())
2022 simplifiedNormalFlowLayout();
2024 // Make sure a forced break is applied after the content if we are a flow thread in a simplified layout.
2025 // This ensures the size information is correctly computed for the last auto-height region receiving content.
2026 if (isRenderFlowThread())
2027 toRenderFlowThread(this)->applyBreakAfterContent(clientLogicalBottom());
2029 // Lay out our positioned objects if our positioned child bit is set.
2030 // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
2031 // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
2032 // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
2033 // are statically positioned and thus need to move with their absolute ancestors.
2034 bool canContainFixedPosObjects = canContainFixedPositionObjects();
2035 if (posChildNeedsLayout() || canContainFixedPosObjects)
2036 layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects);
2038 // Recompute our overflow information.
2039 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2040 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2041 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2042 // lowestPosition on every relayout so it's not a regression.
2043 // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
2044 // simplifiedLayout, we cache the value in m_overflow.
2045 LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
2046 computeOverflow(oldClientAfterEdge, true);
2050 updateLayerTransform();
2052 updateScrollInfoAfterLayout();
2054 setNeedsLayout(false);
2058 void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child)
2060 if (child->style()->position() != FixedPosition)
2063 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
2064 bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
2065 if (!hasStaticBlockPosition && !hasStaticInlinePosition)
2068 RenderObject* o = child->parent();
2069 while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition)
2071 if (o->style()->position() != AbsolutePosition)
2074 RenderBox* box = toRenderBox(child);
2075 if (hasStaticInlinePosition) {
2076 LogicalExtentComputedValues computedValues;
2077 box->computeLogicalWidthInRegion(computedValues);
2078 LayoutUnit newLeft = computedValues.m_position;
2079 if (newLeft != box->logicalLeft())
2080 child->setChildNeedsLayout(true, MarkOnlyThis);
2081 } else if (hasStaticBlockPosition) {
2082 LayoutUnit oldTop = box->logicalTop();
2083 box->updateLogicalHeight();
2084 if (box->logicalTop() != oldTop)
2085 child->setChildNeedsLayout(true, MarkOnlyThis);
2089 void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly)
2091 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2092 if (!positionedDescendants)
2096 view().layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2099 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2100 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2103 estimateRegionRangeForBoxChild(r);
2105 // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
2106 // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e.
2107 // it has static position.
2108 markFixedPositionObjectForLayoutIfNeeded(r);
2109 if (fixedPositionObjectsOnly) {
2110 r->layoutIfNeeded();
2114 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2115 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2116 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2117 // positioned explicitly) this should not incur a performance penalty.
2118 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
2119 r->setChildNeedsLayout(true, MarkOnlyThis);
2121 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2122 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
2123 r->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
2125 if (!r->needsLayout())
2126 r->markForPaginationRelayoutIfNeeded();
2128 // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width
2129 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2130 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2131 r->setNeedsLayout(false);
2133 // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
2134 // If it's wrong we'll lay out again.
2135 LayoutUnit oldLogicalTop = 0;
2136 bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2137 if (needsBlockDirectionLocationSetBeforeLayout) {
2138 if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
2139 r->updateLogicalHeight();
2141 r->updateLogicalWidth();
2142 oldLogicalTop = logicalTopForChild(r);
2145 r->layoutIfNeeded();
2147 // Lay out again if our estimate was wrong.
2148 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) {
2149 r->setChildNeedsLayout(true, MarkOnlyThis);
2150 r->layoutIfNeeded();
2153 if (updateRegionRangeForBoxChild(r)) {
2154 r->setNeedsLayout(true, MarkOnlyThis);
2155 r->layoutIfNeeded();
2160 view().layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2163 void RenderBlock::markPositionedObjectsForLayout()
2165 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2166 if (positionedDescendants) {
2168 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2169 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2171 r->setChildNeedsLayout(true);
2176 void RenderBlock::markForPaginationRelayoutIfNeeded()
2178 ASSERT(!needsLayout());
2182 if (view().layoutState()->pageLogicalHeightChanged() || (view().layoutState()->pageLogicalHeight() && view().layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
2183 setChildNeedsLayout(true, MarkOnlyThis);
2186 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2188 // Repaint any overhanging floats (if we know we're the one to paint them).
2189 // Otherwise, bail out.
2190 if (!hasOverhangingFloats())
2193 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2194 // in this block. Better yet would be to push extra state for the containers of other floats.
2195 LayoutStateDisabler layoutStateDisabler(&view());
2196 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2197 auto end = floatingObjectSet.end();
2198 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2199 FloatingObject* r = it->get();
2200 // Only repaint the object if it is overhanging, is not in its own layer, and
2201 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2202 // condition is replaced with being a descendant of us.
2203 if (r->logicalBottom(isHorizontalWritingMode()) > logicalHeight()
2204 && !r->renderer().hasSelfPaintingLayer()
2205 && (r->shouldPaint() || (paintAllDescendants && r->renderer().isDescendantOf(this)))) {
2206 r->renderer().repaint();
2207 r->renderer().repaintOverhangingFloats(false);
2212 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2214 LayoutPoint adjustedPaintOffset = paintOffset + location();
2216 PaintPhase phase = paintInfo.phase;
2218 // Check if we need to do anything at all.
2219 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2220 // paints the root's background.
2222 LayoutRect overflowBox = overflowRectForPaintRejection();
2223 flipForWritingMode(overflowBox);
2224 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2225 overflowBox.moveBy(adjustedPaintOffset);
2226 if (!overflowBox.intersects(paintInfo.rect))
2230 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
2231 paintObject(paintInfo, adjustedPaintOffset);
2233 popContentsClip(paintInfo, phase, adjustedPaintOffset);
2235 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2236 // z-index. We paint after we painted the background/border, so that the scrollbars will
2237 // sit above the background/border.
2238 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly())
2239 layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
2242 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2244 if (paintInfo.context->paintingDisabled())
2247 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2248 bool ruleTransparent = style()->columnRuleIsTransparent();
2249 EBorderStyle ruleStyle = style()->columnRuleStyle();
2250 LayoutUnit ruleThickness = style()->columnRuleWidth();
2251 LayoutUnit colGap = columnGap();
2252 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
2256 ColumnInfo* colInfo = columnInfo();
2257 unsigned colCount = columnCount(colInfo);
2259 bool antialias = shouldAntialiasLines(paintInfo.context);
2261 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
2262 bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed();
2263 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
2264 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
2265 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
2266 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
2267 BoxSide boxSide = isHorizontalWritingMode()
2268 ? leftToRight ? BSLeft : BSRight
2269 : leftToRight ? BSTop : BSBottom;
2271 for (unsigned i = 0; i < colCount; i++) {
2272 // Move to the next position.
2274 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2275 currLogicalLeftOffset += inlineDirectionSize + colGap;
2277 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2278 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2281 // Now paint the column rule.
2282 if (i < colCount - 1) {
2283 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
2284 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
2285 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
2286 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
2287 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
2288 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2291 ruleLogicalLeft = currLogicalLeftOffset;
2294 bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
2295 LayoutUnit ruleLeft = isHorizontalWritingMode()
2296 ? borderLeft() + paddingLeft()
2297 : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderAndPaddingBefore() : borderAndPaddingAfter());
2298 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2299 LayoutUnit ruleTop = isHorizontalWritingMode()
2300 ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderAndPaddingBefore() : borderAndPaddingAfter())
2301 : borderStart() + paddingStart();
2302 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2303 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2306 if (isHorizontalWritingMode())
2307 ruleRect.setY(height() - ruleRect.maxY());
2309 ruleRect.setX(width() - ruleRect.maxX());
2312 ruleRect.moveBy(paintOffset);
2314 BoxSide boxSide = isHorizontalWritingMode()
2315 ? topToBottom ? BSTop : BSBottom
2316 : topToBottom ? BSLeft : BSRight;
2318 LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2319 if (!isHorizontalWritingMode())
2320 step = step.transposedSize();
2322 for (unsigned i = 1; i < colCount; i++) {
2323 ruleRect.move(step);
2324 IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
2325 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2330 LayoutUnit RenderBlock::initialBlockOffsetForPainting() const
2332 ColumnInfo* colInfo = columnInfo();
2333 LayoutUnit result = 0;
2334 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis && colInfo->progressionIsReversed()) {
2335 LayoutRect colRect = columnRectAt(colInfo, 0);
2336 result = isHorizontalWritingMode() ? colRect.y() : colRect.x();
2337 result -= borderAndPaddingBefore();
2338 if (style()->isFlippedBlocksWritingMode())
2344 LayoutUnit RenderBlock::blockDeltaForPaintingNextColumn() const
2346 ColumnInfo* colInfo = columnInfo();
2347 LayoutUnit blockDelta = -colInfo->columnHeight();
2348 LayoutUnit colGap = columnGap();
2349 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2350 if (!colInfo->progressionIsReversed())
2351 blockDelta = colGap;
2353 blockDelta -= (colInfo->columnHeight() + colGap);
2355 if (style()->isFlippedBlocksWritingMode())
2356 blockDelta = -blockDelta;
2360 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2362 // We need to do multiple passes, breaking up our child painting into strips.
2363 GraphicsContext* context = paintInfo.context;
2364 ColumnInfo* colInfo = columnInfo();
2365 unsigned colCount = columnCount(colInfo);
2368 LayoutUnit colGap = columnGap();
2369 LayoutUnit currLogicalTopOffset = initialBlockOffsetForPainting();
2370 LayoutUnit blockDelta = blockDeltaForPaintingNextColumn();
2371 for (unsigned i = 0; i < colCount; i++) {
2372 // For each rect, we clip to the rect, and then we adjust our coords.
2373 LayoutRect colRect = columnRectAt(colInfo, i);
2374 flipForWritingMode(colRect);
2376 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2377 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2378 colRect.moveBy(paintOffset);
2379 PaintInfo info(paintInfo);
2380 info.rect.intersect(pixelSnappedIntRect(colRect));
2382 if (!info.rect.isEmpty()) {
2383 GraphicsContextStateSaver stateSaver(*context);
2384 LayoutRect clipRect(colRect);
2386 if (i < colCount - 1) {
2387 if (isHorizontalWritingMode())
2388 clipRect.expand(colGap / 2, 0);
2390 clipRect.expand(0, colGap / 2);
2392 // Each strip pushes a clip, since column boxes are specified as being
2393 // like overflow:hidden.
2394 // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
2395 // are clipped according to the 'overflow' property.
2396 context->clip(pixelSnappedIntRect(clipRect));
2398 // Adjust our x and y when painting.
2399 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2401 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2403 paintContents(info, adjustedPaintOffset);
2405 currLogicalTopOffset += blockDelta;
2409 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2411 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2412 // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
2413 // will do a full repaint.
2414 if (document().didLayoutWithPendingStylesheets() && !isRenderView())
2417 if (childrenInline())
2418 m_lineBoxes.paint(this, paintInfo, paintOffset);
2420 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2421 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2423 // We don't paint our own background, but we do let the kids paint their backgrounds.
2424 PaintInfo paintInfoForChild(paintInfo);
2425 paintInfoForChild.phase = newPhase;
2426 paintInfoForChild.updateSubtreePaintRootForChildren(this);
2428 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2429 // NSViews. Do not add any more code for this.
2430 bool usePrintRect = !view().printRect().isEmpty();
2431 paintChildren(paintInfo, paintOffset, paintInfoForChild, usePrintRect);
2435 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
2437 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2438 if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
2443 bool RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
2445 // Check for page-break-before: always, and if it's set, break and bail.
2446 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2447 LayoutUnit absoluteChildY = paintOffset.y() + child->y();
2448 if (checkBeforeAlways
2449 && absoluteChildY > paintInfo.rect.y()
2450 && absoluteChildY < paintInfo.rect.maxY()) {
2451 view().setBestTruncatedAt(absoluteChildY, this, true);
2455 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= view().printRect().height()) {
2456 // Paginate block-level replaced elements.
2457 if (absoluteChildY + child->height() > view().printRect().maxY()) {
2458 if (absoluteChildY < view().truncatedAt())
2459 view().setBestTruncatedAt(absoluteChildY, child);
2460 // If we were able to truncate, don't paint.
2461 if (absoluteChildY >= view().truncatedAt())
2466 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2467 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2468 child->paint(paintInfoForChild, childPoint);
2470 // Check for page-break-after: always, and if it's set, break and bail.
2471 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2472 if (checkAfterAlways
2473 && (absoluteChildY + child->height()) > paintInfo.rect.y()
2474 && (absoluteChildY + child->height()) < paintInfo.rect.maxY()) {
2475 view().setBestTruncatedAt(absoluteChildY + child->height() + max<LayoutUnit>(0, child->collapsedMarginAfter()), this, true);
2482 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2484 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2485 bool caretBrowsing = frame().settings().caretBrowsingEnabled();
2486 RenderObject* caretPainter;
2487 bool isContentEditable;
2488 if (type == CursorCaret) {
2489 caretPainter = frame().selection().caretRenderer();
2490 isContentEditable = frame().selection().rendererIsEditable();
2492 caretPainter = frame().page()->dragCaretController().caretRenderer();
2493 isContentEditable = frame().page()->dragCaretController().isContentEditable();
2496 if (caretPainter == this && (isContentEditable || caretBrowsing)) {
2497 if (type == CursorCaret)
2498 frame().selection().paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2500 frame().page()->dragCaretController().paintDragCaret(&frame(), paintInfo.context, paintOffset, paintInfo.rect);
2504 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2506 PaintPhase paintPhase = paintInfo.phase;
2508 // 1. paint background, borders etc
2509 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2510 if (hasBoxDecorations())
2511 paintBoxDecorations(paintInfo, paintOffset);
2512 if (hasColumns() && !paintInfo.paintRootBackgroundOnly())
2513 paintColumnRules(paintInfo, paintOffset);
2516 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2517 paintMask(paintInfo, paintOffset);
2521 // We're done. We don't bother painting any children.
2522 if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
2525 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2526 LayoutPoint scrolledOffset = paintOffset;
2527 if (hasOverflowClip())
2528 scrolledOffset.move(-scrolledContentOffset());
2530 // 2. paint contents
2531 if (paintPhase != PaintPhaseSelfOutline) {
2533 paintColumnContents(paintInfo, scrolledOffset);
2535 paintContents(paintInfo, scrolledOffset);
2538 // 3. paint selection
2539 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2540 bool isPrinting = document().printing();
2541 if (!isPrinting && !hasColumns())
2542 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2545 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2547 paintColumnContents(paintInfo, scrolledOffset, true);
2549 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2552 // 5. paint outline.
2553 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2554 paintOutline(paintInfo, LayoutRect(paintOffset, size()));
2556 // 6. paint continuation outlines.
2557 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2558 RenderInline* inlineCont = inlineElementContinuation();
2559 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2560 RenderInline* inlineRenderer = toRenderInline(inlineCont->element()->renderer());
2561 RenderBlock* cb = containingBlock();
2563 bool inlineEnclosedInSelfPaintingLayer = false;
2564 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2565 if (box->hasSelfPaintingLayer()) {
2566 inlineEnclosedInSelfPaintingLayer = true;
2571 // Do not add continuations for outline painting by our containing block if we are a relative positioned
2572 // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being
2573 // in the same layer.
2574 if (!inlineEnclosedInSelfPaintingLayer && !hasLayer())
2575 cb->addContinuationWithOutline(inlineRenderer);
2576 else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer()))
2577 inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2579 paintContinuationOutlines(paintInfo, paintOffset);
2583 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2584 // then paint the caret.
2585 if (paintPhase == PaintPhaseForeground) {
2586 paintCaret(paintInfo, paintOffset, CursorCaret);
2587 paintCaret(paintInfo, paintOffset, DragCaret);
2591 LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2593 if (!style()->isFlippedBlocksWritingMode())
2596 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2597 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2599 if (isHorizontalWritingMode())
2600 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2601 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2604 void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2606 if (!m_floatingObjects)
2609 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2610 auto end = floatingObjectSet.end();
2611 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2612 FloatingObject* r = it->get();
2613 // Only paint the object if our m_shouldPaint flag is set.
2614 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
2615 PaintInfo currentPaintInfo(paintInfo);
2616 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2617 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
2618 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2619 r->renderer().paint(currentPaintInfo, childPoint);
2620 if (!preservePhase) {
2621 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2622 r->renderer().paint(currentPaintInfo, childPoint);
2623 currentPaintInfo.phase = PaintPhaseFloat;
2624 r->renderer().paint(currentPaintInfo, childPoint);
2625 currentPaintInfo.phase = PaintPhaseForeground;
2626 r->renderer().paint(currentPaintInfo, childPoint);
2627 currentPaintInfo.phase = PaintPhaseOutline;
2628 r->renderer().paint(currentPaintInfo, childPoint);
2634 RenderInline* RenderBlock::inlineElementContinuation() const
2636 RenderBoxModelObject* continuation = this->continuation();
2637 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2640 RenderBlock* RenderBlock::blockElementContinuation() const
2642 RenderBoxModelObject* currentContinuation = continuation();
2643 if (!currentContinuation || currentContinuation->isInline())
2645 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2646 if (nextContinuation->isAnonymousBlock())
2647 return nextContinuation->blockElementContinuation();
2648 return nextContinuation;
2651 static ContinuationOutlineTableMap* continuationOutlineTable()
2653 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2657 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2659 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2661 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2663 ContinuationOutlineTableMap* table = continuationOutlineTable();
2664 ListHashSet<RenderInline*>* continuations = table->get(this);
2665 if (!continuations) {
2666 continuations = new ListHashSet<RenderInline*>;
2667 table->set(this, adoptPtr(continuations));
2670 continuations->add(flow);
2673 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2675 ContinuationOutlineTableMap* table = continuationOutlineTable();
2676 if (table->isEmpty())
2679 ListHashSet<RenderInline*>* continuations = table->get(this);
2683 return continuations->contains(flow);
2686 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2688 ContinuationOutlineTableMap* table = continuationOutlineTable();
2689 if (table->isEmpty())
2692 OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this);
2696 LayoutPoint accumulatedPaintOffset = paintOffset;
2697 // Paint each continuation outline.
2698 ListHashSet<RenderInline*>::iterator end = continuations->end();
2699 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2700 // Need to add in the coordinates of the intervening blocks.
2701 RenderInline* flow = *it;
2702 RenderBlock* block = flow->containingBlock();
2703 for ( ; block && block != this; block = block->containingBlock())
2704 accumulatedPaintOffset.moveBy(block->location());
2706 flow->paintOutline(info, accumulatedPaintOffset);
2710 bool RenderBlock::shouldPaintSelectionGaps() const
2712 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2715 bool RenderBlock::isSelectionRoot() const
2717 if (isPseudoElement())
2719 ASSERT(element() || isAnonymous());
2721 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2725 if (isBody() || isRoot() || hasOverflowClip()
2726 || isPositioned() || isFloating()
2727 || isTableCell() || isInlineBlockOrInlineTable()
2728 || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot()
2729 || isRenderFlowThread())
2732 if (view().selectionStart()) {
2733 Node* startElement = view().selectionStart()->node();
2734 if (startElement && startElement->rootEditableElement() == element())
2741 GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer)
2743 ASSERT(!needsLayout());
2745 if (!shouldPaintSelectionGaps())
2748 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2749 mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms);
2750 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
2752 if (hasOverflowClip())
2753 offsetFromRepaintContainer -= scrolledContentOffset();
2755 LogicalSelectionOffsetCaches cache(this);
2756 LayoutUnit lastTop = 0;
2757 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
2758 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
2760 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight, cache);
2763 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2765 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2766 LogicalSelectionOffsetCaches cache(this);
2767 LayoutUnit lastTop = 0;
2768 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
2769 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
2770 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2772 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, cache, &paintInfo);
2773 if (!gapRectsBounds.isEmpty()) {
2774 if (RenderLayer* layer = enclosingLayer()) {
2775 gapRectsBounds.moveBy(-paintOffset);
2777 LayoutRect localBounds(gapRectsBounds);
2778 flipForWritingMode(localBounds);
2779 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), &layer->renderer()).enclosingBoundingBox();
2780 if (layer->renderer().hasOverflowClip())
2781 gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
2783 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2789 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, TrackedRendererListHashSet* positionedObjects)
2791 if (!positionedObjects)
2794 TrackedRendererListHashSet::const_iterator end = positionedObjects->end();
2795 for (TrackedRendererListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2797 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2801 static LayoutUnit blockDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
2803 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
2806 static LayoutUnit inlineDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
2808 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
2811 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
2814 if (isHorizontalWritingMode())
2815 result = logicalRect;
2817 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2818 flipForWritingMode(result);
2819 result.moveBy(rootBlockPhysicalPosition);
2823 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2824 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
2826 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2827 // Clip out floating and positioned objects when painting selection gaps.
2829 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2830 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2831 rootBlock->flipForWritingMode(flippedBlockRect);
2832 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
2833 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects());
2834 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2835 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2836 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes.
2837 if (m_floatingObjects) {
2838 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2839 auto end = floatingObjectSet.end();
2840 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2841 FloatingObject* r = it->get();
2842 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
2843 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
2844 r->renderer().width(), r->renderer().height());
2845 rootBlock->flipForWritingMode(floatBox);
2846 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2847 paintInfo->context->clipOut(pixelSnappedIntRect(floatBox));
2852 // FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is
2855 if (!isRenderBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
2858 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2859 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2860 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2861 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
2862 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
2866 if (childrenInline())
2867 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
2869 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
2871 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2872 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) {
2873 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
2874 lastLogicalTop, lastLogicalLeft, lastLogicalRight, logicalHeight(), cache, paintInfo));
2880 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2881 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
2885 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
2887 if (!firstLineBox()) {
2888 if (containsStart) {
2889 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
2891 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2892 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
2893 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
2898 RootInlineBox* lastSelectedLine = 0;
2899 RootInlineBox* curr;
2900 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
2902 // Now paint the gaps for the lines.
2903 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
2904 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
2905 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
2907 if (!containsStart && !lastSelectedLine &&
2908 selectionState() != SelectionStart && selectionState() != SelectionBoth)
2909 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
2911 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
2912 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
2913 LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
2914 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
2915 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
2916 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
2918 lastSelectedLine = curr;
2921 if (containsStart && !lastSelectedLine)
2922 // VisibleSelection must start just after our last line.
2923 lastSelectedLine = lastRootBox();
2925 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
2926 // Go ahead and update our lastY to be the bottom of the last selected line.
2927 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
2928 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
2929 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
2934 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2935 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
2939 // Go ahead and jump right to the first block child that contains some selected objects.
2941 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2946 LogicalSelectionOffsetCaches childCache(this, cache);
2948 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2949 SelectionState childState = curr->selectionState();
2950 if (childState == SelectionBoth || childState == SelectionEnd)
2951 sawSelectionEnd = true;
2953 if (curr->isFloatingOrOutOfFlowPositioned())
2954 continue; // We must be a normal flow object in order to even be considered.
2956 if (curr->isInFlowPositioned() && curr->hasLayer()) {
2957 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2958 // Just disregard it completely.
2959 LayoutSize relOffset = curr->layer()->offsetForInFlowPosition();
2960 if (relOffset.width() || relOffset.height())
2964 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2965 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2966 if (fillBlockGaps) {
2967 // We need to fill the vertical gap above this object.
2968 if (childState == SelectionEnd || childState == SelectionInside) {
2969 // Fill the gap above the object.
2970 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
2971 lastLogicalTop, lastLogicalLeft, lastLogicalRight, curr->logicalTop(), cache, paintInfo));
2974 // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past*
2975 // our object. We know this if the selection did not end inside our object.
2976 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2977 childState = SelectionNone;
2979 // Fill side gaps on this object based off its state.
2980 bool leftGap, rightGap;
2981 getSelectionGapInfo(childState, leftGap, rightGap);
2984 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
2986 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
2988 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
2989 // they can without bumping into floating or positioned objects. Ideally they will go right up
2990 // to the border of the root selection block.
2991 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
2992 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom(), cache);
2993 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom(), cache);
2994 } else if (childState != SelectionNone) {
2995 // We must be a block that has some selected object inside it. Go ahead and recur.
2996 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
2997 lastLogicalTop, lastLogicalLeft, lastLogicalRight, childCache, paintInfo));
3003 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3004 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3006 LayoutUnit logicalTop = lastLogicalTop;
3007 LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
3008 if (logicalHeight <= 0)
3009 return LayoutRect();
3011 // Get the selection offsets for the bottom of the gap
3012 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom, cache));
3013 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom, cache));
3014 LayoutUnit logicalWidth = logicalRight - logicalLeft;
3015 if (logicalWidth <= 0)
3016 return LayoutRect();
3018 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
3020 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor(), style()->colorSpace());
3024 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3025 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3027 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3028 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
3029 LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft),
3030 min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
3031 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3032 if (rootBlockLogicalWidth <= 0)
3033 return LayoutRect();
3035 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3037 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3041 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3042 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3044 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3045 LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight),
3046 max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
3047 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
3048 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3049 if (rootBlockLogicalWidth <= 0)
3050 return LayoutRect();
3052 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3054 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3058 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3060 bool ltr = style()->isLeftToRightDirection();
3061 leftGap = (state == RenderObject::SelectionInside) ||
3062 (state == RenderObject::SelectionEnd && ltr) ||
3063 (state == RenderObject::SelectionStart && !ltr);
3064 rightGap = (state == RenderObject::SelectionInside) ||
3065 (state == RenderObject::SelectionStart && ltr) ||
3066 (state == RenderObject::SelectionEnd && !ltr);
3069 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
3071 LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
3072 if (logicalLeft == logicalLeftOffsetForContent()) {
3073 if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
3074 return cache.containingBlockInfo(this).logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3077 RenderBlock* cb = this;
3078 const LogicalSelectionOffsetCaches* currentCache = &cache;
3079 while (cb != rootBlock) {
3080 logicalLeft += cb->logicalLeft();
3082 ASSERT(currentCache);
3083 const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
3085 currentCache = info.cache();
3091 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
3093 LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
3094 if (logicalRight == logicalRightOffsetForContent()) {
3095 if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
3096 return cache.containingBlockInfo(this).logicalRightSelectionOffset(rootBlock, position + logicalTop());
3097 return logicalRight;
3099 RenderBlock* cb = this;
3100 const LogicalSelectionOffsetCaches* currentCache = &cache;
3101 while (cb != rootBlock) {
3102 logicalRight += cb->logicalLeft();
3104 ASSERT(currentCache);
3105 const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
3107 currentCache = info.cache();
3110 return logicalRight;
3113 RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
3115 if (isSelectionRoot())
3118 const RenderObject* object = this;
3119 RenderObject* sibling;
3121 sibling = object->previousSibling();
3122 while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot()))
3123 sibling = sibling->previousSibling();
3125 offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop());
3126 object = object->parent();
3127 } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot());
3132 RenderBlock* beforeBlock = toRenderBlock(sibling);
3134 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3136 RenderObject* child = beforeBlock->lastChild();
3137 while (child && child->isRenderBlock()) {
3138 beforeBlock = toRenderBlock(child);
3139 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3140 child = beforeBlock->lastChild();
3145 void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
3147 if (!descendantsMap) {
3148 descendantsMap = new TrackedDescendantsMap;
3149 containerMap = new TrackedContainerMap;
3152 TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
3153 if (!descendantSet) {
3154 descendantSet = new TrackedRendererListHashSet;
3155 descendantsMap->set(this, adoptPtr(descendantSet));
3157 bool added = descendantSet->add(descendant).isNewEntry;
3159 ASSERT(containerMap->get(descendant));
3160 ASSERT(containerMap->get(descendant)->contains(this));
3164 HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
3165 if (!containerSet) {
3166 containerSet = new HashSet<RenderBlock*>;
3167 containerMap->set(descendant, adoptPtr(containerSet));
3169 ASSERT(!containerSet->contains(this));
3170 containerSet->add(this);
3173 void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
3175 if (!descendantsMap)
3178 OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant);
3182 HashSet<RenderBlock*>::iterator end = containerSet->end();
3183 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
3184 RenderBlock* container = *it;
3186 // FIXME: Disabling this assert temporarily until we fix the layout
3187 // bugs associated with positioned objects not properly cleared from
3188 // their ancestor chain before being moved. See webkit bug 93766.
3189 // ASSERT(descendant->isDescendantOf(container));
3191 TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
3192 ASSERT(descendantsMapIterator != descendantsMap->end());
3193 if (descendantsMapIterator == descendantsMap->end())
3195 TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get();
3196 ASSERT(descendantSet->contains(descendant));
3197 descendantSet->remove(descendant);
3198 if (descendantSet->isEmpty())
3199 descendantsMap->remove(descendantsMapIterator);
3203 TrackedRendererListHashSet* RenderBlock::positionedObjects() const
3205 if (gPositionedDescendantsMap)
3206 return gPositionedDescendantsMap->get(this);
3210 void RenderBlock::insertPositionedObject(RenderBox* o)
3212 ASSERT(!isAnonymousBlock());
3214 if (o->isRenderFlowThread())
3217 insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
3220 void RenderBlock::removePositionedObject(RenderBox* o)
3222 removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
3225 void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState)
3227 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
3228 if (!positionedDescendants)
3233 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
3235 Vector<RenderBox*, 16> deadObjects;
3237 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
3239 if (!o || r->isDescendantOf(o)) {
3240 if (containingBlockState == NewContainingBlock)
3241 r->setChildNeedsLayout(true, MarkOnlyThis);
3243 // It is parent blocks job to add positioned child to positioned objects list of its containing block
3244 // Parent layout needs to be invalidated to ensure this happens.
3245 RenderObject* p = r->parent();
3246 while (p && !p->isRenderBlock())
3249 p->setChildNeedsLayout(true);
3251 deadObjects.append(r);
3255 for (unsigned i = 0; i < deadObjects.size(); i++)
3256 removePositionedObject(deadObjects.at(i));
3259 void RenderBlock::removeFloatingObjects()
3261 if (!m_floatingObjects)
3264 m_floatingObjects->clear();
3267 FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3269 ASSERT(o->isFloating());
3271 // Create the list of special objects if we don't aleady have one
3272 if (!m_floatingObjects)
3273 createFloatingObjects();
3275 // Don't insert the object again if it's already in the list
3276 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3277 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(*o);
3278 if (it != floatingObjectSet.end())
3282 // Create the special object entry & append it to the list
3284 std::unique_ptr<FloatingObject> object = FloatingObject::create(*o);
3286 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
3287 // Just go ahead and lay out the float.
3288 bool isChildRenderBlock = o->isRenderBlock();
3289 if (isChildRenderBlock && !o->needsLayout() && view().layoutState()->pageLogicalHeightChanged())
3290 o->setChildNeedsLayout(true, MarkOnlyThis);
3292 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
3293 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
3294 o->layoutIfNeeded();
3296 o->updateLogicalWidth();
3297 o->computeAndSetBlockDirectionMargins(this);
3300 object->setLogicalWidth(logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o), isHorizontalWritingMode());
3302 #if ENABLE(CSS_SHAPES)
3303 if (ShapeOutsideInfo* shapeOutside = o->shapeOutsideInfo())
3304 shapeOutside->setShapeSize(logicalWidthForChild(o), logicalHeightForChild(o));
3307 return m_floatingObjects->add(std::move(object));
3310 void RenderBlock::removeFloatingObject(RenderBox* o)
3312 if (m_floatingObjects) {
3313 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3314 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(*o);
3315 if (it != floatingObjectSet.end()) {
3316 FloatingObject* r = it->get();
3317 if (childrenInline()) {
3318 LayoutUnit logicalTop = r->logicalTop(isHorizontalWritingMode());
3319 LayoutUnit logicalBottom = r->logicalBottom(isHorizontalWritingMode());
3321 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
3322 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
3323 logicalBottom = LayoutUnit::max();
3325 // Special-case zero- and less-than-zero-height floats: those don't touch
3326 // the line that they're on, but it still needs to be dirtied. This is
3327 // accomplished by pretending they have a height of 1.
3328 logicalBottom = max(logicalBottom, logicalTop + 1);
3330 if (r->originatingLine()) {
3331 if (!selfNeedsLayout()) {
3332 ASSERT(&r->originatingLine()->renderer() == this);
3333 r->originatingLine()->markDirty();
3335 #if !ASSERT_DISABLED
3336 r->setOriginatingLine(0);
3339 markLinesDirtyInBlockRange(0, logicalBottom);
3341 m_floatingObjects->remove(r);
3346 void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
3348 if (!containsFloats())
3351 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3352 FloatingObject* curr = floatingObjectSet.last().get();
3353 while (curr != lastFloat && (!curr->isPlaced() || curr->logicalTop(isHorizontalWritingMode()) >= logicalOffset)) {
3354 m_floatingObjects->remove(curr);
3355 if (floatingObjectSet.isEmpty())
3357 curr = floatingObjectSet.last().get();
3361 LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
3363 RenderBox* childBox = &floatingObject->renderer();
3364 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3365 LayoutUnit logicalRightOffset; // Constant part of right offset.
3366 #if ENABLE(CSS_SHAPES)
3367 // FIXME Bug 102948: This only works for shape outside directly set on this block.
3368 ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
3369 // FIXME: Implement behavior for right floats.
3370 if (shapeInsideInfo) {
3371 LayoutSize floatLogicalSize = LayoutSize(floatingObject->logicalWidth(isHorizontalWritingMode()), floatingObject->logicalHeight(isHorizontalWritingMode()));
3372 // FIXME: If the float doesn't fit in the shape we should push it under the content box
3373 logicalTopOffset = shapeInsideInfo->computeFirstFitPositionForFloat(floatLogicalSize);
3374 if (logicalHeight() > logicalTopOffset)
3375 logicalTopOffset = logicalHeight();
3377 SegmentList segments = shapeInsideInfo->computeSegmentsForLine(logicalTopOffset, childBox->logicalHeight());
3378 // FIXME Bug 102949: Add support for shapes with multiple segments.
3379 if (segments.size() == 1) {
3380 // The segment offsets are relative to the content box.
3381 logicalRightOffset = logicalLeftOffset + segments[0].logicalRight;
3382 logicalLeftOffset += segments[0].logicalLeft;
3386 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset);
3388 LayoutUnit floatLogicalWidth = min(floatingObject->logicalWidth(isHorizontalWritingMode()), logicalRightOffset - logicalLeftOffset); // The width we look for.
3390 LayoutUnit floatLogicalLeft;
3392 bool insideFlowThread = flowThreadContainingBlock();
3394 if (childBox->style()->floating() == LeftFloat) {
3395 LayoutUnit heightRemainingLeft = 1;
3396 LayoutUnit heightRemainingRight = 1;
3397 floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3398 while (logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
3399 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3400 floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3401 if (insideFlowThread) {
3402 // Have to re-evaluate all of our offsets, since they may have changed.
3403 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3404 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3405 floatLogicalWidth = min(floatingObject->logicalWidth(isHorizontalWritingMode()), logicalRightOffset - logicalLeftOffset);
3408 floatLogicalLeft = max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
3410 LayoutUnit heightRemainingLeft = 1;
3411 LayoutUnit heightRemainingRight = 1;
3412 floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3413 while (floatLogicalLeft - logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
3414 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3415 floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3416 if (insideFlowThread) {
3417 // Have to re-evaluate all of our offsets, since they may have changed.
3418 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3419 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3420 floatLogicalWidth = min(floatingObject->logicalWidth(isHorizontalWritingMode()), logicalRightOffset - logicalLeftOffset);
3423 floatLogicalLeft -= floatingObject->logicalWidth(isHorizontalWritingMode()); // Use the original width of the float here, since the local variable
3424 // |floatLogicalWidth| was capped to the available line width.
3425 // See fast/block/float/clamped-right-float.html.
3428 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
3431 bool RenderBlock::positionNewFloats()
3433 if (!m_floatingObjects)
3436 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3437 if (floatingObjectSet.isEmpty())
3440 // If all floats have already been positioned, then we have no work to do.
3441 if (floatingObjectSet.last()->isPlaced())
3444 // Move backwards through our floating object list until we find a float that has
3445 // already been positioned. Then we'll be able to move forward, positioning all of
3446 // the new floats that need it.
3447 auto it = floatingObjectSet.end();
3448 --it; // Go to last item.
3449 auto begin = floatingObjectSet.begin();
3450 FloatingObject* lastPlacedFloatingObject = 0;
3451 while (it != begin) {
3453 if ((*it)->isPlaced()) {
3454 lastPlacedFloatingObject = it->get();
3460 LayoutUnit logicalTop = logicalHeight();
3462 // The float cannot start above the top position of the last positioned float.
3463 if (lastPlacedFloatingObject)
3464 logicalTop = max(lastPlacedFloatingObject->logicalTop(isHorizontalWritingMode()), logicalTop);
3466 auto end = floatingObjectSet.end();
3467 // Now walk through the set of unpositioned floats and place them.
3468 for (; it != end; ++it) {
3469 FloatingObject* floatingObject = it->get();
3470 // The containing block is responsible for positioning floats, so if we have floats in our
3471 // list that come from somewhere else, do not attempt to position them.
3472 if (floatingObject->renderer().containingBlock() != this)
3475 RenderBox* childBox = &floatingObject->renderer();
3477 LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
3479 LayoutRect oldRect = childBox->frameRect();
3481 if (childBox->style()->clear() & CLEFT)
3482 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
3483 if (childBox->style()->clear() & CRIGHT)
3484 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
3486 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
3488 floatingObject->setLogicalLeft(floatLogicalLocation.x(), isHorizontalWritingMode());
3490 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3491 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3493 estimateRegionRangeForBoxChild(childBox);
3495 LayoutState* layoutState = view().layoutState();
3496 bool isPaginated = layoutState->isPaginated();
3497 if (isPaginated && !childBox->needsLayout())
3498 childBox->markForPaginationRelayoutIfNeeded();
3500 childBox->layoutIfNeeded();
3503 // If we are unsplittable and don't fit, then we need to move down.
3504 // We include our margins as part of the unsplittable area.
3505 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
3507 // See if we have a pagination strut that is making us move down further.
3508 // Note that an unsplittable child can't also have a pagination strut, so this is
3509 // exclusive with the case above.
3510 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
3511 if (childBlock && childBlock->paginationStrut()) {
3512 newLogicalTop += childBlock->paginationStrut();
3513 childBlock->setPaginationStrut(0);
3516 if (newLogicalTop != floatLogicalLocation.y()) {
3517 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
3519 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
3520 floatingObject->setLogicalLeft(floatLogicalLocation.x(), isHorizontalWritingMode());
3522 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3523 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3526 childBlock->setChildNeedsLayout(true, MarkOnlyThis);
3527 childBox->layoutIfNeeded();
3530 if (updateRegionRangeForBoxChild(childBox)) {
3531 childBox->setNeedsLayout(true, MarkOnlyThis);
3532 childBox->layoutIfNeeded();
3536 floatingObject->setLogicalTop(floatLogicalLocation.y(), isHorizontalWritingMode());
3538 floatingObject->setLogicalHeight(logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox), isHorizontalWritingMode());
3540 m_floatingObjects->addPlacedObject(floatingObject);
3542 // If the child moved, we have to repaint it.
3543 if (childBox->checkForRepaintDuringLayout())
3544 childBox->repaintDuringLayoutIfMoved(oldRect);
3549 void RenderBlock::newLine(EClear clear)
3551 positionNewFloats();
3553 LayoutUnit newY = 0;
3557 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
3560 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
3563 newY = lowestFloatLogicalBottom();
3567 if (height() < newY)
3568 setLogicalHeight(newY);
3571 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
3573 insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
3576 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
3578 removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
3581 TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const
3583 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
3586 bool RenderBlock::hasPercentHeightContainerMap()
3588 return gPercentHeightContainerMap;
3591 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
3593 // We don't null check gPercentHeightContainerMap since the caller
3594 // already ensures this and we need to call this function on every
3595 // descendant in clearPercentHeightDescendantsFrom().
3596 ASSERT(gPercentHeightContainerMap);
3597 return gPercentHeightContainerMap->contains(descendant);
3600 void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant)
3602 // We query the map directly, rather than looking at style's
3603 // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
3604 // can change with writing mode/directional changes.
3605 if (!hasPercentHeightContainerMap())
3608 if (!hasPercentHeightDescendant(descendant))
3611 removePercentHeightDescendant(descendant);
3614 void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent)
3616 ASSERT(gPercentHeightContainerMap);
3617 for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) {
3621 RenderBox* box = toRenderBox(curr);
3622 if (!hasPercentHeightDescendant(box))
3625 removePercentHeightDescendant(box);
3629 LayoutUnit RenderBlock::textIndentOffset() const
3632 if (style()->textIndent().isPercent())
3633 cw = containingBlock()->availableLogicalWidth();
3634 return minimumValueForLength(style()->textIndent(), cw);
3637 LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const
3639 LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
3641 return logicalLeftOffset;
3642 LayoutRect boxRect = borderBoxRectInRegion(region);
3643 return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
3646 LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const
3648 LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
3649 logicalRightOffset += availableLogicalWidth();
3651 return logicalRightOffset;
3652 LayoutRect boxRect = borderBoxRectInRegion(region);
3653 return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
3656 LayoutUnit RenderBlock::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
3658 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
3659 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight, offsetMode, heightRemaining);
3664 LayoutUnit RenderBlock::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
3666 LayoutUnit left = offsetFromFloats;
3668 if (applyTextIndent && style()->isLeftToRightDirection())
3669 left += textIndentOffset();
3671 if (style()->lineAlign() == LineAlignNone)
3674 // Push in our left offset so that it is aligned with the character grid.
3675 LayoutState* layoutState = view().layoutState();
3679 RenderBlock* lineGrid = layoutState->lineGrid();
3680 if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
3683 // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
3684 float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
3688 LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
3689 LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
3691 // Push in to the nearest character width (truncated so that we pixel snap left).
3692 // FIXME: Should be patched when subpixel layout lands, since this calculation doesn't have to pixel snap
3693 // any more (https://bugs.webkit.org/show_bug.cgi?id=79946).
3694 // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
3695 // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
3696 // FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
3697 // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
3698 // (https://bugs.webkit.org/show_bug.cgi?id=79944)
3699 float remainder = fmodf(maxCharWidth - fmodf(left + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
3704 LayoutUnit RenderBlock::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
3706 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
3707 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight, offsetMode, heightRemaining);
3712 LayoutUnit RenderBlock::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
3714 LayoutUnit right = offsetFromFloats;
3716 if (applyTextIndent && !style()->isLeftToRightDirection())
3717 right -= textIndentOffset();
3719 if (style()->lineAlign() == LineAlignNone)
3722 // Push in our right offset so that it is aligned with the character grid.
3723 LayoutState* layoutState = view().layoutState();
3727 RenderBlock* lineGrid = layoutState->lineGrid();
3728 if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
3731 // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
3732 float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
3736 LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
3737 LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
3739 // Push in to the nearest character width (truncated so that we pixel snap right).
3740 // FIXME: Should be patched when subpixel layout lands, since this calculation doesn't have to pixel snap
3741 // any more (https://bugs.webkit.org/show_bug.cgi?id=79946).
3742 // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
3743 // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
3744 // FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
3745 // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
3746 // (https://bugs.webkit.org/show_bug.cgi?id=79944)
3747 float remainder = fmodf(fmodf(right + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
3748 right -= ceilf(remainder);
3752 LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
3754 if (!m_floatingObjects)
3755 return logicalHeight;
3757 LayoutUnit bottom = LayoutUnit::max();
3758 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3759 auto end = floatingObjectSet.end();
3760 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
3761 FloatingObject* r = it->get();
3762 LayoutUnit floatBottom;
3763 #if ENABLE(CSS_SHAPES)
3764 ShapeOutsideInfo* shapeOutside = r->renderer().shapeOutsideInfo();
3765 if (offsetMode == ShapeOutsideFloatShapeOffset && shapeOutside)
3766 floatBottom = r->logicalTop(isHorizontalWritingMode()) + marginBeforeForChild(&(r->renderer())) + shapeOutside->shapeLogicalBottom();
3769 floatBottom = r->logicalBottom(isHorizontalWritingMode());
3770 if (floatBottom > logicalHeight)
3771 bottom = min(floatBottom, bottom);
3774 return bottom == LayoutUnit::max() ? LayoutUnit() : bottom;
3777 LayoutUnit RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
3779 if (!m_floatingObjects)
3781 LayoutUnit lowestFloatBottom = 0;
3782 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3783 auto end = floatingObjectSet.end();
3784 for (auto it = floatingObjectSet.begin(); it != end; ++it) {