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 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"
41 #include "PaintInfo.h"
42 #include "RenderCombineText.h"
43 #include "RenderDeprecatedFlexibleBox.h"
44 #include "RenderImage.h"
45 #include "RenderInline.h"
46 #include "RenderLayer.h"
47 #include "RenderMarquee.h"
48 #include "RenderReplica.h"
49 #include "RenderTableCell.h"
50 #include "RenderTextFragment.h"
51 #include "RenderTheme.h"
52 #include "RenderView.h"
54 #include "SVGTextRunRenderingContext.h"
55 #include "TransformState.h"
56 #include <wtf/StdLibExtras.h>
60 using namespace Unicode;
64 using namespace HTMLNames;
66 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
67 static ColumnInfoMap* gColumnInfoMap = 0;
69 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
70 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
72 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
73 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
75 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
77 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
78 static int gDelayUpdateScrollInfo = 0;
79 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
81 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
83 // Our MarginInfo state used when laying out block children.
84 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding, int afterBorderPadding)
85 : m_atBeforeSideOfBlock(true)
86 , m_atAfterSideOfBlock(false)
87 , m_marginBeforeQuirk(false)
88 , m_marginAfterQuirk(false)
89 , m_determinedMarginBeforeQuirk(false)
91 // Whether or not we can collapse our own margins with our children. We don't do this
92 // if we had any border/padding (obviously), if we're the root or HTML elements, or if
93 // we're positioned, floating, a table cell.
94 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned()
95 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
96 && !block->isWritingModeRoot() && block->style()->hasAutoColumnCount() && block->style()->hasAutoColumnWidth()
97 && !block->style()->columnSpan();
99 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && (beforeBorderPadding == 0) && block->style()->marginBeforeCollapse() != MSEPARATE;
101 // If any height other than auto is specified in CSS, then we don't collapse our bottom
102 // margins with our children's margins. To do otherwise would be to risk odd visual
103 // effects when the children overflow out of the parent block and yet still collapse
104 // with it. We also don't collapse if we have any bottom border/padding.
105 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
106 (block->style()->logicalHeight().isAuto() && block->style()->logicalHeight().value() == 0) && block->style()->marginAfterCollapse() != MSEPARATE;
108 m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginBeforeCollapse() == MDISCARD ||
109 block->style()->marginAfterCollapse() == MDISCARD;
111 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0;
112 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0;
115 // -------------------------------------------------------------------------------------------------------
117 RenderBlock::RenderBlock(Node* node)
120 , m_beingDestroyed(false)
121 , m_hasPositionedFloats(false)
123 setChildrenInline(true);
126 RenderBlock::~RenderBlock()
128 if (m_floatingObjects)
129 deleteAllValues(m_floatingObjects->set());
132 delete gColumnInfoMap->take(this);
134 if (gPercentHeightDescendantsMap) {
135 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
136 HashSet<RenderBox*>::iterator end = descendantSet->end();
137 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
138 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
139 ASSERT(containerSet);
142 ASSERT(containerSet->contains(this));
143 containerSet->remove(this);
144 if (containerSet->isEmpty()) {
145 gPercentHeightContainerMap->remove(*descendant);
149 delete descendantSet;
154 void RenderBlock::willBeDestroyed()
156 // Mark as being destroyed to avoid trouble with merges in removeChild().
157 m_beingDestroyed = true;
159 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
160 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
161 children()->destroyLeftoverChildren();
163 // Destroy our continuation before anything other than anonymous children.
164 // The reason we don't destroy it before anonymous children is that they may
165 // have continuations of their own that are anonymous children of our continuation.
166 RenderBoxModelObject* continuation = this->continuation();
168 continuation->destroy();
172 if (!documentBeingDestroyed()) {
173 if (firstLineBox()) {
174 // We can't wait for RenderBox::destroy to clear the selection,
175 // because by then we will have nuked the line boxes.
176 // FIXME: The FrameSelection should be responsible for this when it
177 // is notified of DOM mutations.
178 if (isSelectionBorder())
179 view()->clearSelection();
181 // If we are an anonymous block, then our line boxes might have children
182 // that will outlast this block. In the non-anonymous block case those
183 // children will be destroyed by the time we return from this function.
184 if (isAnonymousBlock()) {
185 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
186 while (InlineBox* childBox = box->firstChild())
191 parent()->dirtyLinesFromChangedChild(this);
194 m_lineBoxes.deleteLineBoxes(renderArena());
196 RenderBox::willBeDestroyed();
199 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
201 s_canPropagateFloatIntoSibling = style() ? !isFloatingOrPositioned() && !avoidsFloats() : false;
203 setReplaced(newStyle->isDisplayInlineType());
205 if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) {
206 if (newStyle->position() == StaticPosition)
207 // Clear our positioned objects list. Our absolutely positioned descendants will be
208 // inserted into our containing block's positioned objects list during layout.
209 removePositionedObjects(0);
210 else if (style()->position() == StaticPosition) {
211 // Remove our absolutely positioned descendants from their current containing block.
212 // They will be inserted into our positioned objects list during layout.
213 RenderObject* cb = parent();
214 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
215 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
216 cb = cb->containingBlock();
222 if (cb->isRenderBlock())
223 toRenderBlock(cb)->removePositionedObjects(this);
226 if (containsFloats() && !isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
227 markAllDescendantsWithFloatsForLayout();
230 RenderBox::styleWillChange(diff, newStyle);
233 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
235 RenderBox::styleDidChange(diff, oldStyle);
237 if (!isAnonymousBlock()) {
238 // Ensure that all of our continuation blocks pick up the new style.
239 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
240 RenderBoxModelObject* nextCont = currCont->continuation();
241 currCont->setContinuation(0);
242 currCont->setStyle(style());
243 currCont->setContinuation(nextCont);
247 // FIXME: We could save this call when the change only affected non-inherited properties
248 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
249 if (child->isAnonymousBlock()) {
250 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
251 if (style()->specifiesColumns()) {
252 if (child->style()->specifiesColumns())
253 newStyle->inheritColumnPropertiesFrom(style());
254 if (child->style()->columnSpan())
255 newStyle->setColumnSpan(true);
257 newStyle->setDisplay(BLOCK);
258 child->setStyle(newStyle.release());
264 // Update pseudos for :before and :after now.
265 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
266 updateBeforeAfterContent(BEFORE);
267 updateBeforeAfterContent(AFTER);
270 // After our style changed, if we lose our ability to propagate floats into next sibling
271 // blocks, then we need to find the top most parent containing that overhanging float and
272 // then mark its descendants with floats for layout and clear all floats from its next
273 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
274 bool canPropagateFloatIntoSibling = !isFloatingOrPositioned() && !avoidsFloats();
275 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
276 RenderBlock* parentBlock = this;
277 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
278 FloatingObjectSetIterator end = floatingObjectSet.end();
280 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
281 if (curr->isRenderBlock()) {
282 RenderBlock* currBlock = toRenderBlock(curr);
284 if (currBlock->hasOverhangingFloats()) {
285 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
286 RenderBox* renderer = (*it)->renderer();
287 if (currBlock->hasOverhangingFloat(renderer)) {
288 parentBlock = currBlock;
296 parentBlock->markAllDescendantsWithFloatsForLayout();
297 parentBlock->markSiblingsWithFloatsForLayout();
301 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
303 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
304 if (parent() && parent()->createsAnonymousWrapper())
306 return children()->updateBeforeAfterContent(this, pseudoId);
309 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
311 if (beforeChild && beforeChild->parent() == this)
314 RenderBlock* curr = toRenderBlock(continuation());
315 RenderBlock* nextToLast = this;
316 RenderBlock* last = this;
318 if (beforeChild && beforeChild->parent() == curr) {
319 if (curr->firstChild() == beforeChild)
326 curr = toRenderBlock(curr->continuation());
329 if (!beforeChild && !last->firstChild())
334 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
336 RenderBlock* flow = continuationBefore(beforeChild);
337 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
338 RenderBoxModelObject* beforeChildParent = 0;
340 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
342 RenderBoxModelObject* cont = flow->continuation();
344 beforeChildParent = cont;
346 beforeChildParent = flow;
349 if (newChild->isFloatingOrPositioned())
350 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
352 // A continuation always consists of two potential candidates: a block or an anonymous
353 // column span box holding column span children.
354 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
355 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
356 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
358 if (flow == beforeChildParent)
359 return flow->addChildIgnoringContinuation(newChild, beforeChild);
361 // The goal here is to match up if we can, so that we can coalesce and create the
362 // minimal # of continuations needed for the inline.
363 if (childIsNormal == bcpIsNormal)
364 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
365 if (flowIsNormal == childIsNormal)
366 return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
367 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
371 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
373 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
375 // The goal is to locate a suitable box in which to place our child.
376 RenderBlock* beforeChildParent = toRenderBlock(beforeChild && beforeChild->parent()->isRenderBlock() ? beforeChild->parent() : lastChild());
378 // If the new child is floating or positioned it can just go in that block.
379 if (newChild->isFloatingOrPositioned())
380 return beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
382 // See if the child can be placed in the box.
383 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
384 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
386 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans)
387 return beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
390 // Create a new block of the correct type.
391 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
392 children()->appendChildNode(this, newBox);
393 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
397 RenderObject* immediateChild = beforeChild;
398 bool isPreviousBlockViable = true;
399 while (immediateChild->parent() != this) {
400 if (isPreviousBlockViable)
401 isPreviousBlockViable = !immediateChild->previousSibling();
402 immediateChild = immediateChild->parent();
404 if (isPreviousBlockViable && immediateChild->previousSibling())
405 return toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
407 // Split our anonymous blocks.
408 RenderObject* newBeforeChild = splitAnonymousBlocksAroundChild(beforeChild);
410 // Create a new anonymous box of the appropriate type.
411 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
412 children()->insertChildNode(this, newBox, newBeforeChild);
413 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
417 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
419 for (RenderObject* curr = this; curr; curr = curr->parent()) {
420 if (!curr->isRenderBlock() || curr->isFloatingOrPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
421 || curr->isInlineBlockOrInlineTable())
424 RenderBlock* currBlock = toRenderBlock(curr);
425 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
428 if (currBlock->isAnonymousColumnSpanBlock())
434 RenderBlock* RenderBlock::clone() const
436 RenderBlock* cloneBlock;
437 if (isAnonymousBlock())
438 cloneBlock = createAnonymousBlock();
440 cloneBlock = new (renderArena()) RenderBlock(node());
441 cloneBlock->setStyle(style());
443 cloneBlock->setChildrenInline(childrenInline());
447 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
448 RenderBlock* middleBlock,
449 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
451 // Create a clone of this inline.
452 RenderBlock* cloneBlock = clone();
453 if (!isAnonymousBlock())
454 cloneBlock->setContinuation(oldCont);
456 // Now take all of the children from beforeChild to the end and remove
457 // them from |this| and place them in the clone.
458 if (!beforeChild && isAfterContent(lastChild()))
459 beforeChild = lastChild();
460 moveChildrenTo(cloneBlock, beforeChild, 0);
462 // Hook |clone| up as the continuation of the middle block.
463 if (!cloneBlock->isAnonymousBlock())
464 middleBlock->setContinuation(cloneBlock);
466 // We have been reparented and are now under the fromBlock. We need
467 // to walk up our block parent chain until we hit the containing anonymous columns block.
468 // Once we hit the anonymous columns block we're done.
469 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
470 RenderBoxModelObject* currChild = this;
472 while (curr && curr != fromBlock) {
473 ASSERT(curr->isRenderBlock());
475 RenderBlock* blockCurr = toRenderBlock(curr);
477 // Create a new clone.
478 RenderBlock* cloneChild = cloneBlock;
479 cloneBlock = blockCurr->clone();
481 // Insert our child clone as the first child.
482 cloneBlock->children()->appendChildNode(cloneBlock, cloneChild);
484 // Hook the clone up as a continuation of |curr|. Note we do encounter
485 // anonymous blocks possibly as we walk up the block chain. When we split an
486 // anonymous block, there's no need to do any continuation hookup, since we haven't
487 // actually split a real element.
488 if (!blockCurr->isAnonymousBlock()) {
489 oldCont = blockCurr->continuation();
490 blockCurr->setContinuation(cloneBlock);
491 cloneBlock->setContinuation(oldCont);
494 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
495 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
496 // content gets properly destroyed.
497 if (document()->usesBeforeAfterRules())
498 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
500 // Now we need to take all of the children starting from the first child
501 // *after* currChild and append them all to the clone.
502 RenderObject* afterContent = isAfterContent(cloneBlock->lastChild()) ? cloneBlock->lastChild() : 0;
503 blockCurr->moveChildrenTo(cloneBlock, currChild->nextSibling(), 0, afterContent);
505 // Keep walking up the chain.
507 curr = toRenderBoxModelObject(curr->parent());
510 // Now we are at the columns block level. We need to put the clone into the toBlock.
511 toBlock->children()->appendChildNode(toBlock, cloneBlock);
513 // Now take all the children after currChild and remove them from the fromBlock
514 // and put them in the toBlock.
515 fromBlock->moveChildrenTo(toBlock, currChild->nextSibling(), 0);
518 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
519 RenderObject* newChild, RenderBoxModelObject* oldCont)
521 RenderBlock* pre = 0;
522 RenderBlock* block = containingColumnsBlock();
524 // Delete our line boxes before we do the inline split into continuations.
525 block->deleteLineBoxTree();
527 bool madeNewBeforeBlock = false;
528 if (block->isAnonymousColumnsBlock()) {
529 // We can reuse this block and make it the preBlock of the next continuation.
531 pre->removePositionedObjects(0);
532 block = toRenderBlock(block->parent());
534 // No anonymous block available for use. Make one.
535 pre = block->createAnonymousColumnsBlock();
536 pre->setChildrenInline(false);
537 madeNewBeforeBlock = true;
540 RenderBlock* post = block->createAnonymousColumnsBlock();
541 post->setChildrenInline(false);
543 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
544 if (madeNewBeforeBlock)
545 block->children()->insertChildNode(block, pre, boxFirst);
546 block->children()->insertChildNode(block, newBlockBox, boxFirst);
547 block->children()->insertChildNode(block, post, boxFirst);
548 block->setChildrenInline(false);
550 if (madeNewBeforeBlock)
551 block->moveChildrenTo(pre, boxFirst, 0);
553 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
555 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
556 // time in makeChildrenNonInline by just setting this explicitly up front.
557 newBlockBox->setChildrenInline(false);
559 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
560 // connected, thus allowing newChild access to a renderArena should it need
561 // to wrap itself in additional boxes (e.g., table construction).
562 newBlockBox->addChild(newChild);
564 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
565 // get deleted properly. Because objects moves from the pre block into the post block, we want to
566 // make new line boxes instead of leaving the old line boxes around.
567 pre->setNeedsLayoutAndPrefWidthsRecalc();
568 block->setNeedsLayoutAndPrefWidthsRecalc();
569 post->setNeedsLayoutAndPrefWidthsRecalc();
572 RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild)
574 while (beforeChild->parent() != this) {
575 RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent());
576 if (blockToSplit->firstChild() != beforeChild) {
577 // We have to split the parentBlock into two blocks.
578 RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit);
579 post->setChildrenInline(blockToSplit->childrenInline());
580 RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent());
581 parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling());
582 blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer());
583 post->setNeedsLayoutAndPrefWidthsRecalc();
584 blockToSplit->setNeedsLayoutAndPrefWidthsRecalc();
587 beforeChild = blockToSplit;
592 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
594 RenderBlock* pre = 0;
595 RenderBlock* post = 0;
596 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
597 // so that we don't have to patch all of the rest of the code later on.
599 // Delete the block's line boxes before we do the split.
600 block->deleteLineBoxTree();
602 if (beforeChild && beforeChild->parent() != this)
603 beforeChild = splitAnonymousBlocksAroundChild(beforeChild);
605 if (beforeChild != firstChild()) {
606 pre = block->createAnonymousColumnsBlock();
607 pre->setChildrenInline(block->childrenInline());
611 post = block->createAnonymousColumnsBlock();
612 post->setChildrenInline(block->childrenInline());
615 RenderObject* boxFirst = block->firstChild();
617 block->children()->insertChildNode(block, pre, boxFirst);
618 block->children()->insertChildNode(block, newBlockBox, boxFirst);
620 block->children()->insertChildNode(block, post, boxFirst);
621 block->setChildrenInline(false);
623 // 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).
624 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
625 block->moveChildrenTo(post, beforeChild, 0, true);
627 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
628 // time in makeChildrenNonInline by just setting this explicitly up front.
629 newBlockBox->setChildrenInline(false);
631 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
632 // connected, thus allowing newChild access to a renderArena should it need
633 // to wrap itself in additional boxes (e.g., table construction).
634 newBlockBox->addChild(newChild);
636 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
637 // get deleted properly. Because objects moved from the pre block into the post block, we want to
638 // make new line boxes instead of leaving the old line boxes around.
640 pre->setNeedsLayoutAndPrefWidthsRecalc();
641 block->setNeedsLayoutAndPrefWidthsRecalc();
643 post->setNeedsLayoutAndPrefWidthsRecalc();
646 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
648 // FIXME: This function is the gateway for the addition of column-span support. It will
649 // be added to in three stages:
650 // (1) Immediate children of a multi-column block can span.
651 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
652 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
653 // cross the streams and have to cope with both types of continuations mixed together).
654 // This function currently supports (1) and (2).
655 RenderBlock* columnsBlockAncestor = 0;
656 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isFloatingOrPositioned()
657 && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
658 if (style()->specifiesColumns())
659 columnsBlockAncestor = this;
660 else if (!isInline() && parent() && parent()->isRenderBlock())
661 columnsBlockAncestor = toRenderBlock(parent())->containingColumnsBlock(false);
663 return columnsBlockAncestor;
666 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
668 // Make sure we don't append things after :after-generated content if we have it.
670 RenderObject* lastRenderer = lastChild();
671 if (isAfterContent(lastRenderer))
672 beforeChild = lastRenderer;
673 else if (lastRenderer && lastRenderer->isAnonymousBlock() && isAfterContent(lastRenderer->lastChild()))
674 beforeChild = lastRenderer->lastChild();
677 // If the requested beforeChild is not one of our children, then this is because
678 // there is an anonymous container within this object that contains the beforeChild.
679 if (beforeChild && beforeChild->parent() != this) {
680 RenderObject* anonymousChild = beforeChild->parent();
681 ASSERT(anonymousChild);
683 while (anonymousChild->parent() != this)
684 anonymousChild = anonymousChild->parent();
686 ASSERT(anonymousChild->isAnonymous());
688 if (anonymousChild->isAnonymousBlock()) {
689 // Insert the child into the anonymous block box instead of here.
690 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
691 beforeChild->parent()->addChild(newChild, beforeChild);
693 addChild(newChild, beforeChild->parent());
697 ASSERT(anonymousChild->isTable());
698 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
699 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
700 || newChild->isTableSection()
701 || newChild->isTableRow()
702 || newChild->isTableCell()) {
703 // Insert into the anonymous table.
704 anonymousChild->addChild(newChild, beforeChild);
708 // Go on to insert before the anonymous table.
709 beforeChild = anonymousChild;
712 // Check for a spanning element in columns.
713 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
714 if (columnsBlockAncestor) {
715 // We are placing a column-span element inside a block.
716 RenderBlock* newBox = createAnonymousColumnSpanBlock();
718 if (columnsBlockAncestor != this) {
719 // We are nested inside a multi-column element and are being split by the span. We have to break up
720 // our block into continuations.
721 RenderBoxModelObject* oldContinuation = continuation();
722 setContinuation(newBox);
724 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
725 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
726 // content gets properly destroyed.
727 bool isLastChild = (beforeChild == lastChild());
728 if (document()->usesBeforeAfterRules())
729 children()->updateBeforeAfterContent(this, AFTER);
730 if (isLastChild && beforeChild != lastChild())
731 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
732 // point to be 0. It's just a straight append now.
734 splitFlow(beforeChild, newBox, newChild, oldContinuation);
738 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
739 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
740 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
741 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
745 bool madeBoxesNonInline = false;
747 // A block has to either have all of its children inline, or all of its children as blocks.
748 // So, if our children are currently inline and a block child has to be inserted, we move all our
749 // inline children into anonymous block boxes.
750 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
751 // This is a block with inline content. Wrap the inline content in anonymous blocks.
752 makeChildrenNonInline(beforeChild);
753 madeBoxesNonInline = true;
755 if (beforeChild && beforeChild->parent() != this) {
756 beforeChild = beforeChild->parent();
757 ASSERT(beforeChild->isAnonymousBlock());
758 ASSERT(beforeChild->parent() == this);
760 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
761 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
762 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
763 // a new one is created and inserted into our list of children in the appropriate position.
764 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
766 if (afterChild && afterChild->isAnonymousBlock()) {
767 afterChild->addChild(newChild);
771 if (newChild->isInline()) {
772 // No suitable existing anonymous box - create a new one.
773 RenderBlock* newBox = createAnonymousBlock();
774 RenderBox::addChild(newBox, beforeChild);
775 newBox->addChild(newChild);
780 RenderBox::addChild(newChild, beforeChild);
782 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
783 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
784 // this object may be dead here
787 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
789 if (continuation() && !isAnonymousBlock())
790 return addChildToContinuation(newChild, beforeChild);
791 return addChildIgnoringContinuation(newChild, beforeChild);
794 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
796 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
797 return addChildToAnonymousColumnBlocks(newChild, beforeChild);
798 return addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
801 static void getInlineRun(RenderObject* start, RenderObject* boundary,
802 RenderObject*& inlineRunStart,
803 RenderObject*& inlineRunEnd)
805 // Beginning at |start| we find the largest contiguous run of inlines that
806 // we can. We denote the run with start and end points, |inlineRunStart|
807 // and |inlineRunEnd|. Note that these two values may be the same if
808 // we encounter only one inline.
810 // We skip any non-inlines we encounter as long as we haven't found any
813 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
814 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
817 // Start by skipping as many non-inlines as we can.
818 RenderObject * curr = start;
821 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
822 curr = curr->nextSibling();
824 inlineRunStart = inlineRunEnd = curr;
827 return; // No more inline children to be found.
829 sawInline = curr->isInline();
831 curr = curr->nextSibling();
832 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
834 if (curr->isInline())
836 curr = curr->nextSibling();
838 } while (!sawInline);
841 void RenderBlock::deleteLineBoxTree()
843 m_lineBoxes.deleteLineBoxTree(renderArena());
846 RootInlineBox* RenderBlock::createRootInlineBox()
848 return new (renderArena()) RootInlineBox(this);
851 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
853 RootInlineBox* rootBox = createRootInlineBox();
854 m_lineBoxes.appendLineBox(rootBox);
858 void RenderBlock::moveChildTo(RenderBlock* to, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
860 ASSERT(this == child->parent());
861 ASSERT(!beforeChild || to == beforeChild->parent());
862 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
865 void RenderBlock::moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
867 ASSERT(!beforeChild || to == beforeChild->parent());
868 RenderObject* nextChild = startChild;
869 while (nextChild && nextChild != endChild) {
870 RenderObject* child = nextChild;
871 nextChild = child->nextSibling();
872 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
873 if (child == endChild)
878 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
880 // makeChildrenNonInline takes a block whose children are *all* inline and it
881 // makes sure that inline children are coalesced under anonymous
882 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
883 // the new block child that is causing us to have to wrap all the inlines. This
884 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
885 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
887 ASSERT(isInlineBlockOrInlineTable() || !isInline());
888 ASSERT(!insertionPoint || insertionPoint->parent() == this);
890 setChildrenInline(false);
892 RenderObject *child = firstChild();
899 RenderObject *inlineRunStart, *inlineRunEnd;
900 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
905 child = inlineRunEnd->nextSibling();
907 RenderBlock* block = createAnonymousBlock();
908 children()->insertChildNode(this, block, inlineRunStart);
909 moveChildrenTo(block, inlineRunStart, child);
913 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
914 ASSERT(!c->isInline());
920 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
922 ASSERT(child->isAnonymousBlock());
923 ASSERT(!child->childrenInline());
925 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
928 RenderObject* firstAnChild = child->m_children.firstChild();
929 RenderObject* lastAnChild = child->m_children.lastChild();
931 RenderObject* o = firstAnChild;
934 o = o->nextSibling();
936 firstAnChild->setPreviousSibling(child->previousSibling());
937 lastAnChild->setNextSibling(child->nextSibling());
938 if (child->previousSibling())
939 child->previousSibling()->setNextSibling(firstAnChild);
940 if (child->nextSibling())
941 child->nextSibling()->setPreviousSibling(lastAnChild);
943 if (child == m_children.firstChild())
944 m_children.setFirstChild(firstAnChild);
945 if (child == m_children.lastChild())
946 m_children.setLastChild(lastAnChild);
948 if (child == m_children.firstChild())
949 m_children.setFirstChild(child->nextSibling());
950 if (child == m_children.lastChild())
951 m_children.setLastChild(child->previousSibling());
953 if (child->previousSibling())
954 child->previousSibling()->setNextSibling(child->nextSibling());
955 if (child->nextSibling())
956 child->nextSibling()->setPreviousSibling(child->previousSibling());
959 child->setPreviousSibling(0);
960 child->setNextSibling(0);
962 child->children()->setFirstChild(0);
968 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
970 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
974 if (oldChild->parent() && oldChild->parent()->isDetails())
978 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
979 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
982 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
983 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
986 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
987 || (next && (next->isRubyRun() || next->isRubyBase())))
993 // Make sure the types of the anonymous blocks match up.
994 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
995 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
998 void RenderBlock::removeChild(RenderObject* oldChild)
1000 // If this child is a block, and if our previous and next siblings are
1001 // both anonymous blocks with inline content, then we can go ahead and
1002 // fold the inline content back together.
1003 RenderObject* prev = oldChild->previousSibling();
1004 RenderObject* next = oldChild->nextSibling();
1005 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1006 if (canMergeAnonymousBlocks && prev && next) {
1007 prev->setNeedsLayoutAndPrefWidthsRecalc();
1008 RenderBlock* nextBlock = toRenderBlock(next);
1009 RenderBlock* prevBlock = toRenderBlock(prev);
1011 if (prev->childrenInline() != next->childrenInline()) {
1012 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1013 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1015 // Place the inline children block inside of the block children block instead of deleting it.
1016 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1017 // to clear out inherited column properties by just making a new style, and to also clear the
1018 // column span flag if it is set.
1019 ASSERT(!inlineChildrenBlock->continuation());
1020 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
1021 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
1022 inlineChildrenBlock->setStyle(newStyle);
1024 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1025 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1026 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer());
1027 next->setNeedsLayoutAndPrefWidthsRecalc();
1029 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1030 // of "this". we null out prev or next so that is not used later in the function.
1031 if (inlineChildrenBlock == prevBlock)
1036 // Take all the children out of the |next| block and put them in
1037 // the |prev| block.
1038 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1040 // Delete the now-empty block's lines and nuke it.
1041 nextBlock->deleteLineBoxTree();
1042 nextBlock->destroy();
1047 RenderBox::removeChild(oldChild);
1049 RenderObject* child = prev ? prev : next;
1050 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isDeprecatedFlexibleBox()) {
1051 // The removal has knocked us down to containing only a single anonymous
1052 // box. We can go ahead and pull the content right back up into our
1054 setNeedsLayoutAndPrefWidthsRecalc();
1055 setChildrenInline(child->childrenInline());
1056 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, child->hasLayer()));
1057 anonBlock->moveAllChildrenTo(this, child->hasLayer());
1058 // Delete the now-empty block's lines and nuke it.
1059 anonBlock->deleteLineBoxTree();
1060 anonBlock->destroy();
1063 if (!firstChild() && !documentBeingDestroyed()) {
1064 // If this was our last child be sure to clear out our line boxes.
1065 if (childrenInline())
1066 lineBoxes()->deleteLineBoxes(renderArena());
1070 bool RenderBlock::isSelfCollapsingBlock() const
1072 // We are not self-collapsing if we
1073 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1075 // (c) have border/padding,
1076 // (d) have a min-height
1077 // (e) have specified that one of our margins can't collapse using a CSS extension
1078 if (logicalHeight() > 0
1079 || isTable() || borderAndPaddingLogicalHeight()
1080 || style()->logicalMinHeight().isPositive()
1081 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1084 Length logicalHeightLength = style()->logicalHeight();
1085 bool hasAutoHeight = logicalHeightLength.isAuto();
1086 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1087 hasAutoHeight = true;
1088 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1089 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1090 hasAutoHeight = false;
1094 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1095 // on whether we have content that is all self-collapsing or not.
1096 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1097 // If the block has inline children, see if we generated any line boxes. If we have any
1098 // line boxes, then we can't be self-collapsing, since we have content.
1099 if (childrenInline())
1100 return !firstLineBox();
1102 // Whether or not we collapse is dependent on whether all our normal flow children
1103 // are also self-collapsing.
1104 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1105 if (child->isFloatingOrPositioned())
1107 if (!child->isSelfCollapsingBlock())
1115 void RenderBlock::startDelayUpdateScrollInfo()
1117 if (gDelayUpdateScrollInfo == 0) {
1118 ASSERT(!gDelayedUpdateScrollInfoSet);
1119 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1121 ASSERT(gDelayedUpdateScrollInfoSet);
1122 ++gDelayUpdateScrollInfo;
1125 void RenderBlock::finishDelayUpdateScrollInfo()
1127 --gDelayUpdateScrollInfo;
1128 ASSERT(gDelayUpdateScrollInfo >= 0);
1129 if (gDelayUpdateScrollInfo == 0) {
1130 ASSERT(gDelayedUpdateScrollInfoSet);
1132 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1133 gDelayedUpdateScrollInfoSet = 0;
1135 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1136 RenderBlock* block = *it;
1137 if (block->hasOverflowClip()) {
1138 block->layer()->updateScrollInfoAfterLayout();
1144 void RenderBlock::updateScrollInfoAfterLayout()
1146 if (hasOverflowClip()) {
1147 if (gDelayUpdateScrollInfo)
1148 gDelayedUpdateScrollInfoSet->add(this);
1150 layer()->updateScrollInfoAfterLayout();
1154 void RenderBlock::layout()
1156 // Update our first letter info now.
1157 updateFirstLetter();
1159 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1163 // It's safe to check for control clip here, since controls can never be table cells.
1164 // If we have a lightweight clip, there can never be any overflow from children.
1165 if (hasControlClip() && m_overflow)
1166 clearLayoutOverflow();
1169 void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight, BlockLayoutPass layoutPass)
1171 ASSERT(needsLayout());
1173 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1174 return; // cause us to come in here. Just bail.
1176 if (!relayoutChildren && simplifiedLayout())
1179 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
1181 int oldWidth = logicalWidth();
1182 int oldColumnWidth = desiredColumnWidth();
1184 computeLogicalWidth();
1189 if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth())
1190 relayoutChildren = true;
1192 // If nothing changed about our floating positioned objects, let's go ahead and try to place them as
1193 // floats to avoid doing two passes.
1194 BlockLayoutPass floatsLayoutPass = layoutPass;
1195 if (floatsLayoutPass == NormalLayoutPass && !relayoutChildren && !positionedFloatsNeedRelayout())
1196 floatsLayoutPass = PositionedFloatLayoutPass;
1197 clearFloats(floatsLayoutPass);
1199 int previousHeight = logicalHeight();
1200 setLogicalHeight(0);
1201 bool hasSpecifiedPageLogicalHeight = false;
1202 bool pageLogicalHeightChanged = false;
1203 ColumnInfo* colInfo = columnInfo();
1205 if (!pageLogicalHeight) {
1206 // We need to go ahead and set our explicit page height if one exists, so that we can
1207 // avoid doing two layout passes.
1208 computeLogicalHeight();
1209 int columnHeight = contentLogicalHeight();
1210 if (columnHeight > 0) {
1211 pageLogicalHeight = columnHeight;
1212 hasSpecifiedPageLogicalHeight = true;
1214 setLogicalHeight(0);
1216 if (colInfo->columnHeight() != pageLogicalHeight && m_everHadLayout) {
1217 colInfo->setColumnHeight(pageLogicalHeight);
1218 pageLogicalHeightChanged = true;
1221 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1222 colInfo->clearForcedBreaks();
1225 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, colInfo);
1227 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1228 // our current maximal positive and negative margins. These values are used when we
1229 // are collapsed with adjacent blocks, so for example, if you have block A and B
1230 // collapsing together, then you'd take the maximal positive margin from both A and B
1231 // and subtract it from the maximal negative margin from both A and B to get the
1232 // true collapsed margin. This algorithm is recursive, so when we finish layout()
1233 // our block knows its current maximal positive/negative values.
1235 // Start out by setting our margin values to our current margins. Table cells have
1236 // no margins, so we don't fill in the values for table cells.
1237 bool isCell = isTableCell();
1239 initMaxMarginValues();
1241 setMarginBeforeQuirk(style()->marginBefore().quirk());
1242 setMarginAfterQuirk(style()->marginAfter().quirk());
1245 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
1246 // See if this form is malformed (i.e., unclosed). If so, don't give the form
1248 setMaxMarginAfterValues(0, 0);
1251 setPaginationStrut(0);
1254 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
1255 if (scrollsOverflow()) {
1256 if (style()->overflowX() == OSCROLL)
1257 layer()->setHasHorizontalScrollbar(true);
1258 if (style()->overflowY() == OSCROLL)
1259 layer()->setHasVerticalScrollbar(true);
1262 int repaintLogicalTop = 0;
1263 int repaintLogicalBottom = 0;
1264 int maxFloatLogicalBottom = 0;
1265 if (!firstChild() && !isAnonymousBlock())
1266 setChildrenInline(true);
1267 if (childrenInline())
1268 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1270 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1272 // Expand our intrinsic height to encompass floats.
1273 int toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1274 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1275 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1277 if (layoutColumns(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1280 // Calculate our new height.
1281 int oldHeight = logicalHeight();
1282 int oldClientAfterEdge = clientLogicalBottom();
1283 computeLogicalHeight();
1284 int newHeight = logicalHeight();
1285 if (oldHeight != newHeight) {
1286 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1287 // One of our children's floats may have become an overhanging float for us. We need to look for it.
1288 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1289 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
1290 RenderBlock* block = toRenderBlock(child);
1291 if (block->lowestFloatLogicalBottomIncludingPositionedFloats() + block->logicalTop() > newHeight)
1292 addOverhangingFloats(block, -block->logicalLeft(), -block->logicalTop(), false);
1298 if (previousHeight != newHeight)
1299 relayoutChildren = true;
1301 bool needAnotherLayoutPass = layoutPositionedObjects(relayoutChildren || isRoot());
1303 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1304 computeOverflow(oldClientAfterEdge);
1308 if (view()->layoutState()->m_pageLogicalHeight)
1309 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop()));
1311 updateLayerTransform();
1313 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1314 // we overflow or not.
1315 updateScrollInfoAfterLayout();
1317 // FIXME: This repaint logic should be moved into a separate helper function!
1318 // Repaint with our new bounds if they are different from our old bounds.
1319 bool didFullRepaint = repainter.repaintAfterLayout();
1320 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1321 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1322 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1323 int repaintLogicalLeft = logicalLeftVisualOverflow();
1324 int repaintLogicalRight = logicalRightVisualOverflow();
1325 if (hasOverflowClip()) {
1326 // 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.
1327 // 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.
1328 // layoutInlineChildren should be patched to compute the entire repaint rect.
1329 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1330 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1333 IntRect repaintRect;
1334 if (isHorizontalWritingMode())
1335 repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1337 repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1339 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1340 adjustRectForColumns(repaintRect);
1342 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1344 if (hasOverflowClip()) {
1345 // Adjust repaint rect for scroll offset
1346 repaintRect.move(-layer()->scrolledContentOffset());
1348 // Don't allow this rect to spill out of our overflow box.
1349 repaintRect.intersect(IntRect(0, 0, width(), height()));
1352 // Make sure the rect is still non-empty after intersecting for overflow above
1353 if (!repaintRect.isEmpty()) {
1354 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1355 if (hasReflection())
1356 repaintRectangle(reflectedRect(repaintRect));
1360 if (needAnotherLayoutPass && layoutPass == NormalLayoutPass) {
1361 setChildNeedsLayout(true, false);
1362 layoutBlock(false, pageLogicalHeight, PositionedFloatLayoutPass);
1364 setNeedsLayout(false);
1367 void RenderBlock::addOverflowFromChildren()
1369 if (!hasColumns()) {
1370 if (childrenInline())
1371 addOverflowFromInlineChildren();
1373 addOverflowFromBlockChildren();
1375 ColumnInfo* colInfo = columnInfo();
1376 if (columnCount(colInfo)) {
1377 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1378 if (isHorizontalWritingMode()) {
1379 int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0;
1380 int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.maxX()) : 0;
1381 int overflowHeight = borderBefore() + paddingBefore() + colInfo->columnHeight();
1382 addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
1383 if (!hasOverflowClip())
1384 addVisualOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
1386 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1387 int overflowTop = !style()->isLeftToRightDirection() ? min(0, lastRect.y()) : 0;
1388 int overflowBottom = style()->isLeftToRightDirection() ? max(height(), lastRect.maxY()) : 0;
1389 int overflowWidth = borderBefore() + paddingBefore() + colInfo->columnHeight();
1390 addLayoutOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
1391 if (!hasOverflowClip())
1392 addVisualOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
1398 void RenderBlock::computeOverflow(int oldClientAfterEdge, bool recomputeFloats)
1400 // Add overflow from children.
1401 addOverflowFromChildren();
1403 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1404 addOverflowFromFloats();
1406 // Add in the overflow from positioned objects.
1407 addOverflowFromPositionedObjects();
1409 if (hasOverflowClip()) {
1410 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1411 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1412 // be considered reachable.
1413 IntRect clientRect(clientBoxRect());
1414 IntRect rectToApply;
1415 if (isHorizontalWritingMode())
1416 rectToApply = IntRect(clientRect.x(), clientRect.y(), 1, max(0, oldClientAfterEdge - clientRect.y()));
1418 rectToApply = IntRect(clientRect.x(), clientRect.y(), max(0, oldClientAfterEdge - clientRect.x()), 1);
1419 addLayoutOverflow(rectToApply);
1422 // Add visual overflow from box-shadow and reflections.
1423 addShadowOverflow();
1426 void RenderBlock::addOverflowFromBlockChildren()
1428 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1429 if (!child->isFloatingOrPositioned())
1430 addOverflowFromChild(child);
1434 void RenderBlock::addOverflowFromFloats()
1436 if (!m_floatingObjects)
1439 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1440 FloatingObjectSetIterator end = floatingObjectSet.end();
1441 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1442 FloatingObject* r = *it;
1443 if (r->m_isDescendant && !r->m_renderer->isPositioned())
1444 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1449 void RenderBlock::addOverflowFromPositionedObjects()
1451 if (!m_positionedObjects)
1454 RenderBox* positionedObject;
1455 Iterator end = m_positionedObjects->end();
1456 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1457 positionedObject = *it;
1459 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1460 if (positionedObject->style()->position() != FixedPosition)
1461 addOverflowFromChild(positionedObject);
1465 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1467 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
1468 || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot() || isRoot();
1471 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1473 bool isHorizontal = isHorizontalWritingMode();
1474 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1475 RenderLayer* childLayer = child->layer();
1477 childLayer->setStaticInlinePosition(borderAndPaddingStart());
1479 int logicalTop = logicalHeight();
1480 if (!marginInfo.canCollapseWithMarginBefore()) {
1481 child->computeBlockDirectionMargins(this);
1482 int marginBefore = marginBeforeForChild(child);
1483 int collapsedBeforePos = marginInfo.positiveMargin();
1484 int collapsedBeforeNeg = marginInfo.negativeMargin();
1485 if (marginBefore > 0) {
1486 if (marginBefore > collapsedBeforePos)
1487 collapsedBeforePos = marginBefore;
1489 if (-marginBefore > collapsedBeforeNeg)
1490 collapsedBeforeNeg = -marginBefore;
1492 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
1494 if (childLayer->staticBlockPosition() != logicalTop) {
1495 childLayer->setStaticBlockPosition(logicalTop);
1496 if (hasStaticBlockPosition)
1497 child->setChildNeedsLayout(true, false);
1501 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1503 // The float should be positioned taking into account the bottom margin
1504 // of the previous flow. We add that margin into the height, get the
1505 // float positioned properly, and then subtract the margin out of the
1506 // height again. In the case of self-collapsing blocks, we always just
1507 // use the top margins, since the self-collapsing block collapsed its
1508 // own bottom margin into its top margin.
1510 // Note also that the previous flow may collapse its margin into the top of
1511 // our block. If this is the case, then we do not add the margin in to our
1512 // height when computing the position of the float. This condition can be tested
1513 // for by simply calling canCollapseWithMarginBefore. See
1514 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1515 // an example of this scenario.
1516 int marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin();
1517 setLogicalHeight(logicalHeight() + marginOffset);
1518 positionNewFloats();
1519 setLogicalHeight(logicalHeight() - marginOffset);
1522 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1524 // Handle in the given order
1525 return handlePositionedChild(child, marginInfo)
1526 || handleFloatingChild(child, marginInfo)
1527 || handleRunInChild(child);
1531 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1533 if (child->isPositioned()) {
1534 child->containingBlock()->insertPositionedObject(child);
1535 adjustPositionedBlock(child, marginInfo);
1541 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1543 if (child->isFloating()) {
1544 insertFloatingObject(child);
1545 adjustFloatingBlock(marginInfo);
1551 bool RenderBlock::handleRunInChild(RenderBox* child)
1553 // See if we have a run-in element with inline children. If the
1554 // children aren't inline, then just treat the run-in as a normal
1556 if (!child->isRunIn() || !child->childrenInline())
1558 // FIXME: We don't handle non-block elements with run-in for now.
1559 if (!child->isRenderBlock())
1562 // Get the next non-positioned/non-floating RenderBlock.
1563 RenderBlock* blockRunIn = toRenderBlock(child);
1564 RenderObject* curr = blockRunIn->nextSibling();
1565 while (curr && curr->isFloatingOrPositioned())
1566 curr = curr->nextSibling();
1568 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous())
1571 RenderBlock* currBlock = toRenderBlock(curr);
1573 // Remove the old child.
1574 children()->removeChildNode(this, blockRunIn);
1576 // Create an inline.
1577 Node* runInNode = blockRunIn->node();
1578 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1579 inlineRunIn->setStyle(blockRunIn->style());
1581 bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER;
1583 // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already
1584 // been regenerated by the new inline.
1585 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) {
1586 RenderObject* nextSibling = runInChild->nextSibling();
1587 if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) {
1588 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
1589 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
1591 runInChild = nextSibling;
1594 // 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
1595 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1596 currBlock->addChild(inlineRunIn, currBlock->firstChild());
1598 // If the run-in had an element, we need to set the new renderer.
1600 runInNode->setRenderer(inlineRunIn);
1602 // Destroy the block run-in, which includes deleting its line box tree.
1603 blockRunIn->deleteLineBoxTree();
1604 blockRunIn->destroy();
1606 // The block acts like an inline, so just null out its
1612 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1614 // Get the four margin values for the child and cache them.
1615 const MarginValues childMargins = marginValuesForChild(child);
1617 // Get our max pos and neg top margins.
1618 int posTop = childMargins.positiveMarginBefore();
1619 int negTop = childMargins.negativeMarginBefore();
1621 // For self-collapsing blocks, collapse our bottom margins into our
1622 // top to get new posTop and negTop values.
1623 if (child->isSelfCollapsingBlock()) {
1624 posTop = max(posTop, childMargins.positiveMarginAfter());
1625 negTop = max(negTop, childMargins.negativeMarginAfter());
1628 // See if the top margin is quirky. We only care if this child has
1629 // margins that will collapse with us.
1630 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
1632 if (marginInfo.canCollapseWithMarginBefore()) {
1633 // This child is collapsing with the top of the
1634 // block. If it has larger margin values, then we need to update
1635 // our own maximal values.
1636 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
1637 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
1639 // The minute any of the margins involved isn't a quirk, don't
1640 // collapse it away, even if the margin is smaller (www.webreference.com
1641 // has an example of this, a <dt> with 0.8em author-specified inside
1642 // a <dl> inside a <td>.
1643 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
1644 setMarginBeforeQuirk(false);
1645 marginInfo.setDeterminedMarginBeforeQuirk(true);
1648 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
1649 // We have no top margin and our top child has a quirky margin.
1650 // We will pick up this quirky margin and pass it through.
1651 // This deals with the <td><div><p> case.
1652 // Don't do this for a block that split two inlines though. You do
1653 // still apply margins in this case.
1654 setMarginBeforeQuirk(true);
1657 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1658 marginInfo.setMarginBeforeQuirk(topQuirk);
1660 int beforeCollapseLogicalTop = logicalHeight();
1661 int logicalTop = beforeCollapseLogicalTop;
1662 if (child->isSelfCollapsingBlock()) {
1663 // This child has no height. We need to compute our
1664 // position before we collapse the child's margins together,
1665 // so that we can get an accurate position for the zero-height block.
1666 int collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1667 int collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1668 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1670 // Now collapse the child's margins together, which means examining our
1671 // bottom margin values as well.
1672 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1673 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1675 if (!marginInfo.canCollapseWithMarginBefore())
1676 // We need to make sure that the position of the self-collapsing block
1677 // is correct, since it could have overflowing content
1678 // that needs to be positioned correctly (e.g., a block that
1679 // had a specified height of 0 but that actually had subcontent).
1680 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1683 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1684 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
1685 logicalTop = logicalHeight();
1687 else if (!marginInfo.atBeforeSideOfBlock() ||
1688 (!marginInfo.canCollapseMarginBeforeWithChildren()
1689 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
1690 // We're collapsing with a previous sibling's margins and not
1691 // with the top of the block.
1692 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
1693 logicalTop = logicalHeight();
1696 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1697 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1699 if (marginInfo.margin())
1700 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
1703 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1704 // collapsed into the page edge.
1705 LayoutState* layoutState = view()->layoutState();
1706 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop) {
1707 int oldLogicalTop = logicalTop;
1708 logicalTop = min(logicalTop, nextPageLogicalTopExcludingBoundaryPoint(beforeCollapseLogicalTop));
1709 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1714 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos)
1716 int heightIncrease = getClearDelta(child, yPos);
1717 if (!heightIncrease)
1720 if (child->isSelfCollapsingBlock()) {
1721 // For self-collapsing blocks that clear, they can still collapse their
1722 // margins with following siblings. Reset the current margins to represent
1723 // the self-collapsing block's margins only.
1725 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
1726 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
1727 // self-collapsing block's bottom margin.
1728 bool atBottomOfBlock = true;
1729 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
1730 if (!curr->isFloatingOrPositioned())
1731 atBottomOfBlock = false;
1734 MarginValues childMargins = marginValuesForChild(child);
1735 if (atBottomOfBlock) {
1736 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1737 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1739 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1740 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1743 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
1744 // of the parent block).
1745 setLogicalHeight(child->y() - max(0, marginInfo.margin()));
1747 // Increase our height by the amount we had to clear.
1748 setLogicalHeight(height() + heightIncrease);
1750 if (marginInfo.canCollapseWithMarginBefore()) {
1751 // We can no longer collapse with the top of the block since a clear
1752 // occurred. The empty blocks collapse into the cleared block.
1753 // FIXME: This isn't quite correct. Need clarification for what to do
1754 // if the height the cleared block is offset by is smaller than the
1755 // margins involved.
1756 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1757 marginInfo.setAtBeforeSideOfBlock(false);
1760 return yPos + heightIncrease;
1763 int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo)
1765 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1766 // relayout if there are intruding floats.
1767 int logicalTopEstimate = logicalHeight();
1768 if (!marginInfo.canCollapseWithMarginBefore()) {
1769 int childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child);
1770 logicalTopEstimate += max(marginInfo.margin(), childMarginBefore);
1773 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1775 LayoutState* layoutState = view()->layoutState();
1776 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight())
1777 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTopExcludingBoundaryPoint(logicalHeight()));
1779 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1781 if (layoutState->isPaginated()) {
1782 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1783 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1785 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1786 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1788 if (!child->selfNeedsLayout() && child->isRenderBlock())
1789 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1792 return logicalTopEstimate;
1795 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
1797 int startPosition = borderStart() + paddingStart();
1798 int totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1800 // Add in our start margin.
1801 int childMarginStart = marginStartForChild(child);
1802 int newPosition = startPosition + childMarginStart;
1804 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1805 // to shift over as necessary to dodge any floats that might get in the way.
1806 if (child->avoidsFloats()) {
1807 int startOff = style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(logicalHeight(), false) : totalAvailableLogicalWidth - logicalRightOffsetForLine(logicalHeight(), false);
1808 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1809 if (childMarginStart < 0)
1810 startOff += childMarginStart;
1811 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1812 } else if (startOff != startPosition) {
1813 // The object is shifting to the "end" side of the block. The object might be centered, so we need to
1814 // recalculate our inline direction margins. Note that the containing block content
1815 // width computation will take into account the delta between |startOff| and |startPosition|
1816 // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
1818 child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(logicalTopForChild(child), false), logicalWidthForChild(child));
1819 newPosition = startOff + marginStartForChild(child);
1823 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
1826 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1828 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1829 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1830 // with our children.
1831 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1833 if (!marginInfo.marginAfterQuirk())
1834 setMarginAfterQuirk(false);
1836 if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
1837 // We have no bottom margin and our last child has a quirky margin.
1838 // We will pick up this quirky margin and pass it through.
1839 // This deals with the <td><div><p> case.
1840 setMarginAfterQuirk(true);
1844 void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginInfo& marginInfo)
1846 marginInfo.setAtAfterSideOfBlock(true);
1848 // If we can't collapse with children then go ahead and add in the bottom margin.
1849 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1850 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
1851 setLogicalHeight(logicalHeight() + marginInfo.margin());
1853 // Now add in our bottom border/padding.
1854 setLogicalHeight(logicalHeight() + afterSide);
1856 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1857 // If this happens, ensure that the computed height is increased to the minimal height.
1858 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1860 // Update our bottom collapsed margin info.
1861 setCollapsedBottomMargin(marginInfo);
1864 void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta)
1866 if (isHorizontalWritingMode()) {
1867 if (applyDelta == ApplyLayoutDelta)
1868 view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0));
1869 child->setX(logicalLeft);
1871 if (applyDelta == ApplyLayoutDelta)
1872 view()->addLayoutDelta(IntSize(0, child->y() - logicalLeft));
1873 child->setY(logicalLeft);
1877 void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta)
1879 if (isHorizontalWritingMode()) {
1880 if (applyDelta == ApplyLayoutDelta)
1881 view()->addLayoutDelta(IntSize(0, child->y() - logicalTop));
1882 child->setY(logicalTop);
1884 if (applyDelta == ApplyLayoutDelta)
1885 view()->addLayoutDelta(IntSize(child->x() - logicalTop, 0));
1886 child->setX(logicalTop);
1890 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom)
1892 if (gPercentHeightDescendantsMap) {
1893 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
1894 HashSet<RenderBox*>::iterator end = descendants->end();
1895 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
1896 RenderBox* box = *it;
1897 while (box != this) {
1898 if (box->normalChildNeedsLayout())
1900 box->setChildNeedsLayout(true, false);
1901 box = box->containingBlock();
1910 int beforeEdge = borderBefore() + paddingBefore();
1911 int afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1913 setLogicalHeight(beforeEdge);
1915 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
1916 MarginInfo marginInfo(this, beforeEdge, afterEdge);
1918 // Fieldsets need to find their legend and position it inside the border of the object.
1919 // The legend then gets skipped during normal layout. The same is true for ruby text.
1920 // It doesn't get included in the normal layout process but is instead skipped.
1921 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
1923 int previousFloatLogicalBottom = 0;
1924 maxFloatLogicalBottom = 0;
1926 RenderBox* next = firstChildBox();
1929 RenderBox* child = next;
1930 next = child->nextSiblingBox();
1932 if (childToExclude == child)
1933 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
1935 // Make sure we layout children if they need it.
1936 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1937 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1938 if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView()))
1939 child->setChildNeedsLayout(true, false);
1941 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1942 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
1943 child->setPreferredLogicalWidthsDirty(true, false);
1945 // Handle the four types of special elements first. These include positioned content, floating content, compacts and
1946 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
1947 if (handleSpecialChild(child, marginInfo))
1950 // Lay out the child.
1951 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
1954 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
1955 // determining the correct collapsed bottom margin information.
1956 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
1959 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom)
1961 int oldPosMarginBefore = maxPositiveMarginBefore();
1962 int oldNegMarginBefore = maxNegativeMarginBefore();
1964 // The child is a normal flow object. Compute the margins we will use for collapsing now.
1965 child->computeBlockDirectionMargins(this);
1967 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
1968 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1969 marginInfo.setAtBeforeSideOfBlock(false);
1970 marginInfo.clearMargin();
1973 // Try to guess our correct logical top position. In most cases this guess will
1974 // be correct. Only if we're wrong (when we compute the real logical top position)
1975 // will we have to potentially relayout.
1976 int logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo);
1978 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
1979 IntRect oldRect(child->x(), child->y() , child->width(), child->height());
1980 int oldLogicalTop = logicalTopForChild(child);
1983 IntSize oldLayoutDelta = view()->layoutDelta();
1985 // Go ahead and position the child as though it didn't collapse with the top.
1986 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
1988 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
1989 bool markDescendantsWithFloats = false;
1990 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
1991 markDescendantsWithFloats = true;
1992 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
1993 // If an element might be affected by the presence of floats, then always mark it for
1995 int fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottomIncludingPositionedFloats());
1996 if (fb > logicalTopEstimate)
1997 markDescendantsWithFloats = true;
2000 if (childRenderBlock) {
2001 if (markDescendantsWithFloats)
2002 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2003 if (!child->isWritingModeRoot())
2004 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottomIncludingPositionedFloats());
2007 if (!child->needsLayout())
2008 child->markForPaginationRelayoutIfNeeded();
2010 bool childHadLayout = child->m_everHadLayout;
2011 bool childNeededLayout = child->needsLayout();
2012 if (childNeededLayout)
2015 // Cache if we are at the top of the block right now.
2016 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
2018 // Now determine the correct ypos based off examination of collapsing margin
2020 int logicalTopBeforeClear = collapseMargins(child, marginInfo);
2022 // Now check for clear.
2023 int logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
2025 bool paginated = view()->layoutState()->isPaginated();
2027 int oldTop = logicalTopAfterClear;
2029 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
2030 logicalTopAfterClear = applyBeforeBreak(child, logicalTopAfterClear);
2032 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
2033 int logicalTopBeforeUnsplittableAdjustment = logicalTopAfterClear;
2034 int logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, logicalTopAfterClear);
2036 int paginationStrut = 0;
2037 int unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
2038 if (unsplittableAdjustmentDelta)
2039 paginationStrut = unsplittableAdjustmentDelta;
2040 else if (childRenderBlock && childRenderBlock->paginationStrut())
2041 paginationStrut = childRenderBlock->paginationStrut();
2043 if (paginationStrut) {
2044 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
2045 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
2046 if (atBeforeSideOfBlock && oldTop == logicalTopBeforeClear && !isPositioned() && !isTableCell()) {
2047 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
2048 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
2049 // and pushes to the next page anyway, so not too concerned about it.
2050 setPaginationStrut(logicalTopAfterClear + paginationStrut);
2051 if (childRenderBlock)
2052 childRenderBlock->setPaginationStrut(0);
2054 logicalTopAfterClear += paginationStrut;
2057 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
2058 setLogicalHeight(logicalHeight() + (logicalTopAfterClear - oldTop));
2061 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2063 // Now we have a final top position. See if it really does end up being different from our estimate.
2064 if (logicalTopAfterClear != logicalTopEstimate) {
2065 if (child->shrinkToAvoidFloats()) {
2066 // The child's width depends on the line width.
2067 // When the child shifts to clear an item, its width can
2068 // change (because it has more available line width).
2069 // So go ahead and mark the item as dirty.
2070 child->setChildNeedsLayout(true, false);
2072 if (childRenderBlock) {
2073 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2074 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2075 if (!child->needsLayout())
2076 child->markForPaginationRelayoutIfNeeded();
2079 // Our guess was wrong. Make the child lay itself out again.
2080 child->layoutIfNeeded();
2083 // We are no longer at the top of the block if we encounter a non-empty child.
2084 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2085 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2086 marginInfo.setAtBeforeSideOfBlock(false);
2088 // Now place the child in the correct left position
2089 determineLogicalLeftPositionForChild(child);
2091 // Update our height now that the child has been placed in the correct position.
2092 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2093 if (child->style()->marginAfterCollapse() == MSEPARATE) {
2094 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2095 marginInfo.clearMargin();
2097 // If the child has overhanging floats that intrude into following siblings (or possibly out
2098 // of this block), then the parent gets notified of the floats now.
2099 if (childRenderBlock && childRenderBlock->containsFloats())
2100 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), -child->logicalLeft(), -child->logicalTop(), !childNeededLayout));
2102 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
2103 if (childOffset.width() || childOffset.height()) {
2104 view()->addLayoutDelta(childOffset);
2106 // If the child moved, we have to repaint it as well as any floating/positioned
2107 // descendants. An exception is if we need a layout. In this case, we know we're going to
2108 // repaint ourselves (and the child) anyway.
2109 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2110 child->repaintDuringLayoutIfMoved(oldRect);
2113 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2115 child->repaintOverhangingFloats(true);
2119 // Check for an after page/column break.
2120 int newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2121 if (newHeight != height())
2122 setLogicalHeight(newHeight);
2125 ASSERT(oldLayoutDelta == view()->layoutDelta());
2128 void RenderBlock::simplifiedNormalFlowLayout()
2130 if (childrenInline()) {
2131 ListHashSet<RootInlineBox*> lineBoxes;
2132 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
2133 RenderObject* o = walker.current();
2134 if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
2135 o->layoutIfNeeded();
2136 if (toRenderBox(o)->inlineBoxWrapper()) {
2137 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2140 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline()))
2141 o->setNeedsLayout(false);
2144 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2145 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2146 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2147 RootInlineBox* box = *it;
2148 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2151 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2152 if (!box->isPositioned())
2153 box->layoutIfNeeded();
2158 bool RenderBlock::simplifiedLayout()
2160 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2163 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2165 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2168 // Lay out positioned descendants or objects that just need to recompute overflow.
2169 if (needsSimplifiedNormalFlowLayout())
2170 simplifiedNormalFlowLayout();
2172 // Lay out our positioned objects if our positioned child bit is set.
2173 if (posChildNeedsLayout() && layoutPositionedObjects(false))
2174 return false; // If a positioned float is causing our normal flow to change, then we have to bail and do a full layout.
2176 // Recompute our overflow information.
2177 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2178 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2179 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2180 // lowestPosition on every relayout so it's not a regression.
2182 computeOverflow(clientLogicalBottom(), true);
2186 updateLayerTransform();
2188 updateScrollInfoAfterLayout();
2190 setNeedsLayout(false);
2194 bool RenderBlock::positionedFloatsNeedRelayout()
2196 if (!hasPositionedFloats())
2199 RenderBox* positionedObject;
2200 Iterator end = m_positionedObjects->end();
2201 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2202 positionedObject = *it;
2203 if (!positionedObject->isFloating())
2206 if (positionedObject->needsLayout())
2209 if (positionedObject->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && positionedObject->parent() != this && positionedObject->parent()->isBlockFlow())
2212 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2219 bool RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2221 if (!m_positionedObjects)
2225 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2227 bool didFloatingBoxRelayout = false;
2230 Iterator end = m_positionedObjects->end();
2231 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2233 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2234 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2235 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2236 // positioned explicitly) this should not incur a performance penalty.
2237 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow()))
2238 r->setChildNeedsLayout(true, false);
2240 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2241 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
2242 r->setPreferredLogicalWidthsDirty(true, false);
2244 if (!r->needsLayout())
2245 r->markForPaginationRelayoutIfNeeded();
2247 // FIXME: Technically we could check the old placement and the new placement of the box and only invalidate if
2248 // the margin box of the object actually changed.
2249 if (r->needsLayout() && r->isFloating())
2250 didFloatingBoxRelayout = true;
2252 // 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
2253 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2254 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2255 r->setNeedsLayout(false);
2256 r->layoutIfNeeded();
2260 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2262 return didFloatingBoxRelayout;
2265 void RenderBlock::markPositionedObjectsForLayout()
2267 if (m_positionedObjects) {
2269 Iterator end = m_positionedObjects->end();
2270 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2272 r->setChildNeedsLayout(true);
2277 void RenderBlock::markForPaginationRelayoutIfNeeded()
2279 ASSERT(!needsLayout());
2283 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2284 setChildNeedsLayout(true, false);
2287 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2289 // Repaint any overhanging floats (if we know we're the one to paint them).
2290 // Otherwise, bail out.
2291 if (!hasOverhangingFloats())
2294 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2295 // in this block. Better yet would be to push extra state for the containers of other floats.
2296 LayoutStateDisabler layoutStateDisabler(view());
2297 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2298 FloatingObjectSetIterator end = floatingObjectSet.end();
2299 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2300 FloatingObject* r = *it;
2301 // Only repaint the object if it is overhanging, is not in its own layer, and
2302 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2303 // condition is replaced with being a descendant of us.
2304 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
2305 r->m_renderer->repaint();
2306 r->m_renderer->repaintOverhangingFloats();
2311 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2313 LayoutPoint adjustedPaintOffset = paintOffset + location();
2315 PaintPhase phase = paintInfo.phase;
2317 // Check if we need to do anything at all.
2318 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2319 // paints the root's background.
2321 LayoutRect overflowBox = visualOverflowRect();
2322 flipForWritingMode(overflowBox);
2323 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2324 overflowBox.moveBy(adjustedPaintOffset);
2325 if (!overflowBox.intersects(paintInfo.rect))
2329 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
2330 paintObject(paintInfo, adjustedPaintOffset);
2332 popContentsClip(paintInfo, phase, adjustedPaintOffset);
2334 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2335 // z-index. We paint after we painted the background/border, so that the scrollbars will
2336 // sit above the background/border.
2337 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2338 layer()->paintOverflowControls(paintInfo.context, adjustedPaintOffset, paintInfo.rect);
2341 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2343 if (paintInfo.context->paintingDisabled())
2346 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2347 bool ruleTransparent = style()->columnRuleIsTransparent();
2348 EBorderStyle ruleStyle = style()->columnRuleStyle();
2349 LayoutUnit ruleWidth = style()->columnRuleWidth();
2350 LayoutUnit colGap = columnGap();
2351 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap;
2355 // We need to do multiple passes, breaking up our child painting into strips.
2356 ColumnInfo* colInfo = columnInfo();
2357 unsigned colCount = columnCount(colInfo);
2358 LayoutUnit currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2359 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
2360 LayoutUnit ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2362 const AffineTransform& currentCTM = paintInfo.context->getCTM();
2363 bool antialias = !currentCTM.isIdentityOrTranslationOrFlipped();
2365 for (unsigned i = 0; i < colCount; i++) {
2366 LayoutRect colRect = columnRectAt(colInfo, i);
2368 LayoutUnit inlineDirectionSize = isHorizontalWritingMode() ? colRect.width() : colRect.height();
2370 // Move to the next position.
2371 if (style()->isLeftToRightDirection()) {
2372 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2373 currLogicalLeftOffset += inlineDirectionSize + colGap;
2375 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2376 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2379 // Now paint the column rule.
2380 if (i < colCount - 1) {
2381 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : paintOffset.x() + borderBefore() + paddingBefore();
2382 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth();
2383 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleWidth / 2 + ruleAdd;
2384 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth;
2385 drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom,
2386 style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0, antialias);
2389 ruleLogicalLeft = currLogicalLeftOffset;
2393 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2395 // We need to do multiple passes, breaking up our child painting into strips.
2396 GraphicsContext* context = paintInfo.context;
2397 ColumnInfo* colInfo = columnInfo();
2398 unsigned colCount = columnCount(colInfo);
2401 LayoutUnit currLogicalTopOffset = 0;
2402 for (unsigned i = 0; i < colCount; i++) {
2403 // For each rect, we clip to the rect, and then we adjust our coords.
2404 LayoutRect colRect = columnRectAt(colInfo, i);
2405 flipForWritingMode(colRect);
2406 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2407 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2408 colRect.moveBy(paintOffset);
2409 PaintInfo info(paintInfo);
2410 info.rect.intersect(colRect);
2412 if (!info.rect.isEmpty()) {
2413 GraphicsContextStateSaver stateSaver(*context);
2415 // Each strip pushes a clip, since column boxes are specified as being
2416 // like overflow:hidden.
2417 context->clip(colRect);
2419 // Adjust our x and y when painting.
2420 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2422 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2424 paintContents(info, adjustedPaintOffset);
2427 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2428 if (style()->isFlippedBlocksWritingMode())
2429 currLogicalTopOffset += blockDelta;
2431 currLogicalTopOffset -= blockDelta;
2435 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2437 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2438 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2439 // will do a full repaint().
2440 if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
2443 if (childrenInline())
2444 m_lineBoxes.paint(this, paintInfo, paintOffset);
2446 paintChildren(paintInfo, paintOffset);
2449 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2451 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2452 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2454 // We don't paint our own background, but we do let the kids paint their backgrounds.
2455 PaintInfo info(paintInfo);
2456 info.phase = newPhase;
2457 info.updatePaintingRootForChildren(this);
2459 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2460 // NSViews. Do not add any more code for this.
2461 RenderView* renderView = view();
2462 bool usePrintRect = !renderView->printRect().isEmpty();
2464 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2465 // Check for page-break-before: always, and if it's set, break and bail.
2466 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2467 LayoutUnit absoluteChildY = paintOffset.y() + child->y();
2468 if (checkBeforeAlways
2469 && absoluteChildY > paintInfo.rect.y()
2470 && absoluteChildY < paintInfo.rect.maxY()) {
2471 view()->setBestTruncatedAt(absoluteChildY, this, true);
2475 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2476 // Paginate block-level replaced elements.
2477 if (absoluteChildY + child->height() > renderView->printRect().maxY()) {
2478 if (absoluteChildY < renderView->truncatedAt())
2479 renderView->setBestTruncatedAt(absoluteChildY, child);
2480 // If we were able to truncate, don't paint.
2481 if (absoluteChildY >= renderView->truncatedAt())
2486 LayoutPoint childPoint = flipForWritingMode(child, paintOffset, ParentToChildFlippingAdjustment);
2487 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2488 child->paint(info, childPoint);
2490 // Check for page-break-after: always, and if it's set, break and bail.
2491 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2492 if (checkAfterAlways
2493 && (absoluteChildY + child->height()) > paintInfo.rect.y()
2494 && (absoluteChildY + child->height()) < paintInfo.rect.maxY()) {
2495 view()->setBestTruncatedAt(absoluteChildY + child->height() + max(0, child->collapsedMarginAfter()), this, true);
2501 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2503 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2504 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2505 RenderObject* caretPainter;
2506 bool isContentEditable;
2507 if (type == CursorCaret) {
2508 caretPainter = frame()->selection()->caretRenderer();
2509 isContentEditable = frame()->selection()->isContentEditable();
2511 caretPainter = frame()->page()->dragCaretController()->caretRenderer();
2512 isContentEditable = frame()->page()->dragCaretController()->isContentEditable();
2515 if (caretPainter == this && (isContentEditable || caretBrowsing)) {
2516 // Convert the painting offset into the local coordinate system of this renderer,
2517 // to match the localCaretRect computed by the FrameSelection
2518 LayoutPoint adjustedPaintOffset = paintOffset;
2519 offsetForContents(adjustedPaintOffset);
2521 if (type == CursorCaret)
2522 frame()->selection()->paintCaret(paintInfo.context, adjustedPaintOffset, paintInfo.rect);
2524 frame()->page()->dragCaretController()->paintDragCaret(frame(), paintInfo.context, adjustedPaintOffset, paintInfo.rect);
2528 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2530 PaintPhase paintPhase = paintInfo.phase;
2532 // 1. paint background, borders etc
2533 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2534 if (hasBoxDecorations())
2535 paintBoxDecorations(paintInfo, paintOffset);
2537 paintColumnRules(paintInfo, paintOffset);
2540 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2541 paintMask(paintInfo, paintOffset);
2545 // We're done. We don't bother painting any children.
2546 if (paintPhase == PaintPhaseBlockBackground)
2549 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2550 LayoutPoint scrolledOffset = paintOffset;
2551 if (hasOverflowClip())
2552 scrolledOffset.move(-layer()->scrolledContentOffset());
2554 // 2. paint contents
2555 if (paintPhase != PaintPhaseSelfOutline) {
2557 paintColumnContents(paintInfo, scrolledOffset);
2559 paintContents(paintInfo, scrolledOffset);
2562 // 3. paint selection
2563 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2564 bool isPrinting = document()->printing();
2565 if (!isPrinting && !hasColumns())
2566 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2569 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2571 paintColumnContents(paintInfo, scrolledOffset, true);
2573 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2576 // 5. paint outline.
2577 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2578 paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
2580 // 6. paint continuation outlines.
2581 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2582 RenderInline* inlineCont = inlineElementContinuation();
2583 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2584 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2585 RenderBlock* cb = containingBlock();
2587 bool inlineEnclosedInSelfPaintingLayer = false;
2588 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2589 if (box->hasSelfPaintingLayer()) {
2590 inlineEnclosedInSelfPaintingLayer = true;
2595 if (!inlineEnclosedInSelfPaintingLayer)
2596 cb->addContinuationWithOutline(inlineRenderer);
2597 else if (!inlineRenderer->firstLineBox())
2598 inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2600 paintContinuationOutlines(paintInfo, paintOffset);
2604 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2605 // then paint the caret.
2606 if (paintPhase == PaintPhaseForeground) {
2607 paintCaret(paintInfo, scrolledOffset, CursorCaret);
2608 paintCaret(paintInfo, scrolledOffset, DragCaret);
2612 IntPoint RenderBlock::flipFloatForWritingMode(const FloatingObject* child, const IntPoint& point) const
2614 if (!style()->isFlippedBlocksWritingMode())
2617 // This is similar to the ParentToChildFlippingAdjustment in RenderBox::flipForWritingMode. We have to subtract out our left/top offsets twice, since
2618 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2620 if (isHorizontalWritingMode())
2621 return IntPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
2622 return IntPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2625 void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2627 if (!m_floatingObjects)
2630 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2631 FloatingObjectSetIterator end = floatingObjectSet.end();
2632 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2633 FloatingObject* r = *it;
2634 // Only paint the object if our m_shouldPaint flag is set.
2635 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
2636 PaintInfo currentPaintInfo(paintInfo);
2637 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2638 LayoutPoint childPoint = flipFloatForWritingMode(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
2639 r->m_renderer->paint(currentPaintInfo, childPoint);
2640 if (!preservePhase) {
2641 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2642 r->m_renderer->paint(currentPaintInfo, childPoint);
2643 currentPaintInfo.phase = PaintPhaseFloat;
2644 r->m_renderer->paint(currentPaintInfo, childPoint);
2645 currentPaintInfo.phase = PaintPhaseForeground;
2646 r->m_renderer->paint(currentPaintInfo, childPoint);
2647 currentPaintInfo.phase = PaintPhaseOutline;
2648 r->m_renderer->paint(currentPaintInfo, childPoint);
2654 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2656 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox())
2659 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
2660 // We can check the first box and last box and avoid painting if we don't
2662 LayoutUnit yPos = paintOffset.y() + firstLineBox()->y();
2663 LayoutUnit h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y();
2664 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y())
2667 // See if our boxes intersect with the dirty rect. If so, then we paint
2668 // them. Note that boxes can easily overlap, so we can't make any assumptions
2669 // based off positions of our first line box or our last line box.
2670 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2671 yPos = paintOffset.y() + curr->y();
2672 h = curr->logicalHeight();
2673 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y())
2674 curr->paintEllipsisBox(paintInfo, paintOffset, curr->lineTop(), curr->lineBottom());
2679 RenderInline* RenderBlock::inlineElementContinuation() const
2681 RenderBoxModelObject* continuation = this->continuation();
2682 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2685 RenderBlock* RenderBlock::blockElementContinuation() const
2687 RenderBoxModelObject* currentContinuation = continuation();
2688 if (!currentContinuation || currentContinuation->isInline())
2690 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2691 if (nextContinuation->isAnonymousBlock())
2692 return nextContinuation->blockElementContinuation();
2693 return nextContinuation;
2696 static ContinuationOutlineTableMap* continuationOutlineTable()
2698 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2702 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2704 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2706 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2708 ContinuationOutlineTableMap* table = continuationOutlineTable();
2709 ListHashSet<RenderInline*>* continuations = table->get(this);
2710 if (!continuations) {
2711 continuations = new ListHashSet<RenderInline*>;
2712 table->set(this, continuations);
2715 continuations->add(flow);
2718 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2720 ContinuationOutlineTableMap* table = continuationOutlineTable();
2721 if (table->isEmpty())
2724 ListHashSet<RenderInline*>* continuations = table->get(this);
2728 return continuations->contains(flow);
2731 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2733 ContinuationOutlineTableMap* table = continuationOutlineTable();
2734 if (table->isEmpty())
2737 ListHashSet<RenderInline*>* continuations = table->get(this);
2741 LayoutPoint accumulatedPaintOffset = paintOffset;
2742 // Paint each continuation outline.
2743 ListHashSet<RenderInline*>::iterator end = continuations->end();
2744 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2745 // Need to add in the coordinates of the intervening blocks.
2746 RenderInline* flow = *it;
2747 RenderBlock* block = flow->containingBlock();
2748 for ( ; block && block != this; block = block->containingBlock())
2749 accumulatedPaintOffset.moveBy(block->location());
2751 flow->paintOutline(info.context, accumulatedPaintOffset);
2755 delete continuations;
2756 table->remove(this);
2759 bool RenderBlock::shouldPaintSelectionGaps() const
2761 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2764 bool RenderBlock::isSelectionRoot() const
2769 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2773 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
2774 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
2775 hasReflection() || hasMask() || isWritingModeRoot())
2778 if (view() && view()->selectionStart()) {
2779 Node* startElement = view()->selectionStart()->node();
2780 if (startElement && startElement->rootEditableElement() == node())
2787 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
2789 ASSERT(!needsLayout());
2791 if (!shouldPaintSelectionGaps())
2794 // FIXME: this is broken with transforms
2795 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2796 mapLocalToContainer(repaintContainer, false, false, transformState);
2797 IntPoint offsetFromRepaintContainer = roundedIntPoint(transformState.mappedPoint());
2799 if (hasOverflowClip())
2800 offsetFromRepaintContainer -= layer()->scrolledContentOffset();
2802 LayoutUnit lastTop = 0;
2803 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2804 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2806 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2809 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2811 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2812 LayoutUnit lastTop = 0;
2813 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2814 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2815 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2817 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
2818 if (!gapRectsBounds.isEmpty()) {
2819 if (RenderLayer* layer = enclosingLayer()) {
2820 gapRectsBounds.moveBy(-paintOffset);
2822 LayoutRect localBounds(gapRectsBounds);
2823 flipForWritingMode(localBounds);
2824 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2825 gapRectsBounds.move(layer->scrolledContentOffset());
2827 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2833 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const IntPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects)
2835 if (!positionedObjects)
2838 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
2839 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2841 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2845 static int blockDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
2847 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
2850 static int inlineDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
2852 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
2855 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
2858 if (isHorizontalWritingMode())
2859 result = logicalRect;
2861 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2862 flipForWritingMode(result);
2863 result.moveBy(rootBlockPhysicalPosition);
2867 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2868 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2870 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2871 // Clip out floating and positioned objects when painting selection gaps.
2873 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2874 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2875 rootBlock->flipForWritingMode(flippedBlockRect);
2876 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
2877 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get());
2878 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2879 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2880 clipOutPositionedObjects(paintInfo, IntPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes.
2881 if (m_floatingObjects) {
2882 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2883 FloatingObjectSetIterator end = floatingObjectSet.end();
2884 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2885 FloatingObject* r = *it;
2886 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
2887 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
2888 r->m_renderer->width(), r->m_renderer->height());
2889 rootBlock->flipForWritingMode(floatBox);
2890 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2891 paintInfo->context->clipOut(floatBox);
2896 // 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
2899 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
2902 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2903 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2904 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2905 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2906 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2910 if (childrenInline())
2911 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2913 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2915 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2916 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2917 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2918 logicalHeight(), paintInfo));
2922 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2923 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2927 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
2929 if (!firstLineBox()) {
2930 if (containsStart) {
2931 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
2933 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2934 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2935 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2940 RootInlineBox* lastSelectedLine = 0;
2941 RootInlineBox* curr;
2942 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
2944 // Now paint the gaps for the lines.
2945 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
2946 LayoutUnit selTop = curr->selectionTop();
2947 LayoutUnit selHeight = curr->selectionHeight();
2949 if (!containsStart && !lastSelectedLine &&
2950 selectionState() != SelectionStart && selectionState() != SelectionBoth)
2951 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2952 selTop, paintInfo));
2954 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
2955 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
2956 IntRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
2957 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
2958 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
2959 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
2961 lastSelectedLine = curr;
2964 if (containsStart && !lastSelectedLine)
2965 // VisibleSelection must start just after our last line.
2966 lastSelectedLine = lastRootBox();
2968 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
2969 // Go ahead and update our lastY to be the bottom of the last selected line.
2970 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
2971 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2972 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2977 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2978 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2982 // Go ahead and jump right to the first block child that contains some selected objects.
2984 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2986 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2987 SelectionState childState = curr->selectionState();
2988 if (childState == SelectionBoth || childState == SelectionEnd)
2989 sawSelectionEnd = true;
2991 if (curr->isFloatingOrPositioned())
2992 continue; // We must be a normal flow object in order to even be considered.
2994 if (curr->isRelPositioned() && curr->hasLayer()) {
2995 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2996 // Just disregard it completely.
2997 LayoutSize relOffset = curr->layer()->relativePositionOffset();
2998 if (relOffset.width() || relOffset.height())
3002 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
3003 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
3004 if (fillBlockGaps) {
3005 // We need to fill the vertical gap above this object.
3006 if (childState == SelectionEnd || childState == SelectionInside)
3007 // Fill the gap above the object.
3008 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3009 curr->logicalTop(), paintInfo));
3011 // 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*
3012 // our object. We know this if the selection did not end inside our object.
3013 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
3014 childState = SelectionNone;
3016 // Fill side gaps on this object based off its state.
3017 bool leftGap, rightGap;
3018 getSelectionGapInfo(childState, leftGap, rightGap);
3021 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3023 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3025 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
3026 // they can without bumping into floating or positioned objects. Ideally they will go right up
3027 // to the border of the root selection block.
3028 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
3029 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
3030 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
3031 } else if (childState != SelectionNone)
3032 // We must be a block that has some selected object inside it. Go ahead and recur.
3033 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
3034 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
3039 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3040 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
3042 LayoutUnit logicalTop = lastLogicalTop;
3043 LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
3044 if (logicalHeight <= static_cast<LayoutUnit>(0))
3045 return LayoutRect();
3047 // Get the selection offsets for the bottom of the gap
3048 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
3049 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
3050 LayoutUnit logicalWidth = logicalRight - logicalLeft;
3051 if (logicalWidth <= static_cast<LayoutUnit>(0))
3052 return LayoutRect();
3054 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
3056 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace());
3060 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3061 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3063 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3064 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
3065 LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalLeft, min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3066 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3067 if (rootBlockLogicalWidth <= static_cast<LayoutUnit>(0))
3068 return LayoutRect();
3070 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3072 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3076 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3077 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3079 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3080 LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalRight, max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3081 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
3082 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3083 if (rootBlockLogicalWidth <= static_cast<LayoutUnit>(0))
3084 return LayoutRect();
3086 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3088 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3092 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3094 bool ltr = style()->isLeftToRightDirection();
3095 leftGap = (state == RenderObject::SelectionInside) ||
3096 (state == RenderObject::SelectionEnd && ltr) ||
3097 (state == RenderObject::SelectionStart && !ltr);
3098 rightGap = (state == RenderObject::SelectionInside) ||
3099 (state == RenderObject::SelectionStart && ltr) ||
3100 (state == RenderObject::SelectionEnd && !ltr);
3103 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3105 LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
3106 if (logicalLeft == logicalLeftOffsetForContent()) {
3107 if (rootBlock != this)
3108 // The border can potentially be further extended by our containingBlock().
3109 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3112 RenderBlock* cb = this;
3113 while (cb != rootBlock) {
3114 logicalLeft += cb->logicalLeft();
3115 cb = cb->containingBlock();
3121 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3123 LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
3124 if (logicalRight == logicalRightOffsetForContent()) {
3125 if (rootBlock != this)
3126 // The border can potentially be further extended by our containingBlock().
3127 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
3128 return logicalRight;
3130 RenderBlock* cb = this;
3131 while (cb != rootBlock) {
3132 logicalRight += cb->logicalLeft();
3133 cb = cb->containingBlock();
3136 return logicalRight;
3139 void RenderBlock::insertPositionedObject(RenderBox* o)
3141 // Create the list of special objects if we don't aleady have one
3142 if (!m_positionedObjects)
3143 m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet);
3145 m_positionedObjects->add(o);
3148 void RenderBlock::removePositionedObject(RenderBox* o)
3150 if (m_positionedObjects)
3151 m_positionedObjects->remove(o);
3154 void RenderBlock::removePositionedObjects(RenderBlock* o)
3156 if (!m_positionedObjects)
3161 Iterator end = m_positionedObjects->end();
3163 Vector<RenderBox*, 16> deadObjects;
3165 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
3167 if (!o || r->isDescendantOf(o)) {
3169 r->setChildNeedsLayout(true, false);
3171 // It is parent blocks job to add positioned child to positioned objects list of its containing block
3172 // Parent layout needs to be invalidated to ensure this happens.
3173 RenderObject* p = r->parent();
3174 while (p && !p->isRenderBlock())
3177 p->setChildNeedsLayout(true);
3179 deadObjects.append(r);
3183 for (unsigned i = 0; i < deadObjects.size(); i++)
3184 m_positionedObjects->remove(deadObjects.at(i));
3187 RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3189 ASSERT(o->isFloating());
3191 // Create the list of special objects if we don't aleady have one
3192 if (!m_floatingObjects)
3193 m_floatingObjects = adoptPtr(new FloatingObjects);
3195 // Don't insert the object again if it's already in the list
3196 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();