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 "ColumnInfo.h"
30 #include "FloatQuad.h"
32 #include "FrameSelection.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLNames.h"
37 #include "HitTestResult.h"
38 #include "InlineIterator.h"
39 #include "InlineTextBox.h"
40 #include "LayoutRepainter.h"
41 #include "PODFreeListArena.h"
43 #include "PaintInfo.h"
44 #include "RenderBoxRegionInfo.h"
45 #include "RenderCombineText.h"
46 #include "RenderDeprecatedFlexibleBox.h"
47 #include "RenderFlowThread.h"
48 #include "RenderImage.h"
49 #include "RenderInline.h"
50 #include "RenderLayer.h"
51 #include "RenderMarquee.h"
52 #include "RenderRegion.h"
53 #include "RenderReplica.h"
54 #include "RenderTableCell.h"
55 #include "RenderTextFragment.h"
56 #include "RenderTheme.h"
57 #include "RenderView.h"
59 #include "SVGTextRunRenderingContext.h"
60 #include "TransformState.h"
61 #include <wtf/StdLibExtras.h>
65 using namespace Unicode;
69 using namespace HTMLNames;
71 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
72 static ColumnInfoMap* gColumnInfoMap = 0;
74 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
75 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
77 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
78 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
80 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
82 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
83 static int gDelayUpdateScrollInfo = 0;
84 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
86 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
88 // Our MarginInfo state used when laying out block children.
89 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
90 : m_atBeforeSideOfBlock(true)
91 , m_atAfterSideOfBlock(false)
92 , m_marginBeforeQuirk(false)
93 , m_marginAfterQuirk(false)
94 , m_determinedMarginBeforeQuirk(false)
96 // Whether or not we can collapse our own margins with our children. We don't do this
97 // if we had any border/padding (obviously), if we're the root or HTML elements, or if
98 // we're positioned, floating, a table cell.
99 RenderStyle* blockStyle = block->style();
100 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned()
101 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
102 && !block->isWritingModeRoot() && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth()
103 && !blockStyle->columnSpan();
105 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
107 // If any height other than auto is specified in CSS, then we don't collapse our bottom
108 // margins with our children's margins. To do otherwise would be to risk odd visual
109 // effects when the children overflow out of the parent block and yet still collapse
110 // with it. We also don't collapse if we have any bottom border/padding.
111 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
112 (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
114 m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD
115 || blockStyle->marginAfterCollapse() == MDISCARD;
117 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0;
118 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0;
121 // -------------------------------------------------------------------------------------------------------
123 RenderBlock::RenderBlock(Node* node)
126 , m_beingDestroyed(false)
127 , m_hasPositionedFloats(false)
129 setChildrenInline(true);
132 RenderBlock::~RenderBlock()
134 if (m_floatingObjects)
135 deleteAllValues(m_floatingObjects->set());
138 delete gColumnInfoMap->take(this);
140 if (gPercentHeightDescendantsMap) {
141 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
142 HashSet<RenderBox*>::iterator end = descendantSet->end();
143 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
144 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
145 ASSERT(containerSet);
148 ASSERT(containerSet->contains(this));
149 containerSet->remove(this);
150 if (containerSet->isEmpty()) {
151 gPercentHeightContainerMap->remove(*descendant);
155 delete descendantSet;
160 void RenderBlock::willBeDestroyed()
162 // Mark as being destroyed to avoid trouble with merges in removeChild().
163 m_beingDestroyed = true;
165 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
166 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
167 children()->destroyLeftoverChildren();
169 // Destroy our continuation before anything other than anonymous children.
170 // The reason we don't destroy it before anonymous children is that they may
171 // have continuations of their own that are anonymous children of our continuation.
172 RenderBoxModelObject* continuation = this->continuation();
174 continuation->destroy();
178 if (!documentBeingDestroyed()) {
179 if (firstLineBox()) {
180 // We can't wait for RenderBox::destroy to clear the selection,
181 // because by then we will have nuked the line boxes.
182 // FIXME: The FrameSelection should be responsible for this when it
183 // is notified of DOM mutations.
184 if (isSelectionBorder())
185 view()->clearSelection();
187 // If we are an anonymous block, then our line boxes might have children
188 // that will outlast this block. In the non-anonymous block case those
189 // children will be destroyed by the time we return from this function.
190 if (isAnonymousBlock()) {
191 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
192 while (InlineBox* childBox = box->firstChild())
197 parent()->dirtyLinesFromChangedChild(this);
200 m_lineBoxes.deleteLineBoxes(renderArena());
203 lineGridBox()->destroy(renderArena());
205 if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
206 gDelayedUpdateScrollInfoSet->remove(this);
208 RenderBox::willBeDestroyed();
211 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
213 RenderStyle* oldStyle = style();
214 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrPositioned() && !avoidsFloats() : false;
216 setReplaced(newStyle->isDisplayInlineType());
218 if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
219 if (newStyle->position() == StaticPosition)
220 // Clear our positioned objects list. Our absolutely positioned descendants will be
221 // inserted into our containing block's positioned objects list during layout.
222 removePositionedObjects(0);
223 else if (oldStyle->position() == StaticPosition) {
224 // Remove our absolutely positioned descendants from their current containing block.
225 // They will be inserted into our positioned objects list during layout.
226 RenderObject* cb = parent();
227 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
228 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
229 cb = cb->containingBlock();
235 if (cb->isRenderBlock())
236 toRenderBlock(cb)->removePositionedObjects(this);
239 if (containsFloats() && !isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
240 markAllDescendantsWithFloatsForLayout();
243 RenderBox::styleWillChange(diff, newStyle);
246 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
248 RenderBox::styleDidChange(diff, oldStyle);
250 if (!isAnonymousBlock()) {
251 // Ensure that all of our continuation blocks pick up the new style.
252 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
253 RenderBoxModelObject* nextCont = currCont->continuation();
254 currCont->setContinuation(0);
255 currCont->setStyle(style());
256 currCont->setContinuation(nextCont);
260 propagateStyleToAnonymousChildren(true);
263 // Update pseudos for :before and :after now.
264 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
265 updateBeforeAfterContent(BEFORE);
266 updateBeforeAfterContent(AFTER);
269 // After our style changed, if we lose our ability to propagate floats into next sibling
270 // blocks, then we need to find the top most parent containing that overhanging float and
271 // then mark its descendants with floats for layout and clear all floats from its next
272 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
273 bool canPropagateFloatIntoSibling = !isFloatingOrPositioned() && !avoidsFloats();
274 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
275 RenderBlock* parentBlock = this;
276 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
277 FloatingObjectSetIterator end = floatingObjectSet.end();
279 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
280 if (curr->isRenderBlock()) {
281 RenderBlock* currBlock = toRenderBlock(curr);
283 if (currBlock->hasOverhangingFloats()) {
284 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
285 RenderBox* renderer = (*it)->renderer();
286 if (currBlock->hasOverhangingFloat(renderer)) {
287 parentBlock = currBlock;
295 parentBlock->markAllDescendantsWithFloatsForLayout();
296 parentBlock->markSiblingsWithFloatsForLayout();
300 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
302 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
303 if (parent() && parent()->createsAnonymousWrapper())
305 children()->updateBeforeAfterContent(this, pseudoId);
308 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
310 if (beforeChild && beforeChild->parent() == this)
313 RenderBlock* curr = toRenderBlock(continuation());
314 RenderBlock* nextToLast = this;
315 RenderBlock* last = this;
317 if (beforeChild && beforeChild->parent() == curr) {
318 if (curr->firstChild() == beforeChild)
325 curr = toRenderBlock(curr->continuation());
328 if (!beforeChild && !last->firstChild())
333 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
335 RenderBlock* flow = continuationBefore(beforeChild);
336 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
337 RenderBoxModelObject* beforeChildParent = 0;
339 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
341 RenderBoxModelObject* cont = flow->continuation();
343 beforeChildParent = cont;
345 beforeChildParent = flow;
348 if (newChild->isFloatingOrPositioned()) {
349 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
353 // A continuation always consists of two potential candidates: a block or an anonymous
354 // column span box holding column span children.
355 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
356 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
357 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
359 if (flow == beforeChildParent) {
360 flow->addChildIgnoringContinuation(newChild, beforeChild);
364 // The goal here is to match up if we can, so that we can coalesce and create the
365 // minimal # of continuations needed for the inline.
366 if (childIsNormal == bcpIsNormal) {
367 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
370 if (flowIsNormal == childIsNormal) {
371 flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
374 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
378 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
380 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
382 // The goal is to locate a suitable box in which to place our child.
383 RenderBlock* beforeChildParent = toRenderBlock(beforeChild && beforeChild->parent()->isRenderBlock() ? beforeChild->parent() : lastChild());
385 // If the new child is floating or positioned it can just go in that block.
386 if (newChild->isFloatingOrPositioned()) {
387 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
391 // See if the child can be placed in the box.
392 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
393 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
395 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
396 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
401 // Create a new block of the correct type.
402 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
403 children()->appendChildNode(this, newBox);
404 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
408 RenderObject* immediateChild = beforeChild;
409 bool isPreviousBlockViable = true;
410 while (immediateChild->parent() != this) {
411 if (isPreviousBlockViable)
412 isPreviousBlockViable = !immediateChild->previousSibling();
413 immediateChild = immediateChild->parent();
415 if (isPreviousBlockViable && immediateChild->previousSibling()) {
416 toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
420 // Split our anonymous blocks.
421 RenderObject* newBeforeChild = splitAnonymousBlocksAroundChild(beforeChild);
423 // Create a new anonymous box of the appropriate type.
424 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
425 children()->insertChildNode(this, newBox, newBeforeChild);
426 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
430 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
432 for (RenderObject* curr = this; curr; curr = curr->parent()) {
433 if (!curr->isRenderBlock() || curr->isFloatingOrPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
434 || curr->isInlineBlockOrInlineTable())
437 RenderBlock* currBlock = toRenderBlock(curr);
438 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
441 if (currBlock->isAnonymousColumnSpanBlock())
447 RenderBlock* RenderBlock::clone() const
449 RenderBlock* cloneBlock;
450 if (isAnonymousBlock()) {
451 cloneBlock = createAnonymousBlock();
452 cloneBlock->setChildrenInline(childrenInline());
455 cloneBlock = new (renderArena()) RenderBlock(node());
456 cloneBlock->setStyle(style());
458 // This takes care of setting the right value of childrenInline in case
459 // generated content is added to cloneBlock and 'this' does not have
460 // generated content added yet.
461 cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
466 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
467 RenderBlock* middleBlock,
468 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
470 // Create a clone of this inline.
471 RenderBlock* cloneBlock = clone();
472 if (!isAnonymousBlock())
473 cloneBlock->setContinuation(oldCont);
475 // Now take all of the children from beforeChild to the end and remove
476 // them from |this| and place them in the clone.
477 if (!beforeChild && isAfterContent(lastChild()))
478 beforeChild = lastChild();
479 moveChildrenTo(cloneBlock, beforeChild, 0, true);
481 // Hook |clone| up as the continuation of the middle block.
482 if (!cloneBlock->isAnonymousBlock())
483 middleBlock->setContinuation(cloneBlock);
485 // We have been reparented and are now under the fromBlock. We need
486 // to walk up our block parent chain until we hit the containing anonymous columns block.
487 // Once we hit the anonymous columns block we're done.
488 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
489 RenderBoxModelObject* currChild = this;
491 while (curr && curr != fromBlock) {
492 ASSERT(curr->isRenderBlock());
494 RenderBlock* blockCurr = toRenderBlock(curr);
496 // Create a new clone.
497 RenderBlock* cloneChild = cloneBlock;
498 cloneBlock = blockCurr->clone();
500 // Insert our child clone as the first child.
501 cloneBlock->addChildIgnoringContinuation(cloneChild, 0);
503 // Hook the clone up as a continuation of |curr|. Note we do encounter
504 // anonymous blocks possibly as we walk up the block chain. When we split an
505 // anonymous block, there's no need to do any continuation hookup, since we haven't
506 // actually split a real element.
507 if (!blockCurr->isAnonymousBlock()) {
508 oldCont = blockCurr->continuation();
509 blockCurr->setContinuation(cloneBlock);
510 cloneBlock->setContinuation(oldCont);
513 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
514 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
515 // content gets properly destroyed.
516 if (document()->usesBeforeAfterRules())
517 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
519 // Now we need to take all of the children starting from the first child
520 // *after* currChild and append them all to the clone.
521 blockCurr->moveChildrenTo(cloneBlock, currChild->nextSibling(), 0, true);
523 // Keep walking up the chain.
525 curr = toRenderBoxModelObject(curr->parent());
528 // Now we are at the columns block level. We need to put the clone into the toBlock.
529 toBlock->children()->appendChildNode(toBlock, cloneBlock);
531 // Now take all the children after currChild and remove them from the fromBlock
532 // and put them in the toBlock.
533 fromBlock->moveChildrenTo(toBlock, currChild->nextSibling(), 0, true);
536 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
537 RenderObject* newChild, RenderBoxModelObject* oldCont)
539 RenderBlock* pre = 0;
540 RenderBlock* block = containingColumnsBlock();
542 // Delete our line boxes before we do the inline split into continuations.
543 block->deleteLineBoxTree();
545 bool madeNewBeforeBlock = false;
546 if (block->isAnonymousColumnsBlock()) {
547 // We can reuse this block and make it the preBlock of the next continuation.
549 pre->removePositionedObjects(0);
550 block = toRenderBlock(block->parent());
552 // No anonymous block available for use. Make one.
553 pre = block->createAnonymousColumnsBlock();
554 pre->setChildrenInline(false);
555 madeNewBeforeBlock = true;
558 RenderBlock* post = block->createAnonymousColumnsBlock();
559 post->setChildrenInline(false);
561 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
562 if (madeNewBeforeBlock)
563 block->children()->insertChildNode(block, pre, boxFirst);
564 block->children()->insertChildNode(block, newBlockBox, boxFirst);
565 block->children()->insertChildNode(block, post, boxFirst);
566 block->setChildrenInline(false);
568 if (madeNewBeforeBlock)
569 block->moveChildrenTo(pre, boxFirst, 0, true);
571 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
573 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
574 // time in makeChildrenNonInline by just setting this explicitly up front.
575 newBlockBox->setChildrenInline(false);
577 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
578 // connected, thus allowing newChild access to a renderArena should it need
579 // to wrap itself in additional boxes (e.g., table construction).
580 newBlockBox->addChild(newChild);
582 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
583 // get deleted properly. Because objects moves from the pre block into the post block, we want to
584 // make new line boxes instead of leaving the old line boxes around.
585 pre->setNeedsLayoutAndPrefWidthsRecalc();
586 block->setNeedsLayoutAndPrefWidthsRecalc();
587 post->setNeedsLayoutAndPrefWidthsRecalc();
590 RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild)
592 while (beforeChild->parent() != this) {
593 RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent());
594 if (blockToSplit->firstChild() != beforeChild) {
595 // We have to split the parentBlock into two blocks.
596 RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit);
597 post->setChildrenInline(blockToSplit->childrenInline());
598 RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent());
599 parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling());
600 blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer());
601 post->setNeedsLayoutAndPrefWidthsRecalc();
602 blockToSplit->setNeedsLayoutAndPrefWidthsRecalc();
605 beforeChild = blockToSplit;
610 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
612 RenderBlock* pre = 0;
613 RenderBlock* post = 0;
614 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
615 // so that we don't have to patch all of the rest of the code later on.
617 // Delete the block's line boxes before we do the split.
618 block->deleteLineBoxTree();
620 if (beforeChild && beforeChild->parent() != this)
621 beforeChild = splitAnonymousBlocksAroundChild(beforeChild);
623 if (beforeChild != firstChild()) {
624 pre = block->createAnonymousColumnsBlock();
625 pre->setChildrenInline(block->childrenInline());
629 post = block->createAnonymousColumnsBlock();
630 post->setChildrenInline(block->childrenInline());
633 RenderObject* boxFirst = block->firstChild();
635 block->children()->insertChildNode(block, pre, boxFirst);
636 block->children()->insertChildNode(block, newBlockBox, boxFirst);
638 block->children()->insertChildNode(block, post, boxFirst);
639 block->setChildrenInline(false);
641 // 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).
642 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
643 block->moveChildrenTo(post, beforeChild, 0, true);
645 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
646 // time in makeChildrenNonInline by just setting this explicitly up front.
647 newBlockBox->setChildrenInline(false);
649 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
650 // connected, thus allowing newChild access to a renderArena should it need
651 // to wrap itself in additional boxes (e.g., table construction).
652 newBlockBox->addChild(newChild);
654 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
655 // get deleted properly. Because objects moved from the pre block into the post block, we want to
656 // make new line boxes instead of leaving the old line boxes around.
658 pre->setNeedsLayoutAndPrefWidthsRecalc();
659 block->setNeedsLayoutAndPrefWidthsRecalc();
661 post->setNeedsLayoutAndPrefWidthsRecalc();
664 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
666 // FIXME: This function is the gateway for the addition of column-span support. It will
667 // be added to in three stages:
668 // (1) Immediate children of a multi-column block can span.
669 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
670 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
671 // cross the streams and have to cope with both types of continuations mixed together).
672 // This function currently supports (1) and (2).
673 RenderBlock* columnsBlockAncestor = 0;
674 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent()
675 && !newChild->isFloatingOrPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
676 if (style()->specifiesColumns())
677 columnsBlockAncestor = this;
678 else if (!isInline() && parent() && parent()->isRenderBlock()) {
679 columnsBlockAncestor = toRenderBlock(parent())->containingColumnsBlock(false);
681 if (columnsBlockAncestor) {
682 // Make sure that none of the parent ancestors have a continuation.
683 // If yes, we do not want split the block into continuations.
684 RenderObject* curr = this;
685 while (curr && curr != columnsBlockAncestor) {
686 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
687 columnsBlockAncestor = 0;
690 curr = curr->parent();
695 return columnsBlockAncestor;
698 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
700 // Make sure we don't append things after :after-generated content if we have it.
702 beforeChild = afterPseudoElementRenderer();
704 // If the requested beforeChild is not one of our children, then this is because
705 // there is an anonymous container within this object that contains the beforeChild.
706 if (beforeChild && beforeChild->parent() != this) {
707 RenderObject* beforeChildAnonymousContainer = anonymousContainer(beforeChild);
708 ASSERT(beforeChildAnonymousContainer);
709 ASSERT(beforeChildAnonymousContainer->isAnonymous());
711 if (beforeChildAnonymousContainer->isAnonymousBlock()) {
712 // Insert the child into the anonymous block box instead of here.
713 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
714 beforeChild->parent()->addChild(newChild, beforeChild);
716 addChild(newChild, beforeChild->parent());
720 ASSERT(beforeChildAnonymousContainer->isTable());
721 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
722 || (newChild->isTableCaption())
723 || newChild->isTableSection()
724 || newChild->isTableRow()
725 || newChild->isTableCell()) {
726 // Insert into the anonymous table.
727 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
731 // Go on to insert before the anonymous table.
732 beforeChild = beforeChildAnonymousContainer;
735 // Check for a spanning element in columns.
736 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
737 if (columnsBlockAncestor) {
738 // We are placing a column-span element inside a block.
739 RenderBlock* newBox = createAnonymousColumnSpanBlock();
741 if (columnsBlockAncestor != this) {
742 // We are nested inside a multi-column element and are being split by the span. We have to break up
743 // our block into continuations.
744 RenderBoxModelObject* oldContinuation = continuation();
745 setContinuation(newBox);
747 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
748 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
749 // content gets properly destroyed.
750 bool isLastChild = (beforeChild == lastChild());
751 if (document()->usesBeforeAfterRules())
752 children()->updateBeforeAfterContent(this, AFTER);
753 if (isLastChild && beforeChild != lastChild())
754 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
755 // point to be 0. It's just a straight append now.
757 splitFlow(beforeChild, newBox, newChild, oldContinuation);
761 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
762 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
763 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
764 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
768 bool madeBoxesNonInline = false;
770 // A block has to either have all of its children inline, or all of its children as blocks.
771 // So, if our children are currently inline and a block child has to be inserted, we move all our
772 // inline children into anonymous block boxes.
773 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
774 // This is a block with inline content. Wrap the inline content in anonymous blocks.
775 makeChildrenNonInline(beforeChild);
776 madeBoxesNonInline = true;
778 if (beforeChild && beforeChild->parent() != this) {
779 beforeChild = beforeChild->parent();
780 ASSERT(beforeChild->isAnonymousBlock());
781 ASSERT(beforeChild->parent() == this);
783 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
784 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
785 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
786 // a new one is created and inserted into our list of children in the appropriate position.
787 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
789 if (afterChild && afterChild->isAnonymousBlock()) {
790 afterChild->addChild(newChild);
794 if (newChild->isInline()) {
795 // No suitable existing anonymous box - create a new one.
796 RenderBlock* newBox = createAnonymousBlock();
797 RenderBox::addChild(newBox, beforeChild);
798 newBox->addChild(newChild);
803 RenderBox::addChild(newChild, beforeChild);
805 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
806 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
807 // this object may be dead here
810 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
812 if (continuation() && !isAnonymousBlock())
813 addChildToContinuation(newChild, beforeChild);
815 addChildIgnoringContinuation(newChild, beforeChild);
818 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
820 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
821 addChildToAnonymousColumnBlocks(newChild, beforeChild);
823 addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
826 static void getInlineRun(RenderObject* start, RenderObject* boundary,
827 RenderObject*& inlineRunStart,
828 RenderObject*& inlineRunEnd)
830 // Beginning at |start| we find the largest contiguous run of inlines that
831 // we can. We denote the run with start and end points, |inlineRunStart|
832 // and |inlineRunEnd|. Note that these two values may be the same if
833 // we encounter only one inline.
835 // We skip any non-inlines we encounter as long as we haven't found any
838 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
839 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
842 // Start by skipping as many non-inlines as we can.
843 RenderObject * curr = start;
846 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
847 curr = curr->nextSibling();
849 inlineRunStart = inlineRunEnd = curr;
852 return; // No more inline children to be found.
854 sawInline = curr->isInline();
856 curr = curr->nextSibling();
857 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
859 if (curr->isInline())
861 curr = curr->nextSibling();
863 } while (!sawInline);
866 void RenderBlock::deleteLineBoxTree()
868 if (containsFloats()) {
869 // Clear references to originating lines, since the lines are being deleted
870 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
871 FloatingObjectSetIterator end = floatingObjectSet.end();
872 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
873 ASSERT(!((*it)->m_originatingLine) || (*it)->m_originatingLine->renderer() == this);
874 (*it)->m_originatingLine = 0;
877 m_lineBoxes.deleteLineBoxTree(renderArena());
880 RootInlineBox* RenderBlock::createRootInlineBox()
882 return new (renderArena()) RootInlineBox(this);
885 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
887 RootInlineBox* rootBox = createRootInlineBox();
888 m_lineBoxes.appendLineBox(rootBox);
892 void RenderBlock::moveChildTo(RenderBlock* toBlock, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
894 ASSERT(this == child->parent());
895 ASSERT(!beforeChild || toBlock == beforeChild->parent());
896 if (fullRemoveInsert) {
897 // Takes care of adding the new child correctly if toBlock and fromBlock
898 // have different kind of children (block vs inline).
899 toBlock->addChildIgnoringContinuation(children()->removeChildNode(this, child), beforeChild);
901 toBlock->children()->insertChildNode(toBlock, children()->removeChildNode(this, child, false), beforeChild, false);
904 void RenderBlock::moveChildrenTo(RenderBlock* toBlock, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
906 ASSERT(!beforeChild || toBlock == beforeChild->parent());
907 RenderObject* nextChild = startChild;
908 while (nextChild && nextChild != endChild) {
909 RenderObject* child = nextChild;
910 nextChild = child->nextSibling();
911 if (fullRemoveInsert) {
912 // Takes care of adding the new child correctly if toBlock and fromBlock
913 // have different kind of children (block vs inline).
914 toBlock->addChildIgnoringContinuation(children()->removeChildNode(this, child), beforeChild);
916 toBlock->children()->insertChildNode(toBlock, children()->removeChildNode(this, child, false), beforeChild, false);
917 if (child == endChild)
922 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
924 // makeChildrenNonInline takes a block whose children are *all* inline and it
925 // makes sure that inline children are coalesced under anonymous
926 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
927 // the new block child that is causing us to have to wrap all the inlines. This
928 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
929 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
931 ASSERT(isInlineBlockOrInlineTable() || !isInline());
932 ASSERT(!insertionPoint || insertionPoint->parent() == this);
934 setChildrenInline(false);
936 RenderObject *child = firstChild();
943 RenderObject *inlineRunStart, *inlineRunEnd;
944 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
949 child = inlineRunEnd->nextSibling();
951 RenderBlock* block = createAnonymousBlock();
952 children()->insertChildNode(this, block, inlineRunStart);
953 moveChildrenTo(block, inlineRunStart, child);
957 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
958 ASSERT(!c->isInline());
964 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
966 ASSERT(child->isAnonymousBlock());
967 ASSERT(!child->childrenInline());
969 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
972 RenderObject* firstAnChild = child->m_children.firstChild();
973 RenderObject* lastAnChild = child->m_children.lastChild();
975 RenderObject* o = firstAnChild;
978 o = o->nextSibling();
980 firstAnChild->setPreviousSibling(child->previousSibling());
981 lastAnChild->setNextSibling(child->nextSibling());
982 if (child->previousSibling())
983 child->previousSibling()->setNextSibling(firstAnChild);
984 if (child->nextSibling())
985 child->nextSibling()->setPreviousSibling(lastAnChild);
987 if (child == m_children.firstChild())
988 m_children.setFirstChild(firstAnChild);
989 if (child == m_children.lastChild())
990 m_children.setLastChild(lastAnChild);
992 if (child == m_children.firstChild())
993 m_children.setFirstChild(child->nextSibling());
994 if (child == m_children.lastChild())
995 m_children.setLastChild(child->previousSibling());
997 if (child->previousSibling())
998 child->previousSibling()->setNextSibling(child->nextSibling());
999 if (child->nextSibling())
1000 child->nextSibling()->setPreviousSibling(child->previousSibling());
1002 child->setParent(0);
1003 child->setPreviousSibling(0);
1004 child->setNextSibling(0);
1006 child->children()->setFirstChild(0);
1012 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
1014 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
1017 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
1018 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
1021 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
1022 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
1025 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
1026 || (next && (next->isRubyRun() || next->isRubyBase())))
1032 // Make sure the types of the anonymous blocks match up.
1033 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1034 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1037 void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* child)
1039 parent->setNeedsLayoutAndPrefWidthsRecalc();
1040 parent->setChildrenInline(child->childrenInline());
1041 RenderObject* nextSibling = child->nextSibling();
1043 RenderFlowThread* childFlowThread = child->enclosingRenderFlowThread();
1044 RenderBlock* anonBlock = toRenderBlock(parent->children()->removeChildNode(parent, child, child->hasLayer()));
1045 anonBlock->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
1046 // Delete the now-empty block's lines and nuke it.
1047 if (!parent->documentBeingDestroyed())
1048 anonBlock->deleteLineBoxTree();
1049 if (childFlowThread && !parent->documentBeingDestroyed())
1050 childFlowThread->removeFlowChildInfo(anonBlock);
1051 anonBlock->destroy();
1054 void RenderBlock::removeChild(RenderObject* oldChild)
1056 // If this child is a block, and if our previous and next siblings are
1057 // both anonymous blocks with inline content, then we can go ahead and
1058 // fold the inline content back together.
1059 RenderObject* prev = oldChild->previousSibling();
1060 RenderObject* next = oldChild->nextSibling();
1061 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1062 if (canMergeAnonymousBlocks && prev && next) {
1063 prev->setNeedsLayoutAndPrefWidthsRecalc();
1064 RenderBlock* nextBlock = toRenderBlock(next);
1065 RenderBlock* prevBlock = toRenderBlock(prev);
1067 if (prev->childrenInline() != next->childrenInline()) {
1068 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1069 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1071 // Place the inline children block inside of the block children block instead of deleting it.
1072 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1073 // to clear out inherited column properties by just making a new style, and to also clear the
1074 // column span flag if it is set.
1075 ASSERT(!inlineChildrenBlock->continuation());
1076 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
1077 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
1078 inlineChildrenBlock->setStyle(newStyle);
1080 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1081 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1082 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer());
1083 next->setNeedsLayoutAndPrefWidthsRecalc();
1085 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1086 // of "this". we null out prev or next so that is not used later in the function.
1087 if (inlineChildrenBlock == prevBlock)
1092 // Take all the children out of the |next| block and put them in
1093 // the |prev| block.
1094 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1096 // Delete the now-empty block's lines and nuke it.
1097 nextBlock->deleteLineBoxTree();
1098 nextBlock->destroy();
1103 RenderBox::removeChild(oldChild);
1105 RenderObject* child = prev ? prev : next;
1106 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBoxIncludingDeprecated()) {
1107 // The removal has knocked us down to containing only a single anonymous
1108 // box. We can go ahead and pull the content right back up into our
1110 collapseAnonymousBoxChild(this, child);
1111 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && !isFlexibleBoxIncludingDeprecated()) {
1112 // It's possible that the removal has knocked us down to a single anonymous
1113 // block with pseudo-style element siblings (e.g. first-letter). If these
1114 // are floating, then we need to pull the content up also.
1115 RenderBlock* anonBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1116 if ((anonBlock->previousSibling() || anonBlock->nextSibling())
1117 && (!anonBlock->previousSibling() || (anonBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonBlock->previousSibling()->isFloating()))
1118 && (!anonBlock->nextSibling() || (anonBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonBlock->nextSibling()->isFloating()))) {
1119 collapseAnonymousBoxChild(this, anonBlock);
1123 if (!firstChild() && !documentBeingDestroyed()) {
1124 // If this was our last child be sure to clear out our line boxes.
1125 if (childrenInline())
1126 deleteLineBoxTree();
1130 bool RenderBlock::isSelfCollapsingBlock() const
1132 // We are not self-collapsing if we
1133 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1135 // (c) have border/padding,
1136 // (d) have a min-height
1137 // (e) have specified that one of our margins can't collapse using a CSS extension
1138 if (logicalHeight() > 0
1139 || isTable() || borderAndPaddingLogicalHeight()
1140 || style()->logicalMinHeight().isPositive()
1141 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1144 Length logicalHeightLength = style()->logicalHeight();
1145 bool hasAutoHeight = logicalHeightLength.isAuto();
1146 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1147 hasAutoHeight = true;
1148 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1149 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1150 hasAutoHeight = false;
1154 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1155 // on whether we have content that is all self-collapsing or not.
1156 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1157 // If the block has inline children, see if we generated any line boxes. If we have any
1158 // line boxes, then we can't be self-collapsing, since we have content.
1159 if (childrenInline())
1160 return !firstLineBox();
1162 // Whether or not we collapse is dependent on whether all our normal flow children
1163 // are also self-collapsing.
1164 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1165 if (child->isFloatingOrPositioned())
1167 if (!child->isSelfCollapsingBlock())
1175 void RenderBlock::startDelayUpdateScrollInfo()
1177 if (gDelayUpdateScrollInfo == 0) {
1178 ASSERT(!gDelayedUpdateScrollInfoSet);
1179 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1181 ASSERT(gDelayedUpdateScrollInfoSet);
1182 ++gDelayUpdateScrollInfo;
1185 void RenderBlock::finishDelayUpdateScrollInfo()
1187 --gDelayUpdateScrollInfo;
1188 ASSERT(gDelayUpdateScrollInfo >= 0);
1189 if (gDelayUpdateScrollInfo == 0) {
1190 ASSERT(gDelayedUpdateScrollInfoSet);
1192 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1193 gDelayedUpdateScrollInfoSet = 0;
1195 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1196 RenderBlock* block = *it;
1197 if (block->hasOverflowClip()) {
1198 block->layer()->updateScrollInfoAfterLayout();
1204 void RenderBlock::updateScrollInfoAfterLayout()
1206 if (hasOverflowClip()) {
1207 if (gDelayUpdateScrollInfo)
1208 gDelayedUpdateScrollInfoSet->add(this);
1210 layer()->updateScrollInfoAfterLayout();
1214 void RenderBlock::layout()
1216 // Update our first letter info now.
1217 updateFirstLetter();
1219 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1223 // It's safe to check for control clip here, since controls can never be table cells.
1224 // If we have a lightweight clip, there can never be any overflow from children.
1225 if (hasControlClip() && m_overflow)
1226 clearLayoutOverflow();
1229 void RenderBlock::computeInitialRegionRangeForBlock()
1231 if (inRenderFlowThread()) {
1232 // Set our start and end regions. No regions above or below us will be considered by our children. They are
1233 // effectively clamped to our region range.
1234 LayoutUnit oldHeight = logicalHeight();
1235 LayoutUnit oldLogicalTop = logicalTop();
1236 setLogicalHeight(numeric_limits<LayoutUnit>::max() / 2);
1237 computeLogicalHeight();
1238 enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1239 setLogicalHeight(oldHeight);
1240 setLogicalTop(oldLogicalTop);
1244 void RenderBlock::computeRegionRangeForBlock()
1246 if (inRenderFlowThread())
1247 enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1250 void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight, BlockLayoutPass layoutPass)
1252 ASSERT(needsLayout());
1254 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1255 return; // cause us to come in here. Just bail.
1257 if (!relayoutChildren && simplifiedLayout())
1260 LayoutRepainter repainter(*this, everHadLayout() && checkForRepaintDuringLayout());
1262 LayoutUnit oldWidth = logicalWidth();
1263 LayoutUnit oldColumnWidth = desiredColumnWidth();
1265 computeLogicalWidth();
1270 if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth())
1271 relayoutChildren = true;
1273 // If nothing changed about our floating positioned objects, let's go ahead and try to place them as
1274 // floats to avoid doing two passes.
1275 BlockLayoutPass floatsLayoutPass = layoutPass;
1276 if (floatsLayoutPass == NormalLayoutPass && !relayoutChildren && !positionedFloatsNeedRelayout())
1277 floatsLayoutPass = PositionedFloatLayoutPass;
1278 clearFloats(floatsLayoutPass);
1280 LayoutUnit previousHeight = logicalHeight();
1281 setLogicalHeight(0);
1282 bool hasSpecifiedPageLogicalHeight = false;
1283 bool pageLogicalHeightChanged = false;
1284 ColumnInfo* colInfo = columnInfo();
1286 if (!pageLogicalHeight) {
1287 // We need to go ahead and set our explicit page height if one exists, so that we can
1288 // avoid doing two layout passes.
1289 computeLogicalHeight();
1290 LayoutUnit columnHeight = contentLogicalHeight();
1291 if (columnHeight > 0) {
1292 pageLogicalHeight = columnHeight;
1293 hasSpecifiedPageLogicalHeight = true;
1295 setLogicalHeight(0);
1297 if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
1298 colInfo->setColumnHeight(pageLogicalHeight);
1299 pageLogicalHeightChanged = true;
1302 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1303 colInfo->clearForcedBreaks();
1305 colInfo->setPaginationUnit(paginationUnit());
1308 RenderView* renderView = view();
1309 RenderStyle* styleToUse = style();
1310 LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, colInfo);
1312 if (inRenderFlowThread()) {
1313 // Regions changing widths can force us to relayout our children.
1314 if (logicalWidthChangedInRegions())
1315 relayoutChildren = true;
1317 computeInitialRegionRangeForBlock();
1319 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1320 // our current maximal positive and negative margins. These values are used when we
1321 // are collapsed with adjacent blocks, so for example, if you have block A and B
1322 // collapsing together, then you'd take the maximal positive margin from both A and B
1323 // and subtract it from the maximal negative margin from both A and B to get the
1324 // true collapsed margin. This algorithm is recursive, so when we finish layout()
1325 // our block knows its current maximal positive/negative values.
1327 // Start out by setting our margin values to our current margins. Table cells have
1328 // no margins, so we don't fill in the values for table cells.
1329 bool isCell = isTableCell();
1331 initMaxMarginValues();
1333 setMarginBeforeQuirk(styleToUse->marginBefore().quirk());
1334 setMarginAfterQuirk(styleToUse->marginAfter().quirk());
1337 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
1338 // See if this form is malformed (i.e., unclosed). If so, don't give the form
1340 setMaxMarginAfterValues(0, 0);
1343 setPaginationStrut(0);
1346 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
1347 if (scrollsOverflow() && style()->appearance() != ListboxPart) {
1348 if (styleToUse->overflowX() == OSCROLL)
1349 layer()->setHasHorizontalScrollbar(true);
1350 if (styleToUse->overflowY() == OSCROLL)
1351 layer()->setHasVerticalScrollbar(true);
1354 LayoutUnit repaintLogicalTop = 0;
1355 LayoutUnit repaintLogicalBottom = 0;
1356 LayoutUnit maxFloatLogicalBottom = 0;
1357 if (!firstChild() && !isAnonymousBlock())
1358 setChildrenInline(true);
1359 if (childrenInline())
1360 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1362 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1364 // Expand our intrinsic height to encompass floats.
1365 LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1366 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1367 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1369 if (layoutColumns(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1372 // Calculate our new height.
1373 LayoutUnit oldHeight = logicalHeight();
1374 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
1375 computeLogicalHeight();
1376 LayoutUnit newHeight = logicalHeight();
1377 if (oldHeight != newHeight) {
1378 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1379 // One of our children's floats may have become an overhanging float for us. We need to look for it.
1380 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1381 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
1382 RenderBlock* block = toRenderBlock(child);
1383 if (block->lowestFloatLogicalBottomIncludingPositionedFloats() + block->logicalTop() > newHeight)
1384 addOverhangingFloats(block, false);
1390 if (previousHeight != newHeight)
1391 relayoutChildren = true;
1393 bool needAnotherLayoutPass = layoutPositionedObjects(relayoutChildren || isRoot());
1395 computeRegionRangeForBlock();
1397 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1398 computeOverflow(oldClientAfterEdge);
1402 if (renderView->layoutState()->m_pageLogicalHeight)
1403 setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(logicalTop()));
1405 updateLayerTransform();
1407 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1408 // we overflow or not.
1409 updateScrollInfoAfterLayout();
1411 // FIXME: This repaint logic should be moved into a separate helper function!
1412 // Repaint with our new bounds if they are different from our old bounds.
1413 bool didFullRepaint = repainter.repaintAfterLayout();
1414 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1415 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1416 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1417 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
1418 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
1419 if (hasOverflowClip()) {
1420 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
1421 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
1422 // layoutInlineChildren should be patched to compute the entire repaint rect.
1423 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1424 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1427 LayoutRect repaintRect;
1428 if (isHorizontalWritingMode())
1429 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1431 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1433 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1434 adjustRectForColumns(repaintRect);
1436 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1438 if (hasOverflowClip()) {
1439 // Adjust repaint rect for scroll offset
1440 repaintRect.move(-layer()->scrolledContentOffset());
1442 // Don't allow this rect to spill out of our overflow box.
1443 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
1446 // Make sure the rect is still non-empty after intersecting for overflow above
1447 if (!repaintRect.isEmpty()) {
1448 // FIXME: Might need rounding once we switch to float, see https://bugs.webkit.org/show_bug.cgi?id=64021
1449 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1450 if (hasReflection())
1451 repaintRectangle(reflectedRect(repaintRect));
1455 if (needAnotherLayoutPass && layoutPass == NormalLayoutPass) {
1456 setChildNeedsLayout(true, false);
1457 layoutBlock(false, pageLogicalHeight, PositionedFloatLayoutPass);
1459 setNeedsLayout(false);
1462 void RenderBlock::addOverflowFromChildren()
1464 if (!hasColumns()) {
1465 if (childrenInline())
1466 addOverflowFromInlineChildren();
1468 addOverflowFromBlockChildren();
1470 ColumnInfo* colInfo = columnInfo();
1471 if (columnCount(colInfo)) {
1472 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1473 addLayoutOverflow(lastRect);
1474 if (!hasOverflowClip())
1475 addVisualOverflow(lastRect);
1480 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
1482 // Add overflow from children.
1483 addOverflowFromChildren();
1485 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1486 addOverflowFromFloats();
1488 // Add in the overflow from positioned objects.
1489 addOverflowFromPositionedObjects();
1491 if (hasOverflowClip()) {
1492 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1493 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1494 // be considered reachable.
1495 LayoutRect clientRect(clientBoxRect());
1496 LayoutRect rectToApply;
1497 if (isHorizontalWritingMode())
1498 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1500 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1501 addLayoutOverflow(rectToApply);
1504 // Add visual overflow from box-shadow and border-image-outset.
1505 addVisualEffectOverflow();
1507 // Add visual overflow from theme.
1508 addVisualOverflowFromTheme();
1511 void RenderBlock::addOverflowFromBlockChildren()
1513 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1514 if (!child->isFloatingOrPositioned())
1515 addOverflowFromChild(child);
1519 void RenderBlock::addOverflowFromFloats()
1521 if (!m_floatingObjects)
1524 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1525 FloatingObjectSetIterator end = floatingObjectSet.end();
1526 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1527 FloatingObject* r = *it;
1528 if (r->m_isDescendant && !r->m_renderer->isPositioned())
1529 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1534 void RenderBlock::addOverflowFromPositionedObjects()
1536 if (!m_positionedObjects)
1539 RenderBox* positionedObject;
1540 Iterator end = m_positionedObjects->end();
1541 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1542 positionedObject = *it;
1544 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1545 if (positionedObject->style()->position() != FixedPosition)
1546 addOverflowFromChild(positionedObject);
1550 void RenderBlock::addVisualOverflowFromTheme()
1552 if (!style()->hasAppearance())
1555 IntRect inflatedRect = borderBoxRect();
1556 theme()->adjustRepaintRect(this, inflatedRect);
1557 addVisualOverflow(inflatedRect);
1560 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1562 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
1563 || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
1566 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1568 bool isHorizontal = isHorizontalWritingMode();
1569 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1571 LayoutUnit logicalTop = logicalHeight();
1572 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
1574 if (!marginInfo.canCollapseWithMarginBefore()) {
1575 child->computeBlockDirectionMargins(this);
1576 LayoutUnit marginBefore = marginBeforeForChild(child);
1577 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
1578 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
1579 if (marginBefore > 0) {
1580 if (marginBefore > collapsedBeforePos)
1581 collapsedBeforePos = marginBefore;
1583 if (-marginBefore > collapsedBeforeNeg)
1584 collapsedBeforeNeg = -marginBefore;
1586 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
1589 RenderLayer* childLayer = child->layer();
1590 if (childLayer->staticBlockPosition() != logicalTop) {
1591 childLayer->setStaticBlockPosition(logicalTop);
1592 if (hasStaticBlockPosition)
1593 child->setChildNeedsLayout(true, false);
1597 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1599 // The float should be positioned taking into account the bottom margin
1600 // of the previous flow. We add that margin into the height, get the
1601 // float positioned properly, and then subtract the margin out of the
1602 // height again. In the case of self-collapsing blocks, we always just
1603 // use the top margins, since the self-collapsing block collapsed its
1604 // own bottom margin into its top margin.
1606 // Note also that the previous flow may collapse its margin into the top of
1607 // our block. If this is the case, then we do not add the margin in to our
1608 // height when computing the position of the float. This condition can be tested
1609 // for by simply calling canCollapseWithMarginBefore. See
1610 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1611 // an example of this scenario.
1612 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin();
1613 setLogicalHeight(logicalHeight() + marginOffset);
1614 positionNewFloats();
1615 setLogicalHeight(logicalHeight() - marginOffset);
1618 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1620 // Handle in the given order
1621 return handlePositionedChild(child, marginInfo)
1622 || handleFloatingChild(child, marginInfo)
1623 || handleRunInChild(child);
1627 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1629 if (child->isPositioned()) {
1630 child->containingBlock()->insertPositionedObject(child);
1631 adjustPositionedBlock(child, marginInfo);
1637 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1639 if (child->isFloating()) {
1640 insertFloatingObject(child);
1641 adjustFloatingBlock(marginInfo);
1647 bool RenderBlock::handleRunInChild(RenderBox* child)
1649 // See if we have a run-in element with inline children. If the
1650 // children aren't inline, then just treat the run-in as a normal
1652 if (!child->isRunIn() || !child->childrenInline())
1654 // FIXME: We don't handle non-block elements with run-in for now.
1655 if (!child->isRenderBlock())
1658 RenderBlock* blockRunIn = toRenderBlock(child);
1659 RenderObject* curr = blockRunIn->nextSibling();
1660 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned())
1663 RenderBlock* currBlock = toRenderBlock(curr);
1665 // First we destroy any :before/:after content. It will be regenerated by the new inline.
1666 // Exception is if the run-in itself is generated.
1667 if (child->style()->styleType() != BEFORE && child->style()->styleType() != AFTER) {
1668 RenderObject* generatedContent;
1669 if (child->getCachedPseudoStyle(BEFORE) && (generatedContent = child->beforePseudoElementRenderer()))
1670 generatedContent->destroy();
1671 if (child->getCachedPseudoStyle(AFTER) && (generatedContent = child->afterPseudoElementRenderer()))
1672 generatedContent->destroy();
1675 // Remove the old child.
1676 children()->removeChildNode(this, blockRunIn);
1678 // Create an inline.
1679 Node* runInNode = blockRunIn->node();
1680 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1681 inlineRunIn->setStyle(blockRunIn->style());
1683 // Move the nodes from the old child to the new child
1684 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) {
1685 RenderObject* nextSibling = runInChild->nextSibling();
1686 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
1687 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
1688 runInChild = nextSibling;
1691 // Now insert the new child under |currBlock|. Use addChild instead of insertChildNode since it handles correct placement of the children, esp where we cannot insert
1692 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1693 currBlock->addChild(inlineRunIn, currBlock->firstChild());
1695 // If the run-in had an element, we need to set the new renderer.
1697 runInNode->setRenderer(inlineRunIn);
1699 // Destroy the block run-in, which includes deleting its line box tree.
1700 blockRunIn->deleteLineBoxTree();
1701 blockRunIn->destroy();
1703 // The block acts like an inline, so just null out its
1709 LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1711 // Get the four margin values for the child and cache them.
1712 const MarginValues childMargins = marginValuesForChild(child);
1714 // Get our max pos and neg top margins.
1715 LayoutUnit posTop = childMargins.positiveMarginBefore();
1716 LayoutUnit negTop = childMargins.negativeMarginBefore();
1718 // For self-collapsing blocks, collapse our bottom margins into our
1719 // top to get new posTop and negTop values.
1720 if (child->isSelfCollapsingBlock()) {
1721 posTop = max(posTop, childMargins.positiveMarginAfter());
1722 negTop = max(negTop, childMargins.negativeMarginAfter());
1725 // See if the top margin is quirky. We only care if this child has
1726 // margins that will collapse with us.
1727 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
1729 if (marginInfo.canCollapseWithMarginBefore()) {
1730 // This child is collapsing with the top of the
1731 // block. If it has larger margin values, then we need to update
1732 // our own maximal values.
1733 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
1734 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
1736 // The minute any of the margins involved isn't a quirk, don't
1737 // collapse it away, even if the margin is smaller (www.webreference.com
1738 // has an example of this, a <dt> with 0.8em author-specified inside
1739 // a <dl> inside a <td>.
1740 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
1741 setMarginBeforeQuirk(false);
1742 marginInfo.setDeterminedMarginBeforeQuirk(true);
1745 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
1746 // We have no top margin and our top child has a quirky margin.
1747 // We will pick up this quirky margin and pass it through.
1748 // This deals with the <td><div><p> case.
1749 // Don't do this for a block that split two inlines though. You do
1750 // still apply margins in this case.
1751 setMarginBeforeQuirk(true);
1754 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1755 marginInfo.setMarginBeforeQuirk(topQuirk);
1757 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1758 LayoutUnit logicalTop = beforeCollapseLogicalTop;
1759 if (child->isSelfCollapsingBlock()) {
1760 // This child has no height. We need to compute our
1761 // position before we collapse the child's margins together,
1762 // so that we can get an accurate position for the zero-height block.
1763 LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1764 LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1765 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1767 // Now collapse the child's margins together, which means examining our
1768 // bottom margin values as well.
1769 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1770 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1772 if (!marginInfo.canCollapseWithMarginBefore())
1773 // We need to make sure that the position of the self-collapsing block
1774 // is correct, since it could have overflowing content
1775 // that needs to be positioned correctly (e.g., a block that
1776 // had a specified height of 0 but that actually had subcontent).
1777 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1780 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1781 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
1782 logicalTop = logicalHeight();
1784 else if (!marginInfo.atBeforeSideOfBlock() ||
1785 (!marginInfo.canCollapseMarginBeforeWithChildren()
1786 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
1787 // We're collapsing with a previous sibling's margins and not
1788 // with the top of the block.
1789 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
1790 logicalTop = logicalHeight();
1793 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1794 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1796 if (marginInfo.margin())
1797 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
1800 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1801 // collapsed into the page edge.
1802 LayoutState* layoutState = view()->layoutState();
1803 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1804 && hasNextPage(beforeCollapseLogicalTop)) {
1805 LayoutUnit oldLogicalTop = logicalTop;
1806 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
1807 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1812 LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
1814 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1815 if (!heightIncrease)
1818 if (child->isSelfCollapsingBlock()) {
1819 // For self-collapsing blocks that clear, they can still collapse their
1820 // margins with following siblings. Reset the current margins to represent
1821 // the self-collapsing block's margins only.
1823 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
1824 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
1825 // self-collapsing block's bottom margin.
1826 bool atBottomOfBlock = true;
1827 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
1828 if (!curr->isFloatingOrPositioned())
1829 atBottomOfBlock = false;
1832 MarginValues childMargins = marginValuesForChild(child);
1833 if (atBottomOfBlock) {
1834 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1835 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1837 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1838 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1841 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
1842 // of the parent block).
1843 setLogicalHeight(child->y() - max<LayoutUnit>(0, marginInfo.margin()));
1845 // Increase our height by the amount we had to clear.
1846 setLogicalHeight(height() + heightIncrease);
1848 if (marginInfo.canCollapseWithMarginBefore()) {
1849 // We can no longer collapse with the top of the block since a clear
1850 // occurred. The empty blocks collapse into the cleared block.
1851 // FIXME: This isn't quite correct. Need clarification for what to do
1852 // if the height the cleared block is offset by is smaller than the
1853 // margins involved.
1854 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1855 marginInfo.setAtBeforeSideOfBlock(false);
1858 return yPos + heightIncrease;
1861 LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
1863 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1864 // relayout if there are intruding floats.
1865 LayoutUnit logicalTopEstimate = logicalHeight();
1866 if (!marginInfo.canCollapseWithMarginBefore()) {
1867 LayoutUnit childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child);
1868 logicalTopEstimate += max(marginInfo.margin(), childMarginBefore);
1871 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1873 LayoutState* layoutState = view()->layoutState();
1874 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1875 && hasNextPage(logicalHeight()))
1876 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1878 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1880 estimateWithoutPagination = logicalTopEstimate;
1882 if (layoutState->isPaginated()) {
1883 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1884 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1886 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1887 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1889 if (!child->selfNeedsLayout() && child->isRenderBlock())
1890 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1893 return logicalTopEstimate;
1896 LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart,
1897 LayoutUnit childLogicalWidth, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
1899 LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
1901 // Add in our start margin.
1902 LayoutUnit oldPosition = startPosition + childMarginStart;
1903 LayoutUnit newPosition = oldPosition;
1905 LayoutUnit blockOffset = logicalTopForChild(child);
1907 blockOffset = max(blockOffset, blockOffset + (region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage));
1909 LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage);
1910 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1911 if (childMarginStart < 0)
1912 startOff += childMarginStart;
1913 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1914 // FIXME: Needs to use epsilon once we switch to float, see https://bugs.webkit.org/show_bug.cgi?id=64021
1915 } else if (startOff != startPosition) {
1916 // The object is shifting to the "end" side of the block. The object might be centered, so we need to
1917 // recalculate our inline direction margins. Note that the containing block content
1918 // width computation will take into account the delta between |startOff| and |startPosition|
1919 // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
1921 LayoutUnit oldMarginStart = marginStartForChild(child);
1922 LayoutUnit oldMarginEnd = marginEndForChild(child);
1923 RenderBox* mutableChild = const_cast<RenderBox*>(child);
1924 mutableChild->computeInlineDirectionMargins(this,
1925 availableLogicalWidthForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage), childLogicalWidth);
1926 newPosition = startOff + marginStartForChild(child);
1927 if (inRenderFlowThread()) {
1928 setMarginStartForChild(mutableChild, oldMarginStart);
1929 setMarginEndForChild(mutableChild, oldMarginEnd);
1933 return newPosition - oldPosition;
1936 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
1938 LayoutUnit startPosition = borderStart() + paddingStart();
1939 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1941 // Add in our start margin.
1942 LayoutUnit childMarginStart = marginStartForChild(child);
1943 LayoutUnit newPosition = startPosition + childMarginStart;
1945 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1946 // to shift over as necessary to dodge any floats that might get in the way.
1947 if (child->avoidsFloats() && containsFloats() && !inRenderFlowThread())
1948 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child), logicalWidthForChild(child));
1950 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
1953 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1955 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1956 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1957 // with our children.
1958 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1960 if (!marginInfo.marginAfterQuirk())
1961 setMarginAfterQuirk(false);
1963 if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
1964 // We have no bottom margin and our last child has a quirky margin.
1965 // We will pick up this quirky margin and pass it through.
1966 // This deals with the <td><div><p> case.
1967 setMarginAfterQuirk(true);
1971 void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1973 marginInfo.setAtAfterSideOfBlock(true);
1975 // If we can't collapse with children then go ahead and add in the bottom margin.
1976 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1977 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
1978 setLogicalHeight(logicalHeight() + marginInfo.margin());
1980 // Now add in our bottom border/padding.
1981 setLogicalHeight(logicalHeight() + afterSide);
1983 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1984 // If this happens, ensure that the computed height is increased to the minimal height.
1985 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1987 // Update our bottom collapsed margin info.
1988 setCollapsedBottomMargin(marginInfo);
1991 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
1993 if (isHorizontalWritingMode()) {
1994 if (applyDelta == ApplyLayoutDelta)
1995 view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
1996 child->setX(logicalLeft);
1998 if (applyDelta == ApplyLayoutDelta)
1999 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
2000 child->setY(logicalLeft);
2004 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
2006 if (isHorizontalWritingMode()) {
2007 if (applyDelta == ApplyLayoutDelta)
2008 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
2009 child->setY(logicalTop);
2011 if (applyDelta == ApplyLayoutDelta)
2012 view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
2013 child->setX(logicalTop);
2017 void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
2019 if (gPercentHeightDescendantsMap) {
2020 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
2021 HashSet<RenderBox*>::iterator end = descendants->end();
2022 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
2023 RenderBox* box = *it;
2024 while (box != this) {
2025 if (box->normalChildNeedsLayout())
2027 box->setChildNeedsLayout(true, false);
2028 box = box->containingBlock();
2037 LayoutUnit beforeEdge = borderBefore() + paddingBefore();
2038 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
2040 setLogicalHeight(beforeEdge);
2042 // Lay out our hypothetical grid line as though it occurs at the top of the block.
2043 if (view()->layoutState()->lineGrid() == this)
2044 layoutLineGridBox();
2046 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
2047 MarginInfo marginInfo(this, beforeEdge, afterEdge);
2049 // Fieldsets need to find their legend and position it inside the border of the object.
2050 // The legend then gets skipped during normal layout. The same is true for ruby text.
2051 // It doesn't get included in the normal layout process but is instead skipped.
2052 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
2054 LayoutUnit previousFloatLogicalBottom = 0;
2055 maxFloatLogicalBottom = 0;
2057 RenderBox* next = firstChildBox();
2060 RenderBox* child = next;
2061 next = child->nextSiblingBox();
2063 if (childToExclude == child)
2064 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
2066 // Make sure we layout children if they need it.
2067 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
2068 // an auto value. Add a method to determine this, so that we can avoid the relayout.
2069 RenderStyle* childStyle = child->style();
2070 if (relayoutChildren || ((childStyle->logicalHeight().isPercent() || childStyle->logicalMinHeight().isPercent() || childStyle->logicalMaxHeight().isPercent()) && !isRenderView()))
2071 child->setChildNeedsLayout(true, false);
2073 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2074 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
2075 child->setPreferredLogicalWidthsDirty(true, false);
2077 // Handle the four types of special elements first. These include positioned content, floating content, compacts and
2078 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
2079 if (handleSpecialChild(child, marginInfo))
2082 // Lay out the child.
2083 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
2086 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
2087 // determining the correct collapsed bottom margin information.
2088 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
2091 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
2093 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
2094 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
2096 // The child is a normal flow object. Compute the margins we will use for collapsing now.
2097 child->computeBlockDirectionMargins(this);
2099 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
2100 RenderStyle* childStyle = child->style();
2101 if (childStyle->marginBeforeCollapse() == MSEPARATE) {
2102 marginInfo.setAtBeforeSideOfBlock(false);
2103 marginInfo.clearMargin();
2106 // Try to guess our correct logical top position. In most cases this guess will
2107 // be correct. Only if we're wrong (when we compute the real logical top position)
2108 // will we have to potentially relayout.
2109 LayoutUnit estimateWithoutPagination;
2110 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
2112 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
2113 LayoutRect oldRect(child->x(), child->y() , child->width(), child->height());
2114 LayoutUnit oldLogicalTop = logicalTopForChild(child);
2116 #if !ASSERT_DISABLED
2117 LayoutSize oldLayoutDelta = view()->layoutDelta();
2119 // Go ahead and position the child as though it didn't collapse with the top.
2120 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
2122 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
2123 bool markDescendantsWithFloats = false;
2124 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
2125 markDescendantsWithFloats = true;
2126 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
2127 // If an element might be affected by the presence of floats, then always mark it for
2129 LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottomIncludingPositionedFloats());
2130 if (fb > logicalTopEstimate)
2131 markDescendantsWithFloats = true;
2134 if (childRenderBlock) {
2135 if (markDescendantsWithFloats)
2136 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2137 if (!child->isWritingModeRoot())
2138 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottomIncludingPositionedFloats());
2141 if (!child->needsLayout())
2142 child->markForPaginationRelayoutIfNeeded();
2144 bool childHadLayout = child->everHadLayout();
2145 bool childNeededLayout = child->needsLayout();
2146 if (childNeededLayout)
2149 // Cache if we are at the top of the block right now.
2150 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
2152 // Now determine the correct ypos based off examination of collapsing margin
2154 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
2156 // Now check for clear.
2157 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
2159 bool paginated = view()->layoutState()->isPaginated();
2161 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
2162 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
2164 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2166 // Now we have a final top position. See if it really does end up being different from our estimate.
2167 if (logicalTopAfterClear != logicalTopEstimate) {
2168 if (child->shrinkToAvoidFloats()) {
2169 // The child's width depends on the line width.
2170 // When the child shifts to clear an item, its width can
2171 // change (because it has more available line width).
2172 // So go ahead and mark the item as dirty.
2173 child->setChildNeedsLayout(true, false);
2176 if (childRenderBlock) {
2177 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2178 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2179 if (!child->needsLayout())
2180 child->markForPaginationRelayoutIfNeeded();
2183 // Our guess was wrong. Make the child lay itself out again.
2184 child->layoutIfNeeded();
2187 // We are no longer at the top of the block if we encounter a non-empty child.
2188 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2189 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2190 marginInfo.setAtBeforeSideOfBlock(false);
2192 // Now place the child in the correct left position
2193 determineLogicalLeftPositionForChild(child);
2195 // Update our height now that the child has been placed in the correct position.
2196 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2197 if (childStyle->marginAfterCollapse() == MSEPARATE) {
2198 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2199 marginInfo.clearMargin();
2201 // If the child has overhanging floats that intrude into following siblings (or possibly out
2202 // of this block), then the parent gets notified of the floats now.
2203 if (childRenderBlock && childRenderBlock->containsFloats())
2204 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
2206 LayoutSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
2207 if (childOffset.width() || childOffset.height()) {
2208 view()->addLayoutDelta(childOffset);
2210 // If the child moved, we have to repaint it as well as any floating/positioned
2211 // descendants. An exception is if we need a layout. In this case, we know we're going to
2212 // repaint ourselves (and the child) anyway.
2213 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2214 child->repaintDuringLayoutIfMoved(oldRect);
2217 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2219 child->repaintOverhangingFloats(true);
2223 // Check for an after page/column break.
2224 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2225 if (newHeight != height())
2226 setLogicalHeight(newHeight);
2229 ASSERT(oldLayoutDelta == view()->layoutDelta());
2232 void RenderBlock::simplifiedNormalFlowLayout()
2234 if (childrenInline()) {
2235 ListHashSet<RootInlineBox*> lineBoxes;
2236 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
2237 RenderObject* o = walker.current();
2238 if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
2239 o->layoutIfNeeded();
2240 if (toRenderBox(o)->inlineBoxWrapper()) {
2241 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2244 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline()))
2245 o->setNeedsLayout(false);
2248 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2249 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2250 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2251 RootInlineBox* box = *it;
2252 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2255 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2256 if (!box->isPositioned())
2257 box->layoutIfNeeded();
2262 bool RenderBlock::simplifiedLayout()
2264 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2267 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2269 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2272 // Lay out positioned descendants or objects that just need to recompute overflow.
2273 if (needsSimplifiedNormalFlowLayout())
2274 simplifiedNormalFlowLayout();
2276 // Lay out our positioned objects if our positioned child bit is set.
2277 if (posChildNeedsLayout() && layoutPositionedObjects(false))
2278 return false; // If a positioned float is causing our normal flow to change, then we have to bail and do a full layout.
2280 // Recompute our overflow information.
2281 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2282 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2283 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2284 // lowestPosition on every relayout so it's not a regression.
2286 computeOverflow(clientLogicalBottom(), true);
2290 updateLayerTransform();
2292 updateScrollInfoAfterLayout();
2294 setNeedsLayout(false);
2298 bool RenderBlock::positionedFloatsNeedRelayout()
2300 if (!hasPositionedFloats())
2303 RenderBox* positionedObject;
2304 Iterator end = m_positionedObjects->end();
2305 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2306 positionedObject = *it;
2307 if (!positionedObject->isFloating())
2310 if (positionedObject->needsLayout())
2313 if (positionedObject->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && positionedObject->parent() != this && positionedObject->parent()->isBlockFlow())
2316 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2323 bool RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2325 if (!m_positionedObjects)
2329 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2331 bool didFloatingBoxRelayout = false;
2334 Iterator end = m_positionedObjects->end();
2335 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2337 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2338 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2339 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2340 // positioned explicitly) this should not incur a performance penalty.
2341 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
2342 r->setChildNeedsLayout(true, false);
2344 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2345 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
2346 r->setPreferredLogicalWidthsDirty(true, false);
2348 if (!r->needsLayout())
2349 r->markForPaginationRelayoutIfNeeded();
2351 // FIXME: Technically we could check the old placement and the new placement of the box and only invalidate if
2352 // the margin box of the object actually changed.
2353 if (r->needsLayout() && r->isFloating())
2354 didFloatingBoxRelayout = true;
2356 // 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
2357 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2358 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2359 r->setNeedsLayout(false);
2361 // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
2362 // If it's wrong we'll lay out again.
2363 LayoutUnit oldLogicalTop = 0;
2364 bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2365 if (needsBlockDirectionLocationSetBeforeLayout) {
2366 if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
2367 r->computeLogicalHeight();
2369 r->computeLogicalWidth();
2370 oldLogicalTop = logicalTopForChild(r);
2373 r->layoutIfNeeded();
2375 // Lay out again if our estimate was wrong.
2376 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) {
2377 r->setChildNeedsLayout(true, false);
2378 r->layoutIfNeeded();
2383 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2385 return didFloatingBoxRelayout;
2388 void RenderBlock::markPositionedObjectsForLayout()
2390 if (m_positionedObjects) {
2392 Iterator end = m_positionedObjects->end();
2393 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2395 r->setChildNeedsLayout(true);
2400 void RenderBlock::markForPaginationRelayoutIfNeeded()
2402 ASSERT(!needsLayout());
2406 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2407 setChildNeedsLayout(true, false);
2410 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2412 // Repaint any overhanging floats (if we know we're the one to paint them).
2413 // Otherwise, bail out.
2414 if (!hasOverhangingFloats())
2417 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2418 // in this block. Better yet would be to push extra state for the containers of other floats.
2419 LayoutStateDisabler layoutStateDisabler(view());
2420 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2421 FloatingObjectSetIterator end = floatingObjectSet.end();
2422 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2423 FloatingObject* r = *it;
2424 // Only repaint the object if it is overhanging, is not in its own layer, and
2425 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2426 // condition is replaced with being a descendant of us.
2427 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
2428 r->m_renderer->repaint();
2429 r->m_renderer->repaintOverhangingFloats();
2434 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2436 LayoutPoint adjustedPaintOffset = paintOffset + location();
2438 PaintPhase phase = paintInfo.phase;
2440 // Check if we need to do anything at all.
2441 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2442 // paints the root's background.
2444 LayoutRect overflowBox = visualOverflowRect();
2445 flipForWritingMode(overflowBox);
2446 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2447 overflowBox.moveBy(adjustedPaintOffset);
2448 if (!overflowBox.intersects(paintInfo.rect))
2452 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
2453 paintObject(paintInfo, adjustedPaintOffset);
2455 popContentsClip(paintInfo, phase, adjustedPaintOffset);
2457 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2458 // z-index. We paint after we painted the background/border, so that the scrollbars will
2459 // sit above the background/border.
2460 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2461 layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
2464 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2466 if (paintInfo.context->paintingDisabled())
2469 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2470 bool ruleTransparent = style()->columnRuleIsTransparent();
2471 EBorderStyle ruleStyle = style()->columnRuleStyle();
2472 LayoutUnit ruleThickness = style()->columnRuleWidth();
2473 LayoutUnit colGap = columnGap();
2474 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleThickness <= colGap;
2478 ColumnInfo* colInfo = columnInfo();
2479 unsigned colCount = columnCount(colInfo);
2481 bool antialias = shouldAntialiasLines(paintInfo.context);
2483 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
2484 LayoutUnit currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2485 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
2486 LayoutUnit ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2487 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
2488 BoxSide boxSide = isHorizontalWritingMode()
2489 ? style()->isLeftToRightDirection() ? BSLeft : BSRight
2490 : style()->isLeftToRightDirection() ? BSTop : BSBottom;
2492 for (unsigned i = 0; i < colCount; i++) {
2493 // Move to the next position.
2494 if (style()->isLeftToRightDirection()) {
2495 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2496 currLogicalLeftOffset += inlineDirectionSize + colGap;
2498 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2499 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2502 // Now paint the column rule.
2503 if (i < colCount - 1) {
2504 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
2505 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
2506 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
2507 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
2508 drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom, boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2511 ruleLogicalLeft = currLogicalLeftOffset;
2514 LayoutUnit ruleLeft = isHorizontalWritingMode() ? borderLeft() + paddingLeft() : colGap / 2 - colGap - ruleThickness / 2 + borderBefore() + paddingBefore();
2515 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2516 LayoutUnit ruleTop = isHorizontalWritingMode() ? colGap / 2 - colGap - ruleThickness / 2 + borderBefore() + paddingBefore() : borderStart() + paddingStart();
2517 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2518 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2520 flipForWritingMode(ruleRect);
2521 ruleRect.moveBy(paintOffset);
2523 BoxSide boxSide = isHorizontalWritingMode()
2524 ? !style()->isFlippedBlocksWritingMode() ? BSTop : BSBottom
2525 : !style()->isFlippedBlocksWritingMode() ? BSLeft : BSRight;
2527 LayoutSize step(0, !style()->isFlippedBlocksWritingMode() ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2528 if (!isHorizontalWritingMode())
2529 step = step.transposedSize();
2531 for (unsigned i = 1; i < colCount; i++) {
2532 ruleRect.move(step);
2533 drawLineForBoxSide(paintInfo.context, ruleRect.x(), ruleRect.y(), ruleRect.maxX(), ruleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2538 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2540 // We need to do multiple passes, breaking up our child painting into strips.
2541 GraphicsContext* context = paintInfo.context;
2542 ColumnInfo* colInfo = columnInfo();
2543 unsigned colCount = columnCount(colInfo);
2546 LayoutUnit currLogicalTopOffset = 0;
2547 for (unsigned i = 0; i < colCount; i++) {
2548 // For each rect, we clip to the rect, and then we adjust our coords.
2549 LayoutRect colRect = columnRectAt(colInfo, i);
2550 flipForWritingMode(colRect);
2551 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2552 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2553 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2554 if (isHorizontalWritingMode())
2555 offset.expand(0, colRect.y() - borderTop() - paddingTop());
2557 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2559 colRect.moveBy(paintOffset);
2560 PaintInfo info(paintInfo);
2561 info.rect.intersect(pixelSnappedIntRect(colRect));
2563 if (!info.rect.isEmpty()) {
2564 GraphicsContextStateSaver stateSaver(*context);
2566 // Each strip pushes a clip, since column boxes are specified as being
2567 // like overflow:hidden.
2568 context->clip(colRect);
2570 // Adjust our x and y when painting.
2571 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2573 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2575 paintContents(info, adjustedPaintOffset);
2578 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2579 if (style()->isFlippedBlocksWritingMode())
2580 currLogicalTopOffset += blockDelta;
2582 currLogicalTopOffset -= blockDelta;
2586 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2588 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2589 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2590 // will do a full repaint().
2591 if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
2594 // We don't want to hand off painting in the line box tree with the accumulated error of the render tree, as this will cause
2595 // us to mess up painting aligned things (such as underlines in text) with both the render tree and line box tree's error.
2596 LayoutPoint roundedPaintOffset = roundedIntPoint(paintOffset);
2597 if (childrenInline())
2598 m_lineBoxes.paint(this, paintInfo, roundedPaintOffset);
2600 paintChildren(paintInfo, roundedPaintOffset);
2603 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2605 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2606 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2608 // We don't paint our own background, but we do let the kids paint their backgrounds.
2609 PaintInfo info(paintInfo);
2610 info.phase = newPhase;
2611 info.updatePaintingRootForChildren(this);
2613 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2614 // NSViews. Do not add any more code for this.
2615 RenderView* renderView = view();
2616 bool usePrintRect = !renderView->printRect().isEmpty();
2618 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2619 // Check for page-break-before: always, and if it's set, break and bail.
2620 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2621 LayoutUnit absoluteChildY = paintOffset.y() + child->y();
2622 if (checkBeforeAlways
2623 && absoluteChildY > paintInfo.rect.y()
2624 && absoluteChildY < paintInfo.rect.maxY()) {
2625 view()->setBestTruncatedAt(absoluteChildY, this, true);
2629 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2630 // Paginate block-level replaced elements.
2631 if (absoluteChildY + child->height() > renderView->printRect().maxY()) {
2632 if (absoluteChildY < renderView->truncatedAt())
2633 renderView->setBestTruncatedAt(absoluteChildY, child);
2634 // If we were able to truncate, don't paint.
2635 if (absoluteChildY >= renderView->truncatedAt())
2640 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2641 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2642 child->paint(info, childPoint);
2644 // Check for page-break-after: always, and if it's set, break and bail.
2645 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2646 if (checkAfterAlways
2647 && (absoluteChildY + child->height()) > paintInfo.rect.y()
2648 && (absoluteChildY + child->height()) < paintInfo.rect.maxY()) {
2649 view()->setBestTruncatedAt(absoluteChildY + child->height() + max<LayoutUnit>(0, child->collapsedMarginAfter()), this, true);
2655 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2657 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2658 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2659 RenderObject* caretPainter;
2660 bool isContentEditable;
2661 if (type == CursorCaret) {
2662 caretPainter = frame()->selection()->caretRenderer();
2663 isContentEditable = frame()->selection()->isContentEditable();
2665 caretPainter = frame()->page()->dragCaretController()->caretRenderer();
2666 isContentEditable = frame()->page()->dragCaretController()->isContentEditable();
2669 if (caretPainter == this && (isContentEditable || caretBrowsing)) {
2670 if (type == CursorCaret)
2671 frame()->selection()->paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2673 frame()->page()->dragCaretController()->paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
2677 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2679 PaintPhase paintPhase = paintInfo.phase;
2681 // 1. paint background, borders etc
2682 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2683 if (hasBoxDecorations())
2684 paintBoxDecorations(paintInfo, paintOffset);
2686 paintColumnRules(paintInfo, paintOffset);
2689 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2690 paintMask(paintInfo, paintOffset);
2694 // We're done. We don't bother painting any children.
2695 if (paintPhase == PaintPhaseBlockBackground)
2698 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2699 LayoutPoint scrolledOffset = paintOffset;
2700 if (hasOverflowClip())
2701 scrolledOffset.move(-layer()->scrolledContentOffset());
2703 // 2. paint contents
2704 if (paintPhase != PaintPhaseSelfOutline) {
2706 paintColumnContents(paintInfo, scrolledOffset);
2708 paintContents(paintInfo, scrolledOffset);
2711 // 3. paint selection
2712 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2713 bool isPrinting = document()->printing();
2714 if (!isPrinting && !hasColumns())
2715 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2718 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2720 paintColumnContents(paintInfo, scrolledOffset, true);
2722 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2725 // 5. paint outline.
2726 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2727 paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
2729 // 6. paint continuation outlines.
2730 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2731 RenderInline* inlineCont = inlineElementContinuation();
2732 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2733 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2734 RenderBlock* cb = containingBlock();
2736 bool inlineEnclosedInSelfPaintingLayer = false;
2737 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2738 if (box->hasSelfPaintingLayer()) {
2739 inlineEnclosedInSelfPaintingLayer = true;
2744 if (!inlineEnclosedInSelfPaintingLayer)
2745 cb->addContinuationWithOutline(inlineRenderer);
2746 else if (!inlineRenderer->firstLineBox())
2747 inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2749 paintContinuationOutlines(paintInfo, paintOffset);
2753 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2754 // then paint the caret.
2755 if (paintPhase == PaintPhaseForeground) {
2756 paintCaret(paintInfo, paintOffset, CursorCaret);
2757 paintCaret(paintInfo, paintOffset, DragCaret);
2761 LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2763 if (!style()->isFlippedBlocksWritingMode())
2766 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2767 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2769 if (isHorizontalWritingMode())
2770 return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
2771 return LayoutPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2774 void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2776 if (!m_floatingObjects)
2779 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2780 FloatingObjectSetIterator end = floatingObjectSet.end();
2781 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2782 FloatingObject* r = *it;
2783 // Only paint the object if our m_shouldPaint flag is set.
2784 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
2785 PaintInfo currentPaintInfo(paintInfo);
2786 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2787 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
2788 r->m_renderer->paint(currentPaintInfo, childPoint);
2789 if (!preservePhase) {
2790 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2791 r->m_renderer->paint(currentPaintInfo, childPoint);
2792 currentPaintInfo.phase = PaintPhaseFloat;
2793 r->m_renderer->paint(currentPaintInfo, childPoint);
2794 currentPaintInfo.phase = PaintPhaseForeground;
2795 r->m_renderer->paint(currentPaintInfo, childPoint);
2796 currentPaintInfo.phase = PaintPhaseOutline;
2797 r->m_renderer->paint(currentPaintInfo, childPoint);
2803 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2805 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox())
2808 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
2809 // We can check the first box and last box and avoid painting if we don't
2811 LayoutUnit yPos = paintOffset.y() + firstLineBox()->y();
2812 LayoutUnit h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y();
2813 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y())
2816 // See if our boxes intersect with the dirty rect. If so, then we paint
2817 // them. Note that boxes can easily overlap, so we can't make any assumptions
2818 // based off positions of our first line box or our last line box.
2819 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2820 yPos = paintOffset.y() + curr->y();
2821 h = curr->logicalHeight();
2822 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y())
2823 curr->paintEllipsisBox(paintInfo, paintOffset, curr->lineTop(), curr->lineBottom());
2828 RenderInline* RenderBlock::inlineElementContinuation() const
2830 RenderBoxModelObject* continuation = this->continuation();
2831 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2834 RenderBlock* RenderBlock::blockElementContinuation() const
2836 RenderBoxModelObject* currentContinuation = continuation();
2837 if (!currentContinuation || currentContinuation->isInline())
2839 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2840 if (nextContinuation->isAnonymousBlock())
2841 return nextContinuation->blockElementContinuation();
2842 return nextContinuation;
2845 static ContinuationOutlineTableMap* continuationOutlineTable()
2847 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2851 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2853 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2855 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2857 ContinuationOutlineTableMap* table = continuationOutlineTable();
2858 ListHashSet<RenderInline*>* continuations = table->get(this);
2859 if (!continuations) {
2860 continuations = new ListHashSet<RenderInline*>;
2861 table->set(this, continuations);
2864 continuations->add(flow);
2867 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2869 ContinuationOutlineTableMap* table = continuationOutlineTable();
2870 if (table->isEmpty())
2873 ListHashSet<RenderInline*>* continuations = table->get(this);
2877 return continuations->contains(flow);
2880 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2882 ContinuationOutlineTableMap* table = continuationOutlineTable();
2883 if (table->isEmpty())
2886 ListHashSet<RenderInline*>* continuations = table->get(this);
2890 LayoutPoint accumulatedPaintOffset = paintOffset;
2891 // Paint each continuation outline.
2892 ListHashSet<RenderInline*>::iterator end = continuations->end();
2893 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2894 // Need to add in the coordinates of the intervening blocks.
2895 RenderInline* flow = *it;
2896 RenderBlock* block = flow->containingBlock();
2897 for ( ; block && block != this; block = block->containingBlock())
2898 accumulatedPaintOffset.moveBy(block->location());
2900 flow->paintOutline(info.context, accumulatedPaintOffset);
2904 delete continuations;
2905 table->remove(this);
2908 bool RenderBlock::shouldPaintSelectionGaps() const
2910 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2913 bool RenderBlock::isSelectionRoot() const
2918 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2922 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
2923 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
2924 hasReflection() || hasMask() || isWritingModeRoot())
2927 if (view() && view()->selectionStart()) {
2928 Node* startElement = view()->selectionStart()->node();
2929 if (startElement && startElement->rootEditableElement() == node())
2936 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
2938 ASSERT(!needsLayout());
2940 if (!shouldPaintSelectionGaps())
2943 // FIXME: this is broken with transforms
2944 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2945 mapLocalToContainer(repaintContainer, false, false, transformState);
2946 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
2948 if (hasOverflowClip())
2949 offsetFromRepaintContainer -= layer()->scrolledContentOffset();
2951 LayoutUnit lastTop = 0;
2952 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2953 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2955 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2958 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2960 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2961 LayoutUnit lastTop = 0;
2962 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2963 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2964 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2966 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
2967 if (!gapRectsBounds.isEmpty()) {
2968 if (RenderLayer* layer = enclosingLayer()) {
2969 gapRectsBounds.moveBy(-paintOffset);
2971 LayoutRect localBounds(gapRectsBounds);
2972 flipForWritingMode(localBounds);
2973 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2974 gapRectsBounds.move(layer->scrolledContentOffset());
2976 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2982 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects)
2984 if (!positionedObjects)
2987 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
2988 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2990 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2994 static int blockDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
2996 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
2999 static int inlineDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
3001 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
3004 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
3007 if (isHorizontalWritingMode())
3008 result = logicalRect;
3010 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
3011 flipForWritingMode(result);
3012 result.moveBy(rootBlockPhysicalPosition);
3016 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3017 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3019 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
3020 // Clip out floating and positioned objects when painting selection gaps.
3022 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
3023 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
3024 rootBlock->flipForWritingMode(flippedBlockRect);
3025 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
3026 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get());
3027 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
3028 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
3029 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes.
3030 if (m_floatingObjects) {
3031 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3032 FloatingObjectSetIterator end = floatingObjectSet.end();
3033 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3034 FloatingObject* r = *it;
3035 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
3036 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
3037 r->m_renderer->width(), r->m_renderer->height());
3038 rootBlock->flipForWritingMode(floatBox);
3039 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
3040 paintInfo->context->clipOut(pixelSnappedIntRect(floatBox));
3045 // 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
3048 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
3051 if (hasColumns() || hasTransform() || style()->columnSpan()) {
3052 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
3053 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3054 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3055 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3059 if (childrenInline())
3060 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
3062 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
3064 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
3065 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
3066 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3067 logicalHeight(), paintInfo));
3071 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3072 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3076 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3078 if (!firstLineBox()) {
3079 if (containsStart) {
3080 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
3082 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3083 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3084 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3089 RootInlineBox* lastSelectedLine = 0;
3090 RootInlineBox* curr;
3091 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3093 // Now paint the gaps for the lines.
3094 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3095 LayoutUnit selTop = curr->selectionTop();
3096 LayoutUnit selHeight = curr->selectionHeight();
3098 if (!containsStart && !lastSelectedLine &&
3099 selectionState() != SelectionStart && selectionState() != SelectionBoth)
3100 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3101 selTop, paintInfo));
3103 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3104 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
3105 LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3106 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3107 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3108 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
3110 lastSelectedLine = curr;
3113 if (containsStart && !lastSelectedLine)
3114 // VisibleSelection must start just after our last line.
3115 lastSelectedLine = lastRootBox();
3117 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3118 // Go ahead and update our lastY to be the bottom of the last selected line.
3119 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3120 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3121 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3126 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3127 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3131 // Go ahead and jump right to the first block child that contains some selected objects.
3133 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
3135 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
3136 SelectionState childState = curr->selectionState();
3137 if (childState == SelectionBoth || childState == SelectionEnd)
3138 sawSelectionEnd = true;
3140 if (curr->isFloatingOrPositioned())
3141 continue; // We must be a normal flow object in order to even be considered.
3143 if (curr->isRelPositioned() && curr->hasLayer()) {
3144 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
3145 // Just disregard it completely.
3146 LayoutSize relOffset = curr->layer()->relativePositionOffset();
3147 if (relOffset.width() || relOffset.height())
3151 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
3152 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
3153 if (fillBlockGaps) {
3154 // We need to fill the vertical gap above this object.
3155 if (childState == SelectionEnd || childState == SelectionInside)
3156 // Fill the gap above the object.
3157 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3158 curr->logicalTop(), paintInfo));
3160 // 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*
3161 // our object. We know this if the selection did not end inside our object.
3162 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
3163 childState = SelectionNone;
3165 // Fill side gaps on this object based off its state.
3166 bool leftGap, rightGap;
3167 getSelectionGapInfo(childState, leftGap, rightGap);
3170 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3172 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3174 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
3175 // they can without bumping into floating or positioned objects. Ideally they will go right up
3176 // to the border of the root selection block.
3177 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
3178 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
3179 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
3180 } else if (childState != SelectionNone)
3181 // We must be a block that has some selected object inside it. Go ahead and recur.
3182 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
3183 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
3188 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3189 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
3191 LayoutUnit logicalTop = lastLogicalTop;
3192 LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
3193 if (logicalHeight <= static_cast<LayoutUnit>(0))
3194 return LayoutRect();
3196 // Get the selection offsets for the bottom of the gap
3197 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
3198 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
3199 LayoutUnit logicalWidth = logicalRight - logicalLeft;
3200 if (logicalWidth <= static_cast<LayoutUnit>(0))
3201 return LayoutRect();