2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include "RenderBlock.h"
27 #include "ColumnInfo.h"
30 #include "FloatQuad.h"
32 #include "FrameSelection.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLNames.h"
37 #include "HitTestResult.h"
38 #include "InlineIterator.h"
39 #include "InlineTextBox.h"
40 #include "LayoutRepainter.h"
42 #include "PaintInfo.h"
43 #include "RenderBoxRegionInfo.h"
44 #include "RenderCombineText.h"
45 #include "RenderDeprecatedFlexibleBox.h"
46 #include "RenderFlowThread.h"
47 #include "RenderImage.h"
48 #include "RenderInline.h"
49 #include "RenderLayer.h"
50 #include "RenderMarquee.h"
51 #include "RenderRegion.h"
52 #include "RenderReplica.h"
53 #include "RenderTableCell.h"
54 #include "RenderTextFragment.h"
55 #include "RenderTheme.h"
56 #include "RenderView.h"
58 #include "SVGTextRunRenderingContext.h"
59 #include "TransformState.h"
60 #include <wtf/StdLibExtras.h>
64 using namespace Unicode;
68 using namespace HTMLNames;
70 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
71 static ColumnInfoMap* gColumnInfoMap = 0;
73 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
74 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
76 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
77 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
79 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
81 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
82 static int gDelayUpdateScrollInfo = 0;
83 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
85 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
87 // Our MarginInfo state used when laying out block children.
88 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
89 : m_atBeforeSideOfBlock(true)
90 , m_atAfterSideOfBlock(false)
91 , m_marginBeforeQuirk(false)
92 , m_marginAfterQuirk(false)
93 , m_determinedMarginBeforeQuirk(false)
95 // Whether or not we can collapse our own margins with our children. We don't do this
96 // if we had any border/padding (obviously), if we're the root or HTML elements, or if
97 // we're positioned, floating, a table cell.
98 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned()
99 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
100 && !block->isWritingModeRoot() && block->style()->hasAutoColumnCount() && block->style()->hasAutoColumnWidth()
101 && !block->style()->columnSpan();
103 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && (beforeBorderPadding == 0) && block->style()->marginBeforeCollapse() != MSEPARATE;
105 // If any height other than auto is specified in CSS, then we don't collapse our bottom
106 // margins with our children's margins. To do otherwise would be to risk odd visual
107 // effects when the children overflow out of the parent block and yet still collapse
108 // with it. We also don't collapse if we have any bottom border/padding.
109 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
110 (block->style()->logicalHeight().isAuto() && block->style()->logicalHeight().value() == 0) && block->style()->marginAfterCollapse() != MSEPARATE;
112 m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginBeforeCollapse() == MDISCARD ||
113 block->style()->marginAfterCollapse() == MDISCARD;
115 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0;
116 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0;
119 // -------------------------------------------------------------------------------------------------------
121 RenderBlock::RenderBlock(Node* node)
124 , m_beingDestroyed(false)
125 , m_hasPositionedFloats(false)
127 setChildrenInline(true);
130 RenderBlock::~RenderBlock()
132 if (m_floatingObjects)
133 deleteAllValues(m_floatingObjects->set());
136 delete gColumnInfoMap->take(this);
138 if (gPercentHeightDescendantsMap) {
139 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
140 HashSet<RenderBox*>::iterator end = descendantSet->end();
141 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
142 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
143 ASSERT(containerSet);
146 ASSERT(containerSet->contains(this));
147 containerSet->remove(this);
148 if (containerSet->isEmpty()) {
149 gPercentHeightContainerMap->remove(*descendant);
153 delete descendantSet;
158 void RenderBlock::willBeDestroyed()
160 // Mark as being destroyed to avoid trouble with merges in removeChild().
161 m_beingDestroyed = true;
163 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
164 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
165 children()->destroyLeftoverChildren();
167 // Destroy our continuation before anything other than anonymous children.
168 // The reason we don't destroy it before anonymous children is that they may
169 // have continuations of their own that are anonymous children of our continuation.
170 RenderBoxModelObject* continuation = this->continuation();
172 continuation->destroy();
176 if (!documentBeingDestroyed()) {
177 if (firstLineBox()) {
178 // We can't wait for RenderBox::destroy to clear the selection,
179 // because by then we will have nuked the line boxes.
180 // FIXME: The FrameSelection should be responsible for this when it
181 // is notified of DOM mutations.
182 if (isSelectionBorder())
183 view()->clearSelection();
185 // If we are an anonymous block, then our line boxes might have children
186 // that will outlast this block. In the non-anonymous block case those
187 // children will be destroyed by the time we return from this function.
188 if (isAnonymousBlock()) {
189 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
190 while (InlineBox* childBox = box->firstChild())
195 parent()->dirtyLinesFromChangedChild(this);
198 m_lineBoxes.deleteLineBoxes(renderArena());
200 if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
201 gDelayedUpdateScrollInfoSet->remove(this);
203 RenderBox::willBeDestroyed();
206 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
208 s_canPropagateFloatIntoSibling = style() ? !isFloatingOrPositioned() && !avoidsFloats() : false;
210 setReplaced(newStyle->isDisplayInlineType());
212 if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) {
213 if (newStyle->position() == StaticPosition)
214 // Clear our positioned objects list. Our absolutely positioned descendants will be
215 // inserted into our containing block's positioned objects list during layout.
216 removePositionedObjects(0);
217 else if (style()->position() == StaticPosition) {
218 // Remove our absolutely positioned descendants from their current containing block.
219 // They will be inserted into our positioned objects list during layout.
220 RenderObject* cb = parent();
221 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
222 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
223 cb = cb->containingBlock();
229 if (cb->isRenderBlock())
230 toRenderBlock(cb)->removePositionedObjects(this);
233 if (containsFloats() && !isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
234 markAllDescendantsWithFloatsForLayout();
237 RenderBox::styleWillChange(diff, newStyle);
240 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
242 RenderBox::styleDidChange(diff, oldStyle);
244 if (!isAnonymousBlock()) {
245 // Ensure that all of our continuation blocks pick up the new style.
246 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
247 RenderBoxModelObject* nextCont = currCont->continuation();
248 currCont->setContinuation(0);
249 currCont->setStyle(style());
250 currCont->setContinuation(nextCont);
254 propagateStyleToAnonymousChildren(true);
257 // Update pseudos for :before and :after now.
258 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
259 updateBeforeAfterContent(BEFORE);
260 updateBeforeAfterContent(AFTER);
263 // After our style changed, if we lose our ability to propagate floats into next sibling
264 // blocks, then we need to find the top most parent containing that overhanging float and
265 // then mark its descendants with floats for layout and clear all floats from its next
266 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
267 bool canPropagateFloatIntoSibling = !isFloatingOrPositioned() && !avoidsFloats();
268 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
269 RenderBlock* parentBlock = this;
270 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
271 FloatingObjectSetIterator end = floatingObjectSet.end();
273 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
274 if (curr->isRenderBlock()) {
275 RenderBlock* currBlock = toRenderBlock(curr);
277 if (currBlock->hasOverhangingFloats()) {
278 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
279 RenderBox* renderer = (*it)->renderer();
280 if (currBlock->hasOverhangingFloat(renderer)) {
281 parentBlock = currBlock;
289 parentBlock->markAllDescendantsWithFloatsForLayout();
290 parentBlock->markSiblingsWithFloatsForLayout();
294 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
296 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
297 if (parent() && parent()->createsAnonymousWrapper())
299 children()->updateBeforeAfterContent(this, pseudoId);
302 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
304 if (beforeChild && beforeChild->parent() == this)
307 RenderBlock* curr = toRenderBlock(continuation());
308 RenderBlock* nextToLast = this;
309 RenderBlock* last = this;
311 if (beforeChild && beforeChild->parent() == curr) {
312 if (curr->firstChild() == beforeChild)
319 curr = toRenderBlock(curr->continuation());
322 if (!beforeChild && !last->firstChild())
327 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
329 RenderBlock* flow = continuationBefore(beforeChild);
330 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
331 RenderBoxModelObject* beforeChildParent = 0;
333 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
335 RenderBoxModelObject* cont = flow->continuation();
337 beforeChildParent = cont;
339 beforeChildParent = flow;
342 if (newChild->isFloatingOrPositioned()) {
343 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
347 // A continuation always consists of two potential candidates: a block or an anonymous
348 // column span box holding column span children.
349 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
350 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
351 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
353 if (flow == beforeChildParent) {
354 flow->addChildIgnoringContinuation(newChild, beforeChild);
358 // The goal here is to match up if we can, so that we can coalesce and create the
359 // minimal # of continuations needed for the inline.
360 if (childIsNormal == bcpIsNormal) {
361 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
364 if (flowIsNormal == childIsNormal) {
365 flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
368 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
372 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
374 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
376 // The goal is to locate a suitable box in which to place our child.
377 RenderBlock* beforeChildParent = toRenderBlock(beforeChild && beforeChild->parent()->isRenderBlock() ? beforeChild->parent() : lastChild());
379 // If the new child is floating or positioned it can just go in that block.
380 if (newChild->isFloatingOrPositioned()) {
381 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
385 // See if the child can be placed in the box.
386 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
387 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
389 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
390 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
395 // Create a new block of the correct type.
396 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
397 children()->appendChildNode(this, newBox);
398 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
402 RenderObject* immediateChild = beforeChild;
403 bool isPreviousBlockViable = true;
404 while (immediateChild->parent() != this) {
405 if (isPreviousBlockViable)
406 isPreviousBlockViable = !immediateChild->previousSibling();
407 immediateChild = immediateChild->parent();
409 if (isPreviousBlockViable && immediateChild->previousSibling()) {
410 toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
414 // Split our anonymous blocks.
415 RenderObject* newBeforeChild = splitAnonymousBlocksAroundChild(beforeChild);
417 // Create a new anonymous box of the appropriate type.
418 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
419 children()->insertChildNode(this, newBox, newBeforeChild);
420 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
424 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
426 for (RenderObject* curr = this; curr; curr = curr->parent()) {
427 if (!curr->isRenderBlock() || curr->isFloatingOrPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
428 || curr->isInlineBlockOrInlineTable())
431 RenderBlock* currBlock = toRenderBlock(curr);
432 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
435 if (currBlock->isAnonymousColumnSpanBlock())
441 RenderBlock* RenderBlock::clone() const
443 RenderBlock* cloneBlock;
444 if (isAnonymousBlock())
445 cloneBlock = createAnonymousBlock();
447 cloneBlock = new (renderArena()) RenderBlock(node());
448 cloneBlock->setStyle(style());
450 cloneBlock->setChildrenInline(childrenInline());
454 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
455 RenderBlock* middleBlock,
456 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
458 // Create a clone of this inline.
459 RenderBlock* cloneBlock = clone();
460 if (!isAnonymousBlock())
461 cloneBlock->setContinuation(oldCont);
463 // Now take all of the children from beforeChild to the end and remove
464 // them from |this| and place them in the clone.
465 if (!beforeChild && isAfterContent(lastChild()))
466 beforeChild = lastChild();
467 moveChildrenTo(cloneBlock, beforeChild, 0);
469 // Hook |clone| up as the continuation of the middle block.
470 if (!cloneBlock->isAnonymousBlock())
471 middleBlock->setContinuation(cloneBlock);
473 // We have been reparented and are now under the fromBlock. We need
474 // to walk up our block parent chain until we hit the containing anonymous columns block.
475 // Once we hit the anonymous columns block we're done.
476 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
477 RenderBoxModelObject* currChild = this;
479 while (curr && curr != fromBlock) {
480 ASSERT(curr->isRenderBlock());
482 RenderBlock* blockCurr = toRenderBlock(curr);
484 // Create a new clone.
485 RenderBlock* cloneChild = cloneBlock;
486 cloneBlock = blockCurr->clone();
488 // Insert our child clone as the first child.
489 cloneBlock->children()->appendChildNode(cloneBlock, cloneChild);
491 // Hook the clone up as a continuation of |curr|. Note we do encounter
492 // anonymous blocks possibly as we walk up the block chain. When we split an
493 // anonymous block, there's no need to do any continuation hookup, since we haven't
494 // actually split a real element.
495 if (!blockCurr->isAnonymousBlock()) {
496 oldCont = blockCurr->continuation();
497 blockCurr->setContinuation(cloneBlock);
498 cloneBlock->setContinuation(oldCont);
501 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
502 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
503 // content gets properly destroyed.
504 if (document()->usesBeforeAfterRules())
505 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
507 // Now we need to take all of the children starting from the first child
508 // *after* currChild and append them all to the clone.
509 RenderObject* afterContent = isAfterContent(cloneBlock->lastChild()) ? cloneBlock->lastChild() : 0;
510 blockCurr->moveChildrenTo(cloneBlock, currChild->nextSibling(), 0, afterContent);
512 // Keep walking up the chain.
514 curr = toRenderBoxModelObject(curr->parent());
517 // Now we are at the columns block level. We need to put the clone into the toBlock.
518 toBlock->children()->appendChildNode(toBlock, cloneBlock);
520 // Now take all the children after currChild and remove them from the fromBlock
521 // and put them in the toBlock.
522 fromBlock->moveChildrenTo(toBlock, currChild->nextSibling(), 0);
525 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
526 RenderObject* newChild, RenderBoxModelObject* oldCont)
528 RenderBlock* pre = 0;
529 RenderBlock* block = containingColumnsBlock();
531 // Delete our line boxes before we do the inline split into continuations.
532 block->deleteLineBoxTree();
534 bool madeNewBeforeBlock = false;
535 if (block->isAnonymousColumnsBlock()) {
536 // We can reuse this block and make it the preBlock of the next continuation.
538 pre->removePositionedObjects(0);
539 block = toRenderBlock(block->parent());
541 // No anonymous block available for use. Make one.
542 pre = block->createAnonymousColumnsBlock();
543 pre->setChildrenInline(false);
544 madeNewBeforeBlock = true;
547 RenderBlock* post = block->createAnonymousColumnsBlock();
548 post->setChildrenInline(false);
550 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
551 if (madeNewBeforeBlock)
552 block->children()->insertChildNode(block, pre, boxFirst);
553 block->children()->insertChildNode(block, newBlockBox, boxFirst);
554 block->children()->insertChildNode(block, post, boxFirst);
555 block->setChildrenInline(false);
557 if (madeNewBeforeBlock)
558 block->moveChildrenTo(pre, boxFirst, 0);
560 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
562 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
563 // time in makeChildrenNonInline by just setting this explicitly up front.
564 newBlockBox->setChildrenInline(false);
566 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
567 // connected, thus allowing newChild access to a renderArena should it need
568 // to wrap itself in additional boxes (e.g., table construction).
569 newBlockBox->addChild(newChild);
571 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
572 // get deleted properly. Because objects moves from the pre block into the post block, we want to
573 // make new line boxes instead of leaving the old line boxes around.
574 pre->setNeedsLayoutAndPrefWidthsRecalc();
575 block->setNeedsLayoutAndPrefWidthsRecalc();
576 post->setNeedsLayoutAndPrefWidthsRecalc();
579 RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild)
581 while (beforeChild->parent() != this) {
582 RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent());
583 if (blockToSplit->firstChild() != beforeChild) {
584 // We have to split the parentBlock into two blocks.
585 RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit);
586 post->setChildrenInline(blockToSplit->childrenInline());
587 RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent());
588 parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling());
589 blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer());
590 post->setNeedsLayoutAndPrefWidthsRecalc();
591 blockToSplit->setNeedsLayoutAndPrefWidthsRecalc();
594 beforeChild = blockToSplit;
599 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
601 RenderBlock* pre = 0;
602 RenderBlock* post = 0;
603 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
604 // so that we don't have to patch all of the rest of the code later on.
606 // Delete the block's line boxes before we do the split.
607 block->deleteLineBoxTree();
609 if (beforeChild && beforeChild->parent() != this)
610 beforeChild = splitAnonymousBlocksAroundChild(beforeChild);
612 if (beforeChild != firstChild()) {
613 pre = block->createAnonymousColumnsBlock();
614 pre->setChildrenInline(block->childrenInline());
618 post = block->createAnonymousColumnsBlock();
619 post->setChildrenInline(block->childrenInline());
622 RenderObject* boxFirst = block->firstChild();
624 block->children()->insertChildNode(block, pre, boxFirst);
625 block->children()->insertChildNode(block, newBlockBox, boxFirst);
627 block->children()->insertChildNode(block, post, boxFirst);
628 block->setChildrenInline(false);
630 // 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).
631 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
632 block->moveChildrenTo(post, beforeChild, 0, true);
634 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
635 // time in makeChildrenNonInline by just setting this explicitly up front.
636 newBlockBox->setChildrenInline(false);
638 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
639 // connected, thus allowing newChild access to a renderArena should it need
640 // to wrap itself in additional boxes (e.g., table construction).
641 newBlockBox->addChild(newChild);
643 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
644 // get deleted properly. Because objects moved from the pre block into the post block, we want to
645 // make new line boxes instead of leaving the old line boxes around.
647 pre->setNeedsLayoutAndPrefWidthsRecalc();
648 block->setNeedsLayoutAndPrefWidthsRecalc();
650 post->setNeedsLayoutAndPrefWidthsRecalc();
653 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
655 // FIXME: This function is the gateway for the addition of column-span support. It will
656 // be added to in three stages:
657 // (1) Immediate children of a multi-column block can span.
658 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
659 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
660 // cross the streams and have to cope with both types of continuations mixed together).
661 // This function currently supports (1) and (2).
662 RenderBlock* columnsBlockAncestor = 0;
663 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isFloatingOrPositioned()
664 && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
665 if (style()->specifiesColumns())
666 columnsBlockAncestor = this;
667 else if (!isInline() && parent() && parent()->isRenderBlock()) {
668 columnsBlockAncestor = toRenderBlock(parent())->containingColumnsBlock(false);
670 if (columnsBlockAncestor) {
671 // Make sure that none of the parent ancestors have a continuation.
672 // If yes, we do not want split the block into continuations.
673 RenderObject* curr = this;
674 while (curr && curr != columnsBlockAncestor) {
675 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
676 columnsBlockAncestor = 0;
679 curr = curr->parent();
684 return columnsBlockAncestor;
687 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
689 // Make sure we don't append things after :after-generated content if we have it.
691 beforeChild = afterPseudoElementRenderer();
693 // If the requested beforeChild is not one of our children, then this is because
694 // there is an anonymous container within this object that contains the beforeChild.
695 if (beforeChild && beforeChild->parent() != this) {
696 RenderObject* beforeChildAnonymousContainer = anonymousContainer(beforeChild);
697 ASSERT(beforeChildAnonymousContainer);
698 ASSERT(beforeChildAnonymousContainer->isAnonymous());
700 if (beforeChildAnonymousContainer->isAnonymousBlock()) {
701 // Insert the child into the anonymous block box instead of here.
702 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
703 beforeChild->parent()->addChild(newChild, beforeChild);
705 addChild(newChild, beforeChild->parent());
709 ASSERT(beforeChildAnonymousContainer->isTable());
710 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
711 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
712 || newChild->isTableSection()
713 || newChild->isTableRow()
714 || newChild->isTableCell()) {
715 // Insert into the anonymous table.
716 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
720 // Go on to insert before the anonymous table.
721 beforeChild = beforeChildAnonymousContainer;
724 // Check for a spanning element in columns.
725 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
726 if (columnsBlockAncestor) {
727 // We are placing a column-span element inside a block.
728 RenderBlock* newBox = createAnonymousColumnSpanBlock();
730 if (columnsBlockAncestor != this) {
731 // We are nested inside a multi-column element and are being split by the span. We have to break up
732 // our block into continuations.
733 RenderBoxModelObject* oldContinuation = continuation();
734 setContinuation(newBox);
736 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
737 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
738 // content gets properly destroyed.
739 bool isLastChild = (beforeChild == lastChild());
740 if (document()->usesBeforeAfterRules())
741 children()->updateBeforeAfterContent(this, AFTER);
742 if (isLastChild && beforeChild != lastChild())
743 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
744 // point to be 0. It's just a straight append now.
746 splitFlow(beforeChild, newBox, newChild, oldContinuation);
750 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
751 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
752 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
753 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
757 bool madeBoxesNonInline = false;
759 // A block has to either have all of its children inline, or all of its children as blocks.
760 // So, if our children are currently inline and a block child has to be inserted, we move all our
761 // inline children into anonymous block boxes.
762 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
763 // This is a block with inline content. Wrap the inline content in anonymous blocks.
764 makeChildrenNonInline(beforeChild);
765 madeBoxesNonInline = true;
767 if (beforeChild && beforeChild->parent() != this) {
768 beforeChild = beforeChild->parent();
769 ASSERT(beforeChild->isAnonymousBlock());
770 ASSERT(beforeChild->parent() == this);
772 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
773 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
774 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
775 // a new one is created and inserted into our list of children in the appropriate position.
776 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
778 if (afterChild && afterChild->isAnonymousBlock()) {
779 afterChild->addChild(newChild);
783 if (newChild->isInline()) {
784 // No suitable existing anonymous box - create a new one.
785 RenderBlock* newBox = createAnonymousBlock();
786 RenderBox::addChild(newBox, beforeChild);
787 newBox->addChild(newChild);
792 RenderBox::addChild(newChild, beforeChild);
794 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
795 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
796 // this object may be dead here
799 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
801 if (continuation() && !isAnonymousBlock())
802 addChildToContinuation(newChild, beforeChild);
804 addChildIgnoringContinuation(newChild, beforeChild);
807 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
809 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
810 addChildToAnonymousColumnBlocks(newChild, beforeChild);
812 addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
815 static void getInlineRun(RenderObject* start, RenderObject* boundary,
816 RenderObject*& inlineRunStart,
817 RenderObject*& inlineRunEnd)
819 // Beginning at |start| we find the largest contiguous run of inlines that
820 // we can. We denote the run with start and end points, |inlineRunStart|
821 // and |inlineRunEnd|. Note that these two values may be the same if
822 // we encounter only one inline.
824 // We skip any non-inlines we encounter as long as we haven't found any
827 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
828 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
831 // Start by skipping as many non-inlines as we can.
832 RenderObject * curr = start;
835 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
836 curr = curr->nextSibling();
838 inlineRunStart = inlineRunEnd = curr;
841 return; // No more inline children to be found.
843 sawInline = curr->isInline();
845 curr = curr->nextSibling();
846 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
848 if (curr->isInline())
850 curr = curr->nextSibling();
852 } while (!sawInline);
855 void RenderBlock::deleteLineBoxTree()
857 if (containsFloats()) {
858 // Clear references to originating lines, since the lines are being deleted
859 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
860 FloatingObjectSetIterator end = floatingObjectSet.end();
861 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
862 ASSERT(!((*it)->m_originatingLine) || (*it)->m_originatingLine->renderer() == this);
863 (*it)->m_originatingLine = 0;
866 m_lineBoxes.deleteLineBoxTree(renderArena());
869 RootInlineBox* RenderBlock::createRootInlineBox()
871 return new (renderArena()) RootInlineBox(this);
874 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
876 RootInlineBox* rootBox = createRootInlineBox();
877 m_lineBoxes.appendLineBox(rootBox);
881 void RenderBlock::moveChildTo(RenderBlock* to, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
883 ASSERT(this == child->parent());
884 ASSERT(!beforeChild || to == beforeChild->parent());
885 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
888 void RenderBlock::moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
890 ASSERT(!beforeChild || to == beforeChild->parent());
891 RenderObject* nextChild = startChild;
892 while (nextChild && nextChild != endChild) {
893 RenderObject* child = nextChild;
894 nextChild = child->nextSibling();
895 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
896 if (child == endChild)
901 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
903 // makeChildrenNonInline takes a block whose children are *all* inline and it
904 // makes sure that inline children are coalesced under anonymous
905 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
906 // the new block child that is causing us to have to wrap all the inlines. This
907 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
908 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
910 ASSERT(isInlineBlockOrInlineTable() || !isInline());
911 ASSERT(!insertionPoint || insertionPoint->parent() == this);
913 setChildrenInline(false);
915 RenderObject *child = firstChild();
922 RenderObject *inlineRunStart, *inlineRunEnd;
923 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
928 child = inlineRunEnd->nextSibling();
930 RenderBlock* block = createAnonymousBlock();
931 children()->insertChildNode(this, block, inlineRunStart);
932 moveChildrenTo(block, inlineRunStart, child);
936 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
937 ASSERT(!c->isInline());
943 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
945 ASSERT(child->isAnonymousBlock());
946 ASSERT(!child->childrenInline());
948 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
951 RenderObject* firstAnChild = child->m_children.firstChild();
952 RenderObject* lastAnChild = child->m_children.lastChild();
954 RenderObject* o = firstAnChild;
957 o = o->nextSibling();
959 firstAnChild->setPreviousSibling(child->previousSibling());
960 lastAnChild->setNextSibling(child->nextSibling());
961 if (child->previousSibling())
962 child->previousSibling()->setNextSibling(firstAnChild);
963 if (child->nextSibling())
964 child->nextSibling()->setPreviousSibling(lastAnChild);
966 if (child == m_children.firstChild())
967 m_children.setFirstChild(firstAnChild);
968 if (child == m_children.lastChild())
969 m_children.setLastChild(lastAnChild);
971 if (child == m_children.firstChild())
972 m_children.setFirstChild(child->nextSibling());
973 if (child == m_children.lastChild())
974 m_children.setLastChild(child->previousSibling());
976 if (child->previousSibling())
977 child->previousSibling()->setNextSibling(child->nextSibling());
978 if (child->nextSibling())
979 child->nextSibling()->setPreviousSibling(child->previousSibling());
982 child->setPreviousSibling(0);
983 child->setNextSibling(0);
985 child->children()->setFirstChild(0);
991 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
993 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
997 if (oldChild->parent() && oldChild->parent()->isDetails())
1001 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
1002 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
1005 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
1006 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
1009 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
1010 || (next && (next->isRubyRun() || next->isRubyBase())))
1016 // Make sure the types of the anonymous blocks match up.
1017 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1018 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1021 void RenderBlock::removeChild(RenderObject* oldChild)
1023 // If this child is a block, and if our previous and next siblings are
1024 // both anonymous blocks with inline content, then we can go ahead and
1025 // fold the inline content back together.
1026 RenderObject* prev = oldChild->previousSibling();
1027 RenderObject* next = oldChild->nextSibling();
1028 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1029 if (canMergeAnonymousBlocks && prev && next) {
1030 prev->setNeedsLayoutAndPrefWidthsRecalc();
1031 RenderBlock* nextBlock = toRenderBlock(next);
1032 RenderBlock* prevBlock = toRenderBlock(prev);
1034 if (prev->childrenInline() != next->childrenInline()) {
1035 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1036 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1038 // Place the inline children block inside of the block children block instead of deleting it.
1039 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1040 // to clear out inherited column properties by just making a new style, and to also clear the
1041 // column span flag if it is set.
1042 ASSERT(!inlineChildrenBlock->continuation());
1043 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
1044 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
1045 inlineChildrenBlock->setStyle(newStyle);
1047 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1048 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1049 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer());
1050 next->setNeedsLayoutAndPrefWidthsRecalc();
1052 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1053 // of "this". we null out prev or next so that is not used later in the function.
1054 if (inlineChildrenBlock == prevBlock)
1059 // Take all the children out of the |next| block and put them in
1060 // the |prev| block.
1061 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1063 // Delete the now-empty block's lines and nuke it.
1064 nextBlock->deleteLineBoxTree();
1065 nextBlock->destroy();
1070 RenderBox::removeChild(oldChild);
1072 RenderObject* child = prev ? prev : next;
1073 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBoxIncludingDeprecated()) {
1074 // The removal has knocked us down to containing only a single anonymous
1075 // box. We can go ahead and pull the content right back up into our
1077 setNeedsLayoutAndPrefWidthsRecalc();
1078 setChildrenInline(child->childrenInline());
1079 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, child->hasLayer()));
1080 anonBlock->moveAllChildrenTo(this, child->hasLayer());
1081 // Delete the now-empty block's lines and nuke it.
1082 anonBlock->deleteLineBoxTree();
1083 anonBlock->destroy();
1086 if (!firstChild() && !documentBeingDestroyed()) {
1087 // If this was our last child be sure to clear out our line boxes.
1088 if (childrenInline())
1089 lineBoxes()->deleteLineBoxes(renderArena());
1093 bool RenderBlock::isSelfCollapsingBlock() const
1095 // We are not self-collapsing if we
1096 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1098 // (c) have border/padding,
1099 // (d) have a min-height
1100 // (e) have specified that one of our margins can't collapse using a CSS extension
1101 if (logicalHeight() > 0
1102 || isTable() || borderAndPaddingLogicalHeight()
1103 || style()->logicalMinHeight().isPositive()
1104 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1107 Length logicalHeightLength = style()->logicalHeight();
1108 bool hasAutoHeight = logicalHeightLength.isAuto();
1109 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1110 hasAutoHeight = true;
1111 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1112 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1113 hasAutoHeight = false;
1117 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1118 // on whether we have content that is all self-collapsing or not.
1119 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1120 // If the block has inline children, see if we generated any line boxes. If we have any
1121 // line boxes, then we can't be self-collapsing, since we have content.
1122 if (childrenInline())
1123 return !firstLineBox();
1125 // Whether or not we collapse is dependent on whether all our normal flow children
1126 // are also self-collapsing.
1127 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1128 if (child->isFloatingOrPositioned())
1130 if (!child->isSelfCollapsingBlock())
1138 void RenderBlock::startDelayUpdateScrollInfo()
1140 if (gDelayUpdateScrollInfo == 0) {
1141 ASSERT(!gDelayedUpdateScrollInfoSet);
1142 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1144 ASSERT(gDelayedUpdateScrollInfoSet);
1145 ++gDelayUpdateScrollInfo;
1148 void RenderBlock::finishDelayUpdateScrollInfo()
1150 --gDelayUpdateScrollInfo;
1151 ASSERT(gDelayUpdateScrollInfo >= 0);
1152 if (gDelayUpdateScrollInfo == 0) {
1153 ASSERT(gDelayedUpdateScrollInfoSet);
1155 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1156 gDelayedUpdateScrollInfoSet = 0;
1158 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1159 RenderBlock* block = *it;
1160 if (block->hasOverflowClip()) {
1161 block->layer()->updateScrollInfoAfterLayout();
1167 void RenderBlock::updateScrollInfoAfterLayout()
1169 if (hasOverflowClip()) {
1170 if (gDelayUpdateScrollInfo)
1171 gDelayedUpdateScrollInfoSet->add(this);
1173 layer()->updateScrollInfoAfterLayout();
1177 void RenderBlock::layout()
1179 // Update our first letter info now.
1180 updateFirstLetter();
1182 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1186 // It's safe to check for control clip here, since controls can never be table cells.
1187 // If we have a lightweight clip, there can never be any overflow from children.
1188 if (hasControlClip() && m_overflow)
1189 clearLayoutOverflow();
1192 void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight, BlockLayoutPass layoutPass)
1194 ASSERT(needsLayout());
1196 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1197 return; // cause us to come in here. Just bail.
1199 if (!relayoutChildren && simplifiedLayout())
1202 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
1204 LayoutUnit oldWidth = logicalWidth();
1205 LayoutUnit oldColumnWidth = desiredColumnWidth();
1207 computeLogicalWidth();
1212 if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth())
1213 relayoutChildren = true;
1215 // If nothing changed about our floating positioned objects, let's go ahead and try to place them as
1216 // floats to avoid doing two passes.
1217 BlockLayoutPass floatsLayoutPass = layoutPass;
1218 if (floatsLayoutPass == NormalLayoutPass && !relayoutChildren && !positionedFloatsNeedRelayout())
1219 floatsLayoutPass = PositionedFloatLayoutPass;
1220 clearFloats(floatsLayoutPass);
1222 LayoutUnit previousHeight = logicalHeight();
1223 setLogicalHeight(0);
1224 bool hasSpecifiedPageLogicalHeight = false;
1225 bool pageLogicalHeightChanged = false;
1226 ColumnInfo* colInfo = columnInfo();
1228 if (!pageLogicalHeight) {
1229 // We need to go ahead and set our explicit page height if one exists, so that we can
1230 // avoid doing two layout passes.
1231 computeLogicalHeight();
1232 LayoutUnit columnHeight = contentLogicalHeight();
1233 if (columnHeight > 0) {
1234 pageLogicalHeight = columnHeight;
1235 hasSpecifiedPageLogicalHeight = true;
1237 setLogicalHeight(0);
1239 if (colInfo->columnHeight() != pageLogicalHeight && m_everHadLayout) {
1240 colInfo->setColumnHeight(pageLogicalHeight);
1241 pageLogicalHeightChanged = true;
1244 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1245 colInfo->clearForcedBreaks();
1248 RenderView* renderView = view();
1249 LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, colInfo);
1251 if (inRenderFlowThread()) {
1252 // Regions changing widths can force us to relayout our children.
1253 if (logicalWidthChangedInRegions())
1254 relayoutChildren = true;
1256 // Set our start and end regions. No regions above or below us will be considered by our children. They are
1257 // effectively clamped to our region range.
1258 LayoutUnit oldHeight = logicalHeight();
1259 LayoutUnit oldLogicalTop = logicalTop();
1260 setLogicalHeight(numeric_limits<LayoutUnit>::max() / 2);
1261 computeLogicalHeight();
1262 enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1263 setLogicalHeight(oldHeight);
1264 setLogicalTop(oldLogicalTop);
1267 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1268 // our current maximal positive and negative margins. These values are used when we
1269 // are collapsed with adjacent blocks, so for example, if you have block A and B
1270 // collapsing together, then you'd take the maximal positive margin from both A and B
1271 // and subtract it from the maximal negative margin from both A and B to get the
1272 // true collapsed margin. This algorithm is recursive, so when we finish layout()
1273 // our block knows its current maximal positive/negative values.
1275 // Start out by setting our margin values to our current margins. Table cells have
1276 // no margins, so we don't fill in the values for table cells.
1277 bool isCell = isTableCell();
1279 initMaxMarginValues();
1281 setMarginBeforeQuirk(style()->marginBefore().quirk());
1282 setMarginAfterQuirk(style()->marginAfter().quirk());
1285 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
1286 // See if this form is malformed (i.e., unclosed). If so, don't give the form
1288 setMaxMarginAfterValues(0, 0);
1291 setPaginationStrut(0);
1294 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
1295 if (scrollsOverflow()) {
1296 if (style()->overflowX() == OSCROLL)
1297 layer()->setHasHorizontalScrollbar(true);
1298 if (style()->overflowY() == OSCROLL)
1299 layer()->setHasVerticalScrollbar(true);
1302 LayoutUnit repaintLogicalTop = 0;
1303 LayoutUnit repaintLogicalBottom = 0;
1304 LayoutUnit maxFloatLogicalBottom = 0;
1305 if (!firstChild() && !isAnonymousBlock())
1306 setChildrenInline(true);
1307 if (childrenInline())
1308 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1310 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1312 // Expand our intrinsic height to encompass floats.
1313 LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1314 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1315 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1317 if (layoutColumns(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1320 // Calculate our new height.
1321 LayoutUnit oldHeight = logicalHeight();
1322 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
1323 computeLogicalHeight();
1324 LayoutUnit newHeight = logicalHeight();
1325 if (oldHeight != newHeight) {
1326 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1327 // One of our children's floats may have become an overhanging float for us. We need to look for it.
1328 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1329 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
1330 RenderBlock* block = toRenderBlock(child);
1331 if (block->lowestFloatLogicalBottomIncludingPositionedFloats() + block->logicalTop() > newHeight)
1332 addOverhangingFloats(block, false);
1338 if (previousHeight != newHeight)
1339 relayoutChildren = true;
1341 bool needAnotherLayoutPass = layoutPositionedObjects(relayoutChildren || isRoot());
1343 if (inRenderFlowThread())
1344 enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1346 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1347 computeOverflow(oldClientAfterEdge);
1351 if (renderView->layoutState()->m_pageLogicalHeight)
1352 setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(logicalTop()));
1354 updateLayerTransform();
1356 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1357 // we overflow or not.
1358 updateScrollInfoAfterLayout();
1360 // FIXME: This repaint logic should be moved into a separate helper function!
1361 // Repaint with our new bounds if they are different from our old bounds.
1362 bool didFullRepaint = repainter.repaintAfterLayout();
1363 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1364 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1365 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1366 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
1367 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
1368 if (hasOverflowClip()) {
1369 // 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.
1370 // 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.
1371 // layoutInlineChildren should be patched to compute the entire repaint rect.
1372 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1373 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1376 LayoutRect repaintRect;
1377 if (isHorizontalWritingMode())
1378 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1380 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1382 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1383 adjustRectForColumns(repaintRect);
1385 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1387 if (hasOverflowClip()) {
1388 // Adjust repaint rect for scroll offset
1389 repaintRect.move(-layer()->scrolledContentOffset());
1391 // Don't allow this rect to spill out of our overflow box.
1392 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
1395 // Make sure the rect is still non-empty after intersecting for overflow above
1396 if (!repaintRect.isEmpty()) {
1397 // FIXME: Might need rounding once we switch to float, see https://bugs.webkit.org/show_bug.cgi?id=64021
1398 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1399 if (hasReflection())
1400 repaintRectangle(reflectedRect(repaintRect));
1404 if (needAnotherLayoutPass && layoutPass == NormalLayoutPass) {
1405 setChildNeedsLayout(true, false);
1406 layoutBlock(false, pageLogicalHeight, PositionedFloatLayoutPass);
1408 setNeedsLayout(false);
1411 void RenderBlock::addOverflowFromChildren()
1413 if (!hasColumns()) {
1414 if (childrenInline())
1415 addOverflowFromInlineChildren();
1417 addOverflowFromBlockChildren();
1419 ColumnInfo* colInfo = columnInfo();
1420 if (columnCount(colInfo)) {
1421 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1422 addLayoutOverflow(lastRect);
1423 if (!hasOverflowClip())
1424 addVisualOverflow(lastRect);
1429 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
1431 // Add overflow from children.
1432 addOverflowFromChildren();
1434 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1435 addOverflowFromFloats();
1437 // Add in the overflow from positioned objects.
1438 addOverflowFromPositionedObjects();
1440 if (hasOverflowClip()) {
1441 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1442 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1443 // be considered reachable.
1444 LayoutRect clientRect(clientBoxRect());
1445 LayoutRect rectToApply;
1446 if (isHorizontalWritingMode())
1447 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1449 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1450 addLayoutOverflow(rectToApply);
1453 // Add visual overflow from box-shadow and border-image-outset.
1454 addBoxShadowAndBorderOverflow();
1457 void RenderBlock::addOverflowFromBlockChildren()
1459 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1460 if (!child->isFloatingOrPositioned())
1461 addOverflowFromChild(child);
1465 void RenderBlock::addOverflowFromFloats()
1467 if (!m_floatingObjects)
1470 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1471 FloatingObjectSetIterator end = floatingObjectSet.end();
1472 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1473 FloatingObject* r = *it;
1474 if (r->m_isDescendant && !r->m_renderer->isPositioned())
1475 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1480 void RenderBlock::addOverflowFromPositionedObjects()
1482 if (!m_positionedObjects)
1485 RenderBox* positionedObject;
1486 Iterator end = m_positionedObjects->end();
1487 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1488 positionedObject = *it;
1490 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1491 if (positionedObject->style()->position() != FixedPosition)
1492 addOverflowFromChild(positionedObject);
1496 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1498 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
1499 || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot() || isRoot();
1502 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1504 bool isHorizontal = isHorizontalWritingMode();
1505 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1507 LayoutUnit logicalTop = logicalHeight();
1508 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
1510 if (!marginInfo.canCollapseWithMarginBefore()) {
1511 child->computeBlockDirectionMargins(this);
1512 LayoutUnit marginBefore = marginBeforeForChild(child);
1513 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
1514 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
1515 if (marginBefore > 0) {
1516 if (marginBefore > collapsedBeforePos)
1517 collapsedBeforePos = marginBefore;
1519 if (-marginBefore > collapsedBeforeNeg)
1520 collapsedBeforeNeg = -marginBefore;
1522 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
1525 RenderLayer* childLayer = child->layer();
1526 if (childLayer->staticBlockPosition() != logicalTop) {
1527 childLayer->setStaticBlockPosition(logicalTop);
1528 if (hasStaticBlockPosition)
1529 child->setChildNeedsLayout(true, false);
1533 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1535 // The float should be positioned taking into account the bottom margin
1536 // of the previous flow. We add that margin into the height, get the
1537 // float positioned properly, and then subtract the margin out of the
1538 // height again. In the case of self-collapsing blocks, we always just
1539 // use the top margins, since the self-collapsing block collapsed its
1540 // own bottom margin into its top margin.
1542 // Note also that the previous flow may collapse its margin into the top of
1543 // our block. If this is the case, then we do not add the margin in to our
1544 // height when computing the position of the float. This condition can be tested
1545 // for by simply calling canCollapseWithMarginBefore. See
1546 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1547 // an example of this scenario.
1548 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin();
1549 setLogicalHeight(logicalHeight() + marginOffset);
1550 positionNewFloats();
1551 setLogicalHeight(logicalHeight() - marginOffset);
1554 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1556 // Handle in the given order
1557 return handlePositionedChild(child, marginInfo)
1558 || handleFloatingChild(child, marginInfo)
1559 || handleRunInChild(child);
1563 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1565 if (child->isPositioned()) {
1566 child->containingBlock()->insertPositionedObject(child);
1567 adjustPositionedBlock(child, marginInfo);
1573 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1575 if (child->isFloating()) {
1576 insertFloatingObject(child);
1577 adjustFloatingBlock(marginInfo);
1583 bool RenderBlock::handleRunInChild(RenderBox* child)
1585 // See if we have a run-in element with inline children. If the
1586 // children aren't inline, then just treat the run-in as a normal
1588 if (!child->isRunIn() || !child->childrenInline())
1590 // FIXME: We don't handle non-block elements with run-in for now.
1591 if (!child->isRenderBlock())
1594 RenderBlock* blockRunIn = toRenderBlock(child);
1595 RenderObject* curr = blockRunIn->nextSibling();
1596 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned())
1599 RenderBlock* currBlock = toRenderBlock(curr);
1601 // First we destroy any :before/:after content. It will be regenerated by the new inline.
1602 // Exception is if the run-in itself is generated.
1603 if (child->style()->styleType() != BEFORE && child->style()->styleType() != AFTER) {
1604 RenderObject* generatedContent;
1605 if (child->getCachedPseudoStyle(BEFORE) && (generatedContent = child->beforePseudoElementRenderer()))
1606 generatedContent->destroy();
1607 if (child->getCachedPseudoStyle(AFTER) && (generatedContent = child->afterPseudoElementRenderer()))
1608 generatedContent->destroy();
1611 // Remove the old child.
1612 children()->removeChildNode(this, blockRunIn);
1614 // Create an inline.
1615 Node* runInNode = blockRunIn->node();
1616 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1617 inlineRunIn->setStyle(blockRunIn->style());
1619 // Move the nodes from the old child to the new child
1620 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) {
1621 RenderObject* nextSibling = runInChild->nextSibling();
1622 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
1623 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
1624 runInChild = nextSibling;
1627 // Now insert the new child under |currBlock|. Use addChild instead of insertChildNode since it handles correct placement of the children, esp where we cannot insert
1628 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1629 currBlock->addChild(inlineRunIn, currBlock->firstChild());
1631 // If the run-in had an element, we need to set the new renderer.
1633 runInNode->setRenderer(inlineRunIn);
1635 // Destroy the block run-in, which includes deleting its line box tree.
1636 blockRunIn->deleteLineBoxTree();
1637 blockRunIn->destroy();
1639 // The block acts like an inline, so just null out its
1645 LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1647 // Get the four margin values for the child and cache them.
1648 const MarginValues childMargins = marginValuesForChild(child);
1650 // Get our max pos and neg top margins.
1651 LayoutUnit posTop = childMargins.positiveMarginBefore();
1652 LayoutUnit negTop = childMargins.negativeMarginBefore();
1654 // For self-collapsing blocks, collapse our bottom margins into our
1655 // top to get new posTop and negTop values.
1656 if (child->isSelfCollapsingBlock()) {
1657 posTop = max(posTop, childMargins.positiveMarginAfter());
1658 negTop = max(negTop, childMargins.negativeMarginAfter());
1661 // See if the top margin is quirky. We only care if this child has
1662 // margins that will collapse with us.
1663 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
1665 if (marginInfo.canCollapseWithMarginBefore()) {
1666 // This child is collapsing with the top of the
1667 // block. If it has larger margin values, then we need to update
1668 // our own maximal values.
1669 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
1670 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
1672 // The minute any of the margins involved isn't a quirk, don't
1673 // collapse it away, even if the margin is smaller (www.webreference.com
1674 // has an example of this, a <dt> with 0.8em author-specified inside
1675 // a <dl> inside a <td>.
1676 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
1677 setMarginBeforeQuirk(false);
1678 marginInfo.setDeterminedMarginBeforeQuirk(true);
1681 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
1682 // We have no top margin and our top child has a quirky margin.
1683 // We will pick up this quirky margin and pass it through.
1684 // This deals with the <td><div><p> case.
1685 // Don't do this for a block that split two inlines though. You do
1686 // still apply margins in this case.
1687 setMarginBeforeQuirk(true);
1690 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1691 marginInfo.setMarginBeforeQuirk(topQuirk);
1693 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1694 LayoutUnit logicalTop = beforeCollapseLogicalTop;
1695 if (child->isSelfCollapsingBlock()) {
1696 // This child has no height. We need to compute our
1697 // position before we collapse the child's margins together,
1698 // so that we can get an accurate position for the zero-height block.
1699 LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1700 LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1701 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1703 // Now collapse the child's margins together, which means examining our
1704 // bottom margin values as well.
1705 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1706 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1708 if (!marginInfo.canCollapseWithMarginBefore())
1709 // We need to make sure that the position of the self-collapsing block
1710 // is correct, since it could have overflowing content
1711 // that needs to be positioned correctly (e.g., a block that
1712 // had a specified height of 0 but that actually had subcontent).
1713 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1716 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1717 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
1718 logicalTop = logicalHeight();
1720 else if (!marginInfo.atBeforeSideOfBlock() ||
1721 (!marginInfo.canCollapseMarginBeforeWithChildren()
1722 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
1723 // We're collapsing with a previous sibling's margins and not
1724 // with the top of the block.
1725 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
1726 logicalTop = logicalHeight();
1729 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1730 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1732 if (marginInfo.margin())
1733 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
1736 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1737 // collapsed into the page edge.
1738 LayoutState* layoutState = view()->layoutState();
1739 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1740 && hasNextPage(beforeCollapseLogicalTop)) {
1741 LayoutUnit oldLogicalTop = logicalTop;
1742 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
1743 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1748 LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
1750 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1751 if (!heightIncrease)
1754 if (child->isSelfCollapsingBlock()) {
1755 // For self-collapsing blocks that clear, they can still collapse their
1756 // margins with following siblings. Reset the current margins to represent
1757 // the self-collapsing block's margins only.
1759 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
1760 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
1761 // self-collapsing block's bottom margin.
1762 bool atBottomOfBlock = true;
1763 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
1764 if (!curr->isFloatingOrPositioned())
1765 atBottomOfBlock = false;
1768 MarginValues childMargins = marginValuesForChild(child);
1769 if (atBottomOfBlock) {
1770 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1771 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1773 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1774 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1777 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
1778 // of the parent block).
1779 setLogicalHeight(child->y() - max<LayoutUnit>(0, marginInfo.margin()));
1781 // Increase our height by the amount we had to clear.
1782 setLogicalHeight(height() + heightIncrease);
1784 if (marginInfo.canCollapseWithMarginBefore()) {
1785 // We can no longer collapse with the top of the block since a clear
1786 // occurred. The empty blocks collapse into the cleared block.
1787 // FIXME: This isn't quite correct. Need clarification for what to do
1788 // if the height the cleared block is offset by is smaller than the
1789 // margins involved.
1790 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1791 marginInfo.setAtBeforeSideOfBlock(false);
1794 return yPos + heightIncrease;
1797 LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
1799 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1800 // relayout if there are intruding floats.
1801 LayoutUnit logicalTopEstimate = logicalHeight();
1802 if (!marginInfo.canCollapseWithMarginBefore()) {
1803 LayoutUnit childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child);
1804 logicalTopEstimate += max(marginInfo.margin(), childMarginBefore);
1807 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1809 LayoutState* layoutState = view()->layoutState();
1810 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1811 && hasNextPage(logicalHeight()))
1812 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1814 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1816 estimateWithoutPagination = logicalTopEstimate;
1818 if (layoutState->isPaginated()) {
1819 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1820 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1822 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1823 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1825 if (!child->selfNeedsLayout() && child->isRenderBlock())
1826 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1829 return logicalTopEstimate;
1832 LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart,
1833 LayoutUnit childLogicalWidth, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
1835 LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
1837 // Add in our start margin.
1838 LayoutUnit oldPosition = startPosition + childMarginStart;
1839 LayoutUnit newPosition = oldPosition;
1841 LayoutUnit blockOffset = logicalTopForChild(child);
1843 blockOffset = max(blockOffset, blockOffset + (region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage));
1845 LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage);
1846 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1847 if (childMarginStart < 0)
1848 startOff += childMarginStart;
1849 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1850 // FIXME: Needs to use epsilon once we switch to float, see https://bugs.webkit.org/show_bug.cgi?id=64021
1851 } else if (startOff != startPosition) {
1852 // The object is shifting to the "end" side of the block. The object might be centered, so we need to
1853 // recalculate our inline direction margins. Note that the containing block content
1854 // width computation will take into account the delta between |startOff| and |startPosition|
1855 // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
1857 LayoutUnit oldMarginStart = marginStartForChild(child);
1858 LayoutUnit oldMarginEnd = marginEndForChild(child);
1859 RenderBox* mutableChild = const_cast<RenderBox*>(child);
1860 mutableChild->computeInlineDirectionMargins(this,
1861 availableLogicalWidthForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage), childLogicalWidth);
1862 newPosition = startOff + marginStartForChild(child);
1863 if (inRenderFlowThread()) {
1864 setMarginStartForChild(mutableChild, oldMarginStart);
1865 setMarginEndForChild(mutableChild, oldMarginEnd);
1869 return newPosition - oldPosition;
1872 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
1874 LayoutUnit startPosition = borderStart() + paddingStart();
1875 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1877 // Add in our start margin.
1878 LayoutUnit childMarginStart = marginStartForChild(child);
1879 LayoutUnit newPosition = startPosition + childMarginStart;
1881 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1882 // to shift over as necessary to dodge any floats that might get in the way.
1883 if (child->avoidsFloats() && containsFloats() && !inRenderFlowThread())
1884 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child), logicalWidthForChild(child));
1886 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
1889 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1891 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1892 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1893 // with our children.
1894 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1896 if (!marginInfo.marginAfterQuirk())
1897 setMarginAfterQuirk(false);
1899 if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
1900 // We have no bottom margin and our last child has a quirky margin.
1901 // We will pick up this quirky margin and pass it through.
1902 // This deals with the <td><div><p> case.
1903 setMarginAfterQuirk(true);
1907 void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1909 marginInfo.setAtAfterSideOfBlock(true);
1911 // If we can't collapse with children then go ahead and add in the bottom margin.
1912 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1913 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
1914 setLogicalHeight(logicalHeight() + marginInfo.margin());
1916 // Now add in our bottom border/padding.
1917 setLogicalHeight(logicalHeight() + afterSide);
1919 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1920 // If this happens, ensure that the computed height is increased to the minimal height.
1921 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1923 // Update our bottom collapsed margin info.
1924 setCollapsedBottomMargin(marginInfo);
1927 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
1929 if (isHorizontalWritingMode()) {
1930 if (applyDelta == ApplyLayoutDelta)
1931 view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
1932 child->setX(logicalLeft);
1934 if (applyDelta == ApplyLayoutDelta)
1935 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
1936 child->setY(logicalLeft);
1940 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
1942 if (isHorizontalWritingMode()) {
1943 if (applyDelta == ApplyLayoutDelta)
1944 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
1945 child->setY(logicalTop);
1947 if (applyDelta == ApplyLayoutDelta)
1948 view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
1949 child->setX(logicalTop);
1953 void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
1955 if (gPercentHeightDescendantsMap) {
1956 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
1957 HashSet<RenderBox*>::iterator end = descendants->end();
1958 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
1959 RenderBox* box = *it;
1960 while (box != this) {
1961 if (box->normalChildNeedsLayout())
1963 box->setChildNeedsLayout(true, false);
1964 box = box->containingBlock();
1973 LayoutUnit beforeEdge = borderBefore() + paddingBefore();
1974 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1976 setLogicalHeight(beforeEdge);
1978 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
1979 MarginInfo marginInfo(this, beforeEdge, afterEdge);
1981 // Fieldsets need to find their legend and position it inside the border of the object.
1982 // The legend then gets skipped during normal layout. The same is true for ruby text.
1983 // It doesn't get included in the normal layout process but is instead skipped.
1984 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
1986 LayoutUnit previousFloatLogicalBottom = 0;
1987 maxFloatLogicalBottom = 0;
1989 RenderBox* next = firstChildBox();
1992 RenderBox* child = next;
1993 next = child->nextSiblingBox();
1995 if (childToExclude == child)
1996 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
1998 // Make sure we layout children if they need it.
1999 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
2000 // an auto value. Add a method to determine this, so that we can avoid the relayout.
2001 if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView()))
2002 child->setChildNeedsLayout(true, false);
2004 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2005 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
2006 child->setPreferredLogicalWidthsDirty(true, false);
2008 // Handle the four types of special elements first. These include positioned content, floating content, compacts and
2009 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
2010 if (handleSpecialChild(child, marginInfo))
2013 // Lay out the child.
2014 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
2017 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
2018 // determining the correct collapsed bottom margin information.
2019 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
2022 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
2024 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
2025 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
2027 // The child is a normal flow object. Compute the margins we will use for collapsing now.
2028 child->computeBlockDirectionMargins(this);
2030 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
2031 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
2032 marginInfo.setAtBeforeSideOfBlock(false);
2033 marginInfo.clearMargin();
2036 // Try to guess our correct logical top position. In most cases this guess will
2037 // be correct. Only if we're wrong (when we compute the real logical top position)
2038 // will we have to potentially relayout.
2039 LayoutUnit estimateWithoutPagination;
2040 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
2042 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
2043 LayoutRect oldRect(child->x(), child->y() , child->width(), child->height());
2044 LayoutUnit oldLogicalTop = logicalTopForChild(child);
2047 LayoutSize oldLayoutDelta = view()->layoutDelta();
2049 // Go ahead and position the child as though it didn't collapse with the top.
2050 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
2052 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
2053 bool markDescendantsWithFloats = false;
2054 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
2055 markDescendantsWithFloats = true;
2056 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
2057 // If an element might be affected by the presence of floats, then always mark it for
2059 LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottomIncludingPositionedFloats());
2060 if (fb > logicalTopEstimate)
2061 markDescendantsWithFloats = true;
2064 if (childRenderBlock) {
2065 if (markDescendantsWithFloats)
2066 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2067 if (!child->isWritingModeRoot())
2068 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottomIncludingPositionedFloats());
2071 if (!child->needsLayout())
2072 child->markForPaginationRelayoutIfNeeded();
2074 bool childHadLayout = child->m_everHadLayout;
2075 bool childNeededLayout = child->needsLayout();
2076 if (childNeededLayout)
2079 // Cache if we are at the top of the block right now.
2080 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
2082 // Now determine the correct ypos based off examination of collapsing margin
2084 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
2086 // Now check for clear.
2087 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
2089 bool paginated = view()->layoutState()->isPaginated();
2091 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
2092 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
2094 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2096 // Now we have a final top position. See if it really does end up being different from our estimate.
2097 if (logicalTopAfterClear != logicalTopEstimate) {
2098 if (child->shrinkToAvoidFloats()) {
2099 // The child's width depends on the line width.
2100 // When the child shifts to clear an item, its width can
2101 // change (because it has more available line width).
2102 // So go ahead and mark the item as dirty.
2103 child->setChildNeedsLayout(true, false);
2106 if (childRenderBlock) {
2107 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2108 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2109 if (!child->needsLayout())
2110 child->markForPaginationRelayoutIfNeeded();
2113 // Our guess was wrong. Make the child lay itself out again.
2114 child->layoutIfNeeded();
2117 // We are no longer at the top of the block if we encounter a non-empty child.
2118 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2119 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2120 marginInfo.setAtBeforeSideOfBlock(false);
2122 // Now place the child in the correct left position
2123 determineLogicalLeftPositionForChild(child);
2125 // Update our height now that the child has been placed in the correct position.
2126 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2127 if (child->style()->marginAfterCollapse() == MSEPARATE) {
2128 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2129 marginInfo.clearMargin();
2131 // If the child has overhanging floats that intrude into following siblings (or possibly out
2132 // of this block), then the parent gets notified of the floats now.
2133 if (childRenderBlock && childRenderBlock->containsFloats())
2134 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
2136 LayoutSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
2137 if (childOffset.width() || childOffset.height()) {
2138 view()->addLayoutDelta(childOffset);
2140 // If the child moved, we have to repaint it as well as any floating/positioned
2141 // descendants. An exception is if we need a layout. In this case, we know we're going to
2142 // repaint ourselves (and the child) anyway.
2143 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2144 child->repaintDuringLayoutIfMoved(oldRect);
2147 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2149 child->repaintOverhangingFloats(true);
2153 // Check for an after page/column break.
2154 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2155 if (newHeight != height())
2156 setLogicalHeight(newHeight);
2159 ASSERT(oldLayoutDelta == view()->layoutDelta());
2162 void RenderBlock::simplifiedNormalFlowLayout()
2164 if (childrenInline()) {
2165 ListHashSet<RootInlineBox*> lineBoxes;
2166 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
2167 RenderObject* o = walker.current();
2168 if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
2169 o->layoutIfNeeded();
2170 if (toRenderBox(o)->inlineBoxWrapper()) {
2171 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2174 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline()))
2175 o->setNeedsLayout(false);
2178 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2179 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2180 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2181 RootInlineBox* box = *it;
2182 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2185 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2186 if (!box->isPositioned())
2187 box->layoutIfNeeded();
2192 bool RenderBlock::simplifiedLayout()
2194 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2197 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2199 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2202 // Lay out positioned descendants or objects that just need to recompute overflow.
2203 if (needsSimplifiedNormalFlowLayout())
2204 simplifiedNormalFlowLayout();
2206 // Lay out our positioned objects if our positioned child bit is set.
2207 if (posChildNeedsLayout() && layoutPositionedObjects(false))
2208 return false; // If a positioned float is causing our normal flow to change, then we have to bail and do a full layout.
2210 // Recompute our overflow information.
2211 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2212 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2213 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2214 // lowestPosition on every relayout so it's not a regression.
2216 computeOverflow(clientLogicalBottom(), true);
2220 updateLayerTransform();
2222 updateScrollInfoAfterLayout();
2224 setNeedsLayout(false);
2228 bool RenderBlock::positionedFloatsNeedRelayout()
2230 if (!hasPositionedFloats())
2233 RenderBox* positionedObject;
2234 Iterator end = m_positionedObjects->end();
2235 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2236 positionedObject = *it;
2237 if (!positionedObject->isFloating())
2240 if (positionedObject->needsLayout())
2243 if (positionedObject->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && positionedObject->parent() != this && positionedObject->parent()->isBlockFlow())
2246 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2253 bool RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2255 if (!m_positionedObjects)
2259 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2261 bool didFloatingBoxRelayout = false;
2264 Iterator end = m_positionedObjects->end();
2265 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2267 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2268 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2269 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2270 // positioned explicitly) this should not incur a performance penalty.
2271 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
2272 r->setChildNeedsLayout(true, false);
2274 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2275 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
2276 r->setPreferredLogicalWidthsDirty(true, false);
2278 if (!r->needsLayout())
2279 r->markForPaginationRelayoutIfNeeded();
2281 // FIXME: Technically we could check the old placement and the new placement of the box and only invalidate if
2282 // the margin box of the object actually changed.
2283 if (r->needsLayout() && r->isFloating())
2284 didFloatingBoxRelayout = true;
2286 // 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
2287 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2288 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2289 r->setNeedsLayout(false);
2291 // If we are in a flow thread, go ahead and compute a vertical position for our object now.
2292 // If it's wrong we'll lay out again.
2293 LayoutUnit oldLogicalTop = 0;
2294 bool checkForPaginationRelayout = r->needsLayout() && view()->layoutState()->isPaginated() && view()->layoutState()->pageLogicalHeight();
2295 if (checkForPaginationRelayout) {
2296 if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
2297 r->computeLogicalHeight();
2299 r->computeLogicalWidth();
2300 oldLogicalTop = logicalTopForChild(r);
2303 r->layoutIfNeeded();
2305 // Lay out again if our estimate was wrong.
2306 if (checkForPaginationRelayout && logicalTopForChild(r) != oldLogicalTop) {
2307 r->setChildNeedsLayout(true, false);
2308 r->layoutIfNeeded();
2313 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2315 return didFloatingBoxRelayout;
2318 void RenderBlock::markPositionedObjectsForLayout()
2320 if (m_positionedObjects) {
2322 Iterator end = m_positionedObjects->end();
2323 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2325 r->setChildNeedsLayout(true);
2330 void RenderBlock::markForPaginationRelayoutIfNeeded()
2332 ASSERT(!needsLayout());
2336 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2337 setChildNeedsLayout(true, false);
2340 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2342 // Repaint any overhanging floats (if we know we're the one to paint them).
2343 // Otherwise, bail out.
2344 if (!hasOverhangingFloats())
2347 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2348 // in this block. Better yet would be to push extra state for the containers of other floats.
2349 LayoutStateDisabler layoutStateDisabler(view());
2350 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2351 FloatingObjectSetIterator end = floatingObjectSet.end();
2352 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2353 FloatingObject* r = *it;
2354 // Only repaint the object if it is overhanging, is not in its own layer, and
2355 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2356 // condition is replaced with being a descendant of us.
2357 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
2358 r->m_renderer->repaint();
2359 r->m_renderer->repaintOverhangingFloats();
2364 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2366 LayoutPoint adjustedPaintOffset = paintOffset + location();
2368 PaintPhase phase = paintInfo.phase;
2370 // Check if we need to do anything at all.
2371 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2372 // paints the root's background.
2374 LayoutRect overflowBox = visualOverflowRect();
2375 flipForWritingMode(overflowBox);
2376 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2377 overflowBox.moveBy(adjustedPaintOffset);
2378 if (!overflowBox.intersects(paintInfo.rect))
2382 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
2383 paintObject(paintInfo, adjustedPaintOffset);
2385 popContentsClip(paintInfo, phase, adjustedPaintOffset);
2387 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2388 // z-index. We paint after we painted the background/border, so that the scrollbars will
2389 // sit above the background/border.
2390 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2391 layer()->paintOverflowControls(paintInfo.context, adjustedPaintOffset, paintInfo.rect);
2394 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2396 if (paintInfo.context->paintingDisabled())
2399 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2400 bool ruleTransparent = style()->columnRuleIsTransparent();
2401 EBorderStyle ruleStyle = style()->columnRuleStyle();
2402 LayoutUnit ruleThickness = style()->columnRuleWidth();
2403 LayoutUnit colGap = columnGap();
2404 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleThickness <= colGap;
2408 ColumnInfo* colInfo = columnInfo();
2409 unsigned colCount = columnCount(colInfo);
2411 bool antialias = shouldAntialiasLines(paintInfo.context);
2413 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
2414 LayoutUnit currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2415 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
2416 LayoutUnit ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2417 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
2418 BoxSide boxSide = isHorizontalWritingMode()
2419 ? style()->isLeftToRightDirection() ? BSLeft : BSRight
2420 : style()->isLeftToRightDirection() ? BSTop : BSBottom;
2422 for (unsigned i = 0; i < colCount; i++) {
2423 // Move to the next position.
2424 if (style()->isLeftToRightDirection()) {
2425 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2426 currLogicalLeftOffset += inlineDirectionSize + colGap;
2428 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2429 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2432 // Now paint the column rule.
2433 if (i < colCount - 1) {
2434 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
2435 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
2436 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
2437 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
2438 drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom, boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2441 ruleLogicalLeft = currLogicalLeftOffset;
2444 LayoutUnit ruleLeft = isHorizontalWritingMode() ? borderLeft() + paddingLeft() : colGap / 2 - colGap - ruleThickness / 2 + borderBefore() + paddingBefore();
2445 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2446 LayoutUnit ruleTop = isHorizontalWritingMode() ? colGap / 2 - colGap - ruleThickness / 2 + borderBefore() + paddingBefore() : borderStart() + paddingStart();
2447 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2448 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2450 flipForWritingMode(ruleRect);
2451 ruleRect.moveBy(paintOffset);
2453 BoxSide boxSide = isHorizontalWritingMode()
2454 ? !style()->isFlippedBlocksWritingMode() ? BSTop : BSBottom
2455 : !style()->isFlippedBlocksWritingMode() ? BSLeft : BSRight;
2457 LayoutSize step(0, !style()->isFlippedBlocksWritingMode() ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2458 if (!isHorizontalWritingMode())
2459 step = step.transposedSize();
2461 for (unsigned i = 1; i < colCount; i++) {
2462 ruleRect.move(step);
2463 drawLineForBoxSide(paintInfo.context, ruleRect.x(), ruleRect.y(), ruleRect.maxX(), ruleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2468 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2470 // We need to do multiple passes, breaking up our child painting into strips.
2471 GraphicsContext* context = paintInfo.context;
2472 ColumnInfo* colInfo = columnInfo();
2473 unsigned colCount = columnCount(colInfo);
2476 LayoutUnit currLogicalTopOffset = 0;
2477 for (unsigned i = 0; i < colCount; i++) {
2478 // For each rect, we clip to the rect, and then we adjust our coords.
2479 LayoutRect colRect = columnRectAt(colInfo, i);
2480 flipForWritingMode(colRect);
2481 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2482 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2483 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2484 if (isHorizontalWritingMode())
2485 offset.expand(0, colRect.y() - borderTop() - paddingTop());
2487 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2489 colRect.moveBy(paintOffset);
2490 PaintInfo info(paintInfo);
2491 info.rect.intersect(colRect);
2493 if (!info.rect.isEmpty()) {
2494 GraphicsContextStateSaver stateSaver(*context);
2496 // Each strip pushes a clip, since column boxes are specified as being
2497 // like overflow:hidden.
2498 context->clip(colRect);
2500 // Adjust our x and y when painting.
2501 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2503 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2505 paintContents(info, adjustedPaintOffset);
2508 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2509 if (style()->isFlippedBlocksWritingMode())
2510 currLogicalTopOffset += blockDelta;
2512 currLogicalTopOffset -= blockDelta;
2516 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2518 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2519 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2520 // will do a full repaint().
2521 if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
2524 // We don't want to hand off painting in the line box tree with the accumulated error of the render tree, as this will cause
2525 // us to mess up painting aligned things (such as underlines in text) with both the render tree and line box tree's error.
2526 LayoutPoint roundedPaintOffset = roundedIntPoint(paintOffset);
2527 if (childrenInline())
2528 m_lineBoxes.paint(this, paintInfo, roundedPaintOffset);
2530 paintChildren(paintInfo, roundedPaintOffset);
2533 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2535 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2536 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2538 // We don't paint our own background, but we do let the kids paint their backgrounds.
2539 PaintInfo info(paintInfo);
2540 info.phase = newPhase;
2541 info.updatePaintingRootForChildren(this);
2543 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2544 // NSViews. Do not add any more code for this.
2545 RenderView* renderView = view();
2546 bool usePrintRect = !renderView->printRect().isEmpty();
2548 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2549 // Check for page-break-before: always, and if it's set, break and bail.
2550 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2551 LayoutUnit absoluteChildY = paintOffset.y() + child->y();
2552 if (checkBeforeAlways
2553 && absoluteChildY > paintInfo.rect.y()
2554 && absoluteChildY < paintInfo.rect.maxY()) {
2555 view()->setBestTruncatedAt(absoluteChildY, this, true);
2559 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2560 // Paginate block-level replaced elements.
2561 if (absoluteChildY + child->height() > renderView->printRect().maxY()) {
2562 if (absoluteChildY < renderView->truncatedAt())
2563 renderView->setBestTruncatedAt(absoluteChildY, child);
2564 // If we were able to truncate, don't paint.
2565 if (absoluteChildY >= renderView->truncatedAt())
2570 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2571 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2572 child->paint(info, childPoint);
2574 // Check for page-break-after: always, and if it's set, break and bail.
2575 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2576 if (checkAfterAlways
2577 && (absoluteChildY + child->height()) > paintInfo.rect.y()
2578 && (absoluteChildY + child->height()) < paintInfo.rect.maxY()) {
2579 view()->setBestTruncatedAt(absoluteChildY + child->height() + max<LayoutUnit>(0, child->collapsedMarginAfter()), this, true);
2585 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2587 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2588 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2589 RenderObject* caretPainter;
2590 bool isContentEditable;
2591 if (type == CursorCaret) {
2592 caretPainter = frame()->selection()->caretRenderer();
2593 isContentEditable = frame()->selection()->isContentEditable();
2595 caretPainter = frame()->page()->dragCaretController()->caretRenderer();
2596 isContentEditable = frame()->page()->dragCaretController()->isContentEditable();
2599 if (caretPainter == this && (isContentEditable || caretBrowsing)) {
2600 if (type == CursorCaret)
2601 frame()->selection()->paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2603 frame()->page()->dragCaretController()->paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
2607 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2609 PaintPhase paintPhase = paintInfo.phase;
2611 // 1. paint background, borders etc
2612 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2613 if (hasBoxDecorations())
2614 paintBoxDecorations(paintInfo, paintOffset);
2616 paintColumnRules(paintInfo, paintOffset);
2619 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2620 paintMask(paintInfo, paintOffset);
2624 // We're done. We don't bother painting any children.
2625 if (paintPhase == PaintPhaseBlockBackground)
2628 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2629 LayoutPoint scrolledOffset = paintOffset;
2630 if (hasOverflowClip())
2631 scrolledOffset.move(-layer()->scrolledContentOffset());
2633 // 2. paint contents
2634 if (paintPhase != PaintPhaseSelfOutline) {
2636 paintColumnContents(paintInfo, scrolledOffset);
2638 paintContents(paintInfo, scrolledOffset);
2641 // 3. paint selection
2642 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2643 bool isPrinting = document()->printing();
2644 if (!isPrinting && !hasColumns())
2645 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2648 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2650 paintColumnContents(paintInfo, scrolledOffset, true);
2652 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2655 // 5. paint outline.
2656 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2657 paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
2659 // 6. paint continuation outlines.
2660 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2661 RenderInline* inlineCont = inlineElementContinuation();
2662 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2663 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2664 RenderBlock* cb = containingBlock();
2666 bool inlineEnclosedInSelfPaintingLayer = false;
2667 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2668 if (box->hasSelfPaintingLayer()) {
2669 inlineEnclosedInSelfPaintingLayer = true;
2674 if (!inlineEnclosedInSelfPaintingLayer)
2675 cb->addContinuationWithOutline(inlineRenderer);
2676 else if (!inlineRenderer->firstLineBox())
2677 inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2679 paintContinuationOutlines(paintInfo, paintOffset);
2683 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2684 // then paint the caret.
2685 if (paintPhase == PaintPhaseForeground) {
2686 paintCaret(paintInfo, paintOffset, CursorCaret);
2687 paintCaret(paintInfo, paintOffset, DragCaret);
2691 LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2693 if (!style()->isFlippedBlocksWritingMode())
2696 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2697 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2699 if (isHorizontalWritingMode())
2700 return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
2701 return LayoutPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2704 void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2706 if (!m_floatingObjects)
2709 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2710 FloatingObjectSetIterator end = floatingObjectSet.end();
2711 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2712 FloatingObject* r = *it;
2713 // Only paint the object if our m_shouldPaint flag is set.
2714 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
2715 PaintInfo currentPaintInfo(paintInfo);
2716 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2717 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
2718 r->m_renderer->paint(currentPaintInfo, childPoint);
2719 if (!preservePhase) {
2720 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2721 r->m_renderer->paint(currentPaintInfo, childPoint);
2722 currentPaintInfo.phase = PaintPhaseFloat;
2723 r->m_renderer->paint(currentPaintInfo, childPoint);
2724 currentPaintInfo.phase = PaintPhaseForeground;
2725 r->m_renderer->paint(currentPaintInfo, childPoint);
2726 currentPaintInfo.phase = PaintPhaseOutline;
2727 r->m_renderer->paint(currentPaintInfo, childPoint);
2733 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2735 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox())
2738 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
2739 // We can check the first box and last box and avoid painting if we don't
2741 LayoutUnit yPos = paintOffset.y() + firstLineBox()->y();
2742 LayoutUnit h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y();
2743 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y())
2746 // See if our boxes intersect with the dirty rect. If so, then we paint
2747 // them. Note that boxes can easily overlap, so we can't make any assumptions
2748 // based off positions of our first line box or our last line box.
2749 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2750 yPos = paintOffset.y() + curr->y();
2751 h = curr->logicalHeight();
2752 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y())
2753 curr->paintEllipsisBox(paintInfo, paintOffset, curr->lineTop(), curr->lineBottom());
2758 RenderInline* RenderBlock::inlineElementContinuation() const
2760 RenderBoxModelObject* continuation = this->continuation();
2761 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2764 RenderBlock* RenderBlock::blockElementContinuation() const
2766 RenderBoxModelObject* currentContinuation = continuation();
2767 if (!currentContinuation || currentContinuation->isInline())
2769 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2770 if (nextContinuation->isAnonymousBlock())
2771 return nextContinuation->blockElementContinuation();
2772 return nextContinuation;
2775 static ContinuationOutlineTableMap* continuationOutlineTable()
2777 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2781 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2783 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2785 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2787 ContinuationOutlineTableMap* table = continuationOutlineTable();
2788 ListHashSet<RenderInline*>* continuations = table->get(this);
2789 if (!continuations) {
2790 continuations = new ListHashSet<RenderInline*>;
2791 table->set(this, continuations);
2794 continuations->add(flow);
2797 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2799 ContinuationOutlineTableMap* table = continuationOutlineTable();
2800 if (table->isEmpty())
2803 ListHashSet<RenderInline*>* continuations = table->get(this);
2807 return continuations->contains(flow);
2810 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2812 ContinuationOutlineTableMap* table = continuationOutlineTable();
2813 if (table->isEmpty())
2816 ListHashSet<RenderInline*>* continuations = table->get(this);
2820 LayoutPoint accumulatedPaintOffset = paintOffset;
2821 // Paint each continuation outline.
2822 ListHashSet<RenderInline*>::iterator end = continuations->end();
2823 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2824 // Need to add in the coordinates of the intervening blocks.
2825 RenderInline* flow = *it;
2826 RenderBlock* block = flow->containingBlock();
2827 for ( ; block && block != this; block = block->containingBlock())
2828 accumulatedPaintOffset.moveBy(block->location());
2830 flow->paintOutline(info.context, accumulatedPaintOffset);
2834 delete continuations;
2835 table->remove(this);
2838 bool RenderBlock::shouldPaintSelectionGaps() const
2840 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2843 bool RenderBlock::isSelectionRoot() const
2848 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2852 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
2853 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
2854 hasReflection() || hasMask() || isWritingModeRoot())
2857 if (view() && view()->selectionStart()) {
2858 Node* startElement = view()->selectionStart()->node();
2859 if (startElement && startElement->rootEditableElement() == node())
2866 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
2868 ASSERT(!needsLayout());
2870 if (!shouldPaintSelectionGaps())
2873 // FIXME: this is broken with transforms
2874 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2875 mapLocalToContainer(repaintContainer, false, false, transformState);
2876 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
2878 if (hasOverflowClip())
2879 offsetFromRepaintContainer -= layer()->scrolledContentOffset();
2881 LayoutUnit lastTop = 0;
2882 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2883 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2885 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2888 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2890 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2891 LayoutUnit lastTop = 0;
2892 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2893 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2894 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2896 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
2897 if (!gapRectsBounds.isEmpty()) {
2898 if (RenderLayer* layer = enclosingLayer()) {
2899 gapRectsBounds.moveBy(-paintOffset);
2901 LayoutRect localBounds(gapRectsBounds);
2902 flipForWritingMode(localBounds);
2903 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2904 gapRectsBounds.move(layer->scrolledContentOffset());
2906 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2912 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects)
2914 if (!positionedObjects)
2917 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
2918 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2920 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2924 static int blockDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
2926 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
2929 static int inlineDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
2931 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
2934 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
2937 if (isHorizontalWritingMode())
2938 result = logicalRect;
2940 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2941 flipForWritingMode(result);
2942 result.moveBy(rootBlockPhysicalPosition);
2946 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2947 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2949 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2950 // Clip out floating and positioned objects when painting selection gaps.
2952 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2953 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2954 rootBlock->flipForWritingMode(flippedBlockRect);
2955 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
2956 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get());
2957 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2958 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2959 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes.
2960 if (m_floatingObjects) {
2961 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2962 FloatingObjectSetIterator end = floatingObjectSet.end();
2963 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2964 FloatingObject* r = *it;
2965 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
2966 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
2967 r->m_renderer->width(), r->m_renderer->height());
2968 rootBlock->flipForWritingMode(floatBox);
2969 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2970 paintInfo->context->clipOut(floatBox);
2975 // 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
2978 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
2981 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2982 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2983 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2984 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2985 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2989 if (childrenInline())
2990 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2992 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2994 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2995 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2996 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2997 logicalHeight(), paintInfo));
3001 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3002 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3006 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3008 if (!firstLineBox()) {
3009 if (containsStart) {
3010 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
3012 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3013 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3014 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3019 RootInlineBox* lastSelectedLine = 0;
3020 RootInlineBox* curr;
3021 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3023 // Now paint the gaps for the lines.
3024 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3025 LayoutUnit selTop = curr->selectionTop();
3026 LayoutUnit selHeight = curr->selectionHeight();
3028 if (!containsStart && !lastSelectedLine &&
3029 selectionState() != SelectionStart && selectionState() != SelectionBoth)
3030 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3031 selTop, paintInfo));
3033 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3034 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
3035 LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3036 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3037 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3038 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
3040 lastSelectedLine = curr;
3043 if (containsStart && !lastSelectedLine)
3044 // VisibleSelection must start just after our last line.
3045 lastSelectedLine = lastRootBox();
3047 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3048 // Go ahead and update our lastY to be the bottom of the last selected line.
3049 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3050 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3051 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3056 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3057 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3061 // Go ahead and jump right to the first block child that contains some selected objects.
3063 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
3065 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
3066 SelectionState childState = curr->selectionState();
3067 if (childState == SelectionBoth || childState == SelectionEnd)
3068 sawSelectionEnd = true;
3070 if (curr->isFloatingOrPositioned())
3071 continue; // We must be a normal flow object in order to even be considered.
3073 if (curr->isRelPositioned() && curr->hasLayer()) {
3074 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
3075 // Just disregard it completely.
3076 LayoutSize relOffset = curr->layer()->relativePositionOffset();
3077 if (relOffset.width() || relOffset.height())
3081 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
3082 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
3083 if (fillBlockGaps) {
3084 // We need to fill the vertical gap above this object.
3085 if (childState == SelectionEnd || childState == SelectionInside)
3086 // Fill the gap above the object.
3087 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3088 curr->logicalTop(), paintInfo));
3090 // 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*
3091 // our object. We know this if the selection did not end inside our object.
3092 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
3093 childState = SelectionNone;
3095 // Fill side gaps on this object based off its state.
3096 bool leftGap, rightGap;
3097 getSelectionGapInfo(childState, leftGap, rightGap);
3100 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3102 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3104 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
3105 // they can without bumping into floating or positioned objects. Ideally they will go right up
3106 // to the border of the root selection block.
3107 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
3108 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
3109 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
3110 } else if (childState != SelectionNone)
3111 // We must be a block that has some selected object inside it. Go ahead and recur.
3112 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
3113 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
3118 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3119 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
3121 LayoutUnit logicalTop = lastLogicalTop;
3122 LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
3123 if (logicalHeight <= static_cast<LayoutUnit>(0))
3124 return LayoutRect();
3126 // Get the selection offsets for the bottom of the gap
3127 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
3128 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
3129 LayoutUnit logicalWidth = logicalRight - logicalLeft;
3130 if (logicalWidth <= static_cast<LayoutUnit>(0))
3131 return LayoutRect();
3133 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
3135 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace());
3139 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3140 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3142 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3143 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
3144 LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalLeft, min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3145 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3146 if (rootBlockLogicalWidth <= static_cast<LayoutUnit>(0))
3147 return LayoutRect();
3149 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3151 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3155 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3156 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3158 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3159 LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalRight, max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3160 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
3161 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3162 if (rootBlockLogicalWidth <= static_cast<LayoutUnit>(0))
3163 return LayoutRect();
3165 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3167 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3171 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3173 bool ltr = style()->isLeftToRightDirection();
3174 leftGap = (state == RenderObject::SelectionInside) ||
3175 (state == RenderObject::SelectionEnd && ltr) ||
3176 (state == RenderObject::SelectionStart && !ltr);
3177 rightGap = (state == RenderObject::SelectionInside) ||
3178 (state == RenderObject::SelectionStart && ltr) ||
3179 (state == RenderObject::SelectionEnd && !ltr);
3182 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3184 LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
3185 if (logicalLeft == logicalLeftOffsetForContent()) {
3186 if (rootBlock != this)
3187 // The border can potentially be further extended by our containingBlock().
3188 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3191 RenderBlock* cb = this;
3192 while (cb != rootBlock) {
3193 logicalLeft += cb->logicalLeft();
3194 cb = cb->containingBlock();
3200 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3202 LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
3203 if (logicalRight == logicalRightOffsetForContent()) {
3204 if (rootBlock != this)
3205 // The border can potentially be further extended by our containingBlock().
3206 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
3207 return logicalRight;
3209 RenderBlock* cb = this;
3210 while (cb != rootBlock) {
3211 logicalRight += cb->logicalLeft();
3212 cb = cb->containingBlock();
3215 return logicalRight;
3218 void RenderBlock::insertPositionedObject(RenderBox* o)
3220 if (o->isRenderFlowThread())
3223 // Create the list of special objects if we don't aleady have one
3224 if (!m_positionedObjects)
3225 m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet);
3227 m_positionedObjects->add(o);
3230 void RenderBlock::removePositionedObject(RenderBox* o)
3232 if (m_positionedObjects)
3233 m_positionedObjects->remove(o);
3236 void RenderBlock::removePositionedObjects(RenderBlock* o)
3238 if (!m_positionedObjects)
3243 Iterator end = m_positionedObjects->end();
3245 Vector<RenderBox*, 16> deadObjects;
3247 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
3249 if (!o || r->isDescendantOf(o)) {
3251 r->setChildNeedsLayout(true, false);
3253 // It is parent blocks job to add positioned child to positioned objects list of its containing block
3254 // Parent layout needs to be invalidated to ensure this happens.
3255 RenderObject* p = r->parent();
3256 while (p && !p->isRenderBlock())
3259 p->setChildNeedsLayout(true);
3261 deadObjects.append(r);
3265 for (unsigned i = 0; i < deadObjects.size(); i++)
3266 m_positionedObjects->remove(deadObjects.at(i));
3269 RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3271 ASSERT(o->isFloating());
3273 // Create the list of special objects if we don't aleady have one
3274 if (!m_floatingObjects)
3275 m_floatingObjects = adoptPtr(new FloatingObjects(isHorizontalWritingMode()));
3277 // Don't insert the object again if it's already in the list
3278 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3279 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3280 if (it != floatingObjectSet.end())
3284 // Create the special object entry & append it to the list
3286 FloatingObject* newObj = new FloatingObject(o->style()->floating());
3288 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
3289 // Just go ahead and lay out the float.
3290 if (!o->isPositioned()) {
3291 bool isChildRenderBlock = o->isRenderBlock();
3292 if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged())
3293 o->setChildNeedsLayout(true, false);
3295 bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageLogicalHeight;
3296 if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
3297 o->layoutIfNeeded();
3299 o->computeLogicalWidth();
3300 o->computeBlockDirectionMargins(this);
3303 setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
3305 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will.
3306 newObj->m_isDescendant = true;
3307 newObj->m_renderer = o;
3309 m_floatingObjects->add(newObj);
3314 void RenderBlock::removeFloatingObject(RenderBox* o)
3316 if (m_floatingObjects) {
3317 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3318 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3319 if (it != floatingObjectSet.end()) {
3320 FloatingObject* r = *it;
3321 if (childrenInline()) {
3322 LayoutUnit logicalTop = logicalTopForFloat(r);
3323 LayoutUnit logicalBottom = logicalBottomForFloat(r);
3325 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
3326 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == numeric_limits<LayoutUnit>::max())
3327 logicalBottom = numeric_limits<LayoutUnit>::max();
3329 // Special-case zero- and less-than-zero-height floats: those don't touch
3330 // the line that they're on, but it still needs to be dirtied. This is
3331 // accomplished by pretending they have a height of 1.
3332 logicalBottom = max(logicalBottom, logicalTop + 1);
3334 if (r->m_originatingLine) {
3335 if (!selfNeedsLayout()) {
3336 ASSERT(r->m_originatingLine->renderer() == this);
3337 r->m_originatingLine->markDirty();
3339 #if !ASSERT_DISABLED
3340 r->m_originatingLine = 0;
3343 markLinesDirtyInBlockRange(0, logicalBottom);
3345 m_floatingObjects->remove(r);
3346 ASSERT(!r->m_originatingLine);
3352 void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
3354 if (!m_floatingObjects)
3357 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3358 FloatingObject* curr = floatingObjectSet.last();
3359 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
3360 m_floatingObjects->remove(curr);
3361 ASSERT(!curr->m_originatingLine);
3363 if (floatingObjectSet.isEmpty())
3365 curr = floatingObjectSet.last();
3369 LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
3371 RenderBox* childBox = floatingObject->renderer();
3372 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3373 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3374 LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
3376 LayoutUnit floatLogicalLeft;
3378 if (childBox->style()->floating() == LeftFloat) {
3379 LayoutUnit heightRemainingLeft = 1;
3380 LayoutUnit heightRemainingRight = 1;
3381 floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3382 while (logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
3383 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3384 floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3385 if (inRenderFlowThread()) {
3386 // Have to re-evaluate all of our offsets, since they may have changed.
3387 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3388 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3389 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
3392 floatLogicalLeft = max<LayoutUnit>(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
3394 LayoutUnit heightRemainingLeft = 1;
3395 LayoutUnit heightRemainingRight = 1;
3396 floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3397 while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
3398 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3399 floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3400 if (inRenderFlowThread()) {
3401 // Have to re-evaluate all of our offsets, since they may have changed.
3402 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3403 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3404 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
3407 floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable
3408 // |floatLogicalWidth| was capped to the available line width.
3409 // See fast/block/float/clamped-right-float.html.
3412 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
3415 bool RenderBlock::positionNewFloats()
3417 if (!m_floatingObjects)
3420 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3421 if (floatingObjectSet.isEmpty())
3424 // If all floats have already been positioned, then we have no work to do.
3425 if (floatingObjectSet.last()->isPlaced())
3428 // Move backwards through our floating object list until we find a float that has
3429 // already been positioned. Then we'll be able to move forward, positioning all of
3430 // the new floats that need it.
3431 FloatingObjectSetIterator it = floatingObjectSet.end();
3432 --it; // Go to last item.
3433 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3434 FloatingObject* lastPlacedFloatingObject = 0;
3435 while (it != begin) {
3437 if ((*it)->isPlaced()) {
3438 lastPlacedFloatingObject = *it;
3444 LayoutUnit logicalTop = logicalHeight();
3446 // The float cannot start above the top position of the last positioned float.
3447 if (lastPlacedFloatingObject)
3448 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
3450 FloatingObjectSetIterator end = floatingObjectSet.end();
3451 // Now walk through the set of unpositioned floats and place them.
3452 for (; it != end; ++it) {
3453 FloatingObject* floatingObject = *it;
3454 // The containing block is responsible for positioning floats, so if we have floats in our
3455 // list that come from somewhere else, do not attempt to position them. Also don't attempt to handle
3456 // positioned floats, since the positioning layout code handles those.
3457 if (floatingObject->renderer()->containingBlock() != this || floatingObject->renderer()->isPositioned())
3460 RenderBox* childBox = floatingObject->renderer();
3461 LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
3463 LayoutRect oldRect(childBox->x(), childBox->y() , childBox->width(), childBox->height());
3465 if (childBox->style()->clear() & CLEFT)
3466 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
3467 if (childBox->style()->clear() & CRIGHT)
3468 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
3470 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
3472 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
3473 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3474 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3476 if (view()->layoutState()->isPaginated()) {
3477 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
3479 if (!childBox->needsLayout())
3480 childBox->markForPaginationRelayoutIfNeeded();
3481 childBox->layoutIfNeeded();
3483 // If we are unsplittable and don't fit, then we need to move down.
3484 // We include our margins as part of the unsplittable area.
3485 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
3487 // See if we have a pagination strut that is making us move down further.
3488 // Note that an unsplittable child can't also have a pagination strut, so this is
3489 // exclusive with the case above.
3490 if (childBlock && childBlock->paginationStrut()) {
3491 newLogicalTop += childBlock->paginationStrut();
3492 childBlock->setPaginationStrut(0);
3495 if (newLogicalTop != floatLogicalLocation.y()) {
3496 floatingObject->m_paginationStrut = newLogicalTop - floatLogicalLocation.y();
3498 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
3499 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
3500 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3501 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3504 childBlock->setChildNeedsLayout(true, false);
3505 childBox->layoutIfNeeded();
3509 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
3510 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
3512 m_floatingObjects->addPlacedObject(floatingObject);
3514 // If the child moved, we have to repaint it.
3515 if (childBox->checkForRepaintDuringLayout())
3516 childBox->repaintDuringLayoutIfMoved(oldRect);
3521 void RenderBlock::newLine(EClear clear)
3523 positionNewFloats();
3529 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
3532 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
3535 newY = lowestFloatLogicalBottom();
3539 if (height() < newY)
3540 setLogicalHeight(newY);
3543 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
3545 if (!gPercentHeightDescendantsMap) {
3546 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
3547 gPercentHeightContainerMap = new PercentHeightContainerMap;
3550 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
3551 if (!descendantSet) {
3552 descendantSet = new HashSet<RenderBox*>;
3553 gPercentHeightDescendantsMap->set(this, descendantSet);
3555 bool added = descendantSet->add(descendant).second;
3557 ASSERT(gPercentHeightContainerMap->get(descendant));
3558 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
3562 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
3563 if (!containerSet) {
3564 containerSet = new HashSet<RenderBlock*>;
3565 gPercentHeightContainerMap->set(descendant, containerSet);
3567 ASSERT(!containerSet->contains(this));
3568 containerSet->add(this);
3571 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
3573 if (!gPercentHeightContainerMap)
3576 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
3580 HashSet<RenderBlock*>::iterator end = containerSet->end();
3581 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
3582 RenderBlock* container = *it;
3583 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
3584 ASSERT(descendantSet);
3587 ASSERT(descendantSet->contains(descendant));
3588 descendantSet->remove(descendant);
3589 if (descendantSet->isEmpty()) {
3590 gPercentHeightDescendantsMap->remove(container);
3591 delete descendantSet;
3595 delete containerSet;
3598 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
3600 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
3603 #if !ASSERT_DISABLED
3604 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
3607 if (!gPercentHeightContainerMap)
3609 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
3610 return containerSet && containerSet->size();
3614 template <RenderBlock::FloatingObject::Type FloatTypeValue>
3615 inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval) const
3617 const FloatingObject* r = interval.data();
3618 if (r->type() == FloatTypeValue && interval.low() <= m_value && m_value < interval.high()) {
3619 // All the objects returned from the tree should be already placed.
3620 ASSERT(r->isPlaced() && m_renderer->logicalTopForFloat(r) <= m_value && m_renderer->logicalBottomForFloat(r) > m_value);
3622 if (FloatTypeValue == FloatingObject::FloatLeft
3623 && m_renderer->logicalRightForFloat(r) > m_offset) {
3624 m_offset = m_renderer->logicalRightForFloat(r);
3625 if (m_heightRemaining)
3626 *m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_value;
3629 if (FloatTypeValue == FloatingObject::FloatRight
3630 && m_renderer->logicalLeftForFloat(r) < m_offset) {
3631 m_offset = m_renderer->logicalLeftForFloat(r);
3632 if (m_heightRemaining)
3633 *m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_value;
3638 LayoutUnit RenderBlock::textIndentOffset() const
3641 if (style()->textIndent().isPercent())
3642 cw = containingBlock()->availableLogicalWidth();
3643 return style()->textIndent().calcMinValue(cw);
3646 LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
3648 LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
3649 if (!inRenderFlowThread())
3650 return logicalLeftOffset;
3651 LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
3652 return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
3655 LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
3657 LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
3658 logicalRightOffset += availableLogicalWidth();
3659 if (!inRenderFlowThread())
3660 return logicalRightOffset;
3661 LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
3662 return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
3665 LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
3667 LayoutUnit left = fixedOffset;
3668 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
3669 if (heightRemaining)
3670 *heightRemaining = 1;
3672 FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, logicalTop, left, heightRemaining);
3673 m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
3676 if (applyTextIndent && style()->isLeftToRightDirection())
3677 left += textIndentOffset();
3682 LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
3684 LayoutUnit right = fixedOffset;
3685 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
3686 if (heightRemaining)
3687 *heightRemaining = 1;
3689 LayoutUnit rightFloatOffset = fixedOffset;
3690 FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, logicalTop, rightFloatOffset, heightRemaining);
3691 m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
3692 right = min(right, rightFloatOffset);
3695 if (applyTextIndent && !style()->isLeftToRightDirection())
3696 right -= textIndentOffset();
3701 LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
3703 if (!m_floatingObjects)
3704 return logicalHeight;
3706 LayoutUnit bottom = numeric_limits<LayoutUnit>::max();
3707 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3708 FloatingObjectSetIterator end = floatingObjectSet.end();
3709 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3710 FloatingObject* r = *it;
3711 LayoutUnit floatBottom = logicalBottomForFloat(r);
3712 if (floatBottom > logicalHeight)
3713 bottom = min(floatBottom, bottom);
3716 return bottom == numeric_limits<LayoutUnit>::max() ? 0 : bottom;
3719 LayoutUnit RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
3721 if (!m_floatingObjects)
3723 LayoutUnit lowestFloatBottom = 0;
3724 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3725 FloatingObjectSetIterator end = floatingObjectSet.end();
3726 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3727 FloatingObject* r = *it;
3728 if (r->isPlaced() && r->type() & floatType)
3729 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r));
3731 return lowestFloatBottom;
3734 void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3736 if (logicalTop >= logicalBottom)
3739 RootInlineBox* lowestDirtyLine = lastRootBox();
3740 RootInlineBox* afterLowest = lowestDirtyLine;
3741 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < numeric_limits<LayoutUnit>::max()) {
3742 afterLowest = lowestDirtyLine;
3743 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3746 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3747 afterLowest->markDirty();
3748 afterLowest = afterLowest->prevRootBox();
3752 void RenderBlock::addPositionedFloats()
3754 if (!m_positionedObjects)
3757 Iterator end = m_positionedObjects->end();
3758 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
3759 RenderBox* positionedObject = *it;
3760 if (!positionedObject->isFloating())
3763 ASSERT(!positionedObject->needsLayout());
3765 // If we're a positioned float, then we need to insert ourselves as a floating object also. We only do
3766 // this after the positioned object has received a layout, since otherwise the dimensions and placement
3767 // won't be correct.
3768 FloatingObject* floatingObject = insertFloatingObject(positionedObject);
3769 setLogicalLeftForFloat(floatingObject, logicalLeftForChild(positionedObject) - marginLogicalLeftForChild(positionedObject));
3770 setLogicalTopForFloat(floatingObject, logicalTopForChild(positionedObject) - marginBeforeForChild(positionedObject));
3771 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(positionedObject) + marginBeforeForChild(positionedObject) + marginAfterForChild(positionedObject));
3773 m_floatingObjects->addPlacedObject(floatingObject);
3775 m_hasPositionedFloats = true;
3779 void RenderBlock::clearFloats(BlockLayoutPass layoutPass)
3781 if (m_floatingObjects)
3782 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
3784 // Clear our positioned floats boolean.
3785 m_hasPositionedFloats = false;
3787 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
3788 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) {
3789 if (m_floatingObjects) {
3790 deleteAllValues(m_floatingObjects->set());
3791 m_floatingObjects->clear();
3793 if (layoutPass == PositionedFloatLayoutPass)
3794 addPositionedFloats();
3798 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
3799 RendererToFloatInfoMap floatMap;
3801 if (m_floatingObjects) {
3802 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3803 if (childrenInline()) {
3804 FloatingObjectSetIterator end = floatingObjectSet.end();
3805 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3806 FloatingObject* f = *it;
3807 floatMap.add(f->m_renderer, f);
3810 deleteAllValues(floatingObjectSet);
3811 m_floatingObjects->clear();
3814 if (layoutPass == PositionedFloatLayoutPass)
3815 addPositionedFloats();
3817 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
3818 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
3819 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
3820 if (!parent() || !parent()->isRenderBlock())
3823 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
3824 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
3826 RenderBlock* parentBlock = toRenderBlock(parent());
3827 bool parentHasFloats = parentBlock->hasPositionedFloats();
3828 RenderObject* prev = previousSibling();
3829 while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
3830 if (prev->isFloating())
3831 parentHasFloats = true;
3832 prev = prev->previousSibling();
3835 // First add in floats from the parent.
3836 LayoutUnit logicalTopOffset = logicalTop();
3837 if (parentHasFloats)
3838 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
3840 LayoutUnit logicalLeftOffset = 0;
3842 logicalTopOffset -= toRenderBox(prev)->logicalTop();
3843 else if (!parentHasFloats) {
3845 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
3848 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
3849 RenderBlock* block = toRenderBlock(prev);
3850 if (block && block->m_floatingObjects && block->lowestFloatLogicalBottomIncludingPositionedFloats() > logicalTopOffset)
3851 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
3853 if (childrenInline()) {
3854 LayoutUnit changeLogicalTop = numeric_limits<LayoutUnit>::max();
3855 LayoutUnit changeLogicalBottom = numeric_limits<LayoutUnit>::min();
3856 if (m_floatingObjects) {
3857 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3858 FloatingObjectSetIterator end = floatingObjectSet.end();
3859 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3860 FloatingObject* f = *it;
3861 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
3862 LayoutUnit logicalBottom = logicalBottomForFloat(f);
3863 if (oldFloatingObject) {
3864 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject);
3865 if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) {
3866 changeLogicalTop = 0;
3867 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
3868 } else if (logicalBottom != oldLogicalBottom) {
3869 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
3870 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
3873 floatMap.remove(f->m_renderer);
3874 if (oldFloatingObject->m_originatingLine && !selfNeedsLayout()) {
3875 ASSERT(oldFloatingObject->m_originatingLine->renderer() == this);
3876 oldFloatingObject->m_originatingLine->markDirty();
3878 delete oldFloatingObject;
3880 changeLogicalTop = 0;
3881 changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
3886 RendererToFloatInfoMap::iterator end = floatMap.end();
3887 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
3888 FloatingObject* floatingObject = (*it).second;
3889 if (!floatingObject->m_isDescendant) {
3890 changeLogicalTop = 0;
3891 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
3894 deleteAllValues(floatMap);
3896 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
3900 LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildPaintOtherFloats)
3902 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
3903 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
3906 LayoutUnit childLogicalTop = child->logicalTop();
3907 LayoutUnit childLogicalLeft = child->logicalLeft();
3908 LayoutUnit lowestFloatLogicalBottom = 0;
3910 // Floats that will remain the child's responsibility to paint should factor into its
3912 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end();
3913 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
3914 FloatingObject* r = *childIt;
3915 LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(r), numeric_limits<LayoutUnit>::max() - childLogicalTop);
3916 LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat;
3917 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
3919 if (logicalBottom > logicalHeight()) {
3920 // If the object is not in the list, we add it now.
3921 if (!containsFloat(r->m_renderer)) {
3922 LayoutUnit leftOffset = isHorizontalWritingMode() ? -childLogicalLeft : -childLogicalTop;
3923 LayoutUnit topOffset = isHorizontalWritingMode() ? -childLogicalTop : -childLogicalLeft;
3924 FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
3925 floatingObj->m_renderer = r->m_renderer;
3927 // The nearest enclosing layer always paints the float (so that zindex and stacking
3928 // behaves properly). We always want to propagate the desire to paint the float as
3929 // far out as we can, to the outermost block that overlaps the float, stopping only
3930 // if we hit a self-painting layer boundary.
3931 if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer())
3932 r->m_shouldPaint = false;
3934 floatingObj->m_shouldPaint = false;
3936 floatingObj->m_isDescendant = true;
3938 // We create the floating object list lazily.
3939 if (!m_floatingObjects)
3940 m_floatingObjects = adoptPtr(new FloatingObjects(isHorizontalWritingMode()));
3942 m_floatingObjects->add(floatingObj);
3945 if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() &&
3946 r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) {
3947 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
3948 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
3950 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
3952 r->m_shouldPaint = true;
3955 // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the
3957 if (r->m_isDescendant)
3958 child->addOverflowFromChild(r->m_renderer, LayoutSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
3961 return lowestFloatLogicalBottom;
3964 bool RenderBlock::hasOverhangingFloat(RenderBox* renderer)
3966 if (!m_floatingObjects || hasColumns() || !parent())
3969 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3970 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(renderer);
3971 if (it == floatingObjectSet.end())
3974 return logicalBottomForFloat(*it) > logicalHeight();
3977 void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
3979 // If the parent or previous sibling doesn't have any floats to add, don't bother.
3980 if (!prev->m_floatingObjects)
3983 logicalLeftOffset += (isHorizontalWritingMode() ? marginLeft() : marginTop());
3985 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
3986 FloatingObjectSetIterator prevEnd = prevSet.end();
3987 for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
3988 FloatingObject* r = *prevIt;
3989 if (logicalBottomForFloat(r) > logicalTopOffset) {
3990 if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) {
3991 LayoutUnit leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
3992 LayoutUnit topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
3994 FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
3996 // Applying the child's margin makes no sense in the case where the child was passed in.
3997 // since this margin was added already through the modification of the |logicalLeftOffset| variable
3998 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
3999 // into account. Only apply this code if prev is the parent, since otherwise the left margin
4000 // will get applied twice.
4001 if (prev != parent()) {
4002 if (isHorizontalWritingMode())
4003 floatingObj->setX(floatingObj->x() + prev->marginLeft());
4005 floatingObj->setY(floatingObj->y() + prev->marginTop());
4008 floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it.
4009 floatingObj->m_renderer = r->m_renderer;
4011 // We create the floating object list lazily.
4012 if (!m_floatingObjects)
4013 m_floatingObjects = adoptPtr(new FloatingObjects(isHorizontalWritingMode()));
4014 m_floatingObjects->add(floatingObj);
4020 bool RenderBlock::avoidsFloats() const
4022 // Floats can't intrude into our box if we have a non-auto column count or width.
4023 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
4026 bool RenderBlock::containsFloat(RenderBox* renderer)
4028 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer);
4031 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
4033 if (!m_everHadLayout)
4036 setChildNeedsLayout(true, !inLayout);
4039 removeFloatingObject(floatToRemove);
4041 // Iterate over our children and mark them as needed.
4042 if (!childrenInline()) {
4043 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
4044 if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock())
4046 RenderBlock* childBlock = toRenderBlock(child);
4047 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats())
4048 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
4053 void RenderBlock::markSiblingsWithFloatsForLayout()
4055 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4056 FloatingObjectSetIterator end = floatingObjectSet.end();
4057 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4058 if (logicalBottomForFloat(*it) > logicalHeight()) {
4059 RenderBox* floatingBox = (*it)->renderer();
4061 RenderObject* next = nextSibling();
4063 if (next->isRenderBlock() && !next->isFloatingOrPositioned() && !toRenderBlock(next)->avoidsFloats()) {
4064 RenderBlock* nextBlock = toRenderBlock(next);
4065 if (nextBlock->containsFloat(floatingBox))
4066 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox);
4071 next = next->nextSibling();
4077 LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
4079 // There is no need to compute clearance if we have no floats.
4080 if (!containsFloats())
4083 // At least one float is present. We need to perform the clearance computation.
4084 bool clearSet = child->style()->clear() != CNONE;
4085 LayoutUnit logicalBottom = 0;
4086 switch (child->style()->clear()) {
4090 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
4093 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
4096 logicalBottom = lowestFloatLogicalBottom();
4100 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
4101 LayoutUnit result = clearSet ? max<LayoutUnit>(0, logicalBottom - logicalTop) : 0;
4102 if (!result && child->avoidsFloats()) {
4103 LayoutUnit newLogicalTop = logicalTop;
4105 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false);
4106 // FIXME: Change to use roughlyEquals when we move to float.
4107 // See https://bugs.webkit.org/show_bug.cgi?id=66148
4108 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
4109 return newLogicalTop - logicalTop;
4111 // FIXME: None of this is right for perpendicular writing-mode children.
4112 LayoutUnit childOldLogicalWidth = child->logicalWidth();
4113 LayoutUnit childOldMarginLeft = child->marginLeft();
4114 LayoutUnit childOldMarginRight = child->marginRight();
4115 LayoutUnit childOldLogicalTop = child->logicalTop();
4117 child->setLogicalTop(newLogicalTop);
4118 child->computeLogicalWidth();
4119 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
4120 LayoutRect borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
4121 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
4123 child->setLogicalTop(childOldLogicalTop);
4124 child->setLogicalWidth(childOldLogicalWidth);
4125 child->setMarginLeft(childOldMarginLeft);
4126 child->setMarginRight(childOldMarginRight);
4128 // FIXME: Change to use roughlyEquals when we move to float.
4129 // See https://bugs.webkit.org/show_bug.cgi?id=66148
4130 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset)
4131 return newLogicalTop - logicalTop;
4133 newLogicalTop = nextFloatLogicalBottomBelow(newLogicalTop);
4134 ASSERT(newLogicalTop >= logicalTop);
4135 if (newLogicalTop < logicalTop)
4138 ASSERT_NOT_REACHED();
4143 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
4145 if (!scrollsOverflow())
4148 return layer()->hitTestOverflowControls(result, pointInContainer - toLayoutSize(accumulatedOffset));
4151 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4153 LayoutPoint adjustedLocation(accumulatedOffset + location());
4154 LayoutSize localOffset = toLayoutSize(adjustedLocation);
4156 if (!isRenderView()) {
4157 // Check if we need to do anything at all.
4158 LayoutRect overflowBox = visualOverflowRect();
4159 flipForWritingMode(overflowBox);
4160 overflowBox.moveBy(adjustedLocation);
4161 if (!overflowBox.intersects(result.rectForPoint(pointInContainer)))
4165 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, pointInContainer, adjustedLocation)) {
4166 updateHitTestResult(result, pointInContainer - localOffset);
4167 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
4168 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer))
4172 // If we have clipping, then we can't have any spillout.
4173 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
4174 bool useClip = (hasControlClip() || useOverflowClip);
4175 LayoutRect hitTestArea(result.rectForPoint(pointInContainer));
4176 bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(adjustedLocation).intersects(hitTestArea) : overflowClipRect(adjustedLocation, result.region(), IncludeOverlayScrollbarSize).intersects(hitTestArea));
4177 if (checkChildren) {
4178 // Hit test descendants first.
4179 LayoutSize scrolledOffset(localOffset);
4180 if (hasOverflowClip()) {
4181 scrolledOffset -= layer()->scrolledContentOffset();
4184 // Hit test contents if we don't have columns.
4185 if (!hasColumns()) {
4186 if (hitTestContents(request, result, pointInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
4187 updateHitTestResult(result, pointInContainer - localOffset);
4190 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, toLayoutPoint(scrolledOffset)))
4192 } else if (hitTestColumns(request, result, pointInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
4193 updateHitTestResult(result, flipForWritingMode(pointInContainer - localOffset));
4198 // Now hit test our background
4199 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
4200 LayoutRect boundsRect(adjustedLocation, size());
4201 if (visibleToHitTesting() && boundsRect.intersects(result.rectForPoint(pointInContainer))) {
4202 updateHitTestResult(result, flipForWritingMode(pointInContainer - localOffset));
4203 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect))
4211 bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
4213 if (!m_floatingObjects)
4216 LayoutPoint adjustedLocation = accumulatedOffset;
4217 if (isRenderView()) {
4218 adjustedLocation += toLayoutSize(toRenderView(this)->frameView()->scrollPosition());
4221 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4222 FloatingObjectSetIterator begin = floatingObjectSet.begin();
4223 for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) {
4225 FloatingObject* floatingObject = *it;
4226 if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) {
4227 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x();
4228 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y();
4229 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
4230 if (floatingObject->m_renderer->hitTest(request, result, pointInContainer, childPoint)) {
4231 updateHitTestResult(result, pointInContainer - toLayoutSize(childPoint));
4240 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4242 // We need to do multiple passes, breaking up our hit testing into strips.
4243 ColumnInfo* colInfo = columnInfo();
4244 int colCount = columnCount(colInfo);
4247 LayoutUnit logicalLeft = logicalLeftOffsetForContent();
4248 LayoutUnit currLogicalTopOffset = !style()->isFlippedBlocksWritingMode() ? -colCount * colInfo->columnHeight() : colCount * colInfo->columnHeight();
4249 bool isHorizontal = isHorizontalWritingMode();
4251 for (int i = colCount - 1; i >= 0; i--) {
4252 LayoutRect colRect = columnRectAt(colInfo, i);
4253 flipForWritingMode(colRect);
4254 LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
4255 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
4256 if (style()->isFlippedBlocksWritingMode())
4257 currLogicalTopOffset -= blockDelta;
4259 currLogicalTopOffset += blockDelta;
4260 colRect.moveBy(accumulatedOffset);
4262 if (colRect.intersects(result.rectForPoint(pointInContainer))) {
4263 // The point is inside this column.
4264 // Adjust accumulatedOffset to change where we hit test.
4266 LayoutSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
4267 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
4269 offset.expand(0, colRect.y() - accumulatedOffset.y() - borderTop() - paddingTop());
4271 offset.expand(colRect.x() - accumulatedOffset.x() - borderLeft() - paddingLeft(), 0);
4274 LayoutPoint finalLocation = accumulatedOffset + offset;
4275 if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(pointInContainer)))
4276 hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction);
4278 return hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, finalLocation));
4285 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4287 if (childrenInline() && !isTable()) {
4288 // We have to hit-test our line boxes.
4289 if (m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction))
4292 // Hit test our children.
4293 HitTestAction childHitTest = hitTestAction;
4294 if (hitTestAction == HitTestChildBlockBackgrounds)
4295 childHitTest = HitTestChildBlockBackground;
4296 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
4297 LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
4298 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, pointInContainer, childPoint, childHitTest))
4306 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
4311 if (!box->renderer()->node())
4312 return createLegacyEditingPosition(node(), start ? caretMinOffset() : caretMaxOffset());
4314 if (!box->isInlineTextBox())
4315 return createLegacyEditingPosition(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
4317 InlineTextBox* textBox = toInlineTextBox(box);
4318 return createLegacyEditingPosition(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
4321 static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
4323 ASSERT(!ancestor || ancestor->node());
4324 ASSERT(child && child->node());
4325 return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
4326 || ancestor->node()->rendererIsEditable() == child->node()->rendererIsEditable();
4329 // FIXME: This function should go on RenderObject as an instance method. Then
4330 // all cases in which positionForPoint recurs could call this instead to
4331 // prevent crossing editable boundaries. This would require many tests.
4332 static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates)
4334 LayoutPoint childLocation = child->location();
4335 if (child->isRelPositioned())
4336 childLocation += child->relativePositionOffset();
4337 // FIXME: This is wrong if the child's writing-mode is different from the parent's.
4338 LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
4340 // If this is an anonymous renderer, we just recur normally
4341 Node* childNode = child->node();
4343 return child->positionForPoint(pointInChildCoordinates);
4345 // Otherwise, first make sure that the editability of the parent and child agree.
4346 // If they don't agree, then we return a visible position just before or after the child
4347 RenderObject* ancestor = parent;
4348 while (ancestor && !ancestor->node())
4349 ancestor = ancestor->parent();
4351 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
4352 if (isEditingBoundary(ancestor, child))
4353 return child->positionForPoint(pointInChildCoordinates);
4355 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
4356 LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2;
4357 LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
4358 if (logicalLeft < childMiddle)
4359 return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM);
4360 return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM);
4363 VisiblePosition RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
4365 ASSERT(childrenInline());
4367 if (!firstRootBox())
4368 return createVisiblePosition(0, DOWNSTREAM);
4370 // look for the closest line box in the root box which is at the passed-in y coordinate
4371 InlineBox* closestBox = 0;
4372 RootInlineBox* firstRootBoxWithChildren = 0;
4373 RootInlineBox* lastRootBoxWithChildren = 0;
4374 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
4375 if (!root->firstLeafChild())
4377 if (!firstRootBoxWithChildren)
4378 firstRootBoxWithChildren = root;
4379 lastRootBoxWithChildren = root;
4381 // check if this root line box is located at this y coordinate
4382 if (pointInLogicalContents.y() < root->selectionBottom()) {
4383 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
4389 bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
4391 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
4392 // y coordinate is below last root line box, pretend we hit it
4393 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
4397 if (moveCaretToBoundary && pointInLogicalContents.y() < firstRootBoxWithChildren->selectionTop()
4398 && pointInLogicalContents.y() < firstRootBoxWithChildren->logicalTop()) {
4399 // y coordinate is above first root line box, so return the start of the first
4400 return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM);
4403 // pass the box a top position that is inside it
4404 LayoutPoint point(pointInLogicalContents.x(), closestBox->logicalTop());
4405 if (!isHorizontalWritingMode())
4406 point = point.transposedPoint();
4407 if (closestBox->renderer()->isReplaced())
4408 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
4409 return closestBox->renderer()->positionForPoint(point);
4412 if (lastRootBoxWithChildren) {
4413 // We hit this case for Mac behavior when the Y coordinate is below the last box.
4414 ASSERT(moveCaretToBoundary);
4415 InlineBox* logicallyLastBox;
4416 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
4417 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
4420 // Can't reach this. We have a root line box, but it has no kids.
4421 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
4422 // seems to hit this code path.
4423 return createVisiblePosition(0, DOWNSTREAM);
4426 static inline bool isChildHitTestCandidate(RenderBox* box)
4428 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned();
4431 VisiblePosition RenderBlock::positionForPoint(const LayoutPoint& point)
4434 return RenderBox::positionForPoint(point);
4437 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
4438 LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
4439 LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
4441 if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0))
4442 return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
4443 if (pointLogicalTop >= logicalHeight() || (pointLogicalTop >= 0 && pointLogicalLeft >= logicalWidth()))
4444 return createVisiblePosition(caretMaxOffset(), DOWNSTREAM);
4447 LayoutPoint pointInContents = point;
4448 offsetForContents(pointInContents);
4449 LayoutPoint pointInLogicalContents(pointInContents);
4450 if (!isHorizontalWritingMode())
4451 pointInLogicalContents = pointInLogicalContents.transposedPoint();
4453 if (childrenInline())
4454 return positionForPointWithInlineChildren(pointInLogicalContents);
4456 RenderBox* lastCandidateBox = lastChildBox();
4457 while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
4458 lastCandidateBox = lastCandidateBox->previousSiblingBox();
4460 if (lastCandidateBox) {
4461 if (pointInContents.y() > lastCandidateBox->logicalTop())
4462 return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
4464 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
4465 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
4466 if (isChildHitTestCandidate(childBox) && pointInContents.y() < childBox->logicalBottom())
4467 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
4471 // We only get here if there are no hit test candidate children below the click.
4472 return RenderBox::positionForPoint(point);
4475 void RenderBlock::offsetForContents(LayoutPoint& offset) const
4477 if (hasOverflowClip())
4478 offset += layer()->scrolledContentOffset();
4481 adjustPointToColumnContents(offset);
4484 LayoutUnit RenderBlock::availableLogicalWidth() const
4486 // If we have multiple columns, then the available logical width is reduced to our column width.
4488 return desiredColumnWidth();
4489 return RenderBox::availableLogicalWidth();
4492 int RenderBlock::columnGap() const
4494 if (style()->hasNormalColumnGap())
4495 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
4496 return static_cast<int>(style()->columnGap());
4499 void RenderBlock::calcColumnWidth()
4501 // Calculate our column width and column count.
4502 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
4503 unsigned desiredColumnCount = 1;
4504 LayoutUnit desiredColumnWidth = contentLogicalWidth();
4506 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
4507 if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) {
4508 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
4512 LayoutUnit availWidth = desiredColumnWidth;
4513 LayoutUnit colGap = columnGap();
4514 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
4515 int colCount = max<int>(1, style()->columnCount());
4517 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
4518 desiredColumnCount = colCount;
4519 desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
4520 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
4521 desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
4522 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
4524 desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
4525 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
4527 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
4530 bool RenderBlock::requiresColumns(int desiredColumnCount) const
4533 && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis())
4534 && !firstChild()->isAnonymousColumnsBlock()
4535 && !firstChild()->isAnonymousColumnSpanBlock();
4538 void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
4540 bool destroyColumns = !requiresColumns(count);
4541 if (destroyColumns) {
4543 delete gColumnInfoMap->take(this);
4544 setHasColumns(false);
4549 info = gColumnInfoMap->get(this);
4551 if (!gColumnInfoMap)
4552 gColumnInfoMap = new ColumnInfoMap;
4553 info = new ColumnInfo;
4554 gColumnInfoMap->add(this, info);
4555 setHasColumns(true);
4557 info->setDesiredColumnCount(count);
4558 info->setDesiredColumnWidth(width);
4559 info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
4563 LayoutUnit RenderBlock::desiredColumnWidth() const
4566 return contentLogicalWidth();
4567 return gColumnInfoMap->get(this)->desiredColumnWidth();
4570 unsigned RenderBlock::desiredColumnCount() const
4574 return gColumnInfoMap->get(this)->desiredColumnCount();
4577 ColumnInfo* RenderBlock::columnInfo() const
4581 return gColumnInfoMap->get(this);
4584 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
4586 ASSERT(hasColumns());
4587 ASSERT(gColumnInfoMap->get(this) == colInfo);
4588 return colInfo->columnCount();
4591 LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
4593 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
4595 // Compute the appropriate rect based off our information.
4596 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
4597 LayoutUnit colLogicalHeight = colInfo->columnHeight();
4598 LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
4599 LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
4600 int colGap = columnGap();
4601 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
4602 if (style()->isLeftToRightDirection())
4603 colLogicalLeft += index * (colLogicalWidth + colGap);
4605 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
4607 colLogicalTop += index * (colLogicalHeight + colGap);
4609 if (isHorizontalWritingMode())
4610 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
4611 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
4614 bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer& statePusher)
4619 // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
4620 // the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
4621 ColumnInfo* colInfo = columnInfo();
4622 int desiredColumnCount = colInfo->desiredColumnCount();
4623 if (!hasSpecifiedPageLogicalHeight) {
4624 LayoutUnit columnHeight = pageLogicalHeight;
4625 int minColumnCount = colInfo->forcedBreaks() + 1;
4626 if (minColumnCount >= desiredColumnCount) {
4627 // The forced page breaks are in control of the balancing. Just set the column height to the
4628 // maximum page break distance.
4629 if (!pageLogicalHeight) {
4630 LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(),
4631 view()->layoutState()->pageLogicalOffset(borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset());
4632 columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
4634 } else if (contentLogicalHeight() > pageLogicalHeight * desiredColumnCount) {
4635 // Now that we know the intrinsic height of the columns, we have to rebalance them.
4636 columnHeight = max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf((float)contentLogicalHeight() / desiredColumnCount));
4639 if (columnHeight && columnHeight != pageLogicalHeight) {
4641 m_everHadLayout = true;
4642 layoutBlock(false, columnHeight);
4647 if (pageLogicalHeight)
4648 colInfo->setColumnCountAndHeight(ceilf((float)contentLogicalHeight() / pageLogicalHeight), pageLogicalHeight);
4650 if (columnCount(colInfo)) {
4651 setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
4658 void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
4660 // Just bail if we have no columns.
4664 ColumnInfo* colInfo = columnInfo();
4665 if (!columnCount(colInfo))
4668 // Determine which columns we intersect.
4669 LayoutUnit colGap = columnGap();
4670 LayoutUnit halfColGap = colGap / 2;
4671 LayoutPoint columnPoint(columnRectAt(colInfo, 0).location());
4672 LayoutUnit logicalOffset = 0;
4673 for (unsigned i = 0; i < colInfo->columnCount(); i++) {
4674 // Add in half the column gap to the left and right of the rect.
4675 LayoutRect colRect = columnRectAt(colInfo, i);
4676 flipForWritingMode(colRect);
4677 if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) {
4678 LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
4679 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
4680 // FIXME: The clamping that follows is not completely right for right-to-left
4682 // Clamp everything above the column to its top left.
4683 if (point.y() < gapAndColumnRect.y())
4684 point = gapAndColumnRect.location();
4685 // Clamp everything below the column to the next column's top left. If there is
4686 // no next column, this still maps to just after this column.
4687 else if (point.y() >= gapAndColumnRect.maxY()) {
4688 point = gapAndColumnRect.location();
4689 point.move(0, gapAndColumnRect.height());
4692 // We're inside the column. Translate the x and y into our column coordinate space.
4693 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
4694 point.move(columnPoint.x() - colRect.x(), logicalOffset);
4696 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0);
4700 // Move to the next position.
4701 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width();
4703 LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
4704 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
4705 // FIXME: The clamping that follows is not completely right for right-to-left
4707 // Clamp everything above the column to its top left.
4708 if (point.x() < gapAndColumnRect.x())
4709 point = gapAndColumnRect.location();
4710 // Clamp everything below the column to the next column's top left. If there is
4711 // no next column, this still maps to just after this column.
4712 else if (point.x() >= gapAndColumnRect.maxX()) {
4713 point = gapAndColumnRect.location();
4714 point.move(gapAndColumnRect.width(), 0);
4717 // We're inside the column. Translate the x and y into our column coordinate space.
4718 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
4719 point.move(logicalOffset, columnPoint.y() - colRect.y());
4721 point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop());
4725 // Move to the next position.
4726 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height();
4731 void RenderBlock::adjustRectForColumns(LayoutRect& r) const
4733 // Just bail if we have no columns.
4737 ColumnInfo* colInfo = columnInfo();
4739 // Determine which columns we intersect.
4740 unsigned colCount = columnCount(colInfo);
4744 // Begin with a result rect that is empty.
4747 bool isHorizontal = isHorizontalWritingMode();
4748 LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
4749 LayoutUnit colHeight = colInfo->columnHeight();
4753 LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
4754 LayoutUnit endOffset = min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight);
4756 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
4757 unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
4758 unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight;
4760 if (startColumn == endColumn) {
4761 // The rect is fully contained within one column. Adjust for our offsets
4762 // and repaint only that portion.
4763 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent();
4764 LayoutRect colRect = columnRectAt(colInfo, startColumn);
4765 LayoutRect repaintRect = r;
4767 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
4769 repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight);
4771 repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset);
4774 repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding);
4776 repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0);
4778 repaintRect.intersect(colRect);
4779 result.unite(repaintRect);
4781 // We span multiple columns. We can just unite the start and end column to get the final
4783 result.unite(columnRectAt(colInfo, startColumn));
4784 result.unite(columnRectAt(colInfo, endColumn));
4790 LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
4792 ASSERT(hasColumns());
4793 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4795 ColumnInfo* colInfo = columnInfo();
4796 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
4797 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
4798 if (isHorizontalWritingMode())
4799 return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
4800 return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
4803 void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const
4805 ASSERT(hasColumns());
4806 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4809 ColumnInfo* colInfo = columnInfo();
4810 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
4811 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
4813 if (isHorizontalWritingMode())
4814 rect.setY(expandedLogicalHeight - rect.maxY());
4816 rect.setX(expandedLogicalHeight - rect.maxX());
4819 void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const
4824 ColumnInfo* colInfo = columnInfo();
4826 LayoutUnit logicalLeft = logicalLeftOffsetForContent();
4827 size_t colCount = columnCount(colInfo);
4828 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
4829 LayoutUnit colLogicalHeight = colInfo->columnHeight();
4831 for (size_t i = 0; i < colCount; ++i) {
4832 // Compute the edges for a given column in the block progression direction.
4833 LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
4834 if (!isHorizontalWritingMode())
4835 sliceRect = sliceRect.transposedRect();
4837 LayoutUnit logicalOffset = i * colLogicalHeight;
4839 // Now we're in the same coordinate space as the point. See if it is inside the rectangle.
4840 if (isHorizontalWritingMode()) {
4841 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
4842 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
4843 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
4845 offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
4849 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
4850 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
4851 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
4853 offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
4860 void RenderBlock::computePreferredLogicalWidths()
4862 ASSERT(preferredLogicalWidthsDirty());
4864 updateFirstLetter();
4866 if (!isTableCell() && style()->logicalWidth().isFixed() && style()->logicalWidth().value() > 0)
4867 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->logicalWidth().value());
4869 m_minPreferredLogicalWidth = 0;
4870 m_maxPreferredLogicalWidth = 0;
4872 if (childrenInline())
4873 computeInlinePreferredLogicalWidths();
4875 computeBlockPreferredLogicalWidths();
4877 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
4879 if (!style()->autoWrap() && childrenInline()) {
4880 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
4882 // A horizontal marquee with inline children has no minimum width.
4883 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
4884 m_minPreferredLogicalWidth = 0;
4887 int scrollbarWidth = 0;
4888 if (hasOverflowClip() && style()->overflowY() == OSCROLL) {
4889 layer()->setHasVerticalScrollbar(true);
4890 scrollbarWidth = verticalScrollbarWidth();
4891 m_maxPreferredLogicalWidth += scrollbarWidth;
4894 if (isTableCell()) {
4895 Length w = toRenderTableCell(this)->styleOrColLogicalWidth();
4896 if (w.isFixed() && w.value() > 0) {
4897 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(w.value()));
4902 m_minPreferredLogicalWidth += scrollbarWidth;
4905 if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) {
4906 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value()));
4907 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value()));
4910 if (style()->logicalMaxWidth().isFixed()) {
4911 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value()));
4912 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value()));
4915 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
4916 m_minPreferredLogicalWidth += borderAndPadding;
4917 m_maxPreferredLogicalWidth += borderAndPadding;
4919 setPreferredLogicalWidthsDirty(false);
4922 struct InlineMinMaxIterator {
4923 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
4924 inline min/max width calculations. Note the following about the way it walks:
4925 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
4926 (2) We do not drill into the children of floats or replaced elements, since you can't break
4927 in the middle of such an element.
4928 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
4929 distinct borders/margin/padding that contribute to the min/max width.
4931 RenderObject* parent;
4932 RenderObject* current;
4935 InlineMinMaxIterator(RenderObject* p, bool end = false)
4936 :parent(p), current(p), endOfInline(end) {}
4938 RenderObject* next();
4941 RenderObject* InlineMinMaxIterator::next()
4943 RenderObject* result = 0;
4944 bool oldEndOfInline = endOfInline;
4945 endOfInline = false;
4946 while (current || current == parent) {
4947 if (!oldEndOfInline &&
4948 (current == parent ||
4949 (!current->isFloating() && !current->isReplaced() && !current->isPositioned())))
4950 result = current->firstChild();
4952 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4953 if (!oldEndOfInline && current->isRenderInline()) {
4959 while (current && current != parent) {
4960 result = current->nextSibling();
4962 current = current->parent();
4963 if (current && current != parent && current->isRenderInline()) {
4974 if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4981 // Update our position.
4986 static int getBPMWidth(int childValue, Length cssUnit)
4988 if (cssUnit.type() != Auto)
4989 return (cssUnit.isFixed() ? cssUnit.value() : childValue);
4993 static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
4995 RenderStyle* cstyle = child->style();
4997 return getBPMWidth(child->marginEnd(), cstyle->marginEnd()) +
4998 getBPMWidth(child->paddingEnd(), cstyle->paddingEnd()) +
5000 return getBPMWidth(child->marginStart(), cstyle->marginStart()) +
5001 getBPMWidth(child->paddingStart(), cstyle->paddingStart()) +
5002 child->borderStart();
5005 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
5006 RenderObject* trailingSpaceChild)
5008 if (trailingSpaceChild && trailingSpaceChild->isText()) {
5009 // Collapse away the trailing space at the end of a block.
5010 RenderText* t = toRenderText(trailingSpaceChild);
5011 const UChar space = ' ';
5012 const Font& font = t->style()->font(); // FIXME: This ignores first-line.
5013 float spaceWidth = font.width(RenderBlock::constructTextRun(t, font, &space, 1, t->style()));
5014 inlineMax -= spaceWidth + font.wordSpacing();
5015 if (inlineMin > inlineMax)
5016 inlineMin = inlineMax;
5020 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
5022 LayoutUnit snappedResult = ceiledLayoutUnit(result);
5023 preferredWidth = max(snappedResult, preferredWidth);
5026 void RenderBlock::computeInlinePreferredLogicalWidths()
5028 float inlineMax = 0;
5029 float inlineMin = 0;
5031 RenderBlock* containingBlock = this->containingBlock();
5032 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : 0;
5034 // If we are at the start of a line, we want to ignore all white-space.
5035 // Also strip spaces if we previously had text that ended in a trailing space.
5036 bool stripFrontSpaces = true;
5037 RenderObject* trailingSpaceChild = 0;
5039 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
5040 // very specific cirucumstances (in order to match common WinIE renderings).
5041 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
5042 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto();
5044 bool autoWrap, oldAutoWrap;
5045 autoWrap = oldAutoWrap = style()->autoWrap();
5047 InlineMinMaxIterator childIterator(this);
5048 bool addedTextIndent = false; // Only gets added in once.
5049 RenderObject* prevFloat = 0;
5050 while (RenderObject* child = childIterator.next()) {
5051 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
5052 child->style()->autoWrap();
5054 if (!child->isBR()) {
5055 // Step One: determine whether or not we need to go ahead and
5056 // terminate our current line. Each discrete chunk can become
5057 // the new min-width, if it is the widest chunk seen so far, and
5058 // it can also become the max-width.
5060 // Children fall into three categories:
5061 // (1) An inline flow object. These objects always have a min/max of 0,
5062 // and are included in the iteration solely so that their margins can
5065 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
5066 // These objects can always be on a line by themselves, so in this situation
5067 // we need to go ahead and break the current line, and then add in our own
5068 // margins and min/max width on its own line, and then terminate the line.
5070 // (3) A text object. Text runs can have breakable characters at the start,
5071 // the middle or the end. They may also lose whitespace off the front if
5072 // we're already ignoring whitespace. In order to compute accurate min-width
5073 // information, we need three pieces of information.
5074 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
5075 // starts with whitespace.
5076 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
5077 // ends with whitespace.
5078 // (c) the min/max width of the string (trimmed for whitespace).
5080 // If the text string starts with whitespace, then we need to go ahead and
5081 // terminate our current line (unless we're already in a whitespace stripping
5084 // If the text string has a breakable character in the middle, but didn't start
5085 // with whitespace, then we add the width of the first non-breakable run and
5086 // then end the current line. We then need to use the intermediate min/max width
5087 // values (if any of them are larger than our current min/max). We then look at
5088 // the width of the last non-breakable run and use that to start a new line
5089 // (unless we end in whitespace).
5090 RenderStyle* cstyle = child->style();
5094 if (!child->isText()) {
5095 // Case (1) and (2). Inline replaced and inline flow elements.
5096 if (child->isRenderInline()) {
5097 // Add in padding/border/margin from the appropriate side of
5099 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
5103 inlineMin += childMin;
5104 inlineMax += childMax;
5106 child->setPreferredLogicalWidthsDirty(false);
5108 // Inline replaced elts add in their margins to their min/max values.
5110 Length startMargin = cstyle->marginStart();
5111 Length endMargin = cstyle->marginEnd();
5112 if (startMargin.isFixed())
5113 margins += startMargin.value();
5114 if (endMargin.isFixed())
5115 margins += endMargin.value();
5116 childMin += margins;
5117 childMax += margins;
5121 if (!child->isRenderInline() && !child->isText()) {
5122 // Case (2). Inline replaced elements and floats.
5123 // Go ahead and terminate the current line as far as
5124 // minwidth is concerned.
5125 childMin += child->minPreferredLogicalWidth();
5126 childMax += child->maxPreferredLogicalWidth();
5128 bool clearPreviousFloat;
5129 if (child->isFloating()) {
5130 clearPreviousFloat = (prevFloat
5131 && ((prevFloat->style()->floating() == LeftFloat && (child->style()->clear() & CLEFT))
5132 || (prevFloat->style()->floating() == RightFloat && (child->style()->clear() & CRIGHT))));
5135 clearPreviousFloat = false;
5137 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
5138 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) {
5139 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5143 // If we're supposed to clear the previous float, then terminate maxwidth as well.
5144 if (clearPreviousFloat) {
5145 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5149 // Add in text-indent. This is added in only once.
5151 if (!addedTextIndent) {
5152 addedTextIndent = true;
5153 ti = style()->textIndent().calcMinValue(cw);
5158 // Add our width to the max.
5159 inlineMax += childMax;
5161 if (!autoWrap || !canBreakReplacedElement) {
5162 if (child->isFloating())
5163 updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
5165 inlineMin += childMin;
5167 // Now check our line.
5168 updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
5170 // Now start a new line.
5174 // We are no longer stripping whitespace at the start of
5176 if (!child->isFloating()) {
5177 stripFrontSpaces = false;
5178 trailingSpaceChild = 0;
5180 } else if (child->isText()) {
5182 RenderText* t = toRenderText(child);
5184 if (t->isWordBreak()) {
5185 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5190 if (t->style()->hasTextCombine() && t->isCombineText())
5191 toRenderCombineText(t)->combineText();
5193 // Determine if we have a breakable character. Pass in
5194 // whether or not we should ignore any spaces at the front
5195 // of the string. If those are going to be stripped out,
5196 // then they shouldn't be considered in the breakable char
5198 bool hasBreakableChar, hasBreak;
5199 float beginMin, endMin;
5200 bool beginWS, endWS;
5201 float beginMax, endMax;
5202 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
5203 hasBreakableChar, hasBreak, beginMax, endMax,
5204 childMin, childMax, stripFrontSpaces);
5206 // This text object will not be rendered, but it may still provide a breaking opportunity.
5207 if (!hasBreak && childMax == 0) {
5208 if (autoWrap && (beginWS || endWS)) {
5209 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5215 if (stripFrontSpaces)
5216 trailingSpaceChild = child;
5218 trailingSpaceChild = 0;
5220 // Add in text-indent. This is added in only once.
5222 if (!addedTextIndent) {
5223 addedTextIndent = true;
5224 ti = style()->textIndent().calcMinValue(cw);
5225 childMin+=ti; beginMin += ti;
5226 childMax+=ti; beginMax += ti;
5229 // If we have no breakable characters at all,
5230 // then this is the easy case. We add ourselves to the current
5231 // min and max and continue.
5232 if (!hasBreakableChar) {
5233 inlineMin += childMin;
5235 // We have a breakable character. Now we need to know if
5236 // we start and end with whitespace.
5238 // Go ahead and end the current line.
5239 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5241 inlineMin += beginMin;
5242 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5246 inlineMin = childMin;
5249 // We end in whitespace, which means we can go ahead
5250 // and end our current line.
5251 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5254 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5260 inlineMax += beginMax;
5261 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5262 updatePreferredWidth(m_maxPreferredLogicalWidth, childMax);
5265 inlineMax += childMax;
5268 // Ignore spaces after a list marker.
5269 if (child->isListMarker())
5270 stripFrontSpaces = true;
5272 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5273 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5274 inlineMin = inlineMax = 0;
5275 stripFrontSpaces = true;
5276 trailingSpaceChild = 0;
5279 oldAutoWrap = autoWrap;
5282 if (style()->collapseWhiteSpace())
5283 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
5285 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5286 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5289 // Use a very large value (in effect infinite).
5290 #define BLOCK_MAX_WIDTH 15000
5292 void RenderBlock::computeBlockPreferredLogicalWidths()
5294 bool nowrap = style()->whiteSpace() == NOWRAP;
5296 RenderObject* child = firstChild();
5297 RenderBlock* containingBlock = this->containingBlock();
5298 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
5300 // Positioned children don't affect the min/max width
5301 if (child->isPositioned()) {
5302 child = child->nextSibling();
5306 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
5307 LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
5308 if (child->style()->clear() & CLEFT) {
5309 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
5312 if (child->style()->clear() & CRIGHT) {
5313 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
5314 floatRightWidth = 0;
5318 // A margin basically has three types: fixed, percentage, and auto (variable).
5319 // Auto and percentage margins simply become 0 when computing min/max width.
5320 // Fixed margins can be added in as is.
5321 Length startMarginLength = child->style()->marginStartUsing(style());
5322 Length endMarginLength = child->style()->marginEndUsing(style());
5323 LayoutUnit margin = 0;
5324 LayoutUnit marginStart = 0;
5325 LayoutUnit marginEnd = 0;
5326 if (startMarginLength.isFixed())
5327 marginStart += startMarginLength.value();
5328 if (endMarginLength.isFixed())
5329 marginEnd += endMarginLength.value();
5330 margin = marginStart + marginEnd;
5332 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
5333 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
5334 RenderBox* childBox = toRenderBox(child);
5335 LayoutUnit oldHeight = childBox->logicalHeight();
5336 childBox->setLogicalHeight(childBox->borderAndPaddingLogicalHeight());
5337 childBox->computeLogicalHeight();
5338 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = childBox->logicalHeight();
5339 childBox->setLogicalHeight(oldHeight);
5341 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
5342 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
5345 LayoutUnit w = childMinPreferredLogicalWidth + margin;
5346 m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth);
5348 // IE ignores tables for calculation of nowrap. Makes some sense.
5349 if (nowrap && !child->isTable())
5350 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
5352 w = childMaxPreferredLogicalWidth + margin;
5354 if (!child->isFloating()) {
5355 if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
5356 // Determine a left and right max value based off whether or not the floats can fit in the
5357 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
5358 // is smaller than the float width.
5359 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : style()->isLeftToRightDirection();
5360 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
5361 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
5362 LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
5363 LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
5364 w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
5365 w = max(w, floatLeftWidth + floatRightWidth);
5368 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
5369 floatLeftWidth = floatRightWidth = 0;
5372 if (child->isFloating()) {
5373 if (style()->floating() == LeftFloat)
5374 floatLeftWidth += w;
5376 floatRightWidth += w;
5378 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
5380 // A very specific WinIE quirk.
5383 <div style="position:absolute; width:100px; top:50px;">
5384 <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green">
5385 <table style="width:100%"><tr><td></table>
5389 // In the above example, the inner absolute positioned block should have a computed width
5390 // of 100px because of the table.
5391 // We can achieve this effect by making the maxwidth of blocks that contain tables
5392 // with percentage widths be infinite (as long as they are not inside a table cell).
5393 // FIXME: There is probably a bug here with orthogonal writing modes since we check logicalWidth only using the child's writing mode.
5394 if (containingBlock && document()->inQuirksMode() && child->style()->logicalWidth().isPercent()
5395 && !isTableCell() && child->isTable() && m_maxPreferredLogicalWidth < BLOCK_MAX_WIDTH) {
5396 RenderBlock* cb = containingBlock;
5397 while (!cb->isRenderView() && !cb->isTableCell())
5398 cb = cb->containingBlock();
5399 if (!cb->isTableCell())
5400 m_maxPreferredLogicalWidth = BLOCK_MAX_WIDTH;
5403 child = child->nextSibling();
5406 // Always make sure these values are non-negative.
5407 m_minPreferredLogicalWidth = max<LayoutUnit>(0, m_minPreferredLogicalWidth);
5408 m_maxPreferredLogicalWidth = max<LayoutUnit>(0, m_maxPreferredLogicalWidth);
5410 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
5413 bool RenderBlock::hasLineIfEmpty() const
5418 if (node()->rendererIsEditable() && node()->rootEditableElement() == node())
5421 if (node()->isShadowRoot() && (node()->shadowHost()->hasTagName(inputTag)))
5427 LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
5429 // Inline blocks are replaced elements. Otherwise, just pass off to
5430 // the base class. If we're being queried as though we're the root line
5431 // box, then the fact that we're an inline-block is irrelevant, and we behave
5432 // just like a block.
5433 if (isReplaced() && linePositionMode == PositionOnContainingLine)
5434 return RenderBox::lineHeight(firstLine, direction, linePositionMode);
5436 if (firstLine && document()->usesFirstLineRules()) {
5437 RenderStyle* s = style(firstLine);
5439 return s->computedLineHeight();
5442 if (m_lineHeight == -1)
5443 m_lineHeight = style()->computedLineHeight();
5445 return m_lineHeight;
5448 LayoutUnit RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
5450 // Inline blocks are replaced elements. Otherwise, just pass off to
5451 // the base class. If we're being queried as though we're the root line
5452 // box, then the fact that we're an inline-block is irrelevant, and we behave
5453 // just like a block.
5454 if (isReplaced() && linePositionMode == PositionOnContainingLine) {
5455 // For "leaf" theme objects, let the theme decide what the baseline position is.
5456 // FIXME: Might be better to have a custom CSS property instead, so that if the theme
5457 // is turned off, checkboxes/radios will still have decent baselines.
5458 // FIXME: Need to patch form controls to deal with vertical lines.
5459 if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
5460 return theme()->baselinePosition(this);
5462 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
5463 // the normal flow. We make an exception for marquees, since their baselines are meaningless
5464 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
5465 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
5466 // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
5467 // of our content box.
5468 bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)
5469 : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || (isWritingModeRoot() && !isRubyRun());
5471 int baselinePos = ignoreBaseline ? LayoutUnit(-1) : lastLineBoxBaseline();
5473 int bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
5474 if (baselinePos != -1 && baselinePos <= bottomOfContent)
5475 return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos;
5477 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
5480 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
5481 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
5484 LayoutUnit RenderBlock::firstLineBoxBaseline() const
5486 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
5489 if (childrenInline()) {
5491 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
5496 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
5497 if (!curr->isFloatingOrPositioned()) {
5498 LayoutUnit result = curr->firstLineBoxBaseline();
5500 return curr->logicalTop() + result; // Translate to our coordinate space.
5508 LayoutUnit RenderBlock::lastLineBoxBaseline() const
5510 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
5513 LineDirectionMode lineDirection = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
5515 if (childrenInline()) {
5516 if (!firstLineBox() && hasLineIfEmpty()) {
5517 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
5518 return fontMetrics.ascent()
5519 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
5520 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
5523 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
5526 bool haveNormalFlowChild = false;
5527 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
5528 if (!curr->isFloatingOrPositioned()) {
5529 haveNormalFlowChild = true;
5530 LayoutUnit result = curr->lastLineBoxBaseline();
5532 return curr->logicalTop() + result; // Translate to our coordinate space.
5535 if (!haveNormalFlowChild && hasLineIfEmpty()) {
5536 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
5537 return fontMetrics.ascent()
5538 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
5539 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
5546 bool RenderBlock::containsNonZeroBidiLevel() const
5548 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
5549 for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
5550 if (box->bidiLevel())
5557 RenderBlock* RenderBlock::firstLineBlock() const
5559 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
5560 bool hasPseudo = false;
5562 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
5565 RenderObject* parentBlock = firstLineBlock->parent();
5566 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
5567 !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
5569 ASSERT(parentBlock->isRenderBlock());
5570 firstLineBlock = toRenderBlock(parentBlock);
5576 return firstLineBlock;
5579 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
5581 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
5582 // Force inline display (except for floating first-letters).
5583 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
5584 // CSS2 says first-letter can't be positioned.
5585 pseudoStyle->setPosition(StaticPosition);
5589 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
5590 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
5591 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
5592 static inline bool isPunctuationForFirstLetter(UChar c)
5594 CharCategory charCategory = category(c);
5595 return charCategory == Punctuation_Open
5596 || charCategory == Punctuation_Close
5597 || charCategory == Punctuation_InitialQuote
5598 || charCategory == Punctuation_FinalQuote
5599 || charCategory == Punctuation_Other;
5602 static inline bool shouldSkipForFirstLetter(UChar c)
5604 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
5607 void RenderBlock::updateFirstLetter()
5609 if (!document()->usesFirstLetterRules())
5612 if (style()->styleType() == FIRST_LETTER)
5615 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
5616 // an efficient way to check for that situation though before implementing anything.
5617 RenderObject* firstLetterBlock = this;
5618 bool hasPseudoStyle = false;
5620 // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly
5621 // prevents form controls from honoring first-letter.
5622 hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
5623 && firstLetterBlock->canHaveChildren();
5626 RenderObject* parentBlock = firstLetterBlock->parent();
5627 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
5628 !parentBlock->isBlockFlow())
5630 firstLetterBlock = parentBlock;
5633 if (!hasPseudoStyle)
5636 // Drill into inlines looking for our first text child.
5637 RenderObject* currChild = firstLetterBlock->firstChild();
5639 if (currChild->isText())
5641 if (currChild->isListMarker())
5642 currChild = currChild->nextSibling();
5643 else if (currChild->isFloatingOrPositioned()) {
5644 if (currChild->style()->styleType() == FIRST_LETTER) {
5645 currChild = currChild->firstChild();
5648 currChild = currChild->nextSibling();
5649 } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList())
5651 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveChildren()) {
5652 // We found a lower-level node with first-letter, which supersedes the higher-level style
5653 firstLetterBlock = currChild;
5654 currChild = currChild->firstChild();
5657 currChild = currChild->firstChild();
5663 // If the child already has style, then it has already been created, so we just want
5665 if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
5666 RenderObject* firstLetter = currChild->parent();
5667 RenderObject* firstLetterContainer = firstLetter->parent();
5668 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
5669 ASSERT(firstLetter->isFloating() || firstLetter->isInline());
5671 if (Node::diff(firstLetter->style(), pseudoStyle) == Node::Detach) {
5672 // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
5673 RenderObject* newFirstLetter;
5674 if (pseudoStyle->display() == INLINE)
5675 newFirstLetter = new (renderArena()) RenderInline(document());
5677 newFirstLetter = new (renderArena()) RenderBlock(document());
5678 newFirstLetter->setStyle(pseudoStyle);
5680 // Move the first letter into the new renderer.
5681 LayoutStateDisabler layoutStateDisabler(view());
5682 while (RenderObject* child = firstLetter->firstChild()) {
5683 if (child->isText())
5684 toRenderText(child)->removeAndDestroyTextBoxes();
5685 firstLetter->removeChild(child);
5686 newFirstLetter->addChild(child, 0);
5689 RenderTextFragment* remainingText = 0;
5690 RenderObject* nextSibling = firstLetter->nextSibling();
5691 RenderObject* next = nextSibling;
5693 if (next->isText() && toRenderText(next)->isTextFragment()) {
5694 remainingText = toRenderTextFragment(next);
5697 next = next->nextSibling();
5699 if (remainingText) {
5700 ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText);
5701 // Replace the old renderer with the new one.
5702 remainingText->setFirstLetter(newFirstLetter);
5704 firstLetter->destroy();
5705 firstLetter = newFirstLetter;
5706 firstLetterContainer->addChild(firstLetter, nextSibling);
5708 firstLetter->setStyle(pseudoStyle);
5710 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
5711 if (genChild->isText())
5712 genChild->setStyle(pseudoStyle);
5718 if (!currChild->isText() || currChild->isBR())
5721 // If the child does not already have style, we create it here.
5722 RenderObject* firstLetterContainer = currChild->parent();
5724 // Our layout state is not valid for the repaints we are going to trigger by
5725 // adding and removing children of firstLetterContainer.
5726 LayoutStateDisabler layoutStateDisabler(view());
5728 RenderText* textObj = toRenderText(currChild);
5730 // Create our pseudo style now that we have our firstLetterContainer determined.
5731 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
5733 RenderObject* firstLetter = 0;
5734 if (pseudoStyle->display() == INLINE)
5735 firstLetter = new (renderArena()) RenderInline(document());
5737 firstLetter = new (renderArena()) RenderBlock(document());
5738 firstLetter->setStyle(pseudoStyle);
5739 firstLetterContainer->addChild(firstLetter, currChild);
5741 // The original string is going to be either a generated content string or a DOM node's
5742 // string. We want the original string before it got transformed in case first-letter has
5743 // no text-transform or a different text-transform applied to it.
5744 RefPtr<StringImpl> oldText = textObj->originalText();
5747 if (oldText && oldText->length() > 0) {
5748 unsigned length = 0;
5750 // Account for leading spaces and punctuation.
5751 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length]))
5754 // Account for first letter.
5757 // Keep looking for whitespace and allowed punctuation, but avoid
5758 // accumulating just whitespace into the :first-letter.
5759 for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) {
5760 UChar c = (*oldText)[scanLength];
5762 if (!shouldSkipForFirstLetter(c))
5765 if (isPunctuationForFirstLetter(c))
5766 length = scanLength + 1;
5769 // Construct a text fragment for the text after the first letter.
5770 // This text fragment might be empty.
5771 RenderTextFragment* remainingText =
5772 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
5773 remainingText->setStyle(textObj->style());
5774 if (remainingText->node())
5775 remainingText->node()->setRenderer(remainingText);
5777 firstLetterContainer->addChild(remainingText, textObj);
5778 firstLetterContainer->removeChild(textObj);
5779 remainingText->setFirstLetter(firstLetter);
5781 // construct text fragment for the first letter
5782 RenderTextFragment* letter =
5783 new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
5784 letter->setStyle(pseudoStyle);
5785 firstLetter->addChild(letter);
5791 // Helper methods for obtaining the last line, computing line counts and heights for line counts
5792 // (crawling into blocks).
5793 static bool shouldCheckLines(RenderObject* obj)
5795 return !obj->isFloatingOrPositioned() && !obj->isRunIn() &&
5796 obj->isBlockFlow() && obj->style()->height().isAuto() &&
5797 (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
5800 static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
5802 if (block->style()->visibility() == VISIBLE) {
5803 if (block->childrenInline()) {
5804 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
5810 for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
5811 if (shouldCheckLines(obj)) {
5812 RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
5822 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
5824 if (block->style()->visibility() == VISIBLE) {
5825 if (block->childrenInline()) {
5826 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
5828 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
5832 RenderBox* normalFlowChildWithoutLines = 0;
5833 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
5834 if (shouldCheckLines(obj)) {
5835 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
5837 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
5839 else if (!obj->isFloatingOrPositioned() && !obj->isRunIn())
5840 normalFlowChildWithoutLines = obj;
5842 if (normalFlowChildWithoutLines && l == 0)
5843 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
5850 RootInlineBox* RenderBlock::lineAtIndex(int i)
5853 return getLineAtIndex(this, i, count);
5856 int RenderBlock::lineCount()
5859 if (style()->visibility() == VISIBLE) {
5860 if (childrenInline())
5861 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
5864 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
5865 if (shouldCheckLines(obj))
5866 count += toRenderBlock(obj)->lineCount();
5871 int RenderBlock::heightForLineCount(int l)
5874 return getHeightForLineCount(this, l, true, count);
5877 void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
5879 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
5880 // for either overflow or translations via relative positioning.
5881 if (style()->visibility() == VISIBLE) {
5882 if (childrenInline()) {
5883 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
5884 if (box->firstChild())
5885 left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
5886 if (box->lastChild())
5887 right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight())));
5891 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
5892 if (!obj->isFloatingOrPositioned()) {
5893 if (obj->isBlockFlow() && !obj->hasOverflowClip())
5894 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
5895 else if (obj->style()->visibility() == VISIBLE) {
5896 // We are a replaced element or some kind of non-block-flow object.
5897 left = min(left, x + obj->x());
5898 right = max(right, x + obj->x() + obj->width());
5904 if (m_floatingObjects) {
5905 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
5906 FloatingObjectSetIterator end = floatingObjectSet.end();
5907 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
5908 FloatingObject* r = *it;
5909 // Only examine the object if our m_shouldPaint flag is set.
5910 if (r->m_shouldPaint) {
5911 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x();
5912 LayoutUnit floatRight = floatLeft + r->m_renderer->width();
5913 left = min(left, floatLeft);
5914 right = max(right, floatRight);
5921 void RenderBlock::borderFitAdjust(LayoutRect& rect) const
5923 if (style()->borderFit() == BorderFitBorder)
5926 // Walk any normal flow lines to snugly fit.
5927 LayoutUnit left = numeric_limits<LayoutUnit>::max();
5928 LayoutUnit right = numeric_limits<LayoutUnit>::min();
5929 LayoutUnit oldWidth = rect.width();
5930 adjustForBorderFit(0, left, right);
5931 if (left != numeric_limits<LayoutUnit>::max()) {
5932 left = min(left, oldWidth - (borderRight() + paddingRight()));
5934 left -= (borderLeft() + paddingLeft());
5937 rect.expand(-left, 0);
5940 if (right != numeric_limits<LayoutUnit>::min()) {
5941 right = max(right, borderLeft() + paddingLeft());
5943 right += (borderRight() + paddingRight());
5944 if (right < oldWidth)
5945 rect.expand(-(oldWidth - right), 0);
5949 void RenderBlock::clearTruncation()
5951 if (style()->visibility() == VISIBLE) {
5952 if (childrenInline() && hasMarkupTruncation()) {
5953 setHasMarkupTruncation(false);
5954 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
5955 box->clearTruncation();
5957 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
5958 if (shouldCheckLines(obj))
5959 toRenderBlock(obj)->clearTruncation();
5965 void RenderBlock::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
5968 if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this))
5970 m_rareData = adoptPtr(new RenderBlockRareData(this));
5972 m_rareData->m_margins.setPositiveMarginBefore(pos);
5973 m_rareData->m_margins.setNegativeMarginBefore(neg);
5976 void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
5979 if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this))
5981 m_rareData = adoptPtr(new RenderBlockRareData(this));
5983 m_rareData->m_margins.setPositiveMarginAfter(pos);
5984 m_rareData->m_margins.setNegativeMarginAfter(neg);
5987 void RenderBlock::setPaginationStrut(LayoutUnit strut)
5992 m_rareData = adoptPtr(new RenderBlockRareData(this));
5994 m_rareData->m_paginationStrut = strut;
5997 void RenderBlock::setPageLogicalOffset(int logicalOffset)
6002 m_rareData = adoptPtr(new RenderBlockRareData(this));
6004 m_rareData->m_pageLogicalOffset = logicalOffset;
6007 void RenderBlock::absoluteRects(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset) const
6009 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
6010 // inline boxes above and below us (thus getting merged with them to form a single irregular
6012 if (isAnonymousBlockContinuation()) {
6013 // FIXME: This is wrong for block-flows that are horizontal.
6014 // https://bugs.webkit.org/show_bug.cgi?id=46781
6015 rects.append(LayoutRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(),
6016 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
6017 continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
6018 inlineElementContinuation()->containingBlock()->location()));
6020 rects.append(LayoutRect(accumulatedOffset, size()));
6023 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
6025 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
6026 // inline boxes above and below us (thus getting merged with them to form a single irregular
6028 if (isAnonymousBlockContinuation()) {
6029 // FIXME: This is wrong for block-flows that are horizontal.
6030 // https://bugs.webkit.org/show_bug.cgi?id=46781
6031 FloatRect localRect(0, -collapsedMarginBefore(),
6032 width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
6033 quads.append(localToAbsoluteQuad(localRect, false, wasFixed));
6034 continuation()->absoluteQuads(quads, wasFixed);
6036 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), false, wasFixed));
6039 LayoutRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const
6041 LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
6042 if (isAnonymousBlockContinuation())
6043 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
6047 RenderObject* RenderBlock::hoverAncestor() const
6049 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
6052 void RenderBlock::updateDragState(bool dragOn)
6054 RenderBox::updateDragState(dragOn);
6056 continuation()->updateDragState(dragOn);
6059 RenderStyle* RenderBlock::outlineStyleForRepaint() const
6061 return isAnonymousBlockContinuation() ? continuation()->style() : style();
6064 void RenderBlock::childBecameNonInline(RenderObject*)
6066 makeChildrenNonInline();
6067 if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
6068 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
6069 // |this| may be dead here
6072 void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
6074 if (result.innerNode())
6078 if (isAnonymousBlockContinuation())
6079 // We are in the margins of block elements that are part of a continuation. In
6080 // this case we're actually still inside the enclosing element that was
6081 // split. Go ahead and set our inner node accordingly.
6082 n = continuation()->node();
6085 result.setInnerNode(n);
6086 if (!result.innerNonSharedNode())
6087 result.setInnerNonSharedNode(n);
6088 result.setLocalPoint(point);
6092 LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
6094 // Do the normal calculation in most cases.
6096 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
6098 // This is a special case:
6099 // The element is not an inline element, and it's empty. So we have to
6100 // calculate a fake position to indicate where objects are to be inserted.
6102 // FIXME: This does not take into account either :first-line or :first-letter
6103 // However, as soon as some content is entered, the line boxes will be
6104 // constructed and this kludge is not called any more. So only the caret size
6105 // of an empty :first-line'd block is wrong. I think we can live with that.
6106 RenderStyle* currentStyle = firstLineStyle();
6107 LayoutUnit height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine);
6109 enum CaretAlignment { alignLeft, alignRight, alignCenter };
6111 CaretAlignment alignment = alignLeft;
6113 switch (currentStyle->textAlign()) {
6116 if (!currentStyle->isLeftToRightDirection())
6117 alignment = alignRight;
6124 alignment = alignCenter;
6128 alignment = alignRight;
6131 if (!currentStyle->isLeftToRightDirection())
6132 alignment = alignRight;
6135 if (currentStyle->isLeftToRightDirection())
6136 alignment = alignRight;
6140 LayoutUnit x = borderLeft() + paddingLeft();
6141 LayoutUnit w = width();
6143 switch (alignment) {
6147 x = (x + w - (borderRight() + paddingRight())) / 2;
6150 x = w - (borderRight() + paddingRight()) - caretWidth;
6154 if (extraWidthToEndOfLine) {
6155 if (isRenderBlock()) {
6156 *extraWidthToEndOfLine = w - (x + caretWidth);
6158 // FIXME: This code looks wrong.
6159 // myRight and containerRight are set up, but then clobbered.
6160 // So *extraWidthToEndOfLine will always be 0 here.
6162 LayoutUnit myRight = x + caretWidth;
6163 // FIXME: why call localToAbsoluteForContent() twice here, too?
6164 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
6166 LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
6167 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
6169 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
6173 LayoutUnit y = paddingTop() + borderTop();
6175 return LayoutRect(x, y, caretWidth, height);
6178 void RenderBlock::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset)
6180 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
6181 // inline boxes above and below us (thus getting merged with them to form a single irregular
6183 if (inlineElementContinuation()) {
6184 // FIXME: This check really isn't accurate.
6185 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
6186 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
6187 // FIXME: This is wrong for block-flows that are horizontal.
6188 // https://bugs.webkit.org/show_bug.cgi?id=46781
6189 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
6190 float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : static_cast<LayoutUnit>(0);
6191 float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : static_cast<LayoutUnit>(0);
6192 LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin);
6193 if (!rect.isEmpty())
6195 } else if (width() && height())
6196 rects.append(LayoutRect(additionalOffset, size()));
6198 if (!hasOverflowClip() && !hasControlClip()) {
6199 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
6200 LayoutUnit top = max(curr->lineTop(), static_cast<LayoutUnit>(curr->top()));
6201 LayoutUnit bottom = min(curr->lineBottom(), static_cast<LayoutUnit>(curr->top() + curr->height()));
6202 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
6203 if (!rect.isEmpty())
6207 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
6208 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
6209 RenderBox* box = toRenderBox(curr);
6211 // FIXME: This doesn't work correctly with transforms.
6213 pos = curr->localToAbsolute();
6215 pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
6216 box->addFocusRingRects(rects, flooredLayoutPoint(pos));
6221 if (inlineElementContinuation())
6222 inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()));
6225 RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const
6227 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
6229 RenderBlock* newBox = 0;
6230 if (isFlexibleBox) {
6231 newStyle->setDisplay(BOX);
6232 newBox = new (renderArena()) RenderDeprecatedFlexibleBox(document() /* anonymous box */);
6234 newStyle->setDisplay(BLOCK);
6235 newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
6238 newBox->setStyle(newStyle.release());
6242 RenderBlock* RenderBlock::createAnonymousBlockWithSameTypeAs(RenderBlock* otherAnonymousBlock) const
6244 if (otherAnonymousBlock->isAnonymousColumnsBlock())
6245 return createAnonymousColumnsBlock();
6246 if (otherAnonymousBlock->isAnonymousColumnSpanBlock())
6247 return createAnonymousColumnSpanBlock();
6248 return createAnonymousBlock(otherAnonymousBlock->style()->display() == BOX);
6251 RenderBlock* RenderBlock::createAnonymousColumnsBlock() const
6253 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
6254 newStyle->inheritColumnPropertiesFrom(style());
6255 newStyle->setDisplay(BLOCK);
6257 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
6258 newBox->setStyle(newStyle.release());
6262 RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const
6264 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
6265 newStyle->setColumnSpan(ColumnSpanAll);
6266 newStyle->setDisplay(BLOCK);
6268 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
6269 newBox->setStyle(newStyle.release());
6273 bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
6275 ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
6277 if (!inRenderFlowThread())
6278 return true; // Printing and multi-column both make new pages to accommodate content.
6280 // See if we're in the last region.
6281 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
6282 RenderRegion* region = enclosingRenderFlowThread()->renderRegionForLine(pageOffset, this);
6285 if (region->isLastRegion())
6286 return region->style()->regionOverflow() == BreakRegionOverflow
6287 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->offsetFromLogicalTopOfFirstPage());
6291 LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
6293 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6294 if (!pageLogicalHeight)
6295 return logicalOffset;
6297 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
6298 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
6299 if (pageBoundaryRule == ExcludePageBoundary)
6300 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
6301 return logicalOffset + remainingLogicalHeight;
6304 static bool inNormalFlow(RenderBox* child)
6306 RenderBlock* curr = child->containingBlock();
6307 RenderView* renderView = child->view();
6308 while (curr && curr != renderView) {
6309 if (curr->hasColumns() || curr->isRenderFlowThread())
6311 if (curr->isFloatingOrPositioned())
6313 curr = curr->containingBlock();
6318 LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
6320 // FIXME: Add page break checking here when we support printing.
6321 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6322 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
6323 bool checkRegionBreaks = inRenderFlowThread();
6324 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
6325 || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
6326 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
6327 if (checkColumnBreaks)
6328 view()->layoutState()->addForcedColumnBreak(logicalOffset);
6329 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
6331 return logicalOffset;
6334 LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
6336 // FIXME: Add page break checking here when we support printing.
6337 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6338 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
6339 bool checkRegionBreaks = inRenderFlowThread();
6340 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
6341 || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
6342 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
6343 marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content.
6344 if (checkColumnBreaks)
6345 view()->layoutState()->addForcedColumnBreak(logicalOffset);
6346 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
6348 return logicalOffset;
6351 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
6353 RenderView* renderView = view();
6354 if (!inRenderFlowThread())
6355 return renderView->layoutState()->m_pageLogicalHeight;
6356 return enclosingRenderFlowThread()->regionLogicalHeightForLine(offset + offsetFromLogicalTopOfFirstPage());
6359 LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
6361 RenderView* renderView = view();
6362 offset += offsetFromLogicalTopOfFirstPage();
6364 if (!inRenderFlowThread()) {
6365 LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
6366 LayoutUnit remainingHeight = pageLogicalHeight - layoutMod(offset, pageLogicalHeight);
6367 if (pageBoundaryRule == IncludePageBoundary) {
6368 // If includeBoundaryPoint is true the line exactly on the top edge of a
6369 // column will act as being part of the previous column.
6370 remainingHeight = layoutMod(remainingHeight, pageLogicalHeight);
6372 return remainingHeight;
6375 return enclosingRenderFlowThread()->regionRemainingLogicalHeightForLine(offset, pageBoundaryRule);
6378 LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
6380 bool isUnsplittable = child->isUnsplittableForPagination() || child->style()->columnBreakInside() == PBAVOID
6381 || child->style()->regionBreakInside() == PBAVOID;
6382 if (!isUnsplittable)
6383 return logicalOffset;
6384 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : 0);
6385 LayoutState* layoutState = view()->layoutState();
6386 if (layoutState->m_columnInfo)
6387 layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
6388 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6389 bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
6390 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
6391 || !hasNextPage(logicalOffset))
6392 return logicalOffset;
6393 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
6394 if (remainingLogicalHeight < childLogicalHeight) {
6395 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
6396 return logicalOffset;
6397 return logicalOffset + remainingLogicalHeight;
6399 return logicalOffset;
6402 bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
6404 bool checkRegion = false;
6405 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
6406 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
6407 if (minimumLogicalHeight <= pageLogicalHeight)
6409 if (!hasNextPage(logicalOffset + adjustment))
6411 adjustment += pageLogicalHeight;
6414 return !checkRegion;
6417 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta)
6419 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
6420 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
6421 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
6422 // of the first column.
6424 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
6425 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
6426 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
6427 // for overflow to occur), and then cache visible overflow for each column rect.
6429 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
6430 // content that paints in a previous column (and content that paints in the following column).
6432 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
6433 // at least make positive leading work in typical cases.
6435 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
6436 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
6437 // line and all following lines.
6438 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
6439 LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
6440 LayoutUnit lineHeight = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()) - logicalOffset;
6441 RenderView* renderView = view();
6442 LayoutState* layoutState = renderView->layoutState();
6443 if (layoutState->m_columnInfo)
6444 layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
6445 logicalOffset += delta;
6446 lineBox->setPaginationStrut(0);
6447 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6448 bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
6449 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && lineHeight > pageLogicalHeight)
6450 || !hasNextPage(logicalOffset))
6452 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
6453 if (remainingLogicalHeight < lineHeight) {
6454 // If we have a non-uniform page height, then we have to shift further possibly.
6455 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
6457 LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
6458 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
6459 if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isPositioned() && !isTableCell())
6460 setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
6462 delta += remainingLogicalHeight;
6463 lineBox->setPaginationStrut(remainingLogicalHeight);
6468 LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
6470 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
6472 if (estimateWithoutPagination != logicalTopAfterClear) {
6473 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
6475 setLogicalHeight(logicalTopAfterClear);
6476 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
6478 if (child->shrinkToAvoidFloats()) {
6479 // The child's width depends on the line width.
6480 // When the child shifts to clear an item, its width can
6481 // change (because it has more available line width).
6482 // So go ahead and mark the item as dirty.
6483 child->setChildNeedsLayout(true, false);
6486 if (childRenderBlock) {
6487 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
6488 childRenderBlock->markAllDescendantsWithFloatsForLayout();
6489 if (!child->needsLayout())
6490 child->markForPaginationRelayoutIfNeeded();
6493 // Our guess was wrong. Make the child lay itself out again.
6494 child->layoutIfNeeded();
6497 LayoutUnit oldTop = logicalTopAfterClear;
6499 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
6500 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
6502 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
6503 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
6504 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
6506 LayoutUnit paginationStrut = 0;
6507 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
6508 if (unsplittableAdjustmentDelta)
6509 paginationStrut = unsplittableAdjustmentDelta;
6510 else if (childRenderBlock && childRenderBlock->paginationStrut())
6511 paginationStrut = childRenderBlock->paginationStrut();
6513 if (paginationStrut) {
6514 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
6515 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
6516 if (atBeforeSideOfBlock && oldTop == result && !isPositioned() && !isTableCell()) {
6517 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
6518 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
6519 // and pushes to the next page anyway, so not too concerned about it.
6520 setPaginationStrut(result + paginationStrut);
6521 if (childRenderBlock)
6522 childRenderBlock->setPaginationStrut(0);
6524 result += paginationStrut;
6527 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
6528 setLogicalHeight(logicalHeight() + (result - oldTop));
6530 // Return the final adjusted logical top.
6534 bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta) const
6536 if (!inRenderFlowThread())
6539 return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(rootBox->lineTopWithLeading() + lineDelta);
6542 LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
6544 // FIXME: This function needs to work without layout state. It's fine to use the layout state as a cache
6545 // for speed, but we need a slow implementation that will walk up the containing block chain and figure
6546 // out our offset from the top of the page.
6547 LayoutState* layoutState = view()->layoutState();
6548 if (!layoutState || !layoutState->isPaginated())
6551 // FIXME: Sanity check that the renderer in the layout state is ours, since otherwise the computation will be off.
6552 // Right now this assert gets hit inside computeLogicalHeight for percentage margins, since they're computed using
6553 // widths which can vary in each region. Until we patch that, we can't have this assert.
6554 // ASSERT(layoutState->m_renderer == this);
6556 LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
6557 return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
6560 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
6562 if (!inRenderFlowThread())
6565 RenderFlowThread* flowThread = enclosingRenderFlowThread();
6566 if (!flowThread || !flowThread->hasValidRegions())
6569 return flowThread->renderRegionForLine(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
6572 void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
6574 if (inRenderFlowThread()) {
6575 // Shift the inline position to exclude the region offset.
6576 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
6578 child->layer()->setStaticInlinePosition(inlinePosition);
6581 bool RenderBlock::logicalWidthChangedInRegions() const
6583 if (!inRenderFlowThread())
6586 RenderFlowThread* flowThread = enclosingRenderFlowThread();
6587 if (!flowThread || !flowThread->hasValidRegions())
6590 return flowThread->logicalWidthChangedInRegions(this, offsetFromLogicalTopOfFirstPage());
6593 RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
6595 ASSERT(region && inRenderFlowThread());
6597 // We need to clamp to the block, since we want any lines or blocks that overflow out of the
6598 // logical top or logical bottom of the block to size as though the border box in the first and
6599 // last regions extended infinitely. Otherwise the lines are going to size according to the regions
6600 // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
6601 RenderRegion* startRegion;
6602 RenderRegion* endRegion;
6603 enclosingRenderFlowThread()->getRegionRangeForBox(this, startRegion, endRegion);
6605 if (startRegion && region->offsetFromLogicalTopOfFirstPage() < startRegion->offsetFromLogicalTopOfFirstPage())
6607 if (endRegion && region->offsetFromLogicalTopOfFirstPage() > endRegion->offsetFromLogicalTopOfFirstPage())
6613 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
6615 // If the child has the same directionality as we do, then we can just return its
6616 // collapsed margin.
6617 if (!child->isWritingModeRoot())
6618 return child->collapsedMarginBefore();
6620 // The child has a different directionality. If the child is parallel, then it's just
6621 // flipped relative to us. We can use the collapsed margin for the opposite edge.
6622 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
6623 return child->collapsedMarginAfter();
6625 // The child is perpendicular to us, which means its margins don't collapse but are on the
6626 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
6627 return marginBeforeForChild(child);
6630 LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) const
6632 // If the child has the same directionality as we do, then we can just return its
6633 // collapsed margin.
6634 if (!child->isWritingModeRoot())
6635 return child->collapsedMarginAfter();
6637 // The child has a different directionality. If the child is parallel, then it's just
6638 // flipped relative to us. We can use the collapsed margin for the opposite edge.
6639 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
6640 return child->collapsedMarginBefore();
6642 // The child is perpendicular to us, which means its margins don't collapse but are on the
6643 // "logical left/right" side of the child box. We can just return the raw margin in this case.
6644 return marginAfterForChild(child);
6647 LayoutUnit RenderBlock::marginBeforeForChild(const RenderBoxModelObject* child) const
6649 switch (style()->writingMode()) {
6650 case TopToBottomWritingMode:
6651 return child->marginTop();
6652 case BottomToTopWritingMode:
6653 return child->marginBottom();
6654 case LeftToRightWritingMode:
6655 return child->marginLeft();
6656 case RightToLeftWritingMode:
6657 return child->marginRight();
6659 ASSERT_NOT_REACHED();
6660 return child->marginTop();
6663 LayoutUnit RenderBlock::marginAfterForChild(const RenderBoxModelObject* child) const
6665 switch (style()->writingMode()) {
6666 case TopToBottomWritingMode:
6667 return child->marginBottom();
6668 case BottomToTopWritingMode:
6669 return child->marginTop();
6670 case LeftToRightWritingMode:
6671 return child->marginRight();
6672 case RightToLeftWritingMode:
6673 return child->marginLeft();
6675 ASSERT_NOT_REACHED();
6676 return child->marginBottom();
6679 LayoutUnit RenderBlock::marginLogicalLeftForChild(const RenderBoxModelObject* child) const
6681 if (isHorizontalWritingMode())
6682 return child->marginLeft();
6683 return child->marginTop();
6686 LayoutUnit RenderBlock::marginLogicalRightForChild(const RenderBoxModelObject* child) const
6688 if (isHorizontalWritingMode())
6689 return child->marginRight();
6690 return child->marginBottom();
6693 LayoutUnit RenderBlock::marginStartForChild(const RenderBoxModelObject* child) const
6695 if (isHorizontalWritingMode())
6696 return style()->isLeftToRightDirection() ? child->marginLeft() : child->marginRight();
6697 return style()->isLeftToRightDirection() ? child->marginTop() : child->marginBottom();
6700 LayoutUnit RenderBlock::marginEndForChild(const RenderBoxModelObject* child) const
6702 if (isHorizontalWritingMode())
6703 return style()->isLeftToRightDirection() ? child->marginRight() : child->marginLeft();
6704 return style()->isLeftToRightDirection() ? child->marginBottom() : child->marginTop();
6707 void RenderBlock::setMarginStartForChild(RenderBox* child, LayoutUnit margin)
6709 if (isHorizontalWritingMode()) {
6710 if (style()->isLeftToRightDirection())
6711 child->setMarginLeft(margin);
6713 child->setMarginRight(margin);
6715 if (style()->isLeftToRightDirection())
6716 child->setMarginTop(margin);
6718 child->setMarginBottom(margin);
6722 void RenderBlock::setMarginEndForChild(RenderBox* child, LayoutUnit margin)
6724 if (isHorizontalWritingMode()) {
6725 if (style()->isLeftToRightDirection())
6726 child->setMarginRight(margin);
6728 child->setMarginLeft(margin);
6730 if (style()->isLeftToRightDirection())
6731 child->setMarginBottom(margin);
6733 child->setMarginTop(margin);
6737 void RenderBlock::setMarginBeforeForChild(RenderBox* child, LayoutUnit margin)
6739 switch (style()->writingMode()) {
6740 case TopToBottomWritingMode:
6741 child->setMarginTop(margin);
6743 case BottomToTopWritingMode:
6744 child->setMarginBottom(margin);
6746 case LeftToRightWritingMode:
6747 child->setMarginLeft(margin);
6749 case RightToLeftWritingMode:
6750 child->setMarginRight(margin);
6755 void RenderBlock::setMarginAfterForChild(RenderBox* child, LayoutUnit margin)
6757 switch (style()->writingMode()) {
6758 case TopToBottomWritingMode:
6759 child->setMarginBottom(margin);
6761 case BottomToTopWritingMode:
6762 child->setMarginTop(margin);
6764 case LeftToRightWritingMode:
6765 child->setMarginRight(margin);
6767 case RightToLeftWritingMode:
6768 child->setMarginLeft(margin);
6773 RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child)
6775 int childBeforePositive = 0;
6776 int childBeforeNegative = 0;
6777 int childAfterPositive = 0;
6778 int childAfterNegative = 0;
6780 int beforeMargin = 0;
6781 int afterMargin = 0;
6783 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
6785 // If the child has the same directionality as we do, then we can just return its
6786 // margins in the same direction.
6787 if (!child->isWritingModeRoot()) {
6788 if (childRenderBlock) {
6789 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
6790 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
6791 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
6792 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
6794 beforeMargin = child->marginBefore();
6795 afterMargin = child->marginAfter();
6797 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
6798 // The child has a different directionality. If the child is parallel, then it's just
6799 // flipped relative to us. We can use the margins for the opposite edges.
6800 if (childRenderBlock) {
6801 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
6802 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
6803 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
6804 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
6806 beforeMargin = child->marginAfter();
6807 afterMargin = child->marginBefore();
6810 // The child is perpendicular to us, which means its margins don't collapse but are on the
6811 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
6812 beforeMargin = marginBeforeForChild(child);
6813 afterMargin = marginAfterForChild(child);
6816 // Resolve uncollapsing margins into their positive/negative buckets.
6818 if (beforeMargin > 0)
6819 childBeforePositive = beforeMargin;
6821 childBeforeNegative = -beforeMargin;
6824 if (afterMargin > 0)
6825 childAfterPositive = afterMargin;
6827 childAfterNegative = -afterMargin;
6830 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
6833 const char* RenderBlock::renderName() const
6836 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
6839 return "RenderBlock (floating)";
6841 return "RenderBlock (positioned)";
6842 if (isAnonymousColumnsBlock())
6843 return "RenderBlock (anonymous multi-column)";
6844 if (isAnonymousColumnSpanBlock())
6845 return "RenderBlock (anonymous multi-column span)";
6846 if (isAnonymousBlock())
6847 return "RenderBlock (anonymous)";
6848 else if (isAnonymous())
6849 return "RenderBlock (generated)";
6850 if (isRelPositioned())
6851 return "RenderBlock (relative positioned)";
6853 return "RenderBlock (run-in)";
6854 return "RenderBlock";
6857 inline void RenderBlock::FloatingObjects::clear()
6860 m_placedFloatsTree.clear();
6861 m_leftObjectsCount = 0;
6862 m_rightObjectsCount = 0;
6863 m_positionedObjectsCount = 0;
6866 inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
6868 if (type == FloatingObject::FloatLeft)
6869 m_leftObjectsCount++;
6870 else if (type == FloatingObject::FloatRight)
6871 m_rightObjectsCount++;
6873 m_positionedObjectsCount++;
6876 inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
6878 if (type == FloatingObject::FloatLeft)
6879 m_leftObjectsCount--;
6880 else if (type == FloatingObject::FloatRight)
6881 m_rightObjectsCount--;
6883 m_positionedObjectsCount--;
6886 inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
6888 if (m_horizontalWritingMode)
6889 return RenderBlock::FloatingObjectInterval(floatingObject->y(), floatingObject->maxY(), floatingObject);
6890 return RenderBlock::FloatingObjectInterval(floatingObject->x(), floatingObject->maxX(), floatingObject);
6893 void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
6895 ASSERT(!floatingObject->isInPlacedTree());
6897 floatingObject->setIsPlaced(true);
6898 if (m_placedFloatsTree.isInitialized())
6899 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
6902 floatingObject->setIsInPlacedTree(true);
6906 void RenderBlock::FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
6908 ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
6910 if (m_placedFloatsTree.isInitialized()) {
6911 bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
6912 ASSERT_UNUSED(removed, removed);
6915 floatingObject->setIsPlaced(false);
6917 floatingObject->setIsInPlacedTree(false);
6921 inline void RenderBlock::FloatingObjects::add(FloatingObject* floatingObject)
6923 increaseObjectsCount(floatingObject->type());
6924 m_set.add(floatingObject);
6925 if (floatingObject->isPlaced())
6926 addPlacedObject(floatingObject);
6929 inline void RenderBlock::FloatingObjects::remove(FloatingObject* floatingObject)
6931 decreaseObjectsCount(floatingObject->type());
6932 m_set.remove(floatingObject);
6933 ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree());
6934 if (floatingObject->isPlaced())
6935 removePlacedObject(floatingObject);
6938 void RenderBlock::FloatingObjects::computePlacedFloatsTree()
6940 ASSERT(!m_placedFloatsTree.isInitialized());
6941 if (m_set.isEmpty())
6943 m_placedFloatsTree.initIfNeeded();
6944 FloatingObjectSetIterator it = m_set.begin();
6945 FloatingObjectSetIterator end = m_set.end();
6946 for (; it != end; ++it) {
6947 FloatingObject* floatingObject = *it;
6948 if (floatingObject->isPlaced())
6949 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
6953 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const UChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags)
6957 TextDirection textDirection = LTR;
6958 bool directionalOverride = style->rtlOrdering() == VisualOrder;
6959 if (flags != DefaultTextRunFlags) {
6960 if (flags & RespectDirection)
6961 textDirection = style->direction();
6962 if (flags & RespectDirectionOverride)
6963 directionalOverride |= style->unicodeBidi() == Override;
6966 TextRun run(characters, length, false, 0, 0, expansion, textDirection, directionalOverride);
6967 if (textRunNeedsRenderingContext(font))
6968 run.setRenderingContext(SVGTextRunRenderingContext::create(context));
6973 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags)
6975 return constructTextRun(context, font, string.characters(), string.length(), style, expansion, flags);
6980 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const
6983 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
6984 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
6987 // These helpers are only used by the PODIntervalTree for debugging purposes.
6988 String ValueToString<int>::string(const int value)
6990 return String::number(value);
6993 String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject)
6995 return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->x(), floatingObject->y(), floatingObject->maxX(), floatingObject->maxY());
7000 } // namespace WebCore