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 "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLFormElement.h"
35 #include "HTMLNames.h"
36 #include "HitTestResult.h"
37 #include "InlineIterator.h"
38 #include "InlineTextBox.h"
39 #include "PaintInfo.h"
40 #include "RenderCombineText.h"
41 #include "RenderFlexibleBox.h"
42 #include "RenderImage.h"
43 #include "RenderInline.h"
44 #include "RenderLayer.h"
45 #include "RenderMarquee.h"
46 #include "RenderReplica.h"
47 #include "RenderTableCell.h"
48 #include "RenderTextFragment.h"
49 #include "RenderTheme.h"
50 #include "RenderView.h"
51 #include "SelectionController.h"
54 #include "TransformState.h"
55 #include <wtf/StdLibExtras.h>
59 using namespace Unicode;
63 using namespace HTMLNames;
65 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
66 static ColumnInfoMap* gColumnInfoMap = 0;
68 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
69 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
71 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
72 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
74 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
76 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
77 static int gDelayUpdateScrollInfo = 0;
78 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
80 // Our MarginInfo state used when laying out block children.
81 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding, int afterBorderPadding)
82 : m_atBeforeSideOfBlock(true)
83 , m_atAfterSideOfBlock(false)
84 , m_marginBeforeQuirk(false)
85 , m_marginAfterQuirk(false)
86 , m_determinedMarginBeforeQuirk(false)
88 // Whether or not we can collapse our own margins with our children. We don't do this
89 // if we had any border/padding (obviously), if we're the root or HTML elements, or if
90 // we're positioned, floating, a table cell.
91 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned()
92 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
93 && !block->isWritingModeRoot();
95 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && (beforeBorderPadding == 0) && block->style()->marginBeforeCollapse() != MSEPARATE;
97 // If any height other than auto is specified in CSS, then we don't collapse our bottom
98 // margins with our children's margins. To do otherwise would be to risk odd visual
99 // effects when the children overflow out of the parent block and yet still collapse
100 // with it. We also don't collapse if we have any bottom border/padding.
101 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
102 (block->style()->logicalHeight().isAuto() && block->style()->logicalHeight().value() == 0) && block->style()->marginAfterCollapse() != MSEPARATE;
104 m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginBeforeCollapse() == MDISCARD ||
105 block->style()->marginAfterCollapse() == MDISCARD;
107 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0;
108 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0;
111 // -------------------------------------------------------------------------------------------------------
113 RenderBlock::RenderBlock(Node* node)
115 , m_floatingObjects(0)
116 , m_positionedObjects(0)
119 , m_beingDestroyed(false)
121 setChildrenInline(true);
124 RenderBlock::~RenderBlock()
126 if (m_floatingObjects)
127 deleteAllValues(m_floatingObjects->set());
130 delete gColumnInfoMap->take(this);
132 if (gPercentHeightDescendantsMap) {
133 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
134 HashSet<RenderBox*>::iterator end = descendantSet->end();
135 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
136 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
137 ASSERT(containerSet);
140 ASSERT(containerSet->contains(this));
141 containerSet->remove(this);
142 if (containerSet->isEmpty()) {
143 gPercentHeightContainerMap->remove(*descendant);
147 delete descendantSet;
152 void RenderBlock::destroy()
154 // Mark as being destroyed to avoid trouble with merges in removeChild().
155 m_beingDestroyed = true;
157 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
158 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
159 children()->destroyLeftoverChildren();
161 // Destroy our continuation before anything other than anonymous children.
162 // The reason we don't destroy it before anonymous children is that they may
163 // have continuations of their own that are anonymous children of our continuation.
164 RenderBoxModelObject* continuation = this->continuation();
166 continuation->destroy();
170 if (!documentBeingDestroyed()) {
171 if (firstLineBox()) {
172 // We can't wait for RenderBox::destroy to clear the selection,
173 // because by then we will have nuked the line boxes.
174 // FIXME: The SelectionController should be responsible for this when it
175 // is notified of DOM mutations.
176 if (isSelectionBorder())
177 view()->clearSelection();
179 // If we are an anonymous block, then our line boxes might have children
180 // that will outlast this block. In the non-anonymous block case those
181 // children will be destroyed by the time we return from this function.
182 if (isAnonymousBlock()) {
183 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
184 while (InlineBox* childBox = box->firstChild())
188 } else if (isInline() && parent())
189 parent()->dirtyLinesFromChangedChild(this);
192 m_lineBoxes.deleteLineBoxes(renderArena());
194 RenderBox::destroy();
197 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
199 setReplaced(newStyle->isDisplayInlineType());
201 if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) {
202 if (newStyle->position() == StaticPosition)
203 // Clear our positioned objects list. Our absolutely positioned descendants will be
204 // inserted into our containing block's positioned objects list during layout.
205 removePositionedObjects(0);
206 else if (style()->position() == StaticPosition) {
207 // Remove our absolutely positioned descendants from their current containing block.
208 // They will be inserted into our positioned objects list during layout.
209 RenderObject* cb = parent();
210 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
211 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
212 cb = cb->containingBlock();
218 if (cb->isRenderBlock())
219 toRenderBlock(cb)->removePositionedObjects(this);
223 RenderBox::styleWillChange(diff, newStyle);
226 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
228 RenderBox::styleDidChange(diff, oldStyle);
230 if (!isAnonymousBlock()) {
231 // Ensure that all of our continuation blocks pick up the new style.
232 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
233 RenderBoxModelObject* nextCont = currCont->continuation();
234 currCont->setContinuation(0);
235 currCont->setStyle(style());
236 currCont->setContinuation(nextCont);
240 // FIXME: We could save this call when the change only affected non-inherited properties
241 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
242 if (child->isAnonymousBlock()) {
243 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
244 if (style()->specifiesColumns()) {
245 if (child->style()->specifiesColumns())
246 newStyle->inheritColumnPropertiesFrom(style());
247 if (child->style()->columnSpan())
248 newStyle->setColumnSpan(true);
250 newStyle->setDisplay(BLOCK);
251 child->setStyle(newStyle.release());
257 // Update pseudos for :before and :after now.
258 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
259 updateBeforeAfterContent(BEFORE);
260 updateBeforeAfterContent(AFTER);
264 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
266 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
267 if (parent() && parent()->createsAnonymousWrapper())
269 return children()->updateBeforeAfterContent(this, pseudoId);
272 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
274 if (beforeChild && beforeChild->parent() == this)
277 RenderBlock* curr = toRenderBlock(continuation());
278 RenderBlock* nextToLast = this;
279 RenderBlock* last = this;
281 if (beforeChild && beforeChild->parent() == curr) {
282 if (curr->firstChild() == beforeChild)
289 curr = toRenderBlock(curr->continuation());
292 if (!beforeChild && !last->firstChild())
297 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
299 RenderBlock* flow = continuationBefore(beforeChild);
300 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
301 RenderBoxModelObject* beforeChildParent = 0;
303 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
305 RenderBoxModelObject* cont = flow->continuation();
307 beforeChildParent = cont;
309 beforeChildParent = flow;
312 if (newChild->isFloatingOrPositioned())
313 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
315 // A continuation always consists of two potential candidates: a block or an anonymous
316 // column span box holding column span children.
317 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
318 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
319 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
321 if (flow == beforeChildParent)
322 return flow->addChildIgnoringContinuation(newChild, beforeChild);
324 // The goal here is to match up if we can, so that we can coalesce and create the
325 // minimal # of continuations needed for the inline.
326 if (childIsNormal == bcpIsNormal)
327 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
328 if (flowIsNormal == childIsNormal)
329 return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
330 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
334 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
336 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
338 // The goal is to locate a suitable box in which to place our child.
339 RenderBlock* beforeChildParent = toRenderBlock(beforeChild && beforeChild->parent()->isRenderBlock() ? beforeChild->parent() : lastChild());
341 // If the new child is floating or positioned it can just go in that block.
342 if (newChild->isFloatingOrPositioned())
343 return beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
345 // See if the child can be placed in the box.
346 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
347 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
349 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans)
350 return beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
353 // Create a new block of the correct type.
354 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
355 children()->appendChildNode(this, newBox);
356 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
360 RenderObject* immediateChild = beforeChild;
361 bool isPreviousBlockViable = true;
362 while (immediateChild->parent() != this) {
363 if (isPreviousBlockViable)
364 isPreviousBlockViable = !immediateChild->previousSibling();
365 immediateChild = immediateChild->parent();
367 if (isPreviousBlockViable && immediateChild->previousSibling())
368 return toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
370 // Split our anonymous blocks.
371 RenderObject* newBeforeChild = splitAnonymousBlocksAroundChild(beforeChild);
373 // Create a new anonymous box of the appropriate type.
374 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
375 children()->insertChildNode(this, newBox, newBeforeChild);
376 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
380 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
382 for (RenderObject* curr = this; curr; curr = curr->parent()) {
383 if (!curr->isRenderBlock() || curr->isFloatingOrPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
384 || curr->isInlineBlockOrInlineTable())
387 RenderBlock* currBlock = toRenderBlock(curr);
388 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
391 if (currBlock->isAnonymousColumnSpanBlock())
397 RenderBlock* RenderBlock::clone() const
399 RenderBlock* cloneBlock;
400 if (isAnonymousBlock())
401 cloneBlock = createAnonymousBlock();
403 cloneBlock = new (renderArena()) RenderBlock(node());
404 cloneBlock->setStyle(style());
406 cloneBlock->setChildrenInline(childrenInline());
410 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
411 RenderBlock* middleBlock,
412 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
414 // Create a clone of this inline.
415 RenderBlock* cloneBlock = clone();
416 if (!isAnonymousBlock())
417 cloneBlock->setContinuation(oldCont);
419 // Now take all of the children from beforeChild to the end and remove
420 // them from |this| and place them in the clone.
421 if (!beforeChild && isAfterContent(lastChild()))
422 beforeChild = lastChild();
423 moveChildrenTo(cloneBlock, beforeChild, 0);
425 // Hook |clone| up as the continuation of the middle block.
426 if (!cloneBlock->isAnonymousBlock())
427 middleBlock->setContinuation(cloneBlock);
429 // We have been reparented and are now under the fromBlock. We need
430 // to walk up our block parent chain until we hit the containing anonymous columns block.
431 // Once we hit the anonymous columns block we're done.
432 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
433 RenderBoxModelObject* currChild = this;
435 while (curr && curr != fromBlock) {
436 ASSERT(curr->isRenderBlock());
438 RenderBlock* blockCurr = toRenderBlock(curr);
440 // Create a new clone.
441 RenderBlock* cloneChild = cloneBlock;
442 cloneBlock = blockCurr->clone();
444 // Insert our child clone as the first child.
445 cloneBlock->children()->appendChildNode(cloneBlock, cloneChild);
447 // Hook the clone up as a continuation of |curr|. Note we do encounter
448 // anonymous blocks possibly as we walk up the block chain. When we split an
449 // anonymous block, there's no need to do any continuation hookup, since we haven't
450 // actually split a real element.
451 if (!blockCurr->isAnonymousBlock()) {
452 oldCont = blockCurr->continuation();
453 blockCurr->setContinuation(cloneBlock);
454 cloneBlock->setContinuation(oldCont);
457 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
458 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
459 // content gets properly destroyed.
460 if (document()->usesBeforeAfterRules())
461 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
463 // Now we need to take all of the children starting from the first child
464 // *after* currChild and append them all to the clone.
465 RenderObject* afterContent = isAfterContent(cloneBlock->lastChild()) ? cloneBlock->lastChild() : 0;
466 blockCurr->moveChildrenTo(cloneBlock, currChild->nextSibling(), 0, afterContent);
468 // Keep walking up the chain.
470 curr = toRenderBoxModelObject(curr->parent());
473 // Now we are at the columns block level. We need to put the clone into the toBlock.
474 toBlock->children()->appendChildNode(toBlock, cloneBlock);
476 // Now take all the children after currChild and remove them from the fromBlock
477 // and put them in the toBlock.
478 fromBlock->moveChildrenTo(toBlock, currChild->nextSibling(), 0);
481 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
482 RenderObject* newChild, RenderBoxModelObject* oldCont)
484 RenderBlock* pre = 0;
485 RenderBlock* block = containingColumnsBlock();
487 // Delete our line boxes before we do the inline split into continuations.
488 block->deleteLineBoxTree();
490 bool madeNewBeforeBlock = false;
491 if (block->isAnonymousColumnsBlock()) {
492 // We can reuse this block and make it the preBlock of the next continuation.
494 pre->removePositionedObjects(0);
495 block = toRenderBlock(block->parent());
497 // No anonymous block available for use. Make one.
498 pre = block->createAnonymousColumnsBlock();
499 pre->setChildrenInline(false);
500 madeNewBeforeBlock = true;
503 RenderBlock* post = block->createAnonymousColumnsBlock();
504 post->setChildrenInline(false);
506 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
507 if (madeNewBeforeBlock)
508 block->children()->insertChildNode(block, pre, boxFirst);
509 block->children()->insertChildNode(block, newBlockBox, boxFirst);
510 block->children()->insertChildNode(block, post, boxFirst);
511 block->setChildrenInline(false);
513 if (madeNewBeforeBlock)
514 block->moveChildrenTo(pre, boxFirst, 0);
516 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
518 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
519 // time in makeChildrenNonInline by just setting this explicitly up front.
520 newBlockBox->setChildrenInline(false);
522 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
523 // connected, thus allowing newChild access to a renderArena should it need
524 // to wrap itself in additional boxes (e.g., table construction).
525 newBlockBox->addChild(newChild);
527 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
528 // get deleted properly. Because objects moves from the pre block into the post block, we want to
529 // make new line boxes instead of leaving the old line boxes around.
530 pre->setNeedsLayoutAndPrefWidthsRecalc();
531 block->setNeedsLayoutAndPrefWidthsRecalc();
532 post->setNeedsLayoutAndPrefWidthsRecalc();
535 RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild)
537 while (beforeChild->parent() != this) {
538 RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent());
539 if (blockToSplit->firstChild() != beforeChild) {
540 // We have to split the parentBlock into two blocks.
541 RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit);
542 post->setChildrenInline(blockToSplit->childrenInline());
543 RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent());
544 parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling());
545 blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer());
546 post->setNeedsLayoutAndPrefWidthsRecalc();
547 blockToSplit->setNeedsLayoutAndPrefWidthsRecalc();
550 beforeChild = blockToSplit;
555 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
557 RenderBlock* pre = 0;
558 RenderBlock* post = 0;
559 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
560 // so that we don't have to patch all of the rest of the code later on.
562 // Delete the block's line boxes before we do the split.
563 block->deleteLineBoxTree();
565 if (beforeChild && beforeChild->parent() != this)
566 beforeChild = splitAnonymousBlocksAroundChild(beforeChild);
568 if (beforeChild != firstChild()) {
569 pre = block->createAnonymousColumnsBlock();
570 pre->setChildrenInline(block->childrenInline());
574 post = block->createAnonymousColumnsBlock();
575 post->setChildrenInline(block->childrenInline());
578 RenderObject* boxFirst = block->firstChild();
580 block->children()->insertChildNode(block, pre, boxFirst);
581 block->children()->insertChildNode(block, newBlockBox, boxFirst);
583 block->children()->insertChildNode(block, post, boxFirst);
584 block->setChildrenInline(false);
586 // 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).
587 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
588 block->moveChildrenTo(post, beforeChild, 0, true);
590 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
591 // time in makeChildrenNonInline by just setting this explicitly up front.
592 newBlockBox->setChildrenInline(false);
594 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
595 // connected, thus allowing newChild access to a renderArena should it need
596 // to wrap itself in additional boxes (e.g., table construction).
597 newBlockBox->addChild(newChild);
599 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
600 // get deleted properly. Because objects moved from the pre block into the post block, we want to
601 // make new line boxes instead of leaving the old line boxes around.
603 pre->setNeedsLayoutAndPrefWidthsRecalc();
604 block->setNeedsLayoutAndPrefWidthsRecalc();
606 post->setNeedsLayoutAndPrefWidthsRecalc();
609 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
611 // FIXME: This function is the gateway for the addition of column-span support. It will
612 // be added to in three stages:
613 // (1) Immediate children of a multi-column block can span.
614 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
615 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
616 // cross the streams and have to cope with both types of continuations mixed together).
617 // This function currently supports (1) and (2).
618 RenderBlock* columnsBlockAncestor = 0;
619 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isFloatingOrPositioned()
620 && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
621 if (style()->specifiesColumns())
622 columnsBlockAncestor = this;
623 else if (parent() && parent()->isRenderBlock())
624 columnsBlockAncestor = toRenderBlock(parent())->containingColumnsBlock(false);
626 return columnsBlockAncestor;
629 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
631 // Make sure we don't append things after :after-generated content if we have it.
633 RenderObject* lastRenderer = lastChild();
634 if (isAfterContent(lastRenderer))
635 beforeChild = lastRenderer;
636 else if (lastRenderer && lastRenderer->isAnonymousBlock() && isAfterContent(lastRenderer->lastChild()))
637 beforeChild = lastRenderer->lastChild();
640 // If the requested beforeChild is not one of our children, then this is because
641 // there is an anonymous container within this object that contains the beforeChild.
642 if (beforeChild && beforeChild->parent() != this) {
643 RenderObject* anonymousChild = beforeChild->parent();
644 ASSERT(anonymousChild);
646 while (anonymousChild->parent() != this)
647 anonymousChild = anonymousChild->parent();
649 ASSERT(anonymousChild->isAnonymous());
651 if (anonymousChild->isAnonymousBlock()) {
652 // Insert the child into the anonymous block box instead of here.
653 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
654 beforeChild->parent()->addChild(newChild, beforeChild);
656 addChild(newChild, beforeChild->parent());
660 ASSERT(anonymousChild->isTable());
661 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
662 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
663 || newChild->isTableSection()
664 || newChild->isTableRow()
665 || newChild->isTableCell()) {
666 // Insert into the anonymous table.
667 anonymousChild->addChild(newChild, beforeChild);
671 // Go on to insert before the anonymous table.
672 beforeChild = anonymousChild;
675 // Check for a spanning element in columns.
676 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
677 if (columnsBlockAncestor) {
678 // We are placing a column-span element inside a block.
679 RenderBlock* newBox = createAnonymousColumnSpanBlock();
681 if (columnsBlockAncestor != this) {
682 // We are nested inside a multi-column element and are being split by the span. We have to break up
683 // our block into continuations.
684 RenderBoxModelObject* oldContinuation = continuation();
685 setContinuation(newBox);
687 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
688 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
689 // content gets properly destroyed.
690 bool isLastChild = (beforeChild == lastChild());
691 if (document()->usesBeforeAfterRules())
692 children()->updateBeforeAfterContent(this, AFTER);
693 if (isLastChild && beforeChild != lastChild())
694 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
695 // point to be 0. It's just a straight append now.
697 splitFlow(beforeChild, newBox, newChild, oldContinuation);
701 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
702 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
703 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
704 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
708 bool madeBoxesNonInline = false;
710 // A block has to either have all of its children inline, or all of its children as blocks.
711 // So, if our children are currently inline and a block child has to be inserted, we move all our
712 // inline children into anonymous block boxes.
713 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
714 // This is a block with inline content. Wrap the inline content in anonymous blocks.
715 makeChildrenNonInline(beforeChild);
716 madeBoxesNonInline = true;
718 if (beforeChild && beforeChild->parent() != this) {
719 beforeChild = beforeChild->parent();
720 ASSERT(beforeChild->isAnonymousBlock());
721 ASSERT(beforeChild->parent() == this);
723 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
724 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
725 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
726 // a new one is created and inserted into our list of children in the appropriate position.
727 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
729 if (afterChild && afterChild->isAnonymousBlock()) {
730 afterChild->addChild(newChild);
734 if (newChild->isInline()) {
735 // No suitable existing anonymous box - create a new one.
736 RenderBlock* newBox = createAnonymousBlock();
737 RenderBox::addChild(newBox, beforeChild);
738 newBox->addChild(newChild);
743 RenderBox::addChild(newChild, beforeChild);
745 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
746 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
747 // this object may be dead here
750 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
752 if (continuation() && !isAnonymousBlock())
753 return addChildToContinuation(newChild, beforeChild);
754 return addChildIgnoringContinuation(newChild, beforeChild);
757 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
759 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
760 return addChildToAnonymousColumnBlocks(newChild, beforeChild);
761 return addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
764 static void getInlineRun(RenderObject* start, RenderObject* boundary,
765 RenderObject*& inlineRunStart,
766 RenderObject*& inlineRunEnd)
768 // Beginning at |start| we find the largest contiguous run of inlines that
769 // we can. We denote the run with start and end points, |inlineRunStart|
770 // and |inlineRunEnd|. Note that these two values may be the same if
771 // we encounter only one inline.
773 // We skip any non-inlines we encounter as long as we haven't found any
776 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
777 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
780 // Start by skipping as many non-inlines as we can.
781 RenderObject * curr = start;
784 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
785 curr = curr->nextSibling();
787 inlineRunStart = inlineRunEnd = curr;
790 return; // No more inline children to be found.
792 sawInline = curr->isInline();
794 curr = curr->nextSibling();
795 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
797 if (curr->isInline())
799 curr = curr->nextSibling();
801 } while (!sawInline);
804 void RenderBlock::deleteLineBoxTree()
806 m_lineBoxes.deleteLineBoxTree(renderArena());
809 RootInlineBox* RenderBlock::createRootInlineBox()
811 return new (renderArena()) RootInlineBox(this);
814 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
816 RootInlineBox* rootBox = createRootInlineBox();
817 m_lineBoxes.appendLineBox(rootBox);
821 void RenderBlock::moveChildTo(RenderBlock* to, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
823 ASSERT(this == child->parent());
824 ASSERT(!beforeChild || to == beforeChild->parent());
825 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
828 void RenderBlock::moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
830 ASSERT(!beforeChild || to == beforeChild->parent());
831 RenderObject* nextChild = startChild;
832 while (nextChild && nextChild != endChild) {
833 RenderObject* child = nextChild;
834 nextChild = child->nextSibling();
835 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
836 if (child == endChild)
841 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
843 // makeChildrenNonInline takes a block whose children are *all* inline and it
844 // makes sure that inline children are coalesced under anonymous
845 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
846 // the new block child that is causing us to have to wrap all the inlines. This
847 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
848 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
850 ASSERT(isInlineBlockOrInlineTable() || !isInline());
851 ASSERT(!insertionPoint || insertionPoint->parent() == this);
853 setChildrenInline(false);
855 RenderObject *child = firstChild();
862 RenderObject *inlineRunStart, *inlineRunEnd;
863 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
868 child = inlineRunEnd->nextSibling();
870 RenderBlock* block = createAnonymousBlock();
871 children()->insertChildNode(this, block, inlineRunStart);
872 moveChildrenTo(block, inlineRunStart, child);
876 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
877 ASSERT(!c->isInline());
883 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
885 ASSERT(child->isAnonymousBlock());
886 ASSERT(!child->childrenInline());
888 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
891 RenderObject* firstAnChild = child->m_children.firstChild();
892 RenderObject* lastAnChild = child->m_children.lastChild();
894 RenderObject* o = firstAnChild;
897 o = o->nextSibling();
899 firstAnChild->setPreviousSibling(child->previousSibling());
900 lastAnChild->setNextSibling(child->nextSibling());
901 if (child->previousSibling())
902 child->previousSibling()->setNextSibling(firstAnChild);
903 if (child->nextSibling())
904 child->nextSibling()->setPreviousSibling(lastAnChild);
906 if (child == m_children.firstChild())
907 m_children.setFirstChild(firstAnChild);
908 if (child == m_children.lastChild())
909 m_children.setLastChild(lastAnChild);
911 if (child == m_children.firstChild())
912 m_children.setFirstChild(child->nextSibling());
913 if (child == m_children.lastChild())
914 m_children.setLastChild(child->previousSibling());
916 if (child->previousSibling())
917 child->previousSibling()->setNextSibling(child->nextSibling());
918 if (child->nextSibling())
919 child->nextSibling()->setPreviousSibling(child->previousSibling());
922 child->setPreviousSibling(0);
923 child->setNextSibling(0);
925 child->children()->setFirstChild(0);
931 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
933 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
936 if (oldChild->parent() && oldChild->parent()->isDetails())
939 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
940 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
943 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
944 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
947 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
948 || (next && (next->isRubyRun() || next->isRubyBase())))
954 // Make sure the types of the anonymous blocks match up.
955 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
956 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
959 void RenderBlock::removeChild(RenderObject* oldChild)
961 // If this child is a block, and if our previous and next siblings are
962 // both anonymous blocks with inline content, then we can go ahead and
963 // fold the inline content back together.
964 RenderObject* prev = oldChild->previousSibling();
965 RenderObject* next = oldChild->nextSibling();
966 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
967 if (canMergeAnonymousBlocks && prev && next) {
968 prev->setNeedsLayoutAndPrefWidthsRecalc();
969 RenderBlock* nextBlock = toRenderBlock(next);
970 RenderBlock* prevBlock = toRenderBlock(prev);
972 if (prev->childrenInline() != next->childrenInline()) {
973 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
974 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
976 // Place the inline children block inside of the block children block instead of deleting it.
977 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
978 // to clear out inherited column properties by just making a new style, and to also clear the
979 // column span flag if it is set.
980 ASSERT(!inlineChildrenBlock->continuation());
981 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
982 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
983 inlineChildrenBlock->setStyle(newStyle);
985 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
986 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
987 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer());
988 next->setNeedsLayoutAndPrefWidthsRecalc();
990 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
991 // of "this". we null out prev or next so that is not used later in the function.
992 if (inlineChildrenBlock == prevBlock)
997 // Take all the children out of the |next| block and put them in
999 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1001 // Delete the now-empty block's lines and nuke it.
1002 nextBlock->deleteLineBoxTree();
1003 nextBlock->destroy();
1008 RenderBox::removeChild(oldChild);
1010 RenderObject* child = prev ? prev : next;
1011 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) {
1012 // The removal has knocked us down to containing only a single anonymous
1013 // box. We can go ahead and pull the content right back up into our
1015 setNeedsLayoutAndPrefWidthsRecalc();
1016 setChildrenInline(child->childrenInline());
1017 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, child->hasLayer()));
1018 anonBlock->moveAllChildrenTo(this, child->hasLayer());
1019 // Delete the now-empty block's lines and nuke it.
1020 anonBlock->deleteLineBoxTree();
1021 anonBlock->destroy();
1024 if (!firstChild() && !documentBeingDestroyed()) {
1025 // If this was our last child be sure to clear out our line boxes.
1026 if (childrenInline())
1027 lineBoxes()->deleteLineBoxes(renderArena());
1031 bool RenderBlock::isSelfCollapsingBlock() const
1033 // We are not self-collapsing if we
1034 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1036 // (c) have border/padding,
1037 // (d) have a min-height
1038 // (e) have specified that one of our margins can't collapse using a CSS extension
1039 if (logicalHeight() > 0
1040 || isTable() || borderAndPaddingLogicalHeight()
1041 || style()->logicalMinHeight().isPositive()
1042 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1045 Length logicalHeightLength = style()->logicalHeight();
1046 bool hasAutoHeight = logicalHeightLength.isAuto();
1047 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1048 hasAutoHeight = true;
1049 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1050 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1051 hasAutoHeight = false;
1055 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1056 // on whether we have content that is all self-collapsing or not.
1057 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1058 // If the block has inline children, see if we generated any line boxes. If we have any
1059 // line boxes, then we can't be self-collapsing, since we have content.
1060 if (childrenInline())
1061 return !firstLineBox();
1063 // Whether or not we collapse is dependent on whether all our normal flow children
1064 // are also self-collapsing.
1065 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1066 if (child->isFloatingOrPositioned())
1068 if (!child->isSelfCollapsingBlock())
1076 void RenderBlock::startDelayUpdateScrollInfo()
1078 if (gDelayUpdateScrollInfo == 0) {
1079 ASSERT(!gDelayedUpdateScrollInfoSet);
1080 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1082 ASSERT(gDelayedUpdateScrollInfoSet);
1083 ++gDelayUpdateScrollInfo;
1086 void RenderBlock::finishDelayUpdateScrollInfo()
1088 --gDelayUpdateScrollInfo;
1089 ASSERT(gDelayUpdateScrollInfo >= 0);
1090 if (gDelayUpdateScrollInfo == 0) {
1091 ASSERT(gDelayedUpdateScrollInfoSet);
1093 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet);
1094 gDelayedUpdateScrollInfoSet = 0;
1096 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1097 RenderBlock* block = *it;
1098 if (block->hasOverflowClip()) {
1099 block->layer()->updateScrollInfoAfterLayout();
1105 void RenderBlock::updateScrollInfoAfterLayout()
1107 if (hasOverflowClip()) {
1108 if (gDelayUpdateScrollInfo)
1109 gDelayedUpdateScrollInfoSet->add(this);
1111 layer()->updateScrollInfoAfterLayout();
1115 void RenderBlock::layout()
1117 // Update our first letter info now.
1118 updateFirstLetter();
1120 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1124 // It's safe to check for control clip here, since controls can never be table cells.
1125 // If we have a lightweight clip, there can never be any overflow from children.
1126 if (hasControlClip() && m_overflow)
1127 clearLayoutOverflow();
1130 void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight)
1132 ASSERT(needsLayout());
1134 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1135 return; // cause us to come in here. Just bail.
1137 if (!relayoutChildren && simplifiedLayout())
1140 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
1142 int oldWidth = logicalWidth();
1143 int oldColumnWidth = desiredColumnWidth();
1145 computeLogicalWidth();
1150 if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth())
1151 relayoutChildren = true;
1155 int previousHeight = logicalHeight();
1156 setLogicalHeight(0);
1157 bool hasSpecifiedPageLogicalHeight = false;
1158 bool pageLogicalHeightChanged = false;
1159 ColumnInfo* colInfo = columnInfo();
1161 if (!pageLogicalHeight) {
1162 // We need to go ahead and set our explicit page height if one exists, so that we can
1163 // avoid doing two layout passes.
1164 computeLogicalHeight();
1165 int columnHeight = contentLogicalHeight();
1166 if (columnHeight > 0) {
1167 pageLogicalHeight = columnHeight;
1168 hasSpecifiedPageLogicalHeight = true;
1170 setLogicalHeight(0);
1172 if (colInfo->columnHeight() != pageLogicalHeight && m_everHadLayout) {
1173 colInfo->setColumnHeight(pageLogicalHeight);
1174 pageLogicalHeightChanged = true;
1177 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1178 colInfo->clearForcedBreaks();
1181 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, colInfo);
1183 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1184 // our current maximal positive and negative margins. These values are used when we
1185 // are collapsed with adjacent blocks, so for example, if you have block A and B
1186 // collapsing together, then you'd take the maximal positive margin from both A and B
1187 // and subtract it from the maximal negative margin from both A and B to get the
1188 // true collapsed margin. This algorithm is recursive, so when we finish layout()
1189 // our block knows its current maximal positive/negative values.
1191 // Start out by setting our margin values to our current margins. Table cells have
1192 // no margins, so we don't fill in the values for table cells.
1193 bool isCell = isTableCell();
1195 initMaxMarginValues();
1197 setMarginBeforeQuirk(style()->marginBefore().quirk());
1198 setMarginAfterQuirk(style()->marginAfter().quirk());
1201 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
1202 // See if this form is malformed (i.e., unclosed). If so, don't give the form
1204 setMaxMarginAfterValues(0, 0);
1207 setPaginationStrut(0);
1210 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
1211 if (scrollsOverflow()) {
1212 if (style()->overflowX() == OSCROLL)
1213 layer()->setHasHorizontalScrollbar(true);
1214 if (style()->overflowY() == OSCROLL)
1215 layer()->setHasVerticalScrollbar(true);
1218 int repaintLogicalTop = 0;
1219 int repaintLogicalBottom = 0;
1220 int maxFloatLogicalBottom = 0;
1221 if (!firstChild() && !isAnonymousBlock())
1222 setChildrenInline(true);
1223 if (childrenInline())
1224 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1226 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1228 // Expand our intrinsic height to encompass floats.
1229 int toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1230 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1231 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1233 if (layoutColumns(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1236 // Calculate our new height.
1237 int oldHeight = logicalHeight();
1238 int oldClientAfterEdge = clientLogicalBottom();
1239 computeLogicalHeight();
1240 int newHeight = logicalHeight();
1241 if (oldHeight != newHeight) {
1242 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1243 // One of our children's floats may have become an overhanging float for us. We need to look for it.
1244 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1245 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
1246 RenderBlock* block = toRenderBlock(child);
1247 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
1248 addOverhangingFloats(block, -block->logicalLeft(), -block->logicalTop(), false);
1254 if (previousHeight != newHeight)
1255 relayoutChildren = true;
1257 layoutPositionedObjects(relayoutChildren || isRoot());
1259 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1260 computeOverflow(oldClientAfterEdge);
1264 if (view()->layoutState()->m_pageLogicalHeight)
1265 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop()));
1267 updateLayerTransform();
1269 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1270 // we overflow or not.
1271 updateScrollInfoAfterLayout();
1273 // Repaint with our new bounds if they are different from our old bounds.
1274 bool didFullRepaint = repainter.repaintAfterLayout();
1275 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1276 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1277 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1278 int repaintLogicalLeft = logicalLeftVisualOverflow();
1279 int repaintLogicalRight = logicalRightVisualOverflow();
1280 if (hasOverflowClip()) {
1281 // 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.
1282 // 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.
1283 // layoutInlineChildren should be patched to compute the entire repaint rect.
1284 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1285 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1288 IntRect repaintRect;
1289 if (isHorizontalWritingMode())
1290 repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1292 repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1294 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1295 adjustRectForColumns(repaintRect);
1297 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1299 if (hasOverflowClip()) {
1300 // Adjust repaint rect for scroll offset
1301 repaintRect.move(-layer()->scrolledContentOffset());
1303 // Don't allow this rect to spill out of our overflow box.
1304 repaintRect.intersect(IntRect(0, 0, width(), height()));
1307 // Make sure the rect is still non-empty after intersecting for overflow above
1308 if (!repaintRect.isEmpty()) {
1309 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1310 if (hasReflection())
1311 repaintRectangle(reflectedRect(repaintRect));
1314 setNeedsLayout(false);
1317 void RenderBlock::addOverflowFromChildren()
1319 if (!hasColumns()) {
1320 if (childrenInline())
1321 addOverflowFromInlineChildren();
1323 addOverflowFromBlockChildren();
1325 ColumnInfo* colInfo = columnInfo();
1326 if (columnCount(colInfo)) {
1327 IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1328 if (isHorizontalWritingMode()) {
1329 int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0;
1330 int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.maxX()) : 0;
1331 int overflowHeight = borderBefore() + paddingBefore() + colInfo->columnHeight();
1332 addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
1333 if (!hasOverflowClip())
1334 addVisualOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
1336 IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1337 int overflowTop = !style()->isLeftToRightDirection() ? min(0, lastRect.y()) : 0;
1338 int overflowBottom = style()->isLeftToRightDirection() ? max(height(), lastRect.maxY()) : 0;
1339 int overflowWidth = borderBefore() + paddingBefore() + colInfo->columnHeight();
1340 addLayoutOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
1341 if (!hasOverflowClip())
1342 addVisualOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
1348 void RenderBlock::computeOverflow(int oldClientAfterEdge, bool recomputeFloats)
1350 // Add overflow from children.
1351 addOverflowFromChildren();
1353 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1354 addOverflowFromFloats();
1356 // Add in the overflow from positioned objects.
1357 addOverflowFromPositionedObjects();
1359 if (hasOverflowClip()) {
1360 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1361 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1362 // be considered reachable.
1363 IntRect clientRect(clientBoxRect());
1364 IntRect rectToApply;
1365 if (isHorizontalWritingMode())
1366 rectToApply = IntRect(clientRect.x(), clientRect.y(), 1, max(0, oldClientAfterEdge - clientRect.y()));
1368 rectToApply = IntRect(clientRect.x(), clientRect.y(), max(0, oldClientAfterEdge - clientRect.x()), 1);
1369 addLayoutOverflow(rectToApply);
1372 // Add visual overflow from box-shadow and reflections.
1373 addShadowOverflow();
1376 void RenderBlock::addOverflowFromBlockChildren()
1378 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1379 if (!child->isFloatingOrPositioned())
1380 addOverflowFromChild(child);
1384 void RenderBlock::addOverflowFromFloats()
1386 if (!m_floatingObjects)
1389 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1390 FloatingObjectSetIterator end = floatingObjectSet.end();
1391 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1392 FloatingObject* r = *it;
1393 if (r->m_isDescendant)
1394 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1399 void RenderBlock::addOverflowFromPositionedObjects()
1401 if (!m_positionedObjects)
1404 RenderBox* positionedObject;
1405 Iterator end = m_positionedObjects->end();
1406 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1407 positionedObject = *it;
1409 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1410 if (positionedObject->style()->position() != FixedPosition)
1411 addOverflowFromChild(positionedObject);
1415 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1417 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox())
1418 || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot();
1421 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1423 bool isHorizontal = isHorizontalWritingMode();
1424 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1425 RenderLayer* childLayer = child->layer();
1427 childLayer->setStaticInlinePosition(borderAndPaddingStart());
1429 int logicalTop = logicalHeight();
1430 if (!marginInfo.canCollapseWithMarginBefore()) {
1431 child->computeBlockDirectionMargins(this);
1432 int marginBefore = marginBeforeForChild(child);
1433 int collapsedBeforePos = marginInfo.positiveMargin();
1434 int collapsedBeforeNeg = marginInfo.negativeMargin();
1435 if (marginBefore > 0) {
1436 if (marginBefore > collapsedBeforePos)
1437 collapsedBeforePos = marginBefore;
1439 if (-marginBefore > collapsedBeforeNeg)
1440 collapsedBeforeNeg = -marginBefore;
1442 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
1444 if (childLayer->staticBlockPosition() != logicalTop) {
1445 childLayer->setStaticBlockPosition(logicalTop);
1446 if (hasStaticBlockPosition)
1447 child->setChildNeedsLayout(true, false);
1451 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1453 // The float should be positioned taking into account the bottom margin
1454 // of the previous flow. We add that margin into the height, get the
1455 // float positioned properly, and then subtract the margin out of the
1456 // height again. In the case of self-collapsing blocks, we always just
1457 // use the top margins, since the self-collapsing block collapsed its
1458 // own bottom margin into its top margin.
1460 // Note also that the previous flow may collapse its margin into the top of
1461 // our block. If this is the case, then we do not add the margin in to our
1462 // height when computing the position of the float. This condition can be tested
1463 // for by simply calling canCollapseWithMarginBefore. See
1464 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1465 // an example of this scenario.
1466 int marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin();
1467 setLogicalHeight(logicalHeight() + marginOffset);
1468 positionNewFloats();
1469 setLogicalHeight(logicalHeight() - marginOffset);
1472 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1474 // Handle in the given order
1475 return handlePositionedChild(child, marginInfo)
1476 || handleFloatingChild(child, marginInfo)
1477 || handleRunInChild(child);
1481 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1483 if (child->isPositioned()) {
1484 child->containingBlock()->insertPositionedObject(child);
1485 adjustPositionedBlock(child, marginInfo);
1491 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1493 if (child->isFloating()) {
1494 insertFloatingObject(child);
1495 adjustFloatingBlock(marginInfo);
1501 bool RenderBlock::handleRunInChild(RenderBox* child)
1503 // See if we have a run-in element with inline children. If the
1504 // children aren't inline, then just treat the run-in as a normal
1506 if (!child->isRunIn() || !child->childrenInline())
1508 // FIXME: We don't handle non-block elements with run-in for now.
1509 if (!child->isRenderBlock())
1512 // Get the next non-positioned/non-floating RenderBlock.
1513 RenderBlock* blockRunIn = toRenderBlock(child);
1514 RenderObject* curr = blockRunIn->nextSibling();
1515 while (curr && curr->isFloatingOrPositioned())
1516 curr = curr->nextSibling();
1518 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous())
1521 RenderBlock* currBlock = toRenderBlock(curr);
1523 // Remove the old child.
1524 children()->removeChildNode(this, blockRunIn);
1526 // Create an inline.
1527 Node* runInNode = blockRunIn->node();
1528 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1529 inlineRunIn->setStyle(blockRunIn->style());
1531 bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER;
1533 // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already
1534 // been regenerated by the new inline.
1535 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) {
1536 RenderObject* nextSibling = runInChild->nextSibling();
1537 if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) {
1538 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
1539 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
1541 runInChild = nextSibling;
1544 // Now insert the new child under |currBlock|.
1545 currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild());
1547 // If the run-in had an element, we need to set the new renderer.
1549 runInNode->setRenderer(inlineRunIn);
1551 // Destroy the block run-in, which includes deleting its line box tree.
1552 blockRunIn->deleteLineBoxTree();
1553 blockRunIn->destroy();
1555 // The block acts like an inline, so just null out its
1561 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1563 // Get the four margin values for the child and cache them.
1564 const MarginValues childMargins = marginValuesForChild(child);
1566 // Get our max pos and neg top margins.
1567 int posTop = childMargins.positiveMarginBefore();
1568 int negTop = childMargins.negativeMarginBefore();
1570 // For self-collapsing blocks, collapse our bottom margins into our
1571 // top to get new posTop and negTop values.
1572 if (child->isSelfCollapsingBlock()) {
1573 posTop = max(posTop, childMargins.positiveMarginAfter());
1574 negTop = max(negTop, childMargins.negativeMarginAfter());
1577 // See if the top margin is quirky. We only care if this child has
1578 // margins that will collapse with us.
1579 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
1581 if (marginInfo.canCollapseWithMarginBefore()) {
1582 // This child is collapsing with the top of the
1583 // block. If it has larger margin values, then we need to update
1584 // our own maximal values.
1585 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
1586 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
1588 // The minute any of the margins involved isn't a quirk, don't
1589 // collapse it away, even if the margin is smaller (www.webreference.com
1590 // has an example of this, a <dt> with 0.8em author-specified inside
1591 // a <dl> inside a <td>.
1592 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
1593 setMarginBeforeQuirk(false);
1594 marginInfo.setDeterminedMarginBeforeQuirk(true);
1597 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
1598 // We have no top margin and our top child has a quirky margin.
1599 // We will pick up this quirky margin and pass it through.
1600 // This deals with the <td><div><p> case.
1601 // Don't do this for a block that split two inlines though. You do
1602 // still apply margins in this case.
1603 setMarginBeforeQuirk(true);
1606 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1607 marginInfo.setMarginBeforeQuirk(topQuirk);
1609 int beforeCollapseLogicalTop = logicalHeight();
1610 int logicalTop = beforeCollapseLogicalTop;
1611 if (child->isSelfCollapsingBlock()) {
1612 // This child has no height. We need to compute our
1613 // position before we collapse the child's margins together,
1614 // so that we can get an accurate position for the zero-height block.
1615 int collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1616 int collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1617 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1619 // Now collapse the child's margins together, which means examining our
1620 // bottom margin values as well.
1621 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1622 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1624 if (!marginInfo.canCollapseWithMarginBefore())
1625 // We need to make sure that the position of the self-collapsing block
1626 // is correct, since it could have overflowing content
1627 // that needs to be positioned correctly (e.g., a block that
1628 // had a specified height of 0 but that actually had subcontent).
1629 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1632 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1633 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
1634 logicalTop = logicalHeight();
1636 else if (!marginInfo.atBeforeSideOfBlock() ||
1637 (!marginInfo.canCollapseMarginBeforeWithChildren()
1638 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
1639 // We're collapsing with a previous sibling's margins and not
1640 // with the top of the block.
1641 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
1642 logicalTop = logicalHeight();
1645 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1646 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1648 if (marginInfo.margin())
1649 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
1652 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1653 // collapsed into the page edge.
1654 bool paginated = view()->layoutState()->isPaginated();
1655 if (paginated && logicalTop > beforeCollapseLogicalTop) {
1656 int oldLogicalTop = logicalTop;
1657 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
1658 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1663 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos)
1665 int heightIncrease = getClearDelta(child, yPos);
1666 if (!heightIncrease)
1669 if (child->isSelfCollapsingBlock()) {
1670 // For self-collapsing blocks that clear, they can still collapse their
1671 // margins with following siblings. Reset the current margins to represent
1672 // the self-collapsing block's margins only.
1674 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
1675 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
1676 // self-collapsing block's bottom margin.
1677 bool atBottomOfBlock = true;
1678 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
1679 if (!curr->isFloatingOrPositioned())
1680 atBottomOfBlock = false;
1683 MarginValues childMargins = marginValuesForChild(child);
1684 if (atBottomOfBlock) {
1685 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1686 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1688 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1689 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1692 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
1693 // of the parent block).
1694 setLogicalHeight(child->y() - max(0, marginInfo.margin()));
1696 // Increase our height by the amount we had to clear.
1697 setLogicalHeight(height() + heightIncrease);
1699 if (marginInfo.canCollapseWithMarginBefore()) {
1700 // We can no longer collapse with the top of the block since a clear
1701 // occurred. The empty blocks collapse into the cleared block.
1702 // FIXME: This isn't quite correct. Need clarification for what to do
1703 // if the height the cleared block is offset by is smaller than the
1704 // margins involved.
1705 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1706 marginInfo.setAtBeforeSideOfBlock(false);
1709 return yPos + heightIncrease;
1712 int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo)
1714 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1715 // relayout if there are intruding floats.
1716 int logicalTopEstimate = logicalHeight();
1717 if (!marginInfo.canCollapseWithMarginBefore()) {
1718 int childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child);
1719 logicalTopEstimate += max(marginInfo.margin(), childMarginBefore);
1722 bool paginated = view()->layoutState()->isPaginated();
1724 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1726 if (paginated && logicalTopEstimate > logicalHeight())
1727 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1729 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1732 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1733 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1735 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1736 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1738 if (!child->selfNeedsLayout() && child->isRenderBlock())
1739 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1742 return logicalTopEstimate;
1745 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
1747 int startPosition = borderStart() + paddingStart();
1748 int totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1750 // Add in our start margin.
1751 int childMarginStart = marginStartForChild(child);
1752 int newPosition = startPosition + childMarginStart;
1754 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1755 // to shift over as necessary to dodge any floats that might get in the way.
1756 if (child->avoidsFloats()) {
1757 int startOff = style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(logicalHeight(), false) : totalAvailableLogicalWidth - logicalRightOffsetForLine(logicalHeight(), false);
1758 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1759 if (childMarginStart < 0)
1760 startOff += childMarginStart;
1761 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1762 } else if (startOff != startPosition) {
1763 // The object is shifting to the "end" side of the block. The object might be centered, so we need to
1764 // recalculate our inline direction margins. Note that the containing block content
1765 // width computation will take into account the delta between |startOff| and |startPosition|
1766 // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
1768 child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(logicalTopForChild(child), false), logicalWidthForChild(child));
1769 newPosition = startOff + marginStartForChild(child);
1773 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
1776 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1778 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1779 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1780 // with our children.
1781 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1783 if (!marginInfo.marginAfterQuirk())
1784 setMarginAfterQuirk(false);
1786 if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
1787 // We have no bottom margin and our last child has a quirky margin.
1788 // We will pick up this quirky margin and pass it through.
1789 // This deals with the <td><div><p> case.
1790 setMarginAfterQuirk(true);
1794 void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginInfo& marginInfo)
1796 marginInfo.setAtAfterSideOfBlock(true);
1798 // If we can't collapse with children then go ahead and add in the bottom margin.
1799 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1800 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
1801 setLogicalHeight(logicalHeight() + marginInfo.margin());
1803 // Now add in our bottom border/padding.
1804 setLogicalHeight(logicalHeight() + afterSide);
1806 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1807 // If this happens, ensure that the computed height is increased to the minimal height.
1808 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1810 // Update our bottom collapsed margin info.
1811 setCollapsedBottomMargin(marginInfo);
1814 void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta)
1816 if (isHorizontalWritingMode()) {
1817 if (applyDelta == ApplyLayoutDelta)
1818 view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0));
1819 child->setX(logicalLeft);
1821 if (applyDelta == ApplyLayoutDelta)
1822 view()->addLayoutDelta(IntSize(0, child->y() - logicalLeft));
1823 child->setY(logicalLeft);
1827 void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta)
1829 if (isHorizontalWritingMode()) {
1830 if (applyDelta == ApplyLayoutDelta)
1831 view()->addLayoutDelta(IntSize(0, child->y() - logicalTop));
1832 child->setY(logicalTop);
1834 if (applyDelta == ApplyLayoutDelta)
1835 view()->addLayoutDelta(IntSize(child->x() - logicalTop, 0));
1836 child->setX(logicalTop);
1840 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom)
1842 if (gPercentHeightDescendantsMap) {
1843 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
1844 HashSet<RenderBox*>::iterator end = descendants->end();
1845 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
1846 RenderBox* box = *it;
1847 while (box != this) {
1848 if (box->normalChildNeedsLayout())
1850 box->setChildNeedsLayout(true, false);
1851 box = box->containingBlock();
1860 int beforeEdge = borderBefore() + paddingBefore();
1861 int afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1863 setLogicalHeight(beforeEdge);
1865 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
1866 MarginInfo marginInfo(this, beforeEdge, afterEdge);
1868 // Fieldsets need to find their legend and position it inside the border of the object.
1869 // The legend then gets skipped during normal layout. The same is true for ruby text.
1870 // It doesn't get included in the normal layout process but is instead skipped.
1871 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
1873 int previousFloatLogicalBottom = 0;
1874 maxFloatLogicalBottom = 0;
1876 RenderBox* next = firstChildBox();
1879 RenderBox* child = next;
1880 next = child->nextSiblingBox();
1882 if (childToExclude == child)
1883 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
1885 // Make sure we layout children if they need it.
1886 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1887 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1888 if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView()))
1889 child->setChildNeedsLayout(true, false);
1891 // If relayoutChildren is set and the child has percentage padding, we also need to invalidate the child's pref widths.
1892 if (relayoutChildren && (child->style()->paddingStart().isPercent() || child->style()->paddingEnd().isPercent()))
1893 child->setPreferredLogicalWidthsDirty(true, false);
1895 // Handle the four types of special elements first. These include positioned content, floating content, compacts and
1896 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
1897 if (handleSpecialChild(child, marginInfo))
1900 // Lay out the child.
1901 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
1904 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
1905 // determining the correct collapsed bottom margin information.
1906 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
1909 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom)
1911 int oldPosMarginBefore = maxPositiveMarginBefore();
1912 int oldNegMarginBefore = maxNegativeMarginBefore();
1914 // The child is a normal flow object. Compute the margins we will use for collapsing now.
1915 child->computeBlockDirectionMargins(this);
1917 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
1918 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1919 marginInfo.setAtBeforeSideOfBlock(false);
1920 marginInfo.clearMargin();
1923 // Try to guess our correct logical top position. In most cases this guess will
1924 // be correct. Only if we're wrong (when we compute the real logical top position)
1925 // will we have to potentially relayout.
1926 int logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo);
1928 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
1929 IntRect oldRect(child->x(), child->y() , child->width(), child->height());
1930 int oldLogicalTop = logicalTopForChild(child);
1933 IntSize oldLayoutDelta = view()->layoutDelta();
1935 // Go ahead and position the child as though it didn't collapse with the top.
1936 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
1938 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
1939 bool markDescendantsWithFloats = false;
1940 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
1941 markDescendantsWithFloats = true;
1942 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
1943 // If an element might be affected by the presence of floats, then always mark it for
1945 int fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
1946 if (fb > logicalTopEstimate)
1947 markDescendantsWithFloats = true;
1950 if (childRenderBlock) {
1951 if (markDescendantsWithFloats)
1952 childRenderBlock->markAllDescendantsWithFloatsForLayout();
1953 if (!child->isWritingModeRoot())
1954 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
1957 if (!child->needsLayout())
1958 child->markForPaginationRelayoutIfNeeded();
1960 bool childHadLayout = child->m_everHadLayout;
1961 bool childNeededLayout = child->needsLayout();
1962 if (childNeededLayout)
1965 // Cache if we are at the top of the block right now.
1966 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
1968 // Now determine the correct ypos based off examination of collapsing margin
1970 int logicalTopBeforeClear = collapseMargins(child, marginInfo);
1972 // Now check for clear.
1973 int logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
1975 bool paginated = view()->layoutState()->isPaginated();
1977 int oldTop = logicalTopAfterClear;
1979 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1980 logicalTopAfterClear = applyBeforeBreak(child, logicalTopAfterClear);
1982 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1983 int logicalTopBeforeUnsplittableAdjustment = logicalTopAfterClear;
1984 int logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, logicalTopAfterClear);
1986 int paginationStrut = 0;
1987 int unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1988 if (unsplittableAdjustmentDelta)
1989 paginationStrut = unsplittableAdjustmentDelta;
1990 else if (childRenderBlock && childRenderBlock->paginationStrut())
1991 paginationStrut = childRenderBlock->paginationStrut();
1993 if (paginationStrut) {
1994 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1995 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1996 if (atBeforeSideOfBlock && oldTop == logicalTopBeforeClear && !isPositioned() && !isTableCell()) {
1997 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1998 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1999 // and pushes to the next page anyway, so not too concerned about it.
2000 setPaginationStrut(logicalTopAfterClear + paginationStrut);
2001 if (childRenderBlock)
2002 childRenderBlock->setPaginationStrut(0);
2004 logicalTopAfterClear += paginationStrut;
2007 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
2008 setLogicalHeight(logicalHeight() + (logicalTopAfterClear - oldTop));
2011 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2013 // Now we have a final top position. See if it really does end up being different from our estimate.
2014 if (logicalTopAfterClear != logicalTopEstimate) {
2015 if (child->shrinkToAvoidFloats()) {
2016 // The child's width depends on the line width.
2017 // When the child shifts to clear an item, its width can
2018 // change (because it has more available line width).
2019 // So go ahead and mark the item as dirty.
2020 child->setChildNeedsLayout(true, false);
2022 if (childRenderBlock) {
2023 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2024 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2025 if (!child->needsLayout())
2026 child->markForPaginationRelayoutIfNeeded();
2029 // Our guess was wrong. Make the child lay itself out again.
2030 child->layoutIfNeeded();
2033 // We are no longer at the top of the block if we encounter a non-empty child.
2034 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2035 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2036 marginInfo.setAtBeforeSideOfBlock(false);
2038 // Now place the child in the correct left position
2039 determineLogicalLeftPositionForChild(child);
2041 // Update our height now that the child has been placed in the correct position.
2042 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2043 if (child->style()->marginAfterCollapse() == MSEPARATE) {
2044 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2045 marginInfo.clearMargin();
2047 // If the child has overhanging floats that intrude into following siblings (or possibly out
2048 // of this block), then the parent gets notified of the floats now.
2049 if (childRenderBlock && childRenderBlock->containsFloats())
2050 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), -child->logicalLeft(), -child->logicalTop(), !childNeededLayout));
2052 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
2053 if (childOffset.width() || childOffset.height()) {
2054 view()->addLayoutDelta(childOffset);
2056 // If the child moved, we have to repaint it as well as any floating/positioned
2057 // descendants. An exception is if we need a layout. In this case, we know we're going to
2058 // repaint ourselves (and the child) anyway.
2059 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2060 child->repaintDuringLayoutIfMoved(oldRect);
2063 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2065 child->repaintOverhangingFloats(true);
2069 // Check for an after page/column break.
2070 int newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2071 if (newHeight != height())
2072 setLogicalHeight(newHeight);
2075 ASSERT(oldLayoutDelta == view()->layoutDelta());
2078 void RenderBlock::simplifiedNormalFlowLayout()
2080 if (childrenInline()) {
2081 ListHashSet<RootInlineBox*> lineBoxes;
2082 bool endOfInline = false;
2083 RenderObject* o = bidiFirst(this, 0, false);
2085 if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
2086 o->layoutIfNeeded();
2087 if (toRenderBox(o)->inlineBoxWrapper()) {
2088 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2091 } else if (o->isText() || (o->isRenderInline() && !endOfInline))
2092 o->setNeedsLayout(false);
2093 o = bidiNext(this, o, 0, false, &endOfInline);
2096 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2097 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2098 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2099 RootInlineBox* box = *it;
2100 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2103 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2104 if (!box->isPositioned())
2105 box->layoutIfNeeded();
2110 bool RenderBlock::simplifiedLayout()
2112 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2115 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2117 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2120 // Lay out positioned descendants or objects that just need to recompute overflow.
2121 if (needsSimplifiedNormalFlowLayout())
2122 simplifiedNormalFlowLayout();
2124 // Lay out our positioned objects if our positioned child bit is set.
2125 if (posChildNeedsLayout())
2126 layoutPositionedObjects(false);
2128 // Recompute our overflow information.
2129 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2130 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2131 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2132 // lowestPosition on every relayout so it's not a regression.
2134 computeOverflow(clientLogicalBottom(), true);
2138 updateLayerTransform();
2140 updateScrollInfoAfterLayout();
2142 setNeedsLayout(false);
2146 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2148 if (!m_positionedObjects)
2152 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2155 Iterator end = m_positionedObjects->end();
2156 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2158 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2159 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2160 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2161 // positioned explicitly) this should not incur a performance penalty.
2162 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow()))
2163 r->setChildNeedsLayout(true, false);
2165 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
2166 if (relayoutChildren && (r->style()->paddingStart().isPercent() || r->style()->paddingEnd().isPercent()))
2167 r->setPreferredLogicalWidthsDirty(true, false);
2169 if (!r->needsLayout())
2170 r->markForPaginationRelayoutIfNeeded();
2172 // 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
2173 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2174 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2175 r->setNeedsLayout(false);
2176 r->layoutIfNeeded();
2180 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2183 void RenderBlock::markPositionedObjectsForLayout()
2185 if (m_positionedObjects) {
2187 Iterator end = m_positionedObjects->end();
2188 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2190 r->setChildNeedsLayout(true);
2195 void RenderBlock::markForPaginationRelayoutIfNeeded()
2197 ASSERT(!needsLayout());
2201 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2202 setChildNeedsLayout(true, false);
2205 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2207 // Repaint any overhanging floats (if we know we're the one to paint them).
2208 if (hasOverhangingFloats()) {
2209 // We think that we must be in a bad state if m_floatingObjects is nil at this point, so
2210 // we assert on Debug builds and nil-check Release builds.
2211 ASSERT(m_floatingObjects);
2212 if (!m_floatingObjects)
2215 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2216 // in this block. Better yet would be to push extra state for the containers of other floats.
2217 view()->disableLayoutState();
2218 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2219 FloatingObjectSetIterator end = floatingObjectSet.end();
2220 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2221 FloatingObject* r = *it;
2222 // Only repaint the object if it is overhanging, is not in its own layer, and
2223 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2224 // condition is replaced with being a descendant of us.
2225 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
2226 r->m_renderer->repaint();
2227 r->m_renderer->repaintOverhangingFloats();
2230 view()->enableLayoutState();
2234 void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
2239 PaintPhase phase = paintInfo.phase;
2241 // Check if we need to do anything at all.
2242 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2243 // paints the root's background.
2245 IntRect overflowBox = visualOverflowRect();
2246 flipForWritingMode(overflowBox);
2247 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2248 overflowBox.move(tx, ty);
2249 if (!overflowBox.intersects(paintInfo.rect))
2253 bool pushedClip = pushContentsClip(paintInfo, tx, ty);
2254 paintObject(paintInfo, tx, ty);
2256 popContentsClip(paintInfo, phase, tx, ty);
2258 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2259 // z-index. We paint after we painted the background/border, so that the scrollbars will
2260 // sit above the background/border.
2261 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2262 layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect);
2265 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
2267 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2268 bool ruleTransparent = style()->columnRuleIsTransparent();
2269 EBorderStyle ruleStyle = style()->columnRuleStyle();
2270 int ruleWidth = style()->columnRuleWidth();
2271 int colGap = columnGap();
2272 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap;
2276 // We need to do multiple passes, breaking up our child painting into strips.
2277 ColumnInfo* colInfo = columnInfo();
2278 unsigned colCount = columnCount(colInfo);
2279 int currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2280 int ruleAdd = logicalLeftOffsetForContent();
2281 int ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2282 for (unsigned i = 0; i < colCount; i++) {
2283 IntRect colRect = columnRectAt(colInfo, i);
2285 int inlineDirectionSize = isHorizontalWritingMode() ? colRect.width() : colRect.height();
2287 // Move to the next position.
2288 if (style()->isLeftToRightDirection()) {
2289 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2290 currLogicalLeftOffset += inlineDirectionSize + colGap;
2292 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2293 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2296 // Now paint the column rule.
2297 if (i < colCount - 1) {
2298 int ruleLeft = isHorizontalWritingMode() ? tx + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : tx + borderBefore() + paddingBefore();
2299 int ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth();
2300 int ruleTop = isHorizontalWritingMode() ? ty + borderTop() + paddingTop() : ty + ruleLogicalLeft - ruleWidth / 2 + ruleAdd;
2301 int ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth;
2302 drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom,
2303 style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0);
2306 ruleLogicalLeft = currLogicalLeftOffset;
2310 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats)
2312 // We need to do multiple passes, breaking up our child painting into strips.
2313 GraphicsContext* context = paintInfo.context;
2314 ColumnInfo* colInfo = columnInfo();
2315 unsigned colCount = columnCount(colInfo);
2318 int currLogicalTopOffset = 0;
2319 for (unsigned i = 0; i < colCount; i++) {
2320 // For each rect, we clip to the rect, and then we adjust our coords.
2321 IntRect colRect = columnRectAt(colInfo, i);
2322 flipForWritingMode(colRect);
2323 int logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2324 IntSize offset = isHorizontalWritingMode() ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset);
2325 colRect.move(tx, ty);
2326 PaintInfo info(paintInfo);
2327 info.rect.intersect(colRect);
2329 if (!info.rect.isEmpty()) {
2332 // Each strip pushes a clip, since column boxes are specified as being
2333 // like overflow:hidden.
2334 context->clip(colRect);
2336 // Adjust our x and y when painting.
2337 int finalX = tx + offset.width();
2338 int finalY = ty + offset.height();
2340 paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2342 paintContents(info, finalX, finalY);
2347 int blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2348 if (style()->isFlippedBlocksWritingMode())
2349 currLogicalTopOffset += blockDelta;
2351 currLogicalTopOffset -= blockDelta;
2355 void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
2357 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2358 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2359 // will do a full repaint().
2360 if (document()->mayCauseFlashOfUnstyledContent() && !isRenderView())
2363 if (childrenInline())
2364 m_lineBoxes.paint(this, paintInfo, tx, ty);
2366 paintChildren(paintInfo, tx, ty);
2369 void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
2371 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2372 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2374 // We don't paint our own background, but we do let the kids paint their backgrounds.
2375 PaintInfo info(paintInfo);
2376 info.phase = newPhase;
2377 info.updatePaintingRootForChildren(this);
2379 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2380 // NSViews. Do not add any more code for this.
2381 RenderView* renderView = view();
2382 bool usePrintRect = !renderView->printRect().isEmpty();
2384 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2385 // Check for page-break-before: always, and if it's set, break and bail.
2386 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2387 if (checkBeforeAlways
2388 && (ty + child->y()) > paintInfo.rect.y()
2389 && (ty + child->y()) < paintInfo.rect.maxY()) {
2390 view()->setBestTruncatedAt(ty + child->y(), this, true);
2394 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2395 // Paginate block-level replaced elements.
2396 if (ty + child->y() + child->height() > renderView->printRect().maxY()) {
2397 if (ty + child->y() < renderView->truncatedAt())
2398 renderView->setBestTruncatedAt(ty + child->y(), child);
2399 // If we were able to truncate, don't paint.
2400 if (ty + child->y() >= renderView->truncatedAt())
2405 IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment);
2406 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2407 child->paint(info, childPoint.x(), childPoint.y());
2409 // Check for page-break-after: always, and if it's set, break and bail.
2410 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2411 if (checkAfterAlways
2412 && (ty + child->y() + child->height()) > paintInfo.rect.y()
2413 && (ty + child->y() + child->height()) < paintInfo.rect.maxY()) {
2414 view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginAfter()), this, true);
2420 void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type)
2422 SelectionController* selection = type == CursorCaret ? frame()->selection() : frame()->page()->dragCaretController();
2424 // Paint the caret if the SelectionController says so or if caret browsing is enabled
2425 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2426 RenderObject* caretPainter = selection->caretRenderer();
2427 if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) {
2428 // Convert the painting offset into the local coordinate system of this renderer,
2429 // to match the localCaretRect computed by the SelectionController
2430 offsetForContents(tx, ty);
2432 if (type == CursorCaret)
2433 frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
2435 frame()->selection()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
2439 void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
2441 PaintPhase paintPhase = paintInfo.phase;
2443 // 1. paint background, borders etc
2444 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2445 if (hasBoxDecorations())
2446 paintBoxDecorations(paintInfo, tx, ty);
2448 paintColumnRules(paintInfo, tx, ty);
2451 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2452 paintMask(paintInfo, tx, ty);
2456 // We're done. We don't bother painting any children.
2457 if (paintPhase == PaintPhaseBlockBackground)
2460 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2463 if (hasOverflowClip()) {
2464 IntSize offset = layer()->scrolledContentOffset();
2465 scrolledX -= offset.width();
2466 scrolledY -= offset.height();
2469 // 2. paint contents
2470 if (paintPhase != PaintPhaseSelfOutline) {
2472 paintColumnContents(paintInfo, scrolledX, scrolledY);
2474 paintContents(paintInfo, scrolledX, scrolledY);
2477 // 3. paint selection
2478 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2479 bool isPrinting = document()->printing();
2480 if (!isPrinting && !hasColumns())
2481 paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
2484 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2486 paintColumnContents(paintInfo, scrolledX, scrolledY, true);
2488 paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2491 // 5. paint outline.
2492 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2493 paintOutline(paintInfo.context, tx, ty, width(), height());
2495 // 6. paint continuation outlines.
2496 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2497 RenderInline* inlineCont = inlineElementContinuation();
2498 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2499 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2500 RenderBlock* cb = containingBlock();
2502 bool inlineEnclosedInSelfPaintingLayer = false;
2503 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2504 if (box->hasSelfPaintingLayer()) {
2505 inlineEnclosedInSelfPaintingLayer = true;
2510 if (!inlineEnclosedInSelfPaintingLayer)
2511 cb->addContinuationWithOutline(inlineRenderer);
2512 else if (!inlineRenderer->firstLineBox())
2513 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(),
2514 ty - y() + inlineRenderer->containingBlock()->y());
2516 paintContinuationOutlines(paintInfo, tx, ty);
2520 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2521 // then paint the caret.
2522 if (paintPhase == PaintPhaseForeground) {
2523 paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret);
2524 paintCaret(paintInfo, scrolledX, scrolledY, DragCaret);
2528 IntPoint RenderBlock::flipFloatForWritingMode(const FloatingObject* child, const IntPoint& point) const
2530 if (!style()->isFlippedBlocksWritingMode())
2533 // This is similar to the ParentToChildFlippingAdjustment in RenderBox::flipForWritingMode. We have to subtract out our left/top offsets twice, since
2534 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2536 if (isHorizontalWritingMode())
2537 return IntPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
2538 return IntPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2541 void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase)
2543 if (!m_floatingObjects)
2546 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2547 FloatingObjectSetIterator end = floatingObjectSet.end();
2548 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2549 FloatingObject* r = *it;
2550 // Only paint the object if our m_shouldPaint flag is set.
2551 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
2552 PaintInfo currentPaintInfo(paintInfo);
2553 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2554 IntPoint childPoint = flipFloatForWritingMode(r, IntPoint(tx + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), ty + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
2555 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2556 if (!preservePhase) {
2557 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2558 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2559 currentPaintInfo.phase = PaintPhaseFloat;
2560 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2561 currentPaintInfo.phase = PaintPhaseForeground;
2562 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2563 currentPaintInfo.phase = PaintPhaseOutline;
2564 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2570 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty)
2572 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox())
2575 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
2576 // We can check the first box and last box and avoid painting if we don't
2578 int yPos = ty + firstLineBox()->y();
2579 int h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y();
2580 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y())
2583 // See if our boxes intersect with the dirty rect. If so, then we paint
2584 // them. Note that boxes can easily overlap, so we can't make any assumptions
2585 // based off positions of our first line box or our last line box.
2586 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2587 yPos = ty + curr->y();
2588 h = curr->logicalHeight();
2589 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y())
2590 curr->paintEllipsisBox(paintInfo, tx, ty, curr->lineTop(), curr->lineBottom());
2595 RenderInline* RenderBlock::inlineElementContinuation() const
2597 RenderBoxModelObject* continuation = this->continuation();
2598 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2601 RenderBlock* RenderBlock::blockElementContinuation() const
2603 RenderBoxModelObject* currentContinuation = continuation();
2604 if (!currentContinuation || currentContinuation->isInline())
2606 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2607 if (nextContinuation->isAnonymousBlock())
2608 return nextContinuation->blockElementContinuation();
2609 return nextContinuation;
2612 static ContinuationOutlineTableMap* continuationOutlineTable()
2614 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2618 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2620 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2622 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2624 ContinuationOutlineTableMap* table = continuationOutlineTable();
2625 ListHashSet<RenderInline*>* continuations = table->get(this);
2626 if (!continuations) {
2627 continuations = new ListHashSet<RenderInline*>;
2628 table->set(this, continuations);
2631 continuations->add(flow);
2634 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2636 ContinuationOutlineTableMap* table = continuationOutlineTable();
2637 if (table->isEmpty())
2640 ListHashSet<RenderInline*>* continuations = table->get(this);
2644 return continuations->contains(flow);
2647 void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty)
2649 ContinuationOutlineTableMap* table = continuationOutlineTable();
2650 if (table->isEmpty())
2653 ListHashSet<RenderInline*>* continuations = table->get(this);
2657 // Paint each continuation outline.
2658 ListHashSet<RenderInline*>::iterator end = continuations->end();
2659 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2660 // Need to add in the coordinates of the intervening blocks.
2661 RenderInline* flow = *it;
2662 RenderBlock* block = flow->containingBlock();
2663 for ( ; block && block != this; block = block->containingBlock()) {
2668 flow->paintOutline(info.context, tx, ty);
2672 delete continuations;
2673 table->remove(this);
2676 bool RenderBlock::shouldPaintSelectionGaps() const
2678 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2681 bool RenderBlock::isSelectionRoot() const
2686 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2690 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
2691 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
2692 hasReflection() || hasMask() || isWritingModeRoot())
2695 if (view() && view()->selectionStart()) {
2696 Node* startElement = view()->selectionStart()->node();
2697 if (startElement && startElement->rootEditableElement() == node())
2704 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
2706 ASSERT(!needsLayout());
2708 if (!shouldPaintSelectionGaps())
2711 // FIXME: this is broken with transforms
2712 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2713 mapLocalToContainer(repaintContainer, false, false, transformState);
2714 IntPoint offsetFromRepaintContainer = roundedIntPoint(transformState.mappedPoint());
2716 if (hasOverflowClip())
2717 offsetFromRepaintContainer -= layer()->scrolledContentOffset();
2720 int lastLeft = logicalLeftSelectionOffset(this, lastTop);
2721 int lastRight = logicalRightSelectionOffset(this, lastTop);
2723 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2726 void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
2728 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2730 int lastLeft = logicalLeftSelectionOffset(this, lastTop);
2731 int lastRight = logicalRightSelectionOffset(this, lastTop);
2732 paintInfo.context->save();
2733 IntRect gapRectsBounds = selectionGaps(this, IntPoint(tx, ty), IntSize(), lastTop, lastLeft, lastRight, &paintInfo);
2734 if (!gapRectsBounds.isEmpty()) {
2735 if (RenderLayer* layer = enclosingLayer()) {
2736 gapRectsBounds.move(IntSize(-tx, -ty));
2738 IntRect localBounds(gapRectsBounds);
2739 flipForWritingMode(localBounds);
2740 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2741 gapRectsBounds.move(layer->scrolledContentOffset());
2743 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2746 paintInfo.context->restore();
2750 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const IntPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects)
2752 if (!positionedObjects)
2755 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
2756 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2758 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2762 static int blockDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
2764 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
2767 static int inlineDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
2769 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
2772 IntRect RenderBlock::logicalRectToPhysicalRect(const IntPoint& rootBlockPhysicalPosition, const IntRect& logicalRect)
2775 if (isHorizontalWritingMode())
2776 result = logicalRect;
2778 result = IntRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2779 flipForWritingMode(result);
2780 result.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2784 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2785 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo)
2787 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2788 // Clip out floating and positioned objects when painting selection gaps.
2790 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2791 IntRect flippedBlockRect = IntRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2792 rootBlock->flipForWritingMode(flippedBlockRect);
2793 flippedBlockRect.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2794 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get());
2795 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2796 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2797 clipOutPositionedObjects(paintInfo, IntPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes.
2798 if (m_floatingObjects) {
2799 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2800 FloatingObjectSetIterator end = floatingObjectSet.end();
2801 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2802 FloatingObject* r = *it;
2803 IntRect floatBox = IntRect(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
2804 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
2805 r->m_renderer->width(), r->m_renderer->height());
2806 rootBlock->flipForWritingMode(floatBox);
2807 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2808 paintInfo->context->clipOut(floatBox);
2813 // 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
2816 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
2819 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2820 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2821 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2822 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2823 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2827 if (childrenInline())
2828 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2830 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2832 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2833 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2834 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2835 logicalHeight(), paintInfo));
2839 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2840 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo)
2844 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
2846 if (!firstLineBox()) {
2847 if (containsStart) {
2848 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
2850 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2851 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2852 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2857 RootInlineBox* lastSelectedLine = 0;
2858 RootInlineBox* curr;
2859 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
2861 // Now paint the gaps for the lines.
2862 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
2863 int selTop = curr->selectionTop();
2864 int selHeight = curr->selectionHeight();
2866 if (!containsStart && !lastSelectedLine &&
2867 selectionState() != SelectionStart && selectionState() != SelectionBoth)
2868 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2869 selTop, paintInfo));
2871 IntRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
2872 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
2873 IntRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
2874 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
2875 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
2876 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
2878 lastSelectedLine = curr;
2881 if (containsStart && !lastSelectedLine)
2882 // VisibleSelection must start just after our last line.
2883 lastSelectedLine = lastRootBox();
2885 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
2886 // Go ahead and update our lastY to be the bottom of the last selected line.
2887 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
2888 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2889 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2894 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2895 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo)
2899 // Go ahead and jump right to the first block child that contains some selected objects.
2901 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2903 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2904 SelectionState childState = curr->selectionState();
2905 if (childState == SelectionBoth || childState == SelectionEnd)
2906 sawSelectionEnd = true;
2908 if (curr->isFloatingOrPositioned())
2909 continue; // We must be a normal flow object in order to even be considered.
2911 if (curr->isRelPositioned() && curr->hasLayer()) {
2912 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2913 // Just disregard it completely.
2914 IntSize relOffset = curr->layer()->relativePositionOffset();
2915 if (relOffset.width() || relOffset.height())
2919 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2920 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2921 if (fillBlockGaps) {
2922 // We need to fill the vertical gap above this object.
2923 if (childState == SelectionEnd || childState == SelectionInside)
2924 // Fill the gap above the object.
2925 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2926 curr->logicalTop(), paintInfo));
2928 // 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*
2929 // our object. We know this if the selection did not end inside our object.
2930 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2931 childState = SelectionNone;
2933 // Fill side gaps on this object based off its state.
2934 bool leftGap, rightGap;
2935 getSelectionGapInfo(childState, leftGap, rightGap);
2938 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2940 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2942 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
2943 // they can without bumping into floating or positioned objects. Ideally they will go right up
2944 // to the border of the root selection block.
2945 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
2946 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
2947 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
2948 } else if (childState != SelectionNone)
2949 // We must be a block that has some selected object inside it. Go ahead and recur.
2950 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, IntSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
2951 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
2956 IntRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2957 int lastLogicalTop, int lastLogicalLeft, int lastLogicalRight, int logicalBottom, const PaintInfo* paintInfo)
2959 int logicalTop = lastLogicalTop;
2960 int logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
2961 if (logicalHeight <= 0)
2964 // Get the selection offsets for the bottom of the gap
2965 int logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
2966 int logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
2967 int logicalWidth = logicalRight - logicalLeft;
2968 if (logicalWidth <= 0)
2971 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
2973 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace());
2977 IntRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2978 RenderObject* selObj, int logicalLeft, int logicalTop, int logicalHeight, const PaintInfo* paintInfo)
2980 int rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
2981 int rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
2982 int rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalLeft, min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2983 int rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2984 if (rootBlockLogicalWidth <= 0)
2987 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2989 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
2993 IntRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2994 RenderObject* selObj, int logicalRight, int logicalTop, int logicalHeight, const PaintInfo* paintInfo)
2996 int rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
2997 int rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalRight, max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2998 int rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
2999 int rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3000 if (rootBlockLogicalWidth <= 0)
3003 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3005 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3009 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3011 bool ltr = style()->isLeftToRightDirection();
3012 leftGap = (state == RenderObject::SelectionInside) ||
3013 (state == RenderObject::SelectionEnd && ltr) ||
3014 (state == RenderObject::SelectionStart && !ltr);
3015 rightGap = (state == RenderObject::SelectionInside) ||
3016 (state == RenderObject::SelectionStart && ltr) ||
3017 (state == RenderObject::SelectionEnd && !ltr);
3020 int RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, int position)
3022 int logicalLeft = logicalLeftOffsetForLine(position, false);
3023 if (logicalLeft == logicalLeftOffsetForContent()) {
3024 if (rootBlock != this)
3025 // The border can potentially be further extended by our containingBlock().
3026 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3029 RenderBlock* cb = this;
3030 while (cb != rootBlock) {
3031 logicalLeft += cb->logicalLeft();
3032 cb = cb->containingBlock();
3038 int RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, int position)
3040 int logicalRight = logicalRightOffsetForLine(position, false);
3041 if (logicalRight == logicalRightOffsetForContent()) {
3042 if (rootBlock != this)
3043 // The border can potentially be further extended by our containingBlock().
3044 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
3045 return logicalRight;
3047 RenderBlock* cb = this;
3048 while (cb != rootBlock) {
3049 logicalRight += cb->logicalLeft();
3050 cb = cb->containingBlock();
3053 return logicalRight;
3056 void RenderBlock::insertPositionedObject(RenderBox* o)
3058 // Create the list of special objects if we don't aleady have one
3059 if (!m_positionedObjects)
3060 m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet);
3062 m_positionedObjects->add(o);
3065 void RenderBlock::removePositionedObject(RenderBox* o)
3067 if (m_positionedObjects)
3068 m_positionedObjects->remove(o);
3071 void RenderBlock::removePositionedObjects(RenderBlock* o)
3073 if (!m_positionedObjects)
3078 Iterator end = m_positionedObjects->end();
3080 Vector<RenderBox*, 16> deadObjects;
3082 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
3084 if (!o || r->isDescendantOf(o)) {
3086 r->setChildNeedsLayout(true, false);
3088 // It is parent blocks job to add positioned child to positioned objects list of its containing block
3089 // Parent layout needs to be invalidated to ensure this happens.
3090 RenderObject* p = r->parent();
3091 while (p && !p->isRenderBlock())
3094 p->setChildNeedsLayout(true);
3096 deadObjects.append(r);
3100 for (unsigned i = 0; i < deadObjects.size(); i++)
3101 m_positionedObjects->remove(deadObjects.at(i));
3104 RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3106 ASSERT(o->isFloating());
3108 // Create the list of special objects if we don't aleady have one
3109 if (!m_floatingObjects)
3110 m_floatingObjects = adoptPtr(new FloatingObjects);
3112 // Don't insert the object again if it's already in the list
3113 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3114 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3115 if (it != floatingObjectSet.end())
3119 // Create the special object entry & append it to the list
3121 FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight);
3123 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
3124 // Just go ahead and lay out the float.
3125 bool isChildRenderBlock = o->isRenderBlock();
3126 if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged())
3127 o->setChildNeedsLayout(true, false);
3129 bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageLogicalHeight;
3130 if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
3131 o->layoutIfNeeded();
3133 o->computeLogicalWidth();
3134 o->computeBlockDirectionMargins(this);
3136 setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
3138 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will.
3139 newObj->m_isDescendant = true;
3140 newObj->m_renderer = o;
3142 m_floatingObjects->increaseObjectsCount(newObj->type());
3143 m_floatingObjects->set().add(newObj);
3148 void RenderBlock::removeFloatingObject(RenderBox* o)
3150 if (m_floatingObjects) {
3151 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3152 FloatingObjectSet::iterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3153 if (it != floatingObjectSet.end()) {
3154 FloatingObject* r = *it;
3155 if (childrenInline()) {
3156 int logicalTop = logicalTopForFloat(r);
3157 int logicalBottom = logicalBottomForFloat(r);
3159 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
3160 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == numeric_limits<int>::max())
3161 logicalBottom = numeric_limits<int>::max();
3163 // Special-case zero- and less-than-zero-height floats: those don't touch
3164 // the line that they're on, but it still needs to be dirtied. This is
3165 // accomplished by pretending they have a height of 1.
3166 logicalBottom = max(logicalBottom, logicalTop + 1);
3168 markLinesDirtyInBlockRange(0, logicalBottom);
3170 m_floatingObjects->decreaseObjectsCount(r->type());
3171 floatingObjectSet.remove(it);
3177 void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
3179 if (!m_floatingObjects)
3182 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3183 FloatingObject* curr = floatingObjectSet.last();
3184 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
3185 m_floatingObjects->decreaseObjectsCount(curr->type());
3186 floatingObjectSet.removeLast();
3188 curr = floatingObjectSet.last();
3192 bool RenderBlock::positionNewFloats()
3194 if (!m_floatingObjects)
3197 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3198 if (floatingObjectSet.isEmpty())
3201 // If all floats have already been positioned, then we have no work to do.
3202 if (floatingObjectSet.last()->isPlaced())
3205 // Move backwards through our floating object list until we find a float that has
3206 // already been positioned. Then we'll be able to move forward, positioning all of
3207 // the new floats that need it.
3208 FloatingObjectSetIterator it = floatingObjectSet.end();
3209 --it; // Go to last item.
3210 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3211 FloatingObject* lastPlacedFloatingObject = 0;
3212 while (it != begin) {
3214 if ((*it)->isPlaced()) {
3215 lastPlacedFloatingObject = *it;
3221 int logicalTop = logicalHeight();
3223 // The float cannot start above the top position of the last positioned float.
3224 if (lastPlacedFloatingObject)
3225 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
3227 FloatingObjectSetIterator end = floatingObjectSet.end();
3228 // Now walk through the set of unpositioned floats and place them.
3229 for (; it != end; ++it) {
3230 FloatingObject* floatingObject = *it;
3231 // The containing block is responsible for positioning floats, so if we have floats in our
3232 // list that come from somewhere else, do not attempt to position them.
3233 if (floatingObject->renderer()->containingBlock() != this)
3236 RenderBox* childBox = floatingObject->renderer();
3237 int childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
3239 int rightOffset = logicalRightOffsetForContent(); // Constant part of right offset.
3240 int leftOffset = logicalLeftOffsetForContent(); // Constant part of left offset.
3241 int floatLogicalWidth = logicalWidthForFloat(floatingObject); // The width we look for.
3242 if (rightOffset - leftOffset < floatLogicalWidth)
3243 floatLogicalWidth = rightOffset - leftOffset; // Never look for more than what will be available.
3245 IntRect oldRect(childBox->x(), childBox->y() , childBox->width(), childBox->height());
3247 if (childBox->style()->clear() & CLEFT)
3248 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
3249 if (childBox->style()->clear() & CRIGHT)
3250 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
3252 int floatLogicalLeft;
3253 if (childBox->style()->floating() == FLEFT) {
3254 int heightRemainingLeft = 1;
3255 int heightRemainingRight = 1;
3256 floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft);
3257 while (logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
3258 logicalTop += min(heightRemainingLeft, heightRemainingRight);
3259 floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft);
3261 floatLogicalLeft = max(0, floatLogicalLeft);
3263 int heightRemainingLeft = 1;
3264 int heightRemainingRight = 1;
3265 floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight);
3266 while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
3267 logicalTop += min(heightRemainingLeft, heightRemainingRight);
3268 floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight);
3270 floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable
3271 // |floatLogicalWidth| was capped to the available line width.
3272 // See fast/block/float/clamped-right-float.html.
3275 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
3276 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
3277 setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox));
3279 if (view()->layoutState()->isPaginated()) {
3280 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
3282 if (!childBox->needsLayout())
3283 childBox->markForPaginationRelayoutIfNeeded();;
3284 childBox->layoutIfNeeded();
3286 // If we are unsplittable and don't fit, then we need to move down.
3287 // We include our margins as part of the unsplittable area.
3288 int newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, true);
3290 // See if we have a pagination strut that is making us move down further.
3291 // Note that an unsplittable child can't also have a pagination strut, so this is
3292 // exclusive with the case above.
3293 if (childBlock && childBlock->paginationStrut()) {
3294 newLogicalTop += childBlock->paginationStrut();
3295 childBlock->setPaginationStrut(0);
3298 if (newLogicalTop != logicalTop) {
3299 floatingObject->m_paginationStrut = newLogicalTop - logicalTop;
3300 logicalTop = newLogicalTop;
3301 setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox));
3303 childBlock->setChildNeedsLayout(true, false);
3304 childBox->layoutIfNeeded();
3308 setLogicalTopForFloat(floatingObject, logicalTop);
3309 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
3311 floatingObject->setIsPlaced();
3313 // If the child moved, we have to repaint it.
3314 if (childBox->checkForRepaintDuringLayout())
3315 childBox->repaintDuringLayoutIfMoved(oldRect);
3320 void RenderBlock::newLine(EClear clear)
3322 positionNewFloats();
3328 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
3331 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
3334 newY = lowestFloatLogicalBottom();
3338 if (height() < newY)
3339 setLogicalHeight(newY);
3342 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
3344 if (!gPercentHeightDescendantsMap) {
3345 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
3346 gPercentHeightContainerMap = new PercentHeightContainerMap;
3349 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
3350 if (!descendantSet) {
3351 descendantSet = new HashSet<RenderBox*>;
3352 gPercentHeightDescendantsMap->set(this, descendantSet);
3354 bool added = descendantSet->add(descendant).second;
3356 ASSERT(gPercentHeightContainerMap->get(descendant));
3357 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
3361 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
3362 if (!containerSet) {
3363 containerSet = new HashSet<RenderBlock*>;
3364 gPercentHeightContainerMap->set(descendant, containerSet);
3366 ASSERT(!containerSet->contains(this));
3367 containerSet->add(this);
3370 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
3372 if (!gPercentHeightContainerMap)
3375 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
3379 HashSet<RenderBlock*>::iterator end = containerSet->end();
3380 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
3381 RenderBlock* container = *it;
3382 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
3383 ASSERT(descendantSet);
3386 ASSERT(descendantSet->contains(descendant));
3387 descendantSet->remove(descendant);
3388 if (descendantSet->isEmpty()) {
3389 gPercentHeightDescendantsMap->remove(container);
3390 delete descendantSet;
3394 delete containerSet;
3397 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
3399 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
3402 // FIXME: The logicalLeftOffsetForLine/logicalRightOffsetForLine functions are very slow if there are many floats
3403 // present. We need to add a structure to floating objects to represent "lines" of floats. Then instead of checking
3404 // each float individually, we'd just walk backwards through the "lines" and stop when we hit a line that is fully above
3405 // the vertical offset that we'd like to check. Computing the "lines" would be rather complicated, but could replace the left
3406 // objects and right objects count hack that is currently used here.
3407 int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
3409 int left = fixedOffset;
3410 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
3411 if (heightRemaining)
3412 *heightRemaining = 1;
3414 // We know the list is non-empty, since we have "left" objects to search for.
3415 // Therefore we can assume that begin != end, and that we can do at least one
3417 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3418 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3419 FloatingObjectSetIterator it = floatingObjectSet.end();
3422 FloatingObject* r = *it;
3423 if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
3424 && r->type() == FloatingObject::FloatLeft
3425 && logicalRightForFloat(r) > left) {
3426 left = max(left, logicalRightForFloat(r));
3427 if (heightRemaining)
3428 *heightRemaining = logicalBottomForFloat(r) - logicalTop;
3430 } while (it != begin);
3433 if (applyTextIndent && style()->isLeftToRightDirection()) {
3435 if (style()->textIndent().isPercent())
3436 cw = containingBlock()->availableLogicalWidth();
3437 left += style()->textIndent().calcMinValue(cw);
3443 int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
3445 int right = fixedOffset;
3447 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
3448 if (heightRemaining)
3449 *heightRemaining = 1;
3451 // We know the list is non-empty, since we have "right" objects to search for.
3452 // Therefore we can assume that begin != end, and that we can do at least one
3454 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3455 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3456 FloatingObjectSetIterator it = floatingObjectSet.end();
3459 FloatingObject* r = *it;
3460 if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
3461 && r->type() == FloatingObject::FloatRight
3462 && logicalLeftForFloat(r) < right) {
3463 right = min(right, logicalLeftForFloat(r));
3464 if (heightRemaining)
3465 *heightRemaining = logicalBottomForFloat(r) - logicalTop;
3467 } while (it != begin);
3470 if (applyTextIndent && !style()->isLeftToRightDirection()) {
3472 if (style()->textIndent().isPercent())
3473 cw = containingBlock()->availableLogicalWidth();
3474 right -= style()->textIndent().calcMinValue(cw);
3480 int RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const
3482 int result = logicalRightOffsetForLine(position, firstLine) - logicalLeftOffsetForLine(position, firstLine);
3483 return (result < 0) ? 0 : result;
3486 int RenderBlock::nextFloatLogicalBottomBelow(int logicalHeight) const
3488 if (!m_floatingObjects)
3491 int bottom = INT_MAX;
3492 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3493 FloatingObjectSetIterator end = floatingObjectSet.end();
3494 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3495 FloatingObject* r = *it;
3496 int floatBottom = logicalBottomForFloat(r);
3497 if (floatBottom > logicalHeight)
3498 bottom = min(floatBottom, bottom);
3501 return bottom == INT_MAX ? 0 : bottom;
3504 int RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
3506 if (!m_floatingObjects)
3508 int lowestFloatBottom = 0;
3509 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3510 FloatingObjectSetIterator end = floatingObjectSet.end();
3511 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3512 FloatingObject* r = *it;
3513 if (r->isPlaced() && r->type() & floatType)
3514 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r));
3516 return lowestFloatBottom;
3519 void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* highest)
3521 if (logicalTop >= logicalBottom)
3524 RootInlineBox* lowestDirtyLine = lastRootBox();
3525 RootInlineBox* afterLowest = lowestDirtyLine;
3526 while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom && logicalBottom < numeric_limits<int>::max()) {
3527 afterLowest = lowestDirtyLine;
3528 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3531 while (afterLowest && afterLowest != highest && (afterLowest->blockLogicalHeight() >= logicalTop || afterLowest->blockLogicalHeight() < 0)) {
3532 afterLowest->markDirty();
3533 afterLowest = afterLowest->prevRootBox();
3537 void RenderBlock::clearFloats()
3539 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
3540 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) {
3541 if (m_floatingObjects) {
3542 deleteAllValues(m_floatingObjects->set());
3543 m_floatingObjects->clear();
3548 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
3549 RendererToFloatInfoMap floatMap;
3551 if (m_floatingObjects) {
3552 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3553 if (childrenInline()) {
3554 FloatingObjectSet::iterator end = floatingObjectSet.end();
3555 for (FloatingObjectSet::iterator it = floatingObjectSet.begin(); it != end; ++it) {
3556 FloatingObject* f = *it;
3557 floatMap.add(f->m_renderer, f);
3560 deleteAllValues(floatingObjectSet);
3561 m_floatingObjects->clear();
3564 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
3565 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
3566 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
3567 if (!parent() || !parent()->isRenderBlock())
3570 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
3571 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
3573 bool parentHasFloats = false;
3574 RenderBlock* parentBlock = toRenderBlock(parent());
3575 RenderObject* prev = previousSibling();
3576 while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
3577 if (prev->isFloating())
3578 parentHasFloats = true;
3579 prev = prev->previousSibling();
3582 // First add in floats from the parent.
3583 int logicalTopOffset = logicalTop();
3584 if (parentHasFloats)
3585 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
3587 int logicalLeftOffset = 0;
3589 logicalTopOffset -= toRenderBox(prev)->logicalTop();
3592 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
3595 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
3596 if (!prev || !prev->isRenderBlock())
3599 RenderBlock* block = toRenderBlock(prev);
3600 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
3601 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
3603 if (childrenInline()) {
3604 int changeLogicalTop = numeric_limits<int>::max();
3605 int changeLogicalBottom = numeric_limits<int>::min();
3606 if (m_floatingObjects) {
3607 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3608 FloatingObjectSetIterator end = floatingObjectSet.end();
3609 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3610 FloatingObject* f = *it;
3611 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
3612 int logicalBottom = logicalBottomForFloat(f);
3613 if (oldFloatingObject) {
3614 int oldLogicalBottom = logicalBottomForFloat(oldFloatingObject);
3615 if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) {
3616 changeLogicalTop = 0;
3617 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
3618 } else if (logicalBottom != oldLogicalBottom) {
3619 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
3620 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
3623 floatMap.remove(f->m_renderer);
3624 delete oldFloatingObject;
3626 changeLogicalTop = 0;
3627 changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
3632 RendererToFloatInfoMap::iterator end = floatMap.end();
3633 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
3634 FloatingObject* floatingObject = (*it).second;
3635 if (!floatingObject->m_isDescendant) {
3636 changeLogicalTop = 0;
3637 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
3640 deleteAllValues(floatMap);
3642 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
3646 int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, int logicalTopOffset, bool makeChildPaintOtherFloats)
3648 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
3649 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
3652 int lowestFloatLogicalBottom = 0;
3654 // Floats that will remain the child's responsibility to paint should factor into its
3656 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end();
3657 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
3658 FloatingObject* r = *childIt;
3659 int logicalBottom = child->logicalTop() + logicalBottomForFloat(r);
3660 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
3662 if (logicalBottom > logicalHeight()) {
3663 // If the object is not in the list, we add it now.
3664 if (!containsFloat(r->m_renderer)) {
3665 int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
3666 int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
3667 FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
3668 floatingObj->m_renderer = r->m_renderer;
3670 // The nearest enclosing layer always paints the float (so that zindex and stacking
3671 // behaves properly). We always want to propagate the desire to paint the float as
3672 // far out as we can, to the outermost block that overlaps the float, stopping only
3673 // if we hit a self-painting layer boundary.
3674 if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer())
3675 r->m_shouldPaint = false;
3677 floatingObj->m_shouldPaint = false;
3679 floatingObj->m_isDescendant = true;
3681 // We create the floating object list lazily.
3682 if (!m_floatingObjects)
3683 m_floatingObjects = adoptPtr(new FloatingObjects);
3685 m_floatingObjects->increaseObjectsCount(floatingObj->type());
3686 m_floatingObjects->set().add(floatingObj);
3689 if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() &&
3690 r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) {
3691 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
3692 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
3694 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats