2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include "RenderBlock.h"
27 #include "ColumnInfo.h"
30 #include "FloatQuad.h"
32 #include "FrameSelection.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLNames.h"
37 #include "HitTestResult.h"
38 #include "InlineIterator.h"
39 #include "InlineTextBox.h"
40 #include "LayoutRepainter.h"
41 #include "OverflowEvent.h"
42 #include "PODFreeListArena.h"
44 #include "PaintInfo.h"
45 #include "RenderBoxRegionInfo.h"
46 #include "RenderCombineText.h"
47 #include "RenderDeprecatedFlexibleBox.h"
48 #include "RenderImage.h"
49 #include "RenderInline.h"
50 #include "RenderLayer.h"
51 #include "RenderMarquee.h"
52 #include "RenderNamedFlowThread.h"
53 #include "RenderRegion.h"
54 #include "RenderReplica.h"
55 #include "RenderTableCell.h"
56 #include "RenderTextFragment.h"
57 #include "RenderTheme.h"
58 #include "RenderView.h"
60 #include "SVGTextRunRenderingContext.h"
61 #include "ShadowRoot.h"
62 #include "TransformState.h"
63 #include <wtf/StdLibExtras.h>
67 using namespace Unicode;
71 using namespace HTMLNames;
73 struct SameSizeAsRenderBlock : public RenderBox {
75 RenderObjectChildList children;
76 RenderLineBoxList lineBoxes;
80 COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small);
82 struct SameSizeAsFloatingObject {
86 uint32_t bitfields : 8;
89 COMPILE_ASSERT(sizeof(RenderBlock::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
91 struct SameSizeAsMarginInfo {
92 uint32_t bitfields : 16;
93 LayoutUnit margins[2];
96 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
97 static ColumnInfoMap* gColumnInfoMap = 0;
99 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
100 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
102 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
103 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
105 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
107 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
108 static int gDelayUpdateScrollInfo = 0;
109 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
111 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
113 // This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
114 // only works on RenderBlocks. If this change, this class should be shared with other RenderBoxes.
115 class OverflowEventDispatcher {
116 WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher);
118 OverflowEventDispatcher(const RenderBlock* block)
120 , m_hadHorizontalLayoutOverflow(false)
121 , m_hadVerticalLayoutOverflow(false)
123 m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER);
124 if (m_shouldDispatchEvent) {
125 m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
126 m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
130 ~OverflowEventDispatcher()
132 if (!m_shouldDispatchEvent)
135 bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
136 bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
138 bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow;
139 bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow;
140 if (horizontalLayoutOverflowChanged || verticalLayoutOverflowChanged) {
141 if (FrameView* frameView = m_block->document()->view())
142 frameView->scheduleEvent(OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow), m_block->node());
147 const RenderBlock* m_block;
148 bool m_shouldDispatchEvent;
149 bool m_hadHorizontalLayoutOverflow;
150 bool m_hadVerticalLayoutOverflow;
153 // Our MarginInfo state used when laying out block children.
154 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
155 : m_atBeforeSideOfBlock(true)
156 , m_atAfterSideOfBlock(false)
157 , m_marginBeforeQuirk(false)
158 , m_marginAfterQuirk(false)
159 , m_determinedMarginBeforeQuirk(false)
161 // Whether or not we can collapse our own margins with our children. We don't do this
162 // if we had any border/padding (obviously), if we're the root or HTML elements, or if
163 // we're positioned, floating, a table cell.
164 RenderStyle* blockStyle = block->style();
165 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
166 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
167 && !block->isWritingModeRoot() && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth()
168 && !blockStyle->columnSpan();
170 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
172 // If any height other than auto is specified in CSS, then we don't collapse our bottom
173 // margins with our children's margins. To do otherwise would be to risk odd visual
174 // effects when the children overflow out of the parent block and yet still collapse
175 // with it. We also don't collapse if we have any bottom border/padding.
176 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
177 (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
179 m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD
180 || blockStyle->marginAfterCollapse() == MDISCARD;
182 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : ZERO_LAYOUT_UNIT;
183 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : ZERO_LAYOUT_UNIT;
186 // -------------------------------------------------------------------------------------------------------
188 RenderBlock::RenderBlock(Node* node)
191 , m_beingDestroyed(false)
192 , m_hasMarkupTruncation(false)
194 setChildrenInline(true);
195 COMPILE_ASSERT(sizeof(RenderBlock::FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
196 COMPILE_ASSERT(sizeof(RenderBlock::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
199 RenderBlock::~RenderBlock()
201 if (m_floatingObjects)
202 deleteAllValues(m_floatingObjects->set());
205 delete gColumnInfoMap->take(this);
207 if (gPercentHeightDescendantsMap) {
208 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
209 HashSet<RenderBox*>::iterator end = descendantSet->end();
210 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
211 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
212 ASSERT(containerSet);
215 ASSERT(containerSet->contains(this));
216 containerSet->remove(this);
217 if (containerSet->isEmpty()) {
218 gPercentHeightContainerMap->remove(*descendant);
222 delete descendantSet;
227 void RenderBlock::willBeDestroyed()
229 // Mark as being destroyed to avoid trouble with merges in removeChild().
230 m_beingDestroyed = true;
232 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
233 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
234 children()->destroyLeftoverChildren();
236 // Destroy our continuation before anything other than anonymous children.
237 // The reason we don't destroy it before anonymous children is that they may
238 // have continuations of their own that are anonymous children of our continuation.
239 RenderBoxModelObject* continuation = this->continuation();
241 continuation->destroy();
245 if (!documentBeingDestroyed()) {
246 if (firstLineBox()) {
247 // We can't wait for RenderBox::destroy to clear the selection,
248 // because by then we will have nuked the line boxes.
249 // FIXME: The FrameSelection should be responsible for this when it
250 // is notified of DOM mutations.
251 if (isSelectionBorder())
252 view()->clearSelection();
254 // If we are an anonymous block, then our line boxes might have children
255 // that will outlast this block. In the non-anonymous block case those
256 // children will be destroyed by the time we return from this function.
257 if (isAnonymousBlock()) {
258 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
259 while (InlineBox* childBox = box->firstChild())
264 parent()->dirtyLinesFromChangedChild(this);
267 m_lineBoxes.deleteLineBoxes(renderArena());
270 lineGridBox()->destroy(renderArena());
272 if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
273 gDelayedUpdateScrollInfoSet->remove(this);
275 RenderBox::willBeDestroyed();
278 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
280 RenderStyle* oldStyle = style();
281 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
283 setReplaced(newStyle->isDisplayInlineType());
285 if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
286 if (newStyle->position() == StaticPosition)
287 // Clear our positioned objects list. Our absolutely positioned descendants will be
288 // inserted into our containing block's positioned objects list during layout.
289 removePositionedObjects(0);
290 else if (oldStyle->position() == StaticPosition) {
291 // Remove our absolutely positioned descendants from their current containing block.
292 // They will be inserted into our positioned objects list during layout.
293 RenderObject* cb = parent();
294 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
295 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
296 cb = cb->containingBlock();
302 if (cb->isRenderBlock())
303 toRenderBlock(cb)->removePositionedObjects(this);
306 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
307 markAllDescendantsWithFloatsForLayout();
310 RenderBox::styleWillChange(diff, newStyle);
313 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
315 RenderBox::styleDidChange(diff, oldStyle);
317 if (!isAnonymousBlock()) {
318 // Ensure that all of our continuation blocks pick up the new style.
319 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
320 RenderBoxModelObject* nextCont = currCont->continuation();
321 currCont->setContinuation(0);
322 currCont->setStyle(style());
323 currCont->setContinuation(nextCont);
327 propagateStyleToAnonymousChildren(true);
330 // Update pseudos for :before and :after now.
331 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveGeneratedChildren()) {
332 updateBeforeAfterContent(BEFORE);
333 updateBeforeAfterContent(AFTER);
336 // After our style changed, if we lose our ability to propagate floats into next sibling
337 // blocks, then we need to find the top most parent containing that overhanging float and
338 // then mark its descendants with floats for layout and clear all floats from its next
339 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
340 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
341 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
342 RenderBlock* parentBlock = this;
343 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
344 FloatingObjectSetIterator end = floatingObjectSet.end();
346 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
347 if (curr->isRenderBlock()) {
348 RenderBlock* currBlock = toRenderBlock(curr);
350 if (currBlock->hasOverhangingFloats()) {
351 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
352 RenderBox* renderer = (*it)->renderer();
353 if (currBlock->hasOverhangingFloat(renderer)) {
354 parentBlock = currBlock;
362 parentBlock->markAllDescendantsWithFloatsForLayout();
363 parentBlock->markSiblingsWithFloatsForLayout();
367 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
369 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
370 if (parent() && parent()->createsAnonymousWrapper())
372 children()->updateBeforeAfterContent(this, pseudoId);
375 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
377 if (beforeChild && beforeChild->parent() == this)
380 RenderBlock* curr = toRenderBlock(continuation());
381 RenderBlock* nextToLast = this;
382 RenderBlock* last = this;
384 if (beforeChild && beforeChild->parent() == curr) {
385 if (curr->firstChild() == beforeChild)
392 curr = toRenderBlock(curr->continuation());
395 if (!beforeChild && !last->firstChild())
400 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
402 RenderBlock* flow = continuationBefore(beforeChild);
403 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
404 RenderBoxModelObject* beforeChildParent = 0;
406 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
408 RenderBoxModelObject* cont = flow->continuation();
410 beforeChildParent = cont;
412 beforeChildParent = flow;
415 if (newChild->isFloatingOrOutOfFlowPositioned()) {
416 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
420 // A continuation always consists of two potential candidates: a block or an anonymous
421 // column span box holding column span children.
422 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
423 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
424 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
426 if (flow == beforeChildParent) {
427 flow->addChildIgnoringContinuation(newChild, beforeChild);
431 // The goal here is to match up if we can, so that we can coalesce and create the
432 // minimal # of continuations needed for the inline.
433 if (childIsNormal == bcpIsNormal) {
434 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
437 if (flowIsNormal == childIsNormal) {
438 flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
441 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
445 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
447 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
449 // The goal is to locate a suitable box in which to place our child.
450 RenderBlock* beforeChildParent = 0;
452 RenderObject* curr = beforeChild;
453 while (curr && curr->parent() != this)
454 curr = curr->parent();
455 beforeChildParent = toRenderBlock(curr);
456 ASSERT(beforeChildParent);
457 ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock());
459 beforeChildParent = toRenderBlock(lastChild());
461 // If the new child is floating or positioned it can just go in that block.
462 if (newChild->isFloatingOrOutOfFlowPositioned()) {
463 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
467 // See if the child can be placed in the box.
468 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
469 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
471 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
472 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
477 // Create a new block of the correct type.
478 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
479 children()->appendChildNode(this, newBox);
480 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
484 RenderObject* immediateChild = beforeChild;
485 bool isPreviousBlockViable = true;
486 while (immediateChild->parent() != this) {
487 if (isPreviousBlockViable)
488 isPreviousBlockViable = !immediateChild->previousSibling();
489 immediateChild = immediateChild->parent();
491 if (isPreviousBlockViable && immediateChild->previousSibling()) {
492 toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
496 // Split our anonymous blocks.
497 RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild);
500 // Create a new anonymous box of the appropriate type.
501 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
502 children()->insertChildNode(this, newBox, newBeforeChild);
503 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
507 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
509 RenderBlock* firstChildIgnoringAnonymousWrappers = 0;
510 for (RenderObject* curr = this; curr; curr = curr->parent()) {
511 if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
512 || curr->isInlineBlockOrInlineTable())
515 // FIXME: Table manages its own table parts, most of which are RenderBoxes.
516 // Multi-column code cannot handle splitting the flow in table. Disabling it
517 // to prevent crashes.
521 RenderBlock* currBlock = toRenderBlock(curr);
522 if (!currBlock->createsAnonymousWrapper())
523 firstChildIgnoringAnonymousWrappers = currBlock;
525 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
526 return firstChildIgnoringAnonymousWrappers;
528 if (currBlock->isAnonymousColumnSpanBlock())
534 RenderBlock* RenderBlock::clone() const
536 RenderBlock* cloneBlock;
537 if (isAnonymousBlock()) {
538 cloneBlock = createAnonymousBlock();
539 cloneBlock->setChildrenInline(childrenInline());
542 RenderObject* cloneRenderer = node()->createRenderer(renderArena(), style());
543 cloneBlock = toRenderBlock(cloneRenderer);
544 cloneBlock->setStyle(style());
546 // This takes care of setting the right value of childrenInline in case
547 // generated content is added to cloneBlock and 'this' does not have
548 // generated content added yet.
549 cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
554 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
555 RenderBlock* middleBlock,
556 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
558 // Create a clone of this inline.
559 RenderBlock* cloneBlock = clone();
560 if (!isAnonymousBlock())
561 cloneBlock->setContinuation(oldCont);
563 if (!beforeChild && isAfterContent(lastChild()))
564 beforeChild = lastChild();
566 // If we are moving inline children from |this| to cloneBlock, then we need
567 // to clear our line box tree.
568 if (beforeChild && childrenInline())
571 // Now take all of the children from beforeChild to the end and remove
572 // them from |this| and place them in the clone.
573 moveChildrenTo(cloneBlock, beforeChild, 0, true);
575 // Hook |clone| up as the continuation of the middle block.
576 if (!cloneBlock->isAnonymousBlock())
577 middleBlock->setContinuation(cloneBlock);
579 // We have been reparented and are now under the fromBlock. We need
580 // to walk up our block parent chain until we hit the containing anonymous columns block.
581 // Once we hit the anonymous columns block we're done.
582 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
583 RenderBoxModelObject* currChild = this;
584 RenderObject* currChildNextSibling = currChild->nextSibling();
585 bool documentUsesBeforeAfterRules = document()->usesBeforeAfterRules();
587 // Note: |this| can be destroyed inside this loop if it is an empty anonymous
588 // block and we try to call updateBeforeAfterContent inside which removes the
589 // generated content and additionally cleans up |this| empty anonymous block.
590 // See RenderBlock::removeChild(). DO NOT reference any local variables to |this|
592 while (curr && curr != fromBlock) {
593 ASSERT(curr->isRenderBlock());
595 RenderBlock* blockCurr = toRenderBlock(curr);
597 // Create a new clone.
598 RenderBlock* cloneChild = cloneBlock;
599 cloneBlock = blockCurr->clone();
601 // Insert our child clone as the first child.
602 cloneBlock->addChildIgnoringContinuation(cloneChild, 0);
604 // Hook the clone up as a continuation of |curr|. Note we do encounter
605 // anonymous blocks possibly as we walk up the block chain. When we split an
606 // anonymous block, there's no need to do any continuation hookup, since we haven't
607 // actually split a real element.
608 if (!blockCurr->isAnonymousBlock()) {
609 oldCont = blockCurr->continuation();
610 blockCurr->setContinuation(cloneBlock);
611 cloneBlock->setContinuation(oldCont);
614 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
615 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
616 // content gets properly destroyed.
617 bool isLastChild = (currChildNextSibling == blockCurr->lastChild());
618 if (documentUsesBeforeAfterRules)
619 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
620 if (isLastChild && currChildNextSibling != blockCurr->lastChild())
621 currChildNextSibling = 0; // We destroyed the last child, so now we need to update
622 // the value of currChildNextSibling.
624 // Now we need to take all of the children starting from the first child
625 // *after* currChild and append them all to the clone.
626 blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
628 // Keep walking up the chain.
630 currChildNextSibling = currChild->nextSibling();
631 curr = toRenderBoxModelObject(curr->parent());
634 // Now we are at the columns block level. We need to put the clone into the toBlock.
635 toBlock->children()->appendChildNode(toBlock, cloneBlock);
637 // Now take all the children after currChild and remove them from the fromBlock
638 // and put them in the toBlock.
639 fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true);
642 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
643 RenderObject* newChild, RenderBoxModelObject* oldCont)
645 RenderBlock* pre = 0;
646 RenderBlock* block = containingColumnsBlock();
648 // Delete our line boxes before we do the inline split into continuations.
649 block->deleteLineBoxTree();
651 bool madeNewBeforeBlock = false;
652 if (block->isAnonymousColumnsBlock()) {
653 // We can reuse this block and make it the preBlock of the next continuation.
655 pre->removePositionedObjects(0);
656 block = toRenderBlock(block->parent());
658 // No anonymous block available for use. Make one.
659 pre = block->createAnonymousColumnsBlock();
660 pre->setChildrenInline(false);
661 madeNewBeforeBlock = true;
664 RenderBlock* post = block->createAnonymousColumnsBlock();
665 post->setChildrenInline(false);
667 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
668 if (madeNewBeforeBlock)
669 block->children()->insertChildNode(block, pre, boxFirst);
670 block->children()->insertChildNode(block, newBlockBox, boxFirst);
671 block->children()->insertChildNode(block, post, boxFirst);
672 block->setChildrenInline(false);
674 if (madeNewBeforeBlock)
675 block->moveChildrenTo(pre, boxFirst, 0, true);
677 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
679 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
680 // time in makeChildrenNonInline by just setting this explicitly up front.
681 newBlockBox->setChildrenInline(false);
683 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
684 // connected, thus allowing newChild access to a renderArena should it need
685 // to wrap itself in additional boxes (e.g., table construction).
686 newBlockBox->addChild(newChild);
688 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
689 // get deleted properly. Because objects moves from the pre block into the post block, we want to
690 // make new line boxes instead of leaving the old line boxes around.
691 pre->setNeedsLayoutAndPrefWidthsRecalc();
692 block->setNeedsLayoutAndPrefWidthsRecalc();
693 post->setNeedsLayoutAndPrefWidthsRecalc();
696 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
698 RenderBlock* pre = 0;
699 RenderBlock* post = 0;
700 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
701 // so that we don't have to patch all of the rest of the code later on.
703 // Delete the block's line boxes before we do the split.
704 block->deleteLineBoxTree();
706 if (beforeChild && beforeChild->parent() != this)
707 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
709 if (beforeChild != firstChild()) {
710 pre = block->createAnonymousColumnsBlock();
711 pre->setChildrenInline(block->childrenInline());
715 post = block->createAnonymousColumnsBlock();
716 post->setChildrenInline(block->childrenInline());
719 RenderObject* boxFirst = block->firstChild();
721 block->children()->insertChildNode(block, pre, boxFirst);
722 block->children()->insertChildNode(block, newBlockBox, boxFirst);
724 block->children()->insertChildNode(block, post, boxFirst);
725 block->setChildrenInline(false);
727 // 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).
728 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
729 block->moveChildrenTo(post, beforeChild, 0, true);
731 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
732 // time in makeChildrenNonInline by just setting this explicitly up front.
733 newBlockBox->setChildrenInline(false);
735 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
736 // connected, thus allowing newChild access to a renderArena should it need
737 // to wrap itself in additional boxes (e.g., table construction).
738 newBlockBox->addChild(newChild);
740 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
741 // get deleted properly. Because objects moved from the pre block into the post block, we want to
742 // make new line boxes instead of leaving the old line boxes around.
744 pre->setNeedsLayoutAndPrefWidthsRecalc();
745 block->setNeedsLayoutAndPrefWidthsRecalc();
747 post->setNeedsLayoutAndPrefWidthsRecalc();
750 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
752 // FIXME: This function is the gateway for the addition of column-span support. It will
753 // be added to in three stages:
754 // (1) Immediate children of a multi-column block can span.
755 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
756 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
757 // cross the streams and have to cope with both types of continuations mixed together).
758 // This function currently supports (1) and (2).
759 RenderBlock* columnsBlockAncestor = 0;
760 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent()
761 && !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
762 columnsBlockAncestor = containingColumnsBlock(false);
763 if (columnsBlockAncestor) {
764 // Make sure that none of the parent ancestors have a continuation.
765 // If yes, we do not want split the block into continuations.
766 RenderObject* curr = this;
767 while (curr && curr != columnsBlockAncestor) {
768 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
769 columnsBlockAncestor = 0;
772 curr = curr->parent();
776 return columnsBlockAncestor;
779 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
781 // Make sure we don't append things after :after-generated content if we have it.
783 beforeChild = afterPseudoElementRenderer();
785 if (beforeChild && beforeChild->parent() != this) {
786 RenderObject* beforeChildContainer = beforeChild->parent();
787 while (beforeChildContainer->parent() != this)
788 beforeChildContainer = beforeChildContainer->parent();
789 ASSERT(beforeChildContainer);
791 if (beforeChildContainer->isAnonymous()) {
792 // If the requested beforeChild is not one of our children, then this is because
793 // there is an anonymous container within this object that contains the beforeChild.
794 RenderObject* beforeChildAnonymousContainer = beforeChildContainer;
795 if (beforeChildAnonymousContainer->isAnonymousBlock()
796 #if ENABLE(FULLSCREEN_API)
797 // Full screen renderers and full screen placeholders act as anonymous blocks, not tables:
798 || beforeChildAnonymousContainer->isRenderFullScreen()
799 || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder()
802 // Insert the child into the anonymous block box instead of here.
803 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
804 beforeChild->parent()->addChild(newChild, beforeChild);
806 addChild(newChild, beforeChild->parent());
810 ASSERT(beforeChildAnonymousContainer->isTable());
811 if (newChild->isTablePart()) {
812 // Insert into the anonymous table.
813 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
817 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
819 ASSERT(beforeChild->parent() == this);
820 if (beforeChild->parent() != this) {
821 // We should never reach here. If we do, we need to use the
822 // safe fallback to use the topmost beforeChild container.
823 beforeChild = beforeChildContainer;
826 // We will reach here when beforeChild is a run-in element.
827 // If run-in element precedes a block-level element, it becomes the
828 // the first inline child of that block level element. The insertion
829 // point will be before that block-level element.
830 ASSERT(beforeChild->isRunIn());
831 beforeChild = beforeChildContainer;
835 // Nothing goes before the intruded run-in.
836 if (beforeChild && beforeChild->isRunIn() && runInIsPlacedIntoSiblingBlock(beforeChild))
837 beforeChild = beforeChild->nextSibling();
839 // Check for a spanning element in columns.
840 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
841 if (columnsBlockAncestor) {
842 // We are placing a column-span element inside a block.
843 RenderBlock* newBox = createAnonymousColumnSpanBlock();
845 if (columnsBlockAncestor != this) {
846 // We are nested inside a multi-column element and are being split by the span. We have to break up
847 // our block into continuations.
848 RenderBoxModelObject* oldContinuation = continuation();
850 // When we split an anonymous block, there's no need to do any continuation hookup,
851 // since we haven't actually split a real element.
852 if (!isAnonymousBlock())
853 setContinuation(newBox);
855 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
856 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
857 // content gets properly destroyed.
858 bool isFirstChild = (beforeChild == firstChild());
859 bool isLastChild = (beforeChild == lastChild());
860 if (document()->usesBeforeAfterRules())
861 children()->updateBeforeAfterContent(this, AFTER);
862 if (isLastChild && beforeChild != lastChild()) {
863 // We destroyed the last child, so now we need to update our insertion
864 // point to be 0. It's just a straight append now.
866 } else if (isFirstChild && beforeChild != firstChild()) {
867 // If beforeChild was the last anonymous block that collapsed,
868 // then we need to update its value.
869 beforeChild = firstChild();
872 splitFlow(beforeChild, newBox, newChild, oldContinuation);
876 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
877 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
878 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
879 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
883 bool madeBoxesNonInline = false;
885 // A block has to either have all of its children inline, or all of its children as blocks.
886 // So, if our children are currently inline and a block child has to be inserted, we move all our
887 // inline children into anonymous block boxes.
888 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
889 // This is a block with inline content. Wrap the inline content in anonymous blocks.
890 makeChildrenNonInline(beforeChild);
891 madeBoxesNonInline = true;
893 if (beforeChild && beforeChild->parent() != this) {
894 beforeChild = beforeChild->parent();
895 ASSERT(beforeChild->isAnonymousBlock());
896 ASSERT(beforeChild->parent() == this);
898 } else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) {
899 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
900 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
901 // a new one is created and inserted into our list of children in the appropriate position.
902 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
904 if (afterChild && afterChild->isAnonymousBlock()) {
905 afterChild->addChild(newChild);
909 if (newChild->isInline()) {
910 // No suitable existing anonymous box - create a new one.
911 RenderBlock* newBox = createAnonymousBlock();
912 RenderBox::addChild(newBox, beforeChild);
913 newBox->addChild(newChild);
918 RenderBox::addChild(newChild, beforeChild);
920 // Handle placement of run-ins.
921 placeRunInIfNeeded(newChild, DoNotPlaceGeneratedRunIn);
923 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
924 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
925 // this object may be dead here
928 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
930 if (continuation() && !isAnonymousBlock())
931 addChildToContinuation(newChild, beforeChild);
933 addChildIgnoringContinuation(newChild, beforeChild);
936 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
938 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
939 addChildToAnonymousColumnBlocks(newChild, beforeChild);
941 addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
944 static void getInlineRun(RenderObject* start, RenderObject* boundary,
945 RenderObject*& inlineRunStart,
946 RenderObject*& inlineRunEnd)
948 // Beginning at |start| we find the largest contiguous run of inlines that
949 // we can. We denote the run with start and end points, |inlineRunStart|
950 // and |inlineRunEnd|. Note that these two values may be the same if
951 // we encounter only one inline.
953 // We skip any non-inlines we encounter as long as we haven't found any
956 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
957 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
960 // Start by skipping as many non-inlines as we can.
961 RenderObject * curr = start;
964 while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()))
965 curr = curr->nextSibling();
967 inlineRunStart = inlineRunEnd = curr;
970 return; // No more inline children to be found.
972 sawInline = curr->isInline();
974 curr = curr->nextSibling();
975 while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) {
977 if (curr->isInline())
979 curr = curr->nextSibling();
981 } while (!sawInline);
984 void RenderBlock::deleteLineBoxTree()
986 if (containsFloats()) {
987 // Clear references to originating lines, since the lines are being deleted
988 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
989 FloatingObjectSetIterator end = floatingObjectSet.end();
990 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
991 ASSERT(!((*it)->m_originatingLine) || (*it)->m_originatingLine->renderer() == this);
992 (*it)->m_originatingLine = 0;
995 m_lineBoxes.deleteLineBoxTree(renderArena());
998 RootInlineBox* RenderBlock::createRootInlineBox()
1000 return new (renderArena()) RootInlineBox(this);
1003 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
1005 RootInlineBox* rootBox = createRootInlineBox();
1006 m_lineBoxes.appendLineBox(rootBox);
1010 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
1012 // makeChildrenNonInline takes a block whose children are *all* inline and it
1013 // makes sure that inline children are coalesced under anonymous
1014 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
1015 // the new block child that is causing us to have to wrap all the inlines. This
1016 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
1017 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
1019 ASSERT(isInlineBlockOrInlineTable() || !isInline());
1020 ASSERT(!insertionPoint || insertionPoint->parent() == this);
1022 setChildrenInline(false);
1024 RenderObject *child = firstChild();
1028 deleteLineBoxTree();
1030 // Since we are going to have block children, we have to move
1031 // back the run-in to its original place.
1032 if (child->isRunIn()) {
1033 moveRunInToOriginalPosition(child);
1034 child = firstChild();
1038 RenderObject *inlineRunStart, *inlineRunEnd;
1039 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
1041 if (!inlineRunStart)
1044 child = inlineRunEnd->nextSibling();
1046 RenderBlock* block = createAnonymousBlock();
1047 children()->insertChildNode(this, block, inlineRunStart);
1048 moveChildrenTo(block, inlineRunStart, child);
1052 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
1053 ASSERT(!c->isInline());
1059 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
1061 ASSERT(child->isAnonymousBlock());
1062 ASSERT(!child->childrenInline());
1064 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
1067 RenderObject* firstAnChild = child->m_children.firstChild();
1068 RenderObject* lastAnChild = child->m_children.lastChild();
1070 RenderObject* o = firstAnChild;
1073 o = o->nextSibling();
1075 firstAnChild->setPreviousSibling(child->previousSibling());
1076 lastAnChild->setNextSibling(child->nextSibling());
1077 if (child->previousSibling())
1078 child->previousSibling()->setNextSibling(firstAnChild);
1079 if (child->nextSibling())
1080 child->nextSibling()->setPreviousSibling(lastAnChild);
1082 if (child == m_children.firstChild())
1083 m_children.setFirstChild(firstAnChild);
1084 if (child == m_children.lastChild())
1085 m_children.setLastChild(lastAnChild);
1087 if (child == m_children.firstChild())
1088 m_children.setFirstChild(child->nextSibling());
1089 if (child == m_children.lastChild())
1090 m_children.setLastChild(child->previousSibling());
1092 if (child->previousSibling())
1093 child->previousSibling()->setNextSibling(child->nextSibling());
1094 if (child->nextSibling())
1095 child->nextSibling()->setPreviousSibling(child->previousSibling());
1097 child->setParent(0);
1098 child->setPreviousSibling(0);
1099 child->setNextSibling(0);
1101 child->children()->setFirstChild(0);
1107 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
1109 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
1112 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
1113 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
1116 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
1117 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
1120 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
1121 || (next && (next->isRubyRun() || next->isRubyBase())))
1127 // Make sure the types of the anonymous blocks match up.
1128 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1129 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1132 void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* child)
1134 parent->setNeedsLayoutAndPrefWidthsRecalc();
1135 parent->setChildrenInline(child->childrenInline());
1136 RenderObject* nextSibling = child->nextSibling();
1138 RenderFlowThread* childFlowThread = child->enclosingRenderFlowThread();
1139 RenderBlock* anonBlock = toRenderBlock(parent->children()->removeChildNode(parent, child, child->hasLayer()));
1140 anonBlock->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
1141 // Delete the now-empty block's lines and nuke it.
1142 if (!parent->documentBeingDestroyed())
1143 anonBlock->deleteLineBoxTree();
1144 if (!parent->documentBeingDestroyed() && childFlowThread && childFlowThread->isRenderNamedFlowThread())
1145 toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(anonBlock);
1146 anonBlock->destroy();
1149 void RenderBlock::removeChild(RenderObject* oldChild)
1151 // If this child is a block, and if our previous and next siblings are
1152 // both anonymous blocks with inline content, then we can go ahead and
1153 // fold the inline content back together.
1154 RenderObject* prev = oldChild->previousSibling();
1155 RenderObject* next = oldChild->nextSibling();
1156 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1157 if (canMergeAnonymousBlocks && prev && next) {
1158 prev->setNeedsLayoutAndPrefWidthsRecalc();
1159 RenderBlock* nextBlock = toRenderBlock(next);
1160 RenderBlock* prevBlock = toRenderBlock(prev);
1162 if (prev->childrenInline() != next->childrenInline()) {
1163 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1164 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1166 // Place the inline children block inside of the block children block instead of deleting it.
1167 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1168 // to clear out inherited column properties by just making a new style, and to also clear the
1169 // column span flag if it is set.
1170 ASSERT(!inlineChildrenBlock->continuation());
1171 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
1172 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
1173 inlineChildrenBlock->setStyle(newStyle);
1175 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1176 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1177 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer());
1178 next->setNeedsLayoutAndPrefWidthsRecalc();
1180 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1181 // of "this". we null out prev or next so that is not used later in the function.
1182 if (inlineChildrenBlock == prevBlock)
1187 // Take all the children out of the |next| block and put them in
1188 // the |prev| block.
1189 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1191 // Delete the now-empty block's lines and nuke it.
1192 nextBlock->deleteLineBoxTree();
1193 nextBlock->destroy();
1198 RenderBox::removeChild(oldChild);
1200 RenderObject* child = prev ? prev : next;
1201 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBoxIncludingDeprecated()) {
1202 // The removal has knocked us down to containing only a single anonymous
1203 // box. We can go ahead and pull the content right back up into our
1205 collapseAnonymousBoxChild(this, child);
1206 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && !isFlexibleBoxIncludingDeprecated()) {
1207 // It's possible that the removal has knocked us down to a single anonymous
1208 // block with pseudo-style element siblings (e.g. first-letter). If these
1209 // are floating, then we need to pull the content up also.
1210 RenderBlock* anonBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1211 if ((anonBlock->previousSibling() || anonBlock->nextSibling())
1212 && (!anonBlock->previousSibling() || (anonBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonBlock->previousSibling()->isFloating() && !anonBlock->previousSibling()->previousSibling()))
1213 && (!anonBlock->nextSibling() || (anonBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonBlock->nextSibling()->isFloating() && !anonBlock->nextSibling()->nextSibling()))) {
1214 collapseAnonymousBoxChild(this, anonBlock);
1218 if (!firstChild() && !documentBeingDestroyed()) {
1219 // If this was our last child be sure to clear out our line boxes.
1220 if (childrenInline())
1221 deleteLineBoxTree();
1223 // If we are an empty anonymous block in the continuation chain,
1224 // we need to remove ourself and fix the continuation chain.
1225 if (!beingDestroyed() && isAnonymousBlockContinuation()) {
1226 RenderObject* containingBlockIgnoringAnonymous = containingBlock();
1227 while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock())
1228 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
1229 for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
1230 if (curr->virtualContinuation() != this)
1233 // Found our previous continuation. We just need to point it to
1234 // |this|'s next continuation.
1235 RenderBoxModelObject* nextContinuation = continuation();
1236 if (curr->isRenderInline())
1237 toRenderInline(curr)->setContinuation(nextContinuation);
1238 else if (curr->isRenderBlock())
1239 toRenderBlock(curr)->setContinuation(nextContinuation);
1241 ASSERT_NOT_REACHED();
1251 bool RenderBlock::isSelfCollapsingBlock() const
1253 // We are not self-collapsing if we
1254 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1256 // (c) have border/padding,
1257 // (d) have a min-height
1258 // (e) have specified that one of our margins can't collapse using a CSS extension
1259 if (logicalHeight() > ZERO_LAYOUT_UNIT
1260 || isTable() || borderAndPaddingLogicalHeight()
1261 || style()->logicalMinHeight().isPositive()
1262 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1265 Length logicalHeightLength = style()->logicalHeight();
1266 bool hasAutoHeight = logicalHeightLength.isAuto();
1267 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1268 hasAutoHeight = true;
1269 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1270 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1271 hasAutoHeight = false;
1275 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1276 // on whether we have content that is all self-collapsing or not.
1277 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1278 // If the block has inline children, see if we generated any line boxes. If we have any
1279 // line boxes, then we can't be self-collapsing, since we have content.
1280 if (childrenInline())
1281 return !firstLineBox();
1283 // Whether or not we collapse is dependent on whether all our normal flow children
1284 // are also self-collapsing.
1285 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1286 if (child->isFloatingOrOutOfFlowPositioned())
1288 if (!child->isSelfCollapsingBlock())
1296 void RenderBlock::startDelayUpdateScrollInfo()
1298 if (gDelayUpdateScrollInfo == 0) {
1299 ASSERT(!gDelayedUpdateScrollInfoSet);
1300 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1302 ASSERT(gDelayedUpdateScrollInfoSet);
1303 ++gDelayUpdateScrollInfo;
1306 void RenderBlock::finishDelayUpdateScrollInfo()
1308 --gDelayUpdateScrollInfo;
1309 ASSERT(gDelayUpdateScrollInfo >= 0);
1310 if (gDelayUpdateScrollInfo == 0) {
1311 ASSERT(gDelayedUpdateScrollInfoSet);
1313 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1314 gDelayedUpdateScrollInfoSet = 0;
1316 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1317 RenderBlock* block = *it;
1318 if (block->hasOverflowClip()) {
1319 block->layer()->updateScrollInfoAfterLayout();
1325 void RenderBlock::updateScrollInfoAfterLayout()
1327 if (hasOverflowClip()) {
1328 if (gDelayUpdateScrollInfo)
1329 gDelayedUpdateScrollInfoSet->add(this);
1331 layer()->updateScrollInfoAfterLayout();
1335 void RenderBlock::layout()
1337 OverflowEventDispatcher dispatcher(this);
1339 // Update our first letter info now.
1340 updateFirstLetter();
1342 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1346 // It's safe to check for control clip here, since controls can never be table cells.
1347 // If we have a lightweight clip, there can never be any overflow from children.
1348 if (hasControlClip() && m_overflow)
1349 clearLayoutOverflow();
1352 void RenderBlock::computeInitialRegionRangeForBlock()
1354 if (inRenderFlowThread()) {
1355 // Set our start and end regions. No regions above or below us will be considered by our children. They are
1356 // effectively clamped to our region range.
1357 LayoutUnit oldHeight = logicalHeight();
1358 LayoutUnit oldLogicalTop = logicalTop();
1359 setLogicalHeight(MAX_LAYOUT_UNIT / 2);
1360 computeLogicalHeight();
1361 enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1362 setLogicalHeight(oldHeight);
1363 setLogicalTop(oldLogicalTop);
1367 void RenderBlock::computeRegionRangeForBlock()
1369 if (inRenderFlowThread())
1370 enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1373 bool RenderBlock::recomputeLogicalWidth()
1375 LayoutUnit oldWidth = logicalWidth();
1376 LayoutUnit oldColumnWidth = desiredColumnWidth();
1378 computeLogicalWidth();
1381 return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth();
1384 void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
1386 ColumnInfo* colInfo = columnInfo();
1388 if (!pageLogicalHeight) {
1389 // We need to go ahead and set our explicit page height if one exists, so that we can
1390 // avoid doing two layout passes.
1391 computeLogicalHeight();
1392 LayoutUnit columnHeight = contentLogicalHeight();
1393 if (columnHeight > ZERO_LAYOUT_UNIT) {
1394 pageLogicalHeight = columnHeight;
1395 hasSpecifiedPageLogicalHeight = true;
1397 setLogicalHeight(ZERO_LAYOUT_UNIT);
1399 if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
1400 colInfo->setColumnHeight(pageLogicalHeight);
1401 pageLogicalHeightChanged = true;
1404 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1405 colInfo->clearForcedBreaks();
1407 colInfo->setPaginationUnit(paginationUnit());
1411 void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
1413 ASSERT(needsLayout());
1415 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1416 return; // cause us to come in here. Just bail.
1418 if (!relayoutChildren && simplifiedLayout())
1421 LayoutRepainter repainter(*this, everHadLayout() && checkForRepaintDuringLayout());
1423 if (recomputeLogicalWidth())
1424 relayoutChildren = true;
1430 LayoutUnit previousHeight = logicalHeight();
1431 setLogicalHeight(ZERO_LAYOUT_UNIT);
1433 bool pageLogicalHeightChanged = false;
1434 bool hasSpecifiedPageLogicalHeight = false;
1435 checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight);
1437 RenderView* renderView = view();
1438 RenderStyle* styleToUse = style();
1439 LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo());
1441 if (inRenderFlowThread()) {
1442 // Regions changing widths can force us to relayout our children.
1443 if (logicalWidthChangedInRegions())
1444 relayoutChildren = true;
1446 computeInitialRegionRangeForBlock();
1448 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1449 // our current maximal positive and negative margins. These values are used when we
1450 // are collapsed with adjacent blocks, so for example, if you have block A and B
1451 // collapsing together, then you'd take the maximal positive margin from both A and B
1452 // and subtract it from the maximal negative margin from both A and B to get the
1453 // true collapsed margin. This algorithm is recursive, so when we finish layout()
1454 // our block knows its current maximal positive/negative values.
1456 // Start out by setting our margin values to our current margins. Table cells have
1457 // no margins, so we don't fill in the values for table cells.
1458 bool isCell = isTableCell();
1460 initMaxMarginValues();
1462 setMarginBeforeQuirk(styleToUse->marginBefore().quirk());
1463 setMarginAfterQuirk(styleToUse->marginAfter().quirk());
1466 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
1467 // See if this form is malformed (i.e., unclosed). If so, don't give the form
1469 setMaxMarginAfterValues(0, 0);
1472 setPaginationStrut(0);
1475 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
1476 if (scrollsOverflow() && style()->appearance() != ListboxPart) {
1477 if (styleToUse->overflowX() == OSCROLL)
1478 layer()->setHasHorizontalScrollbar(true);
1479 if (styleToUse->overflowY() == OSCROLL)
1480 layer()->setHasVerticalScrollbar(true);
1483 LayoutUnit repaintLogicalTop = ZERO_LAYOUT_UNIT;
1484 LayoutUnit repaintLogicalBottom = ZERO_LAYOUT_UNIT;
1485 LayoutUnit maxFloatLogicalBottom = ZERO_LAYOUT_UNIT;
1486 if (!firstChild() && !isAnonymousBlock())
1487 setChildrenInline(true);
1488 if (childrenInline())
1489 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1491 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1493 // Expand our intrinsic height to encompass floats.
1494 LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1495 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1496 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1498 if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1501 // Calculate our new height.
1502 LayoutUnit oldHeight = logicalHeight();
1503 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
1504 computeLogicalHeight();
1505 LayoutUnit newHeight = logicalHeight();
1506 if (oldHeight != newHeight) {
1507 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1508 // One of our children's floats may have become an overhanging float for us. We need to look for it.
1509 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1510 if (child->isBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) {
1511 RenderBlock* block = toRenderBlock(child);
1512 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
1513 addOverhangingFloats(block, false);
1519 if (previousHeight != newHeight)
1520 relayoutChildren = true;
1522 layoutPositionedObjects(relayoutChildren || isRoot());
1524 computeRegionRangeForBlock();
1526 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1527 computeOverflow(oldClientAfterEdge);
1531 if (renderView->layoutState()->m_pageLogicalHeight)
1532 setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop()));
1534 updateLayerTransform();
1536 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1537 // we overflow or not.
1538 updateScrollInfoAfterLayout();
1540 // FIXME: This repaint logic should be moved into a separate helper function!
1541 // Repaint with our new bounds if they are different from our old bounds.
1542 bool didFullRepaint = repainter.repaintAfterLayout();
1543 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1544 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1545 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1546 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
1547 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
1548 if (hasOverflowClip()) {
1549 // 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.
1550 // 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.
1551 // layoutInlineChildren should be patched to compute the entire repaint rect.
1552 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1553 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1556 LayoutRect repaintRect;
1557 if (isHorizontalWritingMode())
1558 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1560 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1562 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1563 adjustRectForColumns(repaintRect);
1565 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1567 if (hasOverflowClip()) {
1568 // Adjust repaint rect for scroll offset
1569 repaintRect.move(-scrolledContentOffset());
1571 // Don't allow this rect to spill out of our overflow box.
1572 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
1575 // Make sure the rect is still non-empty after intersecting for overflow above
1576 if (!repaintRect.isEmpty()) {
1577 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1578 if (hasReflection())
1579 repaintRectangle(reflectedRect(repaintRect));
1583 setNeedsLayout(false);
1586 void RenderBlock::addOverflowFromChildren()
1588 if (!hasColumns()) {
1589 if (childrenInline())
1590 addOverflowFromInlineChildren();
1592 addOverflowFromBlockChildren();
1594 ColumnInfo* colInfo = columnInfo();
1595 if (columnCount(colInfo)) {
1596 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1597 addLayoutOverflow(lastRect);
1598 if (!hasOverflowClip())
1599 addVisualOverflow(lastRect);
1604 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
1606 // Add overflow from children.
1607 addOverflowFromChildren();
1609 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1610 addOverflowFromFloats();
1612 // Add in the overflow from positioned objects.
1613 addOverflowFromPositionedObjects();
1615 if (hasOverflowClip()) {
1616 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1617 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1618 // be considered reachable.
1619 LayoutRect clientRect(clientBoxRect());
1620 LayoutRect rectToApply;
1621 if (isHorizontalWritingMode())
1622 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max(ZERO_LAYOUT_UNIT, oldClientAfterEdge - clientRect.y()));
1624 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max(ZERO_LAYOUT_UNIT, oldClientAfterEdge - clientRect.x()), 1);
1625 addLayoutOverflow(rectToApply);
1628 // Add visual overflow from box-shadow and border-image-outset.
1629 addVisualEffectOverflow();
1631 // Add visual overflow from theme.
1632 addVisualOverflowFromTheme();
1634 if (isRenderFlowThread())
1635 enclosingRenderFlowThread()->computeOverflowStateForRegions(oldClientAfterEdge);
1638 void RenderBlock::addOverflowFromBlockChildren()
1640 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1641 if (!child->isFloatingOrOutOfFlowPositioned())
1642 addOverflowFromChild(child);
1646 void RenderBlock::addOverflowFromFloats()
1648 if (!m_floatingObjects)
1651 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1652 FloatingObjectSetIterator end = floatingObjectSet.end();
1653 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1654 FloatingObject* r = *it;
1655 if (r->isDescendant())
1656 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1661 void RenderBlock::addOverflowFromPositionedObjects()
1663 if (!m_positionedObjects)
1666 RenderBox* positionedObject;
1667 Iterator end = m_positionedObjects->end();
1668 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1669 positionedObject = *it;
1671 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1672 if (positionedObject->style()->position() != FixedPosition)
1673 addOverflowFromChild(positionedObject, IntSize(positionedObject->x(), positionedObject->y()));
1677 void RenderBlock::addVisualOverflowFromTheme()
1679 if (!style()->hasAppearance())
1682 IntRect inflatedRect = pixelSnappedBorderBoxRect();
1683 theme()->adjustRepaintRect(this, inflatedRect);
1684 addVisualOverflow(inflatedRect);
1687 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1689 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
1690 || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
1693 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1695 bool isHorizontal = isHorizontalWritingMode();
1696 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1698 LayoutUnit logicalTop = logicalHeight();
1699 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
1701 if (!marginInfo.canCollapseWithMarginBefore()) {
1702 child->computeBlockDirectionMargins(this);
1703 LayoutUnit marginBefore = marginBeforeForChild(child);
1704 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
1705 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
1706 if (marginBefore > 0) {
1707 if (marginBefore > collapsedBeforePos)
1708 collapsedBeforePos = marginBefore;
1710 if (-marginBefore > collapsedBeforeNeg)
1711 collapsedBeforeNeg = -marginBefore;
1713 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
1716 RenderLayer* childLayer = child->layer();
1717 if (childLayer->staticBlockPosition() != logicalTop) {
1718 childLayer->setStaticBlockPosition(logicalTop);
1719 if (hasStaticBlockPosition)
1720 child->setChildNeedsLayout(true, MarkOnlyThis);
1724 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1726 // The float should be positioned taking into account the bottom margin
1727 // of the previous flow. We add that margin into the height, get the
1728 // float positioned properly, and then subtract the margin out of the
1729 // height again. In the case of self-collapsing blocks, we always just
1730 // use the top margins, since the self-collapsing block collapsed its
1731 // own bottom margin into its top margin.
1733 // Note also that the previous flow may collapse its margin into the top of
1734 // our block. If this is the case, then we do not add the margin in to our
1735 // height when computing the position of the float. This condition can be tested
1736 // for by simply calling canCollapseWithMarginBefore. See
1737 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1738 // an example of this scenario.
1739 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? ZERO_LAYOUT_UNIT : marginInfo.margin();
1740 setLogicalHeight(logicalHeight() + marginOffset);
1741 positionNewFloats();
1742 setLogicalHeight(logicalHeight() - marginOffset);
1745 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1747 // Handle in the given order
1748 return handlePositionedChild(child, marginInfo)
1749 || handleFloatingChild(child, marginInfo);
1753 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1755 if (child->isOutOfFlowPositioned()) {
1756 child->containingBlock()->insertPositionedObject(child);
1757 adjustPositionedBlock(child, marginInfo);
1763 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1765 if (child->isFloating()) {
1766 insertFloatingObject(child);
1767 adjustFloatingBlock(marginInfo);
1773 static void destroyRunIn(RenderBoxModelObject* runIn)
1775 ASSERT(runIn->isRunIn());
1776 ASSERT(!runIn->firstChild());
1778 // Delete our line box tree. This is needed as our children got moved
1779 // and our line box tree is no longer valid.
1780 if (runIn->isRenderBlock())
1781 toRenderBlock(runIn)->deleteLineBoxTree();
1782 else if (runIn->isRenderInline())
1783 toRenderInline(runIn)->deleteLineBoxTree();
1785 ASSERT_NOT_REACHED();
1790 void RenderBlock::placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunInFlag flag)
1792 if (newChild->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
1793 moveRunInUnderSiblingBlockIfNeeded(newChild);
1794 else if (RenderObject* prevSibling = newChild->previousSibling()) {
1795 if (prevSibling->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
1796 moveRunInUnderSiblingBlockIfNeeded(prevSibling);
1800 RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn)
1802 ASSERT(runIn->isRunIn());
1804 // First we destroy any :before/:after content. It will be regenerated by the new run-in.
1805 // Exception is if the run-in itself is generated.
1806 if (runIn->style()->styleType() != BEFORE && runIn->style()->styleType() != AFTER) {
1807 RenderObject* generatedContent;
1808 if (runIn->getCachedPseudoStyle(BEFORE) && (generatedContent = runIn->beforePseudoElementRenderer()))
1809 generatedContent->destroy();
1810 if (runIn->getCachedPseudoStyle(AFTER) && (generatedContent = runIn->afterPseudoElementRenderer()))
1811 generatedContent->destroy();
1814 bool newRunInShouldBeBlock = !runIn->isRenderBlock();
1815 Node* runInNode = runIn->node();
1816 RenderBoxModelObject* newRunIn = 0;
1817 if (newRunInShouldBeBlock)
1818 newRunIn = new (renderArena()) RenderBlock(runInNode ? runInNode : document());
1820 newRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1821 newRunIn->setStyle(runIn->style());
1823 runIn->moveAllChildrenTo(newRunIn, true);
1825 // If the run-in had an element, we need to set the new renderer.
1827 runInNode->setRenderer(newRunIn);
1832 void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn)
1834 ASSERT(runIn->isRunIn());
1836 // See if we have inline children. If the children aren't inline,
1837 // then just treat the run-in as a normal block.
1838 if (!runIn->childrenInline())
1841 // FIXME: We don't handle non-block elements with run-in for now.
1842 if (!runIn->isRenderBlock())
1845 // FIXME: We don't support run-ins with or as part of a continuation
1846 // as it makes the back-and-forth placing complex.
1847 if (runIn->isElementContinuation() || runIn->virtualContinuation())
1850 // Check if this node is allowed to run-in. E.g. <select> expects its renderer to
1851 // be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in.
1852 Node* runInNode = runIn->node();
1853 if (runInNode && runInNode->hasTagName(selectTag))
1856 if (runInNode && runInNode->hasTagName(progressTag))
1859 RenderObject* curr = runIn->nextSibling();
1860 if (!curr || !curr->isRenderBlock() || !curr->childrenInline())
1863 // Per CSS3, "A run-in cannot run in to a block that already starts with a
1864 // run-in or that itself is a run-in".
1865 if (curr->isRunIn() || (curr->firstChild() && curr->firstChild()->isRunIn()))
1868 if (curr->isAnonymous() || curr->isFloatingOrOutOfFlowPositioned())
1871 RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn);
1872 RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn);
1873 destroyRunIn(oldRunIn);
1875 // Now insert the new child under |curr| block. Use addChild instead of insertChildNode
1876 // since it handles correct placement of the children, especially where we cannot insert
1877 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1878 curr->addChild(newRunIn, curr->firstChild());
1880 // Make sure that |this| get a layout since its run-in child moved.
1881 curr->setNeedsLayoutAndPrefWidthsRecalc();
1884 bool RenderBlock::runInIsPlacedIntoSiblingBlock(RenderObject* runIn)
1886 ASSERT(runIn->isRunIn());
1888 // If we don't have a parent, we can't be moved into our sibling block.
1892 // An intruded run-in needs to be an inline.
1893 if (!runIn->isRenderInline())
1899 void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn)
1901 ASSERT(runIn->isRunIn());
1903 if (!runInIsPlacedIntoSiblingBlock(runIn))
1906 // FIXME: Run-in that are now placed in sibling block can break up into continuation
1907 // chains when new children are added to it. We cannot easily send them back to their
1908 // original place since that requires writing integration logic with RenderInline::addChild
1909 // and all other places that might cause continuations to be created (without blowing away
1910 // |this|). Disabling this feature for now to prevent crashes.
1911 if (runIn->isElementContinuation() || runIn->virtualContinuation())
1914 RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn);
1915 RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn);
1916 destroyRunIn(oldRunIn);
1918 // Add the run-in block as our previous sibling.
1919 parent()->addChild(newRunIn, this);
1921 // Make sure that the parent holding the new run-in gets layout.
1922 parent()->setNeedsLayoutAndPrefWidthsRecalc();
1925 LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1927 // Get the four margin values for the child and cache them.
1928 const MarginValues childMargins = marginValuesForChild(child);
1930 // Get our max pos and neg top margins.
1931 LayoutUnit posTop = childMargins.positiveMarginBefore();
1932 LayoutUnit negTop = childMargins.negativeMarginBefore();
1934 // For self-collapsing blocks, collapse our bottom margins into our
1935 // top to get new posTop and negTop values.
1936 if (child->isSelfCollapsingBlock()) {
1937 posTop = max(posTop, childMargins.positiveMarginAfter());
1938 negTop = max(negTop, childMargins.negativeMarginAfter());
1941 // See if the top margin is quirky. We only care if this child has
1942 // margins that will collapse with us.
1943 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
1945 if (marginInfo.canCollapseWithMarginBefore()) {
1946 // This child is collapsing with the top of the
1947 // block. If it has larger margin values, then we need to update
1948 // our own maximal values.
1949 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
1950 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
1952 // The minute any of the margins involved isn't a quirk, don't
1953 // collapse it away, even if the margin is smaller (www.webreference.com
1954 // has an example of this, a <dt> with 0.8em author-specified inside
1955 // a <dl> inside a <td>.
1956 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
1957 setMarginBeforeQuirk(false);
1958 marginInfo.setDeterminedMarginBeforeQuirk(true);
1961 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
1962 // We have no top margin and our top child has a quirky margin.
1963 // We will pick up this quirky margin and pass it through.
1964 // This deals with the <td><div><p> case.
1965 // Don't do this for a block that split two inlines though. You do
1966 // still apply margins in this case.
1967 setMarginBeforeQuirk(true);
1970 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1971 marginInfo.setMarginBeforeQuirk(topQuirk);
1973 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1974 LayoutUnit logicalTop = beforeCollapseLogicalTop;
1975 if (child->isSelfCollapsingBlock()) {
1976 // This child has no height. We need to compute our
1977 // position before we collapse the child's margins together,
1978 // so that we can get an accurate position for the zero-height block.
1979 LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1980 LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1981 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1983 // Now collapse the child's margins together, which means examining our
1984 // bottom margin values as well.
1985 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1986 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1988 if (!marginInfo.canCollapseWithMarginBefore())
1989 // We need to make sure that the position of the self-collapsing block
1990 // is correct, since it could have overflowing content
1991 // that needs to be positioned correctly (e.g., a block that
1992 // had a specified height of 0 but that actually had subcontent).
1993 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1996 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1997 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
1998 logicalTop = logicalHeight();
2000 else if (!marginInfo.atBeforeSideOfBlock() ||
2001 (!marginInfo.canCollapseMarginBeforeWithChildren()
2002 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
2003 // We're collapsing with a previous sibling's margins and not
2004 // with the top of the block.
2005 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
2006 logicalTop = logicalHeight();
2009 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
2010 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
2012 if (marginInfo.margin())
2013 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
2016 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
2017 // collapsed into the page edge.
2018 LayoutState* layoutState = view()->layoutState();
2019 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
2020 && hasNextPage(beforeCollapseLogicalTop)) {
2021 LayoutUnit oldLogicalTop = logicalTop;
2022 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
2023 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
2026 // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
2027 // overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
2028 // or clear it anyway, so don't worry about any floating children it may contain.
2029 RenderObject* prev = child->previousSibling();
2030 if (prev && prev->isBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
2031 RenderBlock* block = toRenderBlock(prev);
2032 if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
2033 addOverhangingFloats(block, false);
2039 LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
2041 LayoutUnit heightIncrease = getClearDelta(child, yPos);
2042 if (!heightIncrease)
2045 if (child->isSelfCollapsingBlock()) {
2046 // For self-collapsing blocks that clear, they can still collapse their
2047 // margins with following siblings. Reset the current margins to represent
2048 // the self-collapsing block's margins only.
2050 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
2051 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
2052 // self-collapsing block's bottom margin.
2053 bool atBottomOfBlock = true;
2054 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
2055 if (!curr->isFloatingOrOutOfFlowPositioned())
2056 atBottomOfBlock = false;
2059 MarginValues childMargins = marginValuesForChild(child);
2060 if (atBottomOfBlock) {
2061 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
2062 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
2064 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
2065 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
2068 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
2069 // of the parent block).
2070 setLogicalHeight(child->logicalTop() - max(ZERO_LAYOUT_UNIT, marginInfo.margin()));
2072 // Increase our height by the amount we had to clear.
2073 setLogicalHeight(logicalHeight() + heightIncrease);
2075 if (marginInfo.canCollapseWithMarginBefore()) {
2076 // We can no longer collapse with the top of the block since a clear
2077 // occurred. The empty blocks collapse into the cleared block.
2078 // FIXME: This isn't quite correct. Need clarification for what to do
2079 // if the height the cleared block is offset by is smaller than the
2080 // margins involved.
2081 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
2082 marginInfo.setAtBeforeSideOfBlock(false);
2085 return yPos + heightIncrease;
2088 void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const
2090 // FIXME: We should deal with the margin-collapse-* style extensions that prevent collapsing and that discard margins.
2091 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
2092 if (document()->inQuirksMode() && child->isMarginBeforeQuirk() && (isTableCell() || isBody()))
2095 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
2096 positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
2097 negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin);
2099 if (!child->isRenderBlock())
2102 RenderBlock* childBlock = toRenderBlock(child);
2103 if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
2106 MarginInfo childMarginInfo(childBlock, childBlock->borderBefore() + childBlock->paddingBefore(), childBlock->borderAfter() + childBlock->paddingAfter());
2107 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
2110 RenderBox* grandchildBox = childBlock->firstChildBox();
2111 for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
2112 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
2116 // Give up if there is clearance on the box, since it probably won't collapse into us.
2117 if (!grandchildBox || grandchildBox->style()->clear() != CNONE)
2120 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
2121 if (grandchildBox->needsLayout()) {
2122 grandchildBox->computeBlockDirectionMargins(this);
2123 grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->marginBefore().quirk());
2124 grandchildBox->setMarginAfterQuirk(grandchildBox->style()->marginAfter().quirk());
2127 // Collapse the margin of the grandchild box with our own to produce an estimate.
2128 childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore);
2131 LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
2133 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
2134 // relayout if there are intruding floats.
2135 LayoutUnit logicalTopEstimate = logicalHeight();
2136 if (!marginInfo.canCollapseWithMarginBefore()) {
2137 LayoutUnit positiveMarginBefore = ZERO_LAYOUT_UNIT;
2138 LayoutUnit negativeMarginBefore = ZERO_LAYOUT_UNIT;
2139 if (child->selfNeedsLayout()) {
2140 // Try to do a basic estimation of how the collapse is going to go.
2141 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore);
2143 // Use the cached collapsed margin values from a previous layout. Most of the time they
2145 MarginValues marginValues = marginValuesForChild(child);
2146 positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
2147 negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
2150 // Collapse the result with our current margins.
2151 logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
2154 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
2156 LayoutState* layoutState = view()->layoutState();
2157 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
2158 && hasNextPage(logicalHeight()))
2159 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
2161 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
2163 estimateWithoutPagination = logicalTopEstimate;
2165 if (layoutState->isPaginated()) {
2166 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
2167 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
2169 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
2170 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
2172 if (!child->selfNeedsLayout() && child->isRenderBlock())
2173 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
2176 return logicalTopEstimate;
2179 LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart,
2180 RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
2182 LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
2184 // Add in our start margin.
2185 LayoutUnit oldPosition = startPosition + childMarginStart;
2186 LayoutUnit newPosition = oldPosition;
2188 LayoutUnit blockOffset = logicalTopForChild(child);
2190 blockOffset = max(blockOffset, blockOffset + (region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage));
2192 LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage, logicalHeightForChild(child));
2194 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
2195 if (childMarginStart < 0)
2196 startOff += childMarginStart;
2197 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
2198 } else if (startOff != startPosition)
2199 newPosition = startOff + childMarginStart;
2201 return newPosition - oldPosition;
2204 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
2206 LayoutUnit startPosition = borderStart() + paddingStart();
2207 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
2209 // Add in our start margin.
2210 LayoutUnit childMarginStart = marginStartForChild(child);
2211 LayoutUnit newPosition = startPosition + childMarginStart;
2213 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
2214 // to shift over as necessary to dodge any floats that might get in the way.
2215 if (child->avoidsFloats() && containsFloats() && !inRenderFlowThread())
2216 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
2218 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
2221 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
2223 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
2224 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
2225 // with our children.
2226 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
2228 if (!marginInfo.marginAfterQuirk())
2229 setMarginAfterQuirk(false);
2231 if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
2232 // We have no bottom margin and our last child has a quirky margin.
2233 // We will pick up this quirky margin and pass it through.
2234 // This deals with the <td><div><p> case.
2235 setMarginAfterQuirk(true);
2239 void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
2241 marginInfo.setAtAfterSideOfBlock(true);
2243 // If we can't collapse with children then go ahead and add in the bottom margin.
2244 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
2245 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
2246 setLogicalHeight(logicalHeight() + marginInfo.margin());
2248 // Now add in our bottom border/padding.
2249 setLogicalHeight(logicalHeight() + afterSide);
2251 // Negative margins can cause our height to shrink below our minimal height (border/padding).
2252 // If this happens, ensure that the computed height is increased to the minimal height.
2253 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
2255 // Update our bottom collapsed margin info.
2256 setCollapsedBottomMargin(marginInfo);
2259 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
2261 if (isHorizontalWritingMode()) {
2262 if (applyDelta == ApplyLayoutDelta)
2263 view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
2264 child->setX(logicalLeft);
2266 if (applyDelta == ApplyLayoutDelta)
2267 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
2268 child->setY(logicalLeft);
2272 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
2274 if (isHorizontalWritingMode()) {
2275 if (applyDelta == ApplyLayoutDelta)
2276 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
2277 child->setY(logicalTop);
2279 if (applyDelta == ApplyLayoutDelta)
2280 view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
2281 child->setX(logicalTop);
2285 void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
2287 if (gPercentHeightDescendantsMap) {
2288 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
2289 HashSet<RenderBox*>::iterator end = descendants->end();
2290 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
2291 RenderBox* box = *it;
2292 while (box != this) {
2293 if (box->normalChildNeedsLayout())
2295 box->setChildNeedsLayout(true, MarkOnlyThis);
2296 box = box->containingBlock();
2305 LayoutUnit beforeEdge = borderBefore() + paddingBefore();
2306 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
2308 setLogicalHeight(beforeEdge);
2310 // Lay out our hypothetical grid line as though it occurs at the top of the block.
2311 if (view()->layoutState()->lineGrid() == this)
2312 layoutLineGridBox();
2314 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
2315 MarginInfo marginInfo(this, beforeEdge, afterEdge);
2317 // Fieldsets need to find their legend and position it inside the border of the object.
2318 // The legend then gets skipped during normal layout. The same is true for ruby text.
2319 // It doesn't get included in the normal layout process but is instead skipped.
2320 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
2322 LayoutUnit previousFloatLogicalBottom = 0;
2323 maxFloatLogicalBottom = 0;
2325 RenderBox* next = firstChildBox();
2328 RenderBox* child = next;
2329 next = child->nextSiblingBox();
2331 if (childToExclude == child)
2332 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
2334 // Make sure we layout children if they need it.
2335 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
2336 // an auto value. Add a method to determine this, so that we can avoid the relayout.
2337 if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
2338 child->setChildNeedsLayout(true, MarkOnlyThis);
2340 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2341 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
2342 child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
2344 // Handle the four types of special elements first. These include positioned content, floating content, compacts and
2345 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
2346 if (handleSpecialChild(child, marginInfo))
2349 // Lay out the child.
2350 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
2353 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
2354 // determining the correct collapsed bottom margin information.
2355 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
2358 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
2360 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
2361 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
2363 // The child is a normal flow object. Compute the margins we will use for collapsing now.
2364 child->computeBlockDirectionMargins(this);
2366 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
2367 RenderStyle* childStyle = child->style();
2368 if (childStyle->marginBeforeCollapse() == MSEPARATE) {
2369 marginInfo.setAtBeforeSideOfBlock(false);
2370 marginInfo.clearMargin();
2373 // Try to guess our correct logical top position. In most cases this guess will
2374 // be correct. Only if we're wrong (when we compute the real logical top position)
2375 // will we have to potentially relayout.
2376 LayoutUnit estimateWithoutPagination;
2377 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
2379 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
2380 LayoutRect oldRect = child->frameRect();
2381 LayoutUnit oldLogicalTop = logicalTopForChild(child);
2383 #if !ASSERT_DISABLED
2384 LayoutSize oldLayoutDelta = view()->layoutDelta();
2386 // Go ahead and position the child as though it didn't collapse with the top.
2387 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
2389 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
2390 bool markDescendantsWithFloats = false;
2391 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
2392 markDescendantsWithFloats = true;
2393 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
2394 // If an element might be affected by the presence of floats, then always mark it for
2396 LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
2397 if (fb > logicalTopEstimate)
2398 markDescendantsWithFloats = true;
2401 if (childRenderBlock) {
2402 if (markDescendantsWithFloats)
2403 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2404 if (!child->isWritingModeRoot())
2405 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
2408 if (!child->needsLayout())
2409 child->markForPaginationRelayoutIfNeeded();
2411 bool childHadLayout = child->everHadLayout();
2412 bool childNeededLayout = child->needsLayout();
2413 if (childNeededLayout)
2416 // Cache if we are at the top of the block right now.
2417 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
2419 // Now determine the correct ypos based off examination of collapsing margin
2421 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
2423 // Now check for clear.
2424 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
2426 bool paginated = view()->layoutState()->isPaginated();
2428 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
2429 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
2431 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2433 // Now we have a final top position. See if it really does end up being different from our estimate.
2434 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
2435 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
2436 if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout()) {
2437 if (child->shrinkToAvoidFloats()) {
2438 // The child's width depends on the line width.
2439 // When the child shifts to clear an item, its width can
2440 // change (because it has more available line width).
2441 // So go ahead and mark the item as dirty.
2442 child->setChildNeedsLayout(true, MarkOnlyThis);
2445 if (childRenderBlock) {
2446 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2447 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2448 if (!child->needsLayout())
2449 child->markForPaginationRelayoutIfNeeded();
2452 // Our guess was wrong. Make the child lay itself out again.
2453 child->layoutIfNeeded();
2456 // We are no longer at the top of the block if we encounter a non-empty child.
2457 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2458 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2459 marginInfo.setAtBeforeSideOfBlock(false);
2461 // Now place the child in the correct left position
2462 determineLogicalLeftPositionForChild(child);
2464 // Update our height now that the child has been placed in the correct position.
2465 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2466 if (childStyle->marginAfterCollapse() == MSEPARATE) {
2467 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2468 marginInfo.clearMargin();
2470 // If the child has overhanging floats that intrude into following siblings (or possibly out
2471 // of this block), then the parent gets notified of the floats now.
2472 if (childRenderBlock && childRenderBlock->containsFloats())
2473 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
2475 LayoutSize childOffset = child->location() - oldRect.location();
2476 if (childOffset.width() || childOffset.height()) {
2477 view()->addLayoutDelta(childOffset);
2479 // If the child moved, we have to repaint it as well as any floating/positioned
2480 // descendants. An exception is if we need a layout. In this case, we know we're going to
2481 // repaint ourselves (and the child) anyway.
2482 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2483 child->repaintDuringLayoutIfMoved(oldRect);
2486 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2488 child->repaintOverhangingFloats(true);
2492 // Check for an after page/column break.
2493 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2494 if (newHeight != height())
2495 setLogicalHeight(newHeight);
2498 ASSERT(oldLayoutDelta == view()->layoutDelta());
2501 void RenderBlock::simplifiedNormalFlowLayout()
2503 if (childrenInline()) {
2504 ListHashSet<RootInlineBox*> lineBoxes;
2505 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
2506 RenderObject* o = walker.current();
2507 if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
2508 o->layoutIfNeeded();
2509 if (toRenderBox(o)->inlineBoxWrapper()) {
2510 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2513 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline()))
2514 o->setNeedsLayout(false);
2517 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2518 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2519 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2520 RootInlineBox* box = *it;
2521 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2524 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2525 if (!box->isOutOfFlowPositioned())
2526 box->layoutIfNeeded();
2531 bool RenderBlock::simplifiedLayout()
2533 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2536 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2538 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2541 // Lay out positioned descendants or objects that just need to recompute overflow.
2542 if (needsSimplifiedNormalFlowLayout())
2543 simplifiedNormalFlowLayout();
2545 // Lay out our positioned objects if our positioned child bit is set.
2546 if (posChildNeedsLayout())
2547 layoutPositionedObjects(false);
2549 // Recompute our overflow information.
2550 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2551 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2552 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2553 // lowestPosition on every relayout so it's not a regression.
2555 computeOverflow(clientLogicalBottom(), true);
2559 updateLayerTransform();
2561 updateScrollInfoAfterLayout();
2563 setNeedsLayout(false);
2567 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2569 if (!m_positionedObjects)
2573 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2576 Iterator end = m_positionedObjects->end();
2577 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2579 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2580 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2581 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2582 // positioned explicitly) this should not incur a performance penalty.
2583 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
2584 r->setChildNeedsLayout(true, MarkOnlyThis);
2586 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2587 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
2588 r->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
2590 if (!r->needsLayout())
2591 r->markForPaginationRelayoutIfNeeded();
2593 // 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
2594 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2595 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2596 r->setNeedsLayout(false);
2598 // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
2599 // If it's wrong we'll lay out again.
2600 LayoutUnit oldLogicalTop = 0;
2601 bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2602 if (needsBlockDirectionLocationSetBeforeLayout) {
2603 if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
2604 r->computeLogicalHeight();
2606 r->computeLogicalWidth();
2607 oldLogicalTop = logicalTopForChild(r);
2610 r->layoutIfNeeded();
2612 // Lay out again if our estimate was wrong.
2613 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) {
2614 r->setChildNeedsLayout(true, MarkOnlyThis);
2615 r->layoutIfNeeded();
2620 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2623 void RenderBlock::markPositionedObjectsForLayout()
2625 if (m_positionedObjects) {
2627 Iterator end = m_positionedObjects->end();
2628 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2630 r->setChildNeedsLayout(true);
2635 void RenderBlock::markForPaginationRelayoutIfNeeded()
2637 ASSERT(!needsLayout());
2641 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
2642 setChildNeedsLayout(true, MarkOnlyThis);
2645 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2647 // Repaint any overhanging floats (if we know we're the one to paint them).
2648 // Otherwise, bail out.
2649 if (!hasOverhangingFloats())
2652 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2653 // in this block. Better yet would be to push extra state for the containers of other floats.
2654 LayoutStateDisabler layoutStateDisabler(view());
2655 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2656 FloatingObjectSetIterator end = floatingObjectSet.end();
2657 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2658 FloatingObject* r = *it;
2659 // Only repaint the object if it is overhanging, is not in its own layer, and
2660 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2661 // condition is replaced with being a descendant of us.
2662 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->shouldPaint()) && !r->m_renderer->hasSelfPaintingLayer()) {
2663 r->m_renderer->repaint();
2664 r->m_renderer->repaintOverhangingFloats();
2669 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2671 LayoutPoint adjustedPaintOffset = paintOffset + location();
2673 PaintPhase phase = paintInfo.phase;
2675 // Check if we need to do anything at all.
2676 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2677 // paints the root's background.
2679 LayoutRect overflowBox = visualOverflowRect();
2680 flipForWritingMode(overflowBox);
2681 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2682 overflowBox.moveBy(adjustedPaintOffset);
2683 if (!overflowBox.intersects(paintInfo.rect)
2684 #if ENABLE(TIZEN_WEBKIT2) && ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
2685 && (!hasLayer() || !layer()->isComposited())
2691 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
2692 paintObject(paintInfo, adjustedPaintOffset);
2694 popContentsClip(paintInfo, phase, adjustedPaintOffset);
2696 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2697 // z-index. We paint after we painted the background/border, so that the scrollbars will
2698 // sit above the background/border.
2699 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2700 layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
2703 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2705 if (paintInfo.context->paintingDisabled())
2708 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2709 bool ruleTransparent = style()->columnRuleIsTransparent();
2710 EBorderStyle ruleStyle = style()->columnRuleStyle();
2711 LayoutUnit ruleThickness = style()->columnRuleWidth();
2712 LayoutUnit colGap = columnGap();
2713 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
2717 ColumnInfo* colInfo = columnInfo();
2718 unsigned colCount = columnCount(colInfo);
2720 bool antialias = shouldAntialiasLines(paintInfo.context);
2722 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
2723 bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed();
2724 LayoutUnit currLogicalLeftOffset = leftToRight ? ZERO_LAYOUT_UNIT : contentLogicalWidth();
2725 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
2726 LayoutUnit ruleLogicalLeft = leftToRight ? ZERO_LAYOUT_UNIT : contentLogicalWidth();
2727 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
2728 BoxSide boxSide = isHorizontalWritingMode()
2729 ? leftToRight ? BSLeft : BSRight
2730 : leftToRight ? BSTop : BSBottom;
2732 for (unsigned i = 0; i < colCount; i++) {
2733 // Move to the next position.
2735 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2736 currLogicalLeftOffset += inlineDirectionSize + colGap;
2738 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2739 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2742 // Now paint the column rule.
2743 if (i < colCount - 1) {
2744 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
2745 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
2746 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
2747 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
2748 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
2749 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2752 ruleLogicalLeft = currLogicalLeftOffset;
2755 bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
2756 LayoutUnit ruleLeft = isHorizontalWritingMode()
2757 ? borderLeft() + paddingLeft()
2758 : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
2759 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2760 LayoutUnit ruleTop = isHorizontalWritingMode()
2761 ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
2762 : borderStart() + paddingStart();
2763 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2764 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2767 if (isHorizontalWritingMode())
2768 ruleRect.setY(height() - ruleRect.maxY());
2770 ruleRect.setX(width() - ruleRect.maxX());
2773 ruleRect.moveBy(paintOffset);
2775 BoxSide boxSide = isHorizontalWritingMode()
2776 ? topToBottom ? BSTop : BSBottom
2777 : topToBottom ? BSLeft : BSRight;
2779 LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2780 if (!isHorizontalWritingMode())
2781 step = step.transposedSize();
2783 for (unsigned i = 1; i < colCount; i++) {
2784 ruleRect.move(step);
2785 IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
2786 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2791 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2793 // We need to do multiple passes, breaking up our child painting into strips.
2794 GraphicsContext* context = paintInfo.context;
2795 ColumnInfo* colInfo = columnInfo();
2796 unsigned colCount = columnCount(colInfo);
2799 LayoutUnit currLogicalTopOffset = 0;
2800 LayoutUnit colGap = columnGap();
2801 for (unsigned i = 0; i < colCount; i++) {
2802 // For each rect, we clip to the rect, and then we adjust our coords.
2803 LayoutRect colRect = columnRectAt(colInfo, i);
2804 flipForWritingMode(colRect);
2805 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2806 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2807 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2808 if (isHorizontalWritingMode())
2809 offset.expand(0, colRect.y() - borderTop() - paddingTop());
2811 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2813 colRect.moveBy(paintOffset);
2814 PaintInfo info(paintInfo);
2815 info.rect.intersect(pixelSnappedIntRect(colRect));
2817 if (!info.rect.isEmpty()) {
2818 GraphicsContextStateSaver stateSaver(*context);
2819 LayoutRect clipRect(colRect);
2821 if (i < colCount - 1) {
2822 if (isHorizontalWritingMode())
2823 clipRect.expand(colGap / 2, 0);
2825 clipRect.expand(0, colGap / 2);
2827 // Each strip pushes a clip, since column boxes are specified as being
2828 // like overflow:hidden.
2829 // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
2830 // are clipped according to the 'overflow' property.
2831 context->clip(pixelSnappedIntRect(clipRect));
2833 // Adjust our x and y when painting.
2834 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2836 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2838 paintContents(info, adjustedPaintOffset);
2841 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2842 if (style()->isFlippedBlocksWritingMode())
2843 currLogicalTopOffset += blockDelta;
2845 currLogicalTopOffset -= blockDelta;
2849 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2851 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2852 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2853 // will do a full repaint().
2854 if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
2857 if (childrenInline())
2858 m_lineBoxes.paint(this, paintInfo, paintOffset);
2860 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2861 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2863 // We don't paint our own background, but we do let the kids paint their backgrounds.
2864 PaintInfo paintInfoForChild(paintInfo);
2865 paintInfoForChild.phase = newPhase;
2866 paintInfoForChild.updatePaintingRootForChildren(this);
2868 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2869 // NSViews. Do not add any more code for this.
2870 bool usePrintRect = !view()->printRect().isEmpty();
2871 paintChildren(paintInfo, paintOffset, paintInfoForChild, usePrintRect);
2875 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
2877 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2878 if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
2883 bool RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
2885 // Check for page-break-before: always, and if it's set, break and bail.
2886 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2887 LayoutUnit absoluteChildY = paintOffset.y() + child->y();
2888 if (checkBeforeAlways
2889 && absoluteChildY > paintInfo.rect.y()
2890 && absoluteChildY < paintInfo.rect.maxY()) {
2891 view()->setBestTruncatedAt(absoluteChildY, this, true);
2895 RenderView* renderView = view();
2896 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2897 // Paginate block-level replaced elements.
2898 if (absoluteChildY + child->height() > renderView->printRect().maxY()) {
2899 if (absoluteChildY < renderView->truncatedAt())
2900 renderView->setBestTruncatedAt(absoluteChildY, child);
2901 // If we were able to truncate, don't paint.
2902 if (absoluteChildY >= renderView->truncatedAt())
2907 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2908 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2909 child->paint(paintInfoForChild, childPoint);
2911 // Check for page-break-after: always, and if it's set, break and bail.
2912 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2913 if (checkAfterAlways
2914 && (absoluteChildY + child->height()) > paintInfo.rect.y()
2915 && (absoluteChildY + child->height()) < paintInfo.rect.maxY()) {
2916 view()->setBestTruncatedAt(absoluteChildY + child->height() + max(ZERO_LAYOUT_UNIT, child->collapsedMarginAfter()), this, true);
2923 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2925 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2926 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2927 RenderObject* caretPainter;
2928 bool isContentEditable;
2929 if (type == CursorCaret) {
2930 caretPainter = frame()->selection()->caretRenderer();
2931 isContentEditable = frame()->selection()->rendererIsEditable();
2933 caretPainter = frame()->page()->dragCaretController()->caretRenderer();
2934 isContentEditable = frame()->page()->dragCaretController()->isContentEditable();
2937 if (caretPainter == this && (isContentEditable || caretBrowsing)) {
2938 if (type == CursorCaret)
2939 frame()->selection()->paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2941 frame()->page()->dragCaretController()->paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
2945 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2947 PaintPhase paintPhase = paintInfo.phase;
2949 // 1. paint background, borders etc
2950 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2951 if (hasBoxDecorations())
2952 paintBoxDecorations(paintInfo, paintOffset);
2954 paintColumnRules(paintInfo, paintOffset);
2957 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2958 paintMask(paintInfo, paintOffset);
2962 // We're done. We don't bother painting any children.
2963 if (paintPhase == PaintPhaseBlockBackground)
2966 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2967 LayoutPoint scrolledOffset = paintOffset;
2968 if (hasOverflowClip()) {
2969 scrolledOffset.move(-scrolledContentOffset());
2970 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2971 scrolledOffset.move(verticalScrollbarWidth(), 0);
2974 // 2. paint contents
2975 if (paintPhase != PaintPhaseSelfOutline) {
2977 paintColumnContents(paintInfo, scrolledOffset);
2979 paintContents(paintInfo, scrolledOffset);
2982 // 3. paint selection
2983 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2984 bool isPrinting = document()->printing();
2985 if (!isPrinting && !hasColumns())
2986 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2989 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2991 paintColumnContents(paintInfo, scrolledOffset, true);
2993 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2996 // 5. paint outline.
2997 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2998 paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
3000 // 6. paint continuation outlines.
3001 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
3002 RenderInline* inlineCont = inlineElementContinuation();
3003 // FIXME: For now, do not add continuations for outline painting by our containing block if we are a relative positioned
3004 // anonymous block (i.e. have our own layer). This is because a block depends on renderers in its continuation table being
3005 // in the same layer.
3006 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE && !hasLayer()) {
3007 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
3008 RenderBlock* cb = containingBlock();
3010 bool inlineEnclosedInSelfPaintingLayer = false;
3011 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
3012 if (box->hasSelfPaintingLayer()) {
3013 inlineEnclosedInSelfPaintingLayer = true;
3018 if (!inlineEnclosedInSelfPaintingLayer)
3019 cb->addContinuationWithOutline(inlineRenderer);
3020 else if (!inlineRenderer->firstLineBox())
3021 inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
3023 paintContinuationOutlines(paintInfo, paintOffset);
3027 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
3028 // then paint the caret.
3029 if (paintPhase == PaintPhaseForeground) {
3030 paintCaret(paintInfo, paintOffset, CursorCaret);
3031 paintCaret(paintInfo, paintOffset, DragCaret);
3035 LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
3037 if (!style()->isFlippedBlocksWritingMode())
3040 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
3041 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
3043 if (isHorizontalWritingMode())
3044 return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
3045 return LayoutPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
3048 void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
3050 if (!m_floatingObjects)
3053 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3054 FloatingObjectSetIterator end = floatingObjectSet.end();
3055 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3056 FloatingObject* r = *it;
3057 // Only paint the object if our m_shouldPaint flag is set.
3058 if (r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer()) {
3059 PaintInfo currentPaintInfo(paintInfo);
3060 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
3061 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
3062 r->m_renderer->paint(currentPaintInfo, childPoint);
3063 if (!preservePhase) {
3064 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
3065 r->m_renderer->paint(currentPaintInfo, childPoint);
3066 currentPaintInfo.phase = PaintPhaseFloat;
3067 r->m_renderer->paint(currentPaintInfo, childPoint);
3068 currentPaintInfo.phase = PaintPhaseForeground;
3069 r->m_renderer->paint(currentPaintInfo, childPoint);
3070 currentPaintInfo.phase = PaintPhaseOutline;
3071 r->m_renderer->paint(currentPaintInfo, childPoint);
3077 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3079 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox())
3082 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
3083 // We can check the first box and last box and avoid painting if we don't
3085 LayoutUnit yPos = paintOffset.y() + firstLineBox()->y();
3086 LayoutUnit h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y();
3087 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y())
3090 // See if our boxes intersect with the dirty rect. If so, then we paint
3091 // them. Note that boxes can easily overlap, so we can't make any assumptions
3092 // based off positions of our first line box or our last line box.
3093 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
3094 yPos = paintOffset.y() + curr->y();
3095 h = curr->logicalHeight();
3096 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y())
3097 curr->paintEllipsisBox(paintInfo, paintOffset, curr->lineTop(), curr->lineBottom());
3102 RenderInline* RenderBlock::inlineElementContinuation() const
3104 RenderBoxModelObject* continuation = this->continuation();
3105 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
3108 RenderBlock* RenderBlock::blockElementContinuation() const
3110 RenderBoxModelObject* currentContinuation = continuation();
3111 if (!currentContinuation || currentContinuation->isInline())
3113 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
3114 if (nextContinuation->isAnonymousBlock())
3115 return nextContinuation->blockElementContinuation();
3116 return nextContinuation;
3119 static ContinuationOutlineTableMap* continuationOutlineTable()
3121 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
3125 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
3127 // We can't make this work if the inline is in a layer. We'll just rely on the broken
3129 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
3131 ContinuationOutlineTableMap* table = continuationOutlineTable();
3132 ListHashSet<RenderInline*>* continuations = table->get(this);
3133 if (!continuations) {
3134 continuations = new ListHashSet<RenderInline*>;
3135 table->set(this, continuations);
3138 continuations->add(flow);
3141 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
3143 ContinuationOutlineTableMap* table = continuationOutlineTable();
3144 if (table->isEmpty())
3147 ListHashSet<RenderInline*>* continuations = table->get(this);
3151 return continuations->contains(flow);
3154 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
3156 ContinuationOutlineTableMap* table = continuationOutlineTable();
3157 if (table->isEmpty())
3160 ListHashSet<RenderInline*>* continuations = table->get(this);
3164 LayoutPoint accumulatedPaintOffset = paintOffset;
3165 // Paint each continuation outline.
3166 ListHashSet<RenderInline*>::iterator end = continuations->end();
3167 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
3168 // Need to add in the coordinates of the intervening blocks.
3169 RenderInline* flow = *it;
3170 RenderBlock* block = flow->containingBlock();
3171 for ( ; block && block != this; block = block->containingBlock())
3172 accumulatedPaintOffset.moveBy(block->location());
3174 flow->paintOutline(info.context, accumulatedPaintOffset);
3178 delete continuations;
3179 table->remove(this);
3182 bool RenderBlock::shouldPaintSelectionGaps() const
3184 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
3187 bool RenderBlock::isSelectionRoot() const
3192 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
3196 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned()
3197 || isFloatingOrOutOfFlowPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform()
3198 || hasReflection() || hasMask() || isWritingModeRoot())
3201 if (view() && view()->selectionStart()) {
3202 Node* startElement = view()->selectionStart()->node();
3203 if (startElement && startElement->rootEditableElement() == node())
3210 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
3212 ASSERT(!needsLayout());
3214 if (!shouldPaintSelectionGaps())
3217 // FIXME: this is broken with transforms
3218 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
3219 mapLocalToContainer(repaintContainer, false, false, transformState);
3220 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
3222 if (hasOverflowClip())
3223 offsetFromRepaintContainer -= scrolledContentOffset();
3225 LayoutUnit lastTop = 0;
3226 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
3227 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
3229 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
3232 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3234 #if !ENABLE(TIZEN_PAINT_SELECTION_ANTIALIAS_NONE)
3235 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
3236 LayoutUnit lastTop = 0;
3237 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
3238 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
3239 GraphicsContextStateSaver stateSaver(*paintInfo.context);
3241 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
3242 if (!gapRectsBounds.isEmpty()) {
3243 if (RenderLayer* layer = enclosingLayer()) {
3244 gapRectsBounds.moveBy(-paintOffset);
3246 LayoutRect localBounds(gapRectsBounds);
3247 flipForWritingMode(localBounds);
3248 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
3249 if (layer->renderer()->hasOverflowClip())
3250 gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
3252 layer->addBlockSelectionGapsBounds(gapRectsBounds);
3259 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects)
3261 if (!positionedObjects)
3264 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
3265 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
3267 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
3271 static LayoutUnit blockDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
3273 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
3276 static LayoutUnit inlineDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
3278 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
3281 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
3284 if (isHorizontalWritingMode())
3285 result = logicalRect;
3287 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
3288 flipForWritingMode(result);
3289 result.moveBy(rootBlockPhysicalPosition);
3293 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3294 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3296 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
3297 // Clip out floating and positioned objects when painting selection gaps.
3299 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
3300 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
3301 rootBlock->flipForWritingMode(flippedBlockRect);
3302 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
3303 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get());
3304 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
3305 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
3306 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes.
3307 if (m_floatingObjects) {
3308 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3309 FloatingObjectSetIterator end = floatingObjectSet.end();
3310 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3311 FloatingObject* r = *it;
3312 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
3313 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
3314 r->m_renderer->width(), r->m_renderer->height());
3315 rootBlock->flipForWritingMode(floatBox);
3316 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
3317 paintInfo->context->clipOut(pixelSnappedIntRect(floatBox));
3322 // 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
3325 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
3328 if (hasColumns() || hasTransform() || style()->columnSpan()) {
3329 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
3330 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3331 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3332 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3336 if (childrenInline())
3337 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
3339 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
3341 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
3342 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
3343 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3344 logicalHeight(), paintInfo));
3348 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3349 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3353 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3355 if (!firstLineBox()) {
3356 if (containsStart) {
3357 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
3359 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3360 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3361 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3366 RootInlineBox* lastSelectedLine = 0;
3367 RootInlineBox* curr;
3368 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3370 // Now paint the gaps for the lines.
3371 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3372 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3373 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3375 if (!containsStart && !lastSelectedLine &&
3376 selectionState() != SelectionStart && selectionState() != SelectionBoth)
3377 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3378 selTop, paintInfo));
3380 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3381 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
3382 LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3383 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3384 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3385 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
3387 lastSelectedLine = curr;
3390 if (containsStart && !lastSelectedLine)
3391 // VisibleSelection must start just after our last line.
3392 lastSelectedLine = lastRootBox();
3394 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3395 // Go ahead and update our lastY to be the bottom of the last selected line.
3396 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3397 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3398 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3403 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3404 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3408 // Go ahead and jump right to the first block child that contains some selected objects.
3410 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
3412 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
3413 SelectionState childState = curr->selectionState();
3414 if (childState == SelectionBoth || childState == SelectionEnd)
3415 sawSelectionEnd = true;
3417 if (curr->isFloatingOrOutOfFlowPositioned())
3418 continue; // We must be a normal flow object in order to even be considered.
3420 if (curr->isRelPositioned() && curr->hasLayer()) {
3421 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
3422 // Just disregard it completely.
3423 LayoutSize relOffset = curr->layer()->relativePositionOffset();
3424 if (relOffset.width() || relOffset.height())
3428 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
3429 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
3430 if (fillBlockGaps) {
3431 // We need to fill the vertical gap above this object.
3432 if (childState == SelectionEnd || childState == SelectionInside)
3433 // Fill the gap above the object.
3434 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3435 curr->logicalTop(), paintInfo));
3437 // 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*
3438 // our object. We know this if the selection did not end inside our object.
3439 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
3440 childState = SelectionNone;
3442 // Fill side gaps on this object based off its state.
3443 bool leftGap, rightGap;
3444 getSelectionGapInfo(childState, leftGap, rightGap);
3447 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3449 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3451 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
3452 // they can without bumping into floating or positioned objects. Ideally they will go right up
3453 // to the border of the root selection block.
3454 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
3455 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
3456 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
3457 } else if (childState != SelectionNone)
3458 // We must be a block that has some selected object inside it. Go ahead and recur.
3459 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
3460 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
3465 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3466 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
3468 LayoutUnit logicalTop = lastLogicalTop;
3469 LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
3470 if (logicalHeight <= ZERO_LAYOUT_UNIT)
3471 return LayoutRect();
3473 // Get the selection offsets for the bottom of the gap
3474 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
3475 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
3476 LayoutUnit logicalWidth = logicalRight - logicalLeft;
3477 if (logicalWidth <= ZERO_LAYOUT_UNIT)
3478 return LayoutRect();
3480 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
3482 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor(), style()->colorSpace());
3486 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3487 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3489 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3490 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
3491 LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3492 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3493 if (rootBlockLogicalWidth <= ZERO_LAYOUT_UNIT)
3494 return LayoutRect();
3496 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3498 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3502 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3503 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3505 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3506 LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3507 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
3508 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3509 if (rootBlockLogicalWidth <= ZERO_LAYOUT_UNIT)
3510 return LayoutRect();
3512 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3514 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3518 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3520 bool ltr = style()->isLeftToRightDirection();
3521 leftGap = (state == RenderObject::SelectionInside) ||
3522 (state == RenderObject::SelectionEnd && ltr) ||
3523 (state == RenderObject::SelectionStart && !ltr);
3524 rightGap = (state == RenderObject::SelectionInside) ||
3525 (state == RenderObject::SelectionStart && ltr) ||
3526 (state == RenderObject::SelectionEnd && !ltr);
3529 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3531 LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
3532 if (logicalLeft == logicalLeftOffsetForContent()) {
3533 if (rootBlock != this)
3534 // The border can potentially be further extended by our containingBlock().
3535 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3538 RenderBlock* cb = this;
3539 while (cb != rootBlock) {
3540 logicalLeft += cb->logicalLeft();
3541 cb = cb->containingBlock();
3547 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3549 LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
3550 if (logicalRight == logicalRightOffsetForContent()) {
3551 if (rootBlock != this)
3552 // The border can potentially be further extended by our containingBlock().
3553 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
3554 return logicalRight;
3556 RenderBlock* cb = this;
3557 while (cb != rootBlock) {
3558 logicalRight += cb->logicalLeft();
3559 cb = cb->containingBlock();
3562 return logicalRight;
3565 RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
3567 if (isSelectionRoot())
3570 const RenderObject* object = this;
3571 RenderObject* sibling;
3573 sibling = object->previousSibling();
3574 while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot()))
3575 sibling = sibling->previousSibling();
3577 offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop());
3578 object = object->parent();
3579 } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot());
3584 RenderBlock* beforeBlock = toRenderBlock(sibling);
3586 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3588 RenderObject* child = beforeBlock->lastChild();
3589 while (child && child->isRenderBlock()) {
3590 beforeBlock = toRenderBlock(child);
3591 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3592 child = beforeBlock->lastChild();
3597 void RenderBlock::insertPositionedObject(RenderBox* o)
3599 ASSERT(!isAnonymousBlock());
3601 if (o->isRenderFlowThread())
3604 // Create the list of special objects if we don't aleady have one
3605 if (!m_positionedObjects)
3606 m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet);
3608 m_positionedObjects->add(o);
3611 void RenderBlock::removePositionedObject(RenderBox* o)
3613 if (m_positionedObjects)
3614 m_positionedObjects->remove(o);
3617 void RenderBlock::removePositionedObjects(RenderBlock* o)
3619 if (!m_positionedObjects)
3624 Iterator end = m_positionedObjects->end();
3626 Vector<RenderBox*, 16> deadObjects;
3628 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
3630 if (!o || r->isDescendantOf(o)) {
3632 r->setChildNeedsLayout(true, MarkOnlyThis);
3634 // It is parent blocks job to add positioned child to positioned objects list of its containing block
3635 // Parent layout needs to be invalidated to ensure this happens.
3636 RenderObject* p = r->parent();
3637 while (p && !p->isRenderBlock())
3640 p->setChildNeedsLayout(true);
3642 deadObjects.append(r);
3646 for (unsigned i = 0; i < deadObjects.size(); i++)
3647 m_positionedObjects->remove(deadObjects.at(i));
3650 RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3652 ASSERT(o->isFloating());
3654 // Create the list of special objects if we don't aleady have one
3655 if (!m_floatingObjects)
3656 m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
3658 // Don't insert the object again if it's already in the list
3659 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3660 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3661 if (it != floatingObjectSet.end())
3665 // Create the special object entry & append it to the list
3667 FloatingObject* newObj = new FloatingObject(o->style()->floating());
3669 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
3670 // Just go ahead and lay out the float.
3671 bool isChildRenderBlock = o->isRenderBlock();
3672 if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged())
3673 o->setChildNeedsLayout(true, MarkOnlyThis);
3675 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
3676 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
3677 o->layoutIfNeeded();
3679 o->computeLogicalWidth();
3680 o->computeBlockDirectionMargins(this);
3682 setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
3684 newObj->setShouldPaint(!o->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will.
3685 newObj->setIsDescendant(true);
3686 newObj->m_renderer = o;
3688 m_floatingObjects->add(newObj);
3693 void RenderBlock::removeFloatingObject(RenderBox* o)
3695 if (m_floatingObjects) {
3696 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3697 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3698 if (it != floatingObjectSet.end()) {
3699 FloatingObject* r = *it;
3700 if (childrenInline()) {
3701 LayoutUnit logicalTop = logicalTopForFloat(r);
3702 LayoutUnit logicalBottom = logicalBottomForFloat(r);
3704 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
3705 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == MAX_LAYOUT_UNIT)
3706 logicalBottom = MAX_LAYOUT_UNIT;
3708 // Special-case zero- and less-than-zero-height floats: those don't touch
3709 // the line that they're on, but it still needs to be dirtied. This is
3710 // accomplished by pretending they have a height of 1.
3711 logicalBottom = max(logicalBottom, logicalTop + 1);
3713 if (r->m_originatingLine) {
3714 if (!selfNeedsLayout()) {
3715 ASSERT(r->m_originatingLine->renderer() == this);
3716 r->m_originatingLine->markDirty();
3718 #if !ASSERT_DISABLED
3719 r->m_originatingLine = 0;
3722 markLinesDirtyInBlockRange(0, logicalBottom);
3724 m_floatingObjects->remove(r);
3725 ASSERT(!r->m_originatingLine);
3731 void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
3733 if (!m_floatingObjects)
3736 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3737 FloatingObject* curr = floatingObjectSet.last();
3738 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
3739 m_floatingObjects->remove(curr);
3740 ASSERT(!curr->m_originatingLine);
3742 if (floatingObjectSet.isEmpty())
3744 curr = floatingObjectSet.last();
3748 LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
3750 RenderBox* childBox = floatingObject->renderer();
3751 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3752 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3753 LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
3755 LayoutUnit floatLogicalLeft;
3757 if (childBox->style()->floating() == LeftFloat) {
3758 LayoutUnit heightRemainingLeft = 1;
3759 LayoutUnit heightRemainingRight = 1;
3760 floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3761 while (logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
3762 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3763 floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3764 if (inRenderFlowThread()) {
3765 // Have to re-evaluate all of our offsets, since they may have changed.
3766 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3767 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3768 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
3771 floatLogicalLeft = max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
3773 LayoutUnit heightRemainingLeft = 1;
3774 LayoutUnit heightRemainingRight = 1;
3775 floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3776 while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
3777 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3778 floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3779 if (inRenderFlowThread()) {
3780 // Have to re-evaluate all of our offsets, since they may have changed.
3781 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3782 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3783 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
3786 floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable
3787 // |floatLogicalWidth| was capped to the available line width.
3788 // See fast/block/float/clamped-right-float.html.
3791 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
3794 bool RenderBlock::positionNewFloats()
3796 if (!m_floatingObjects)
3799 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3800 if (floatingObjectSet.isEmpty())
3803 // If all floats have already been positioned, then we have no work to do.
3804 if (floatingObjectSet.last()->isPlaced())
3807 // Move backwards through our floating object list until we find a float that has
3808 // already been positioned. Then we'll be able to move forward, positioning all of
3809 // the new floats that need it.
3810 FloatingObjectSetIterator it = floatingObjectSet.end();
3811 --it; // Go to last item.
3812 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3813 FloatingObject* lastPlacedFloatingObject = 0;
3814 while (it != begin) {
3816 if ((*it)->isPlaced()) {
3817 lastPlacedFloatingObject = *it;
3823 LayoutUnit logicalTop = logicalHeight();
3825 // The float cannot start above the top position of the last positioned float.
3826 if (lastPlacedFloatingObject)
3827 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
3829 FloatingObjectSetIterator end = floatingObjectSet.end();
3830 // Now walk through the set of unpositioned floats and place them.
3831 for (; it != end; ++it) {
3832 FloatingObject* floatingObject = *it;
3833 // The containing block is responsible for positioning floats, so if we have floats in our
3834 // list that come from somewhere else, do not attempt to position them.
3835 if (floatingObject->renderer()->containingBlock() != this)
3838 RenderBox* childBox = floatingObject->renderer();
3839 LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
3841 LayoutRect oldRect = childBox->frameRect();
3843 if (childBox->style()->clear() & CLEFT)
3844 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
3845 if (childBox->style()->clear() & CRIGHT)
3846 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
3848 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
3850 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
3851 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3852 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3854 LayoutState* layoutState = view()->layoutState();
3855 bool isPaginated = layoutState->isPaginated();
3856 if (isPaginated && !childBox->needsLayout())
3857 childBox->markForPaginationRelayoutIfNeeded();
3859 childBox->layoutIfNeeded();
3862 // If we are unsplittable and don't fit, then we need to move down.
3863 // We include our margins as part of the unsplittable area.
3864 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
3866 // See if we have a pagination strut that is making us move down further.
3867 // Note that an unsplittable child can't also have a pagination strut, so this is
3868 // exclusive with the case above.
3869 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
3870 if (childBlock && childBlock->paginationStrut()) {
3871 newLogicalTop += childBlock->paginationStrut();
3872 childBlock->setPaginationStrut(0);
3875 if (newLogicalTop != floatLogicalLocation.y()) {
3876 floatingObject->m_paginationStrut = newLogicalTop - floatLogicalLocation.y();
3878 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
3879 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
3880 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3881 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3884 childBlock->setChildNeedsLayout(true, MarkOnlyThis);
3885 childBox->layoutIfNeeded();
3889 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
3890 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
3892 m_floatingObjects->addPlacedObject(floatingObject);
3894 // If the child moved, we have to repaint it.
3895 if (childBox->checkForRepaintDuringLayout())
3896 childBox->repaintDuringLayoutIfMoved(oldRect);
3901 void RenderBlock::newLine(EClear clear)
3903 positionNewFloats();
3905 LayoutUnit newY = 0;
3909 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
3912 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
3915 newY = lowestFloatLogicalBottom();
3919 if (height() < newY)
3920 setLogicalHeight(newY);
3923 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
3925 if (!gPercentHeightDescendantsMap) {
3926 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
3927 gPercentHeightContainerMap = new PercentHeightContainerMap;
3930 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
3931 if (!descendantSet) {
3932 descendantSet = new HashSet<RenderBox*>;
3933 gPercentHeightDescendantsMap->set(this, descendantSet);
3935 bool added = descendantSet->add(descendant).isNewEntry;
3937 ASSERT(gPercentHeightContainerMap->get(descendant));
3938 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
3942 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
3943 if (!containerSet) {
3944 containerSet = new HashSet<RenderBlock*>;
3945 gPercentHeightContainerMap->set(descendant, containerSet);
3947 ASSERT(!containerSet->contains(this));
3948 containerSet->add(this);
3951 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
3953 if (!gPercentHeightContainerMap)
3956 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
3960 HashSet<RenderBlock*>::iterator end = containerSet->end();
3961 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
3962 RenderBlock* container = *it;
3963 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
3964 ASSERT(descendantSet);
3967 ASSERT(descendantSet->contains(descendant));
3968 descendantSet->remove(descendant);
3969 if (descendantSet->isEmpty()) {
3970 gPercentHeightDescendantsMap->remove(container);
3971 delete descendantSet;
3975 delete containerSet;
3978 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
3980 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
3983 bool RenderBlock::hasPercentHeightContainerMap()
3985 return gPercentHeightContainerMap;
3988 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
3990 // We don't null check gPercentHeightContainerMap since the caller
3991 // already ensures this and we need to call this function on every
3992 // descendant in clearPercentHeightDescendantsFrom().
3993 ASSERT(gPercentHeightContainerMap);
3994 return gPercentHeightContainerMap->contains(descendant);
3997 void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant)
3999 // We query the map directly, rather than looking at style's
4000 // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
4001 // can change with writing mode/directional changes.
4002 if (!hasPercentHeightContainerMap())
4005 if (!hasPercentHeightDescendant(descendant))
4008 removePercentHeightDescendant(descendant);
4011 void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent)
4013 ASSERT(gPercentHeightContainerMap);
4014 for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) {
4018 RenderBox* box = toRenderBox(curr);
4019 if (!hasPercentHeightDescendant(box))
4022 removePercentHeightDescendant(box);
4026 static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom)
4028 if (objectTop >= floatBottom || objectBottom < floatTop)
4031 // The top of the object overlaps the float
4032 if (objectTop >= floatTop)
4035 // The object encloses the float
4036 if (objectTop < floatTop && objectBottom > floatBottom)
4039 // The bottom of the object overlaps the float
4040 if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom)
4046 template <RenderBlock::FloatingObject::Type FloatTypeValue>
4047 inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval) const
4049 const FloatingObject* r = interval.data();
4050 if (r->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lowValue, m_highValue))
4053 // All the objects returned from the tree should be already placed.
4054 ASSERT(r->isPlaced() && rangesIntersect(m_renderer->pixelSnappedLogicalTopForFloat(r), m_renderer->pixelSnappedLogicalBottomForFloat(r), m_lowValue, m_highValue));
4056 if (FloatTypeValue == FloatingObject::FloatLeft
4057 && m_renderer->logicalRightForFloat(r) > m_offset) {
4058 m_offset = m_renderer->logicalRightForFloat(r);
4059 if (m_heightRemaining)
4060 *m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
4063 if (FloatTypeValue == FloatingObject::FloatRight
4064 && m_renderer->logicalLeftForFloat(r) < m_offset) {
4065 m_offset = m_renderer->logicalLeftForFloat(r);
4066 if (m_heightRemaining)
4067 *m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
4071 LayoutUnit RenderBlock::textIndentOffset() const
4074 RenderView* renderView = 0;
4075 if (style()->textIndent().isPercent())
4076 cw = containingBlock()->availableLogicalWidth();
4077 else if (style()->textIndent().isViewportPercentage())
4078 renderView = view();
4079 return minimumValueForLength(style()->textIndent(), cw, renderView);
4082 LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
4084 LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
4085 if (!inRenderFlowThread())
4086 return logicalLeftOffset;
4087 LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
4088 return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
4091 LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
4093 LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
4094 logicalRightOffset += availableLogicalWidth();
4095 if (!inRenderFlowThread())
4096 return logicalRightOffset;
4097 LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
4098 return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
4101 LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
4103 LayoutUnit left = fixedOffset;
4104 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
4105 if (heightRemaining)
4106 *heightRemaining = 1;
4108 FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), left, heightRemaining);
4109 m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
4112 if (applyTextIndent && style()->isLeftToRightDirection())
4113 left += textIndentOffset();
4115 if (style()->lineAlign() == LineAlignNone)
4118 // Push in our left offset so that it is aligned with the character grid.
4119 LayoutState* layoutState = view()->layoutState();
4123 RenderBlock* lineGrid = layoutState->lineGrid();
4124 if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
4127 // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
4128 float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
4132 LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
4133 LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
4135 // Push in to the nearest character width (truncated so that we pixel snap left).
4136 // FIXME: Should be patched when subpixel layout lands, since this calculation doesn't have to pixel snap
4137 // any more (https://bugs.webkit.org/show_bug.cgi?id=79946).
4138 // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
4139 // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
4140 // FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
4141 // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
4142 // (https://bugs.webkit.org/show_bug.cgi?id=79944)
4143 float remainder = fmodf(maxCharWidth - fmodf(left + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
4148 LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
4150 LayoutUnit right = fixedOffset;
4151 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
4152 if (heightRemaining)
4153 *heightRemaining = 1;
4155 LayoutUnit rightFloatOffset = fixedOffset;
4156 FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), rightFloatOffset, heightRemaining);
4157 m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
4158 right = min(right, rightFloatOffset);
4161 if (applyTextIndent && !style()->isLeftToRightDirection())
4162 right -= textIndentOffset();
4164 if (style()->lineAlign() == LineAlignNone)
4167 // Push in our right offset so that it is aligned with the character grid.
4168 LayoutState* layoutState = view()->layoutState();
4172 RenderBlock* lineGrid = layoutState->lineGrid();
4173 if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
4176 // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
4177 float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
4181 LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
4182 LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
4184 // Push in to the nearest character width (truncated so that we pixel snap right).
4185 // FIXME: Should be patched when subpixel layout lands, since this calculation doesn't have to pixel snap
4186 // any more (https://bugs.webkit.org/show_bug.cgi?id=79946).
4187 // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
4188 // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
4189 // FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
4190 // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
4191 // (https://bugs.webkit.org/show_bug.cgi?id=79944)
4192 float remainder = fmodf(fmodf(right + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
4193 right -= ceilf(remainder);
4197 LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
4199 if (!m_floatingObjects)
4200 return logicalHeight;
4202 LayoutUnit bottom = MAX_LAYOUT_UNIT;
4203 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4204 FloatingObjectSetIterator end = floatingObjectSet.end();
4205 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4206 FloatingObject* r = *it;
4207 LayoutUnit floatBottom = logicalBottomForFloat(r);
4208 if (floatBottom > logicalHeight)
4209 bottom = min(floatBottom, bottom);
4212 return bottom == MAX_LAYOUT_UNIT ? ZERO_LAYOUT_UNIT : bottom;
4215 LayoutUnit RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
4217 if (!m_floatingObjects)
4218 return ZERO_LAYOUT_UNIT;
4219 LayoutUnit lowestFloatBottom = ZERO_LAYOUT_UNIT;
4220 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4221 FloatingObjectSetIterator end = floatingObjectSet.end();
4222 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4223 FloatingObject* r = *it;
4224 if (r->isPlaced() && r->type() & floatType)
4225 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r));
4227 return lowestFloatBottom;
4230 void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
4232 if (logicalTop >= logicalBottom)
4235 RootInlineBox* lowestDirtyLine = lastRootBox();
4236 RootInlineBox* afterLowest = lowestDirtyLine;
4237 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < MAX_LAYOUT_UNIT) {
4238 afterLowest = lowestDirtyLine;
4239 lowestDirtyLine = lowestDirtyLine->prevRootBox();
4242 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
4243 afterLowest->markDirty();
4244 afterLowest = afterLowest->prevRootBox();
4248 void RenderBlock::clearFloats()
4250 if (m_floatingObjects)
4251 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
4253 HashSet<RenderBox*> oldIntrudingFloatSet;
4254 if (!childrenInline() && m_floatingObjects) {
4255 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4256 FloatingObjectSetIterator end = floatingObjectSet.end();
4257 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4258 FloatingObject* floatingObject = *it;
4259 if (!floatingObject->isDescendant())
4260 oldIntrudingFloatSet.add(floatingObject->m_renderer);
4264 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
4265 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
4266 if (m_floatingObjects) {
4267 deleteAllValues(m_floatingObjects->set());
4268 m_floatingObjects->clear();
4270 if (!oldIntrudingFloatSet.isEmpty())
4271 markAllDescendantsWithFloatsForLayout();
4275 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
4276 RendererToFloatInfoMap floatMap;
4278 if (m_floatingObjects) {
4279 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4280 if (childrenInline()) {
4281 FloatingObjectSetIterator end = floatingObjectSet.end();
4282 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4283 FloatingObject* f = *it;
4284 floatMap.add(f->m_renderer, f);
4287 deleteAllValues(floatingObjectSet);
4288 m_floatingObjects->clear();
4291 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
4292 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
4293 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
4294 if (!parent() || !parent()->isRenderBlock())
4297 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
4298 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
4300 RenderBlock* parentBlock = toRenderBlock(parent());
4301 bool parentHasFloats = false;
4302 RenderObject* prev = previousSibling();
4303 while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
4304 if (prev->isFloating())
4305 parentHasFloats = true;
4306 prev = prev->previousSibling();
4309 // First add in floats from the parent.
4310 LayoutUnit logicalTopOffset = logicalTop();
4311 if (parentHasFloats)
4312 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
4314 LayoutUnit logicalLeftOffset = 0;
4316 logicalTopOffset -= toRenderBox(prev)->logicalTop();
4319 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
4322 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
4323 RenderBlock* block = toRenderBlock(prev);
4324 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
4325 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
4327 if (childrenInline()) {
4328 LayoutUnit changeLogicalTop = MAX_LAYOUT_UNIT;
4329 LayoutUnit changeLogicalBottom = MIN_LAYOUT_UNIT;
4330 if (m_floatingObjects) {
4331 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4332 FloatingObjectSetIterator end = floatingObjectSet.end();
4333 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4334 FloatingObject* f = *it;
4335 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
4336 LayoutUnit logicalBottom = logicalBottomForFloat(f);
4337 if (oldFloatingObject) {
4338 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject);
4339 if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) {
4340 changeLogicalTop = 0;
4341 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
4343 if (logicalBottom != oldLogicalBottom) {
4344 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
4345 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
4347 LayoutUnit logicalTop = logicalTopForFloat(f);
4348 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject);
4349 if (logicalTop != oldLogicalTop) {
4350 changeLogicalTop = min(changeLogicalTop, min(logicalTop, oldLogicalTop));
4351 changeLogicalBottom = max(changeLogicalBottom, max(logicalTop, oldLogicalTop));
4355 floatMap.remove(f->m_renderer);
4356 if (oldFloatingObject->m_originatingLine && !selfNeedsLayout()) {
4357 ASSERT(oldFloatingObject->m_originatingLine->renderer() == this);
4358 oldFloatingObject->m_originatingLine->markDirty();
4360 delete oldFloatingObject;
4362 changeLogicalTop = 0;
4363 changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
4368 RendererToFloatInfoMap::iterator end = floatMap.end();
4369 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
4370 FloatingObject* floatingObject = (*it).second;
4371 if (!floatingObject->isDescendant()) {
4372 changeLogicalTop = 0;
4373 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
4376 deleteAllValues(floatMap);
4378 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
4379 } else if (!oldIntrudingFloatSet.isEmpty()) {
4380 // If there are previously intruding floats that no longer intrude, then children with floats
4381 // should also get layout because they might need their floating object lists cleared.
4382 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
4383 markAllDescendantsWithFloatsForLayout();
4385 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4386 FloatingObjectSetIterator end = floatingObjectSet.end();
4387 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
4388 oldIntrudingFloatSet.remove((*it)->m_renderer);
4389 if (!oldIntrudingFloatSet.isEmpty())
4390 markAllDescendantsWithFloatsForLayout();
4395 LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildPaintOtherFloats)
4397 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
4398 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
4401 LayoutUnit childLogicalTop = child->logicalTop();
4402 LayoutUnit childLogicalLeft = child->logicalLeft();
4403 LayoutUnit lowestFloatLogicalBottom = 0;
4405 // Floats that will remain the child's responsibility to paint should factor into its
4407 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end();
4408 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
4409 FloatingObject* r = *childIt;
4410 LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(r), MAX_LAYOUT_UNIT - childLogicalTop);
4411 LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat;
4412 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
4414 if (logicalBottom > logicalHeight()) {
4415 // If the object is not in the list, we add it now.
4416 if (!containsFloat(r->m_renderer)) {
4417 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
4418 FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size()));
4419 floatingObj->m_renderer = r->m_renderer;
4421 // The nearest enclosing layer always paints the float (so that zindex and stacking
4422 // behaves properly). We always want to propagate the desire to paint the float as
4423 // far out as we can, to the outermost block that overlaps the float, stopping only
4424 // if we hit a self-painting layer boundary.
4425 if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer())
4426 r->setShouldPaint(false);
4428 floatingObj->setShouldPaint(false);
4430 floatingObj->setIsDescendant(true);
4432 // We create the floating object list lazily.
4433 if (!m_floatingObjects)
4434 m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
4436 m_floatingObjects->add(floatingObj);
4439 if (makeChildPaintOtherFloats && !r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer()
4440 && r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) {
4441 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
4442 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
4444 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
4446 r->setShouldPaint(true);
4449 // 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
4451 if (r->isDescendant())
4452 child->addOverflowFromChild(r->m_renderer, LayoutSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
4455 return lowestFloatLogicalBottom;
4458 bool RenderBlock::hasOverhangingFloat(RenderBox* renderer)
4460 if (!m_floatingObjects || hasColumns() || !parent())
4463 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4464 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(renderer);
4465 if (it == floatingObjectSet.end())
4468 return logicalBottomForFloat(*it) > logicalHeight();
4471 void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
4473 // If the parent or previous sibling doesn't have any floats to add, don't bother.
4474 if (!prev->m_floatingObjects)
4477 logicalLeftOffset += marginLogicalLeft();
4479 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
4480 FloatingObjectSetIterator prevEnd = prevSet.end();
4481 for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
4482 FloatingObject* r = *prevIt;
4483 if (logicalBottomForFloat(r) > logicalTopOffset) {
4484 if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) {
4485 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, logicalTopOffset) : LayoutSize(logicalTopOffset, logicalLeftOffset);
4486 FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size()));
4488 // Applying the child's margin makes no sense in the case where the child was passed in.
4489 // since this margin was added already through the modification of the |logicalLeftOffset| variable
4490 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
4491 // into account. Only apply this code if prev is the parent, since otherwise the left margin
4492 // will get applied twice.
4493 if (prev != parent()) {
4494 if (isHorizontalWritingMode())
4495 floatingObj->setX(floatingObj->x() + prev->marginLeft());
4497 floatingObj->setY(floatingObj->y() + prev->marginTop());
4500 floatingObj->setShouldPaint(false); // We are not in the direct inheritance chain for this float. We will never paint it.
4501 floatingObj->m_renderer = r->m_renderer;
4503 // We create the floating object list lazily.
4504 if (!m_floatingObjects)
4505 m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
4506 m_floatingObjects->add(floatingObj);
4512 bool RenderBlock::avoidsFloats() const
4514 // Floats can't intrude into our box if we have a non-auto column count or width.
4515 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
4518 bool RenderBlock::containsFloat(RenderBox* renderer) const
4520 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer);
4523 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
4525 if (!everHadLayout())
4528 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
4529 setChildNeedsLayout(true, markParents);
4532 removeFloatingObject(floatToRemove);
4534 // Iterate over our children and mark them as needed.
4535 if (!childrenInline()) {
4536 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
4537 if ((!floatToRemove && child->isFloatingOrOutOfFlowPositioned()) || !child->isRenderBlock())
4539 RenderBlock* childBlock = toRenderBlock(child);
4540 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats())
4541 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
4546 void RenderBlock::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
4548 if (!m_floatingObjects)
4551 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4552 FloatingObjectSetIterator end = floatingObjectSet.end();
4554 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
4555 if (!next->isRenderBlock() || next->isFloatingOrOutOfFlowPositioned() || toRenderBlock(next)->avoidsFloats())
4558 RenderBlock* nextBlock = toRenderBlock(next);
4559 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4560 RenderBox* floatingBox = (*it)->renderer();
4561 if (floatToRemove && floatingBox != floatToRemove)
4563 if (nextBlock->containsFloat(floatingBox))
4564 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox);
4569 LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
4571 // There is no need to compute clearance if we have no floats.
4572 if (!containsFloats())
4575 // At least one float is present. We need to perform the clearance computation.
4576 bool clearSet = child->style()->clear() != CNONE;
4577 LayoutUnit logicalBottom = 0;
4578 switch (child->style()->clear()) {
4582 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
4585 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
4588 logicalBottom = lowestFloatLogicalBottom();
4592 // 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).
4593 LayoutUnit result = clearSet ? max(ZERO_LAYOUT_UNIT, logicalBottom - logicalTop) : ZERO_LAYOUT_UNIT;
4594 if (!result && child->avoidsFloats()) {
4595 LayoutUnit newLogicalTop = logicalTop;
4597 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
4598 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
4599 return newLogicalTop - logicalTop;
4601 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
4602 LayoutRect borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
4603 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
4605 // FIXME: None of this is right for perpendicular writing-mode children.
4606 LayoutUnit childOldLogicalWidth = child->logicalWidth();
4607 LayoutUnit childOldMarginLeft = child->marginLeft();
4608 LayoutUnit childOldMarginRight = child->marginRight();
4609 LayoutUnit childOldLogicalTop = child->logicalTop();
4611 child->setLogicalTop(newLogicalTop);
4612 child->computeLogicalWidth();
4613 region = regionAtBlockOffset(logicalTopForChild(child));
4614 borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
4615 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
4617 child->setLogicalTop(childOldLogicalTop);
4618 child->setLogicalWidth(childOldLogicalWidth);
4619 child->setMarginLeft(childOldMarginLeft);
4620 child->setMarginRight(childOldMarginRight);
4622 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
4623 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
4624 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
4625 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
4626 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
4627 child->setChildNeedsLayout(true, MarkOnlyThis);
4628 return newLogicalTop - logicalTop;
4631 newLogicalTop = nextFloatLogicalBottomBelow(newLogicalTop);
4632 ASSERT(newLogicalTop >= logicalTop);
4633 if (newLogicalTop < logicalTop)
4636 ASSERT_NOT_REACHED();
4641 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
4643 if (!scrollsOverflow())
4646 return layer()->hitTestOverflowControls(result, roundedIntPoint(pointInContainer - toLayoutSize(accumulatedOffset)));
4649 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4651 LayoutPoint adjustedLocation(accumulatedOffset + location());
4652 LayoutSize localOffset = toLayoutSize(adjustedLocation);
4654 if (!isRenderView()) {
4655 // Check if we need to do anything at all.
4656 LayoutRect overflowBox = visualOverflowRect();
4657 flipForWritingMode(overflowBox);
4658 overflowBox.moveBy(adjustedLocation);
4659 if (!pointInContainer.intersects(overflowBox))
4663 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, pointInContainer.point(), adjustedLocation)) {
4664 updateHitTestResult(result, pointInContainer.point() - localOffset);
4665 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
4666 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer))
4670 // If we have clipping, then we can't have any spillout.
4671 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
4672 bool useClip = (hasControlClip() || useOverflowClip);
4673 bool checkChildren = !useClip || (hasControlClip() ? pointInContainer.intersects(controlClipRect(adjustedLocation)) : pointInContainer.intersects(overflowClipRect(adjustedLocation, pointInContainer.region(), IncludeOverlayScrollbarSize)));
4674 if (checkChildren) {
4675 // Hit test descendants first.
4676 LayoutSize scrolledOffset(localOffset);
4677 if (hasOverflowClip())
4678 scrolledOffset -= scrolledContentOffset();
4680 // Hit test contents if we don't have columns.
4681 if (!hasColumns()) {
4682 if (hitTestContents(request, result, pointInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
4683 updateHitTestResult(result, pointInContainer.point() - localOffset);
4686 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, toLayoutPoint(scrolledOffset)))
4688 } else if (hitTestColumns(request, result, pointInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
4689 updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - localOffset));
4694 // Now hit test our background
4695 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
4696 LayoutRect boundsRect(adjustedLocation, size());
4697 if (visibleToHitTesting() && pointInContainer.intersects(boundsRect)) {
4698 updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - localOffset));
4699 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect))
4707 bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
4709 if (!m_floatingObjects)
4712 LayoutPoint adjustedLocation = accumulatedOffset;
4713 if (isRenderView()) {
4714 adjustedLocation += toLayoutSize(toRenderView(this)->frameView()->scrollPosition());
4717 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4718 FloatingObjectSetIterator begin = floatingObjectSet.begin();
4719 for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) {
4721 FloatingObject* floatingObject = *it;
4722 if (floatingObject->shouldPaint() && !floatingObject->m_renderer->hasSelfPaintingLayer()) {
4723 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x();
4724 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y();
4725 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
4726 if (floatingObject->m_renderer->hitTest(request, result, pointInContainer, childPoint)) {
4727 updateHitTestResult(result, pointInContainer.point() - toLayoutSize(childPoint));
4736 class ColumnRectIterator {
4737 WTF_MAKE_NONCOPYABLE(ColumnRectIterator);
4739 ColumnRectIterator(const RenderBlock& block)
4741 , m_colInfo(block.columnInfo())
4742 , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1)
4743 , m_isHorizontal(block.isHorizontalWritingMode())
4744 , m_logicalLeft(block.logicalLeftOffsetForContent())
4746 int colCount = m_colInfo->columnCount();
4747 m_colIndex = colCount - 1;
4748 m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
4759 LayoutRect columnRect() const { return m_colRect; }
4760 bool hasMore() const { return m_colIndex >= 0; }
4762 void adjust(LayoutSize& offset) const
4764 LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
4765 offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
4766 if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
4768 offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
4770 offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
4780 m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
4781 m_block.flipForWritingMode(m_colRect);
4782 m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
4785 const RenderBlock& m_block;
4786 const ColumnInfo* const m_colInfo;
4787 const int m_direction;
4788 const bool m_isHorizontal;
4789 const LayoutUnit m_logicalLeft;
4791 LayoutUnit m_currLogicalTopOffset;
4792 LayoutRect m_colRect;
4795 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4797 // We need to do multiple passes, breaking up our hit testing into strips.
4801 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
4802 LayoutRect hitRect = pointInContainer.boundingBox();
4803 LayoutRect colRect = it.columnRect();
4804 colRect.moveBy(accumulatedOffset);
4805 if (pointInContainer.intersects(colRect)) {
4806 // The point is inside this column.
4807 // Adjust accumulatedOffset to change where we hit test.
4810 LayoutPoint finalLocation = accumulatedOffset + offset;
4811 if (!result.isRectBasedTest() || colRect.contains(hitRect))
4812 return hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, finalLocation));
4814 hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction);
4821 void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& pointInContainer) const
4823 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
4824 LayoutRect colRect = it.columnRect();
4825 if (colRect.contains(pointInContainer)) {
4832 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4834 if (childrenInline() && !isTable()) {
4835 // We have to hit-test our line boxes.
4836 if (m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction))
4839 // Hit test our children.
4840 HitTestAction childHitTest = hitTestAction;
4841 if (hitTestAction == HitTestChildBlockBackgrounds)
4842 childHitTest = HitTestChildBlockBackground;
4843 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
4844 LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
4845 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, pointInContainer, childPoint, childHitTest))
4853 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
4858 if (!box->renderer()->node())
4859 return createLegacyEditingPosition(node(), start ? caretMinOffset() : caretMaxOffset());
4861 if (!box->isInlineTextBox())
4862 return createLegacyEditingPosition(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
4864 InlineTextBox* textBox = toInlineTextBox(box);
4865 return createLegacyEditingPosition(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
4868 static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
4870 ASSERT(!ancestor || ancestor->node());
4871 ASSERT(child && child->node());
4872 return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
4873 || ancestor->node()->rendererIsEditable() == child->node()->rendererIsEditable();
4876 // FIXME: This function should go on RenderObject as an instance method. Then
4877 // all cases in which positionForPoint recurs could call this instead to
4878 // prevent crossing editable boundaries. This would require many tests.
4879 static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates)
4881 LayoutPoint childLocation = child->location();
4882 if (child->isRelPositioned())
4883 childLocation += child->relativePositionOffset();
4884 // FIXME: This is wrong if the child's writing-mode is different from the parent's.
4885 LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
4887 // If this is an anonymous renderer, we just recur normally
4888 Node* childNode = child->node();
4890 return child->positionForPoint(pointInChildCoordinates);
4892 // Otherwise, first make sure that the editability of the parent and child agree.
4893 // If they don't agree, then we return a visible position just before or after the child
4894 RenderObject* ancestor = parent;
4895 while (ancestor && !ancestor->node())
4896 ancestor = ancestor->parent();
4898 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
4899 if (isEditingBoundary(ancestor, child))
4900 return child->positionForPoint(pointInChildCoordinates);
4902 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
4903 LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2;
4904 LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
4905 if (logicalLeft < childMiddle)
4906 return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM);
4907 return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM);
4910 VisiblePosition RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
4912 ASSERT(childrenInline());
4914 if (!firstRootBox())
4915 return createVisiblePosition(0, DOWNSTREAM);
4917 bool linesAreFlipped = style()->isFlippedLinesWritingMode();
4918 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
4920 // look for the closest line box in the root box which is at the passed-in y coordinate
4921 InlineBox* closestBox = 0;
4922 RootInlineBox* firstRootBoxWithChildren = 0;
4923 RootInlineBox* lastRootBoxWithChildren = 0;
4924 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
4925 if (!root->firstLeafChild())
4927 if (!firstRootBoxWithChildren)
4928 firstRootBoxWithChildren = root;
4930 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
4931 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
4934 lastRootBoxWithChildren = root;
4936 // check if this root line box is located at this y coordinate
4937 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
4938 if (linesAreFlipped) {
4939 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
4940 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
4941 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
4943 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
4944 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
4947 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
4953 bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
4955 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
4956 // y coordinate is below last root line box, pretend we hit it
4957 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
4961 if (moveCaretToBoundary) {
4962 LayoutUnit firstRootBoxWithChildrenTop = min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
4963 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
4964 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
4965 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
4966 if (box->isLineBreak()) {
4967 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
4970 // y coordinate is above first root line box, so return the start of the first
4971 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
4975 // pass the box a top position that is inside it
4976 LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine());
4977 if (!isHorizontalWritingMode())
4978 point = point.transposedPoint();
4979 if (closestBox->renderer()->isReplaced())
4980 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
4981 return closestBox->renderer()->positionForPoint(point);
4984 if (lastRootBoxWithChildren) {
4985 // We hit this case for Mac behavior when the Y coordinate is below the last box.
4986 ASSERT(moveCaretToBoundary);
4987 InlineBox* logicallyLastBox;
4988 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
4989 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
4992 // Can't reach this. We have a root line box, but it has no kids.
4993 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
4994 // seems to hit this code path.
4995 return createVisiblePosition(0, DOWNSTREAM);
4998 static inline bool isChildHitTestCandidate(RenderBox* box)
5000 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned();
5003 VisiblePosition RenderBlock::positionForPoint(const LayoutPoint& point)
5006 return RenderBox::positionForPoint(point);
5009 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
5010 LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
5011 LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
5013 if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0))
5014 return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
5015 if (pointLogicalTop >= logicalHeight() || (pointLogicalTop >= 0 && pointLogicalLeft >= logicalWidth()))
5016 return createVisiblePosition(caretMaxOffset(), DOWNSTREAM);
5019 LayoutPoint pointInContents = point;
5020 offsetForContents(pointInContents);
5021 LayoutPoint pointInLogicalContents(pointInContents);
5022 if (!isHorizontalWritingMode())
5023 pointInLogicalContents = pointInLogicalContents.transposedPoint();
5025 if (childrenInline())
5026 return positionForPointWithInlineChildren(pointInLogicalContents);
5028 RenderBox* lastCandidateBox = lastChildBox();
5029 while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
5030 lastCandidateBox = lastCandidateBox->previousSiblingBox();
5032 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
5033 if (lastCandidateBox) {
5034 if (pointInLogicalContents.y() > logicalTopForChild(lastCandidateBox)
5035 || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(lastCandidateBox)))
5036 return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
5038 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
5039 if (!isChildHitTestCandidate(childBox))
5041 LayoutUnit childLogicalBottom = logicalTopForChild(childBox) + logicalHeightForChild(childBox);
5042 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
5043 if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
5044 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
5045 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
5049 // We only get here if there are no hit test candidate children below the click.
5050 return RenderBox::positionForPoint(point);
5053 void RenderBlock::offsetForContents(LayoutPoint& offset) const
5055 offset = flipForWritingMode(offset);
5057 if (hasOverflowClip())
5058 offset += scrolledContentOffset();
5061 adjustPointToColumnContents(offset);
5063 offset = flipForWritingMode(offset);
5066 LayoutUnit RenderBlock::availableLogicalWidth() const
5068 // If we have multiple columns, then the available logical width is reduced to our column width.
5070 return desiredColumnWidth();
5071 return RenderBox::availableLogicalWidth();
5074 int RenderBlock::columnGap() const
5076 if (style()->hasNormalColumnGap())
5077 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
5078 return static_cast<int>(style()->columnGap());
5081 void RenderBlock::calcColumnWidth()
5083 if (document()->regionBasedColumnsEnabled())
5086 // Calculate our column width and column count.
5087 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
5088 unsigned desiredColumnCount = 1;
5089 LayoutUnit desiredColumnWidth = contentLogicalWidth();
5091 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
5092 if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) {
5093 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
5097 LayoutUnit availWidth = desiredColumnWidth;
5098 LayoutUnit colGap = columnGap();
5099 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
5100 int colCount = max<int>(1, style()->columnCount());
5102 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
5103 desiredColumnCount = colCount;
5104 desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
5105 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
5106 desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
5107 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
5109 desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
5110 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
5112 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
5115 bool RenderBlock::requiresColumns(int desiredColumnCount) const
5118 && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis())
5119 && !firstChild()->isAnonymousColumnsBlock()
5120 && !firstChild()->isAnonymousColumnSpanBlock();
5123 void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
5125 bool destroyColumns = !requiresColumns(count);
5126 if (destroyColumns) {
5128 delete gColumnInfoMap->take(this);
5129 setHasColumns(false);
5134 info = gColumnInfoMap->get(this);
5136 if (!gColumnInfoMap)
5137 gColumnInfoMap = new ColumnInfoMap;
5138 info = new ColumnInfo;
5139 gColumnInfoMap->add(this, info);
5140 setHasColumns(true);
5142 info->setDesiredColumnCount(count);
5143 info->setDesiredColumnWidth(width);
5144 info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
5145 info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
5149 LayoutUnit RenderBlock::desiredColumnWidth() const
5152 return contentLogicalWidth();
5153 return gColumnInfoMap->get(this)->desiredColumnWidth();
5156 unsigned RenderBlock::desiredColumnCount() const
5160 return gColumnInfoMap->get(this)->desiredColumnCount();
5163 ColumnInfo* RenderBlock::columnInfo() const
5167 return gColumnInfoMap->get(this);
5170 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
5172 ASSERT(hasColumns());
5173 ASSERT(gColumnInfoMap->get(this) == colInfo);
5174 return colInfo->columnCount();
5177 LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
5179 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
5181 // Compute the appropriate rect based off our information.
5182 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
5183 LayoutUnit colLogicalHeight = colInfo->columnHeight();
5184 LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
5185 LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
5186 int colGap = columnGap();
5187 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5188 if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
5189 colLogicalLeft += index * (colLogicalWidth + colGap);
5191 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
5193 if (!colInfo->progressionIsReversed())
5194 colLogicalTop += index * (colLogicalHeight + colGap);
5196 colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap);
5199 if (isHorizontalWritingMode())
5200 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
5201 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
5204 bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer& statePusher)
5209 OwnPtr<RenderOverflow> savedOverflow = m_overflow.release();
5210 if (childrenInline())
5211 addOverflowFromInlineChildren();
5213 addOverflowFromBlockChildren();
5214 LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore();
5216 // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
5217 // the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
5218 ColumnInfo* colInfo = columnInfo();
5219 if (!hasSpecifiedPageLogicalHeight) {
5220 LayoutUnit columnHeight = pageLogicalHeight;
5221 int minColumnCount = colInfo->forcedBreaks() + 1;
5222 int desiredColumnCount = colInfo->desiredColumnCount();
5223 if (minColumnCount >= desiredColumnCount) {
5224 // The forced page breaks are in control of the balancing. Just set the column height to the
5225 // maximum page break distance.
5226 if (!pageLogicalHeight) {
5227 LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(),
5228 view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset());
5229 columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
5231 } else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) {
5232 // Now that we know the intrinsic height of the columns, we have to rebalance them.
5233 columnHeight = max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf((float)layoutOverflowLogicalBottom / desiredColumnCount));
5236 if (columnHeight && columnHeight != pageLogicalHeight) {
5238 setEverHadLayout(true);
5239 layoutBlock(false, columnHeight);
5244 if (pageLogicalHeight)
5245 colInfo->setColumnCountAndHeight(ceilf((float)layoutOverflowLogicalBottom / pageLogicalHeight), pageLogicalHeight);
5247 if (columnCount(colInfo)) {
5248 setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
5251 m_overflow = savedOverflow.release();
5256 void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
5258 // Just bail if we have no columns.
5262 ColumnInfo* colInfo = columnInfo();
5263 if (!columnCount(colInfo))
5266 // Determine which columns we intersect.
5267 LayoutUnit colGap = columnGap();
5268 LayoutUnit halfColGap = colGap / 2;
5269 LayoutPoint columnPoint(columnRectAt(colInfo, 0).location());
5270 LayoutUnit logicalOffset = 0;
5271 for (unsigned i = 0; i < colInfo->columnCount(); i++) {
5272 // Add in half the column gap to the left and right of the rect.
5273 LayoutRect colRect = columnRectAt(colInfo, i);
5274 flipForWritingMode(colRect);
5275 if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) {
5276 LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
5277 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
5278 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5279 // FIXME: The clamping that follows is not completely right for right-to-left
5281 // Clamp everything above the column to its top left.
5282 if (point.y() < gapAndColumnRect.y())
5283 point = gapAndColumnRect.location();
5284 // Clamp everything below the column to the next column's top left. If there is
5285 // no next column, this still maps to just after this column.
5286 else if (point.y() >= gapAndColumnRect.maxY()) {
5287 point = gapAndColumnRect.location();
5288 point.move(0, gapAndColumnRect.height());
5291 if (point.x() < colRect.x())
5292 point.setX(colRect.x());
5293 else if (point.x() >= colRect.maxX())
5294 point.setX(colRect.maxX() - 1);
5297 // We're inside the column. Translate the x and y into our column coordinate space.
5298 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5299 point.move(columnPoint.x() - colRect.x(), (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset));
5301 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0);
5305 // Move to the next position.
5306 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width();
5308 LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
5309 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
5310 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5311 // FIXME: The clamping that follows is not completely right for right-to-left
5313 // Clamp everything above the column to its top left.
5314 if (point.x() < gapAndColumnRect.x())
5315 point = gapAndColumnRect.location();
5316 // Clamp everything below the column to the next column's top left. If there is
5317 // no next column, this still maps to just after this column.
5318 else if (point.x() >= gapAndColumnRect.maxX()) {
5319 point = gapAndColumnRect.location();
5320 point.move(gapAndColumnRect.width(), 0);
5323 if (point.y() < colRect.y())
5324 point.setY(colRect.y());
5325 else if (point.y() >= colRect.maxY())
5326 point.setY(colRect.maxY() - 1);
5329 // We're inside the column. Translate the x and y into our column coordinate space.
5330 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5331 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset), columnPoint.y() - colRect.y());
5333 point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop());
5337 // Move to the next position.
5338 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height();
5343 void RenderBlock::adjustRectForColumns(LayoutRect& r) const
5345 // Just bail if we have no columns.
5349 ColumnInfo* colInfo = columnInfo();
5351 // Determine which columns we intersect.
5352 unsigned colCount = columnCount(colInfo);
5356 // Begin with a result rect that is empty.
5359 bool isHorizontal = isHorizontalWritingMode();
5360 LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
5361 LayoutUnit colHeight = colInfo->columnHeight();
5365 LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
5366 LayoutUnit endOffset = min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight);
5368 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
5369 unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
5370 unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight;
5372 if (startColumn == endColumn) {
5373 // The rect is fully contained within one column. Adjust for our offsets
5374 // and repaint only that portion.
5375 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent();
5376 LayoutRect colRect = columnRectAt(colInfo, startColumn);
5377 LayoutRect repaintRect = r;
5379 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5381 repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight);
5383 repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset);
5386 repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding);
5388 repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0);
5390 repaintRect.intersect(colRect);
5391 result.unite(repaintRect);
5393 // We span multiple columns. We can just unite the start and end column to get the final
5395 result.unite(columnRectAt(colInfo, startColumn));
5396 result.unite(columnRectAt(colInfo, endColumn));
5402 LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
5404 ASSERT(hasColumns());
5405 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
5407 ColumnInfo* colInfo = columnInfo();
5408 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
5409 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
5410 if (isHorizontalWritingMode())
5411 return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
5412 return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
5415 void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const
5417 ASSERT(hasColumns());
5418 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
5421 ColumnInfo* colInfo = columnInfo();
5422 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
5423 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
5425 if (isHorizontalWritingMode())
5426 rect.setY(expandedLogicalHeight - rect.maxY());
5428 rect.setX(expandedLogicalHeight - rect.maxX());
5431 void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const
5436 ColumnInfo* colInfo = columnInfo();
5438 LayoutUnit logicalLeft = logicalLeftOffsetForContent();
5439 unsigned colCount = columnCount(colInfo);
5440 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
5441 LayoutUnit colLogicalHeight = colInfo->columnHeight();
5443 for (unsigned i = 0; i < colCount; ++i) {
5444 // Compute the edges for a given column in the block progression direction.
5445 LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
5446 if (!isHorizontalWritingMode())
5447 sliceRect = sliceRect.transposedRect();
5449 LayoutUnit logicalOffset = i * colLogicalHeight;
5451 // Now we're in the same coordinate space as the point. See if it is inside the rectangle.
5452 if (isHorizontalWritingMode()) {
5453 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
5454 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5455 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
5457 offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
5461 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
5462 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5463 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
5465 offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
5472 void RenderBlock::computePreferredLogicalWidths()
5474 ASSERT(preferredLogicalWidthsDirty());
5476 updateFirstLetter();
5478 RenderStyle* styleToUse = style();
5479 if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
5480 && style()->marqueeBehavior() != MALTERNATE && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
5481 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(styleToUse->logicalWidth().value());
5483 m_minPreferredLogicalWidth = 0;
5484 m_maxPreferredLogicalWidth = 0;
5486 if (childrenInline())
5487 computeInlinePreferredLogicalWidths();
5489 computeBlockPreferredLogicalWidths();
5491 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
5493 if (!styleToUse->autoWrap() && childrenInline()) {
5494 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
5496 // A horizontal marquee with inline children has no minimum width.
5497 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
5498 m_minPreferredLogicalWidth = 0;
5501 int scrollbarWidth = 0;
5502 // FIXME: This should only be done for horizontal writing mode.
5503 // For vertical writing mode, this should check overflowX and use the horizontalScrollbarHeight.
5504 if (hasOverflowClip() && styleToUse->overflowY() == OSCROLL) {
5505 layer()->setHasVerticalScrollbar(true);
5506 scrollbarWidth = verticalScrollbarWidth();
5507 m_maxPreferredLogicalWidth += scrollbarWidth;
5510 if (isTableCell()) {
5511 Length w = toRenderTableCell(this)->styleOrColLogicalWidth();
5512 if (w.isFixed() && w.value() > 0) {
5513 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(w.value()));
5518 m_minPreferredLogicalWidth += scrollbarWidth;
5521 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
5522 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
5523 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
5526 if (styleToUse->logicalMaxWidth().isFixed()) {
5527 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
5528 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
5531 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
5532 m_minPreferredLogicalWidth += borderAndPadding;
5533 m_maxPreferredLogicalWidth += borderAndPadding;
5535 setPreferredLogicalWidthsDirty(false);
5538 struct InlineMinMaxIterator {
5539 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
5540 inline min/max width calculations. Note the following about the way it walks:
5541 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
5542 (2) We do not drill into the children of floats or replaced elements, since you can't break
5543 in the middle of such an element.
5544 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
5545 distinct borders/margin/padding that contribute to the min/max width.
5547 RenderObject* parent;
5548 RenderObject* current;
5551 InlineMinMaxIterator(RenderObject* p, bool end = false)
5552 :parent(p), current(p), endOfInline(end) {}
5554 RenderObject* next();
5557 RenderObject* InlineMinMaxIterator::next()
5559 RenderObject* result = 0;
5560 bool oldEndOfInline = endOfInline;
5561 endOfInline = false;
5562 while (current || current == parent) {
5563 if (!oldEndOfInline &&
5564 (current == parent ||
5565 (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
5566 result = current->firstChild();
5568 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
5569 if (!oldEndOfInline && current->isRenderInline()) {
5575 while (current && current != parent) {
5576 result = current->nextSibling();
5578 current = current->parent();
5579 if (current && current != parent && current->isRenderInline()) {
5590 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
5597 // Update our position.
5602 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
5604 if (cssUnit.type() != Auto)
5605 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
5609 static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
5611 RenderStyle* childStyle = child->style();
5613 return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
5614 getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
5616 return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
5617 getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
5618 child->borderStart();
5621 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
5622 RenderObject* trailingSpaceChild)
5624 if (trailingSpaceChild && trailingSpaceChild->isText()) {
5625 // Collapse away the trailing space at the end of a block.
5626 RenderText* t = toRenderText(trailingSpaceChild);
5627 const UChar space = ' ';
5628 const Font& font = t->style()->font(); // FIXME: This ignores first-line.
5629 float spaceWidth = font.width(RenderBlock::constructTextRun(t, font, &space, 1, t->style()));
5630 inlineMax -= spaceWidth + font.wordSpacing();
5631 if (inlineMin > inlineMax)
5632 inlineMin = inlineMax;
5636 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
5638 LayoutUnit snappedResult = ceiledLayoutUnit(result);
5639 preferredWidth = max(snappedResult, preferredWidth);
5642 void RenderBlock::computeInlinePreferredLogicalWidths()
5644 float inlineMax = 0;
5645 float inlineMin = 0;
5647 RenderStyle* styleToUse = style();
5648 RenderBlock* containingBlock = this->containingBlock();
5649 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : ZERO_LAYOUT_UNIT;
5651 // If we are at the start of a line, we want to ignore all white-space.
5652 // Also strip spaces if we previously had text that ended in a trailing space.
5653 bool stripFrontSpaces = true;
5654 RenderObject* trailingSpaceChild = 0;
5656 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
5657 // very specific cirucumstances (in order to match common WinIE renderings).
5658 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
5659 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto();
5661 bool autoWrap, oldAutoWrap;
5662 autoWrap = oldAutoWrap = styleToUse->autoWrap();
5664 InlineMinMaxIterator childIterator(this);
5665 bool addedTextIndent = false; // Only gets added in once.
5666 LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view());
5667 RenderObject* prevFloat = 0;
5668 while (RenderObject* child = childIterator.next()) {
5669 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
5670 child->style()->autoWrap();
5672 if (!child->isBR()) {
5673 // Step One: determine whether or not we need to go ahead and
5674 // terminate our current line. Each discrete chunk can become
5675 // the new min-width, if it is the widest chunk seen so far, and
5676 // it can also become the max-width.
5678 // Children fall into three categories:
5679 // (1) An inline flow object. These objects always have a min/max of 0,
5680 // and are included in the iteration solely so that their margins can
5683 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
5684 // These objects can always be on a line by themselves, so in this situation
5685 // we need to go ahead and break the current line, and then add in our own
5686 // margins and min/max width on its own line, and then terminate the line.
5688 // (3) A text object. Text runs can have breakable characters at the start,
5689 // the middle or the end. They may also lose whitespace off the front if
5690 // we're already ignoring whitespace. In order to compute accurate min-width
5691 // information, we need three pieces of information.
5692 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
5693 // starts with whitespace.
5694 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
5695 // ends with whitespace.
5696 // (c) the min/max width of the string (trimmed for whitespace).
5698 // If the text string starts with whitespace, then we need to go ahead and
5699 // terminate our current line (unless we're already in a whitespace stripping
5702 // If the text string has a breakable character in the middle, but didn't start
5703 // with whitespace, then we add the width of the first non-breakable run and
5704 // then end the current line. We then need to use the intermediate min/max width
5705 // values (if any of them are larger than our current min/max). We then look at
5706 // the width of the last non-breakable run and use that to start a new line
5707 // (unless we end in whitespace).
5708 RenderStyle* childStyle = child->style();
5712 if (!child->isText()) {
5713 // Case (1) and (2). Inline replaced and inline flow elements.
5714 if (child->isRenderInline()) {
5715 // Add in padding/border/margin from the appropriate side of
5717 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
5721 inlineMin += childMin;
5722 inlineMax += childMax;
5724 child->setPreferredLogicalWidthsDirty(false);
5726 // Inline replaced elts add in their margins to their min/max values.
5727 LayoutUnit margins = 0;
5728 Length startMargin = childStyle->marginStart();
5729 Length endMargin = childStyle->marginEnd();
5730 if (startMargin.isFixed())
5731 margins += startMargin.value();
5732 if (endMargin.isFixed())
5733 margins += endMargin.value();
5734 childMin += margins;
5735 childMax += margins;
5739 if (!child->isRenderInline() && !child->isText()) {
5740 // Case (2). Inline replaced elements and floats.
5741 // Go ahead and terminate the current line as far as
5742 // minwidth is concerned.
5743 childMin += child->minPreferredLogicalWidth();
5744 childMax += child->maxPreferredLogicalWidth();
5746 bool clearPreviousFloat;
5747 if (child->isFloating()) {
5748 clearPreviousFloat = (prevFloat
5749 && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT))
5750 || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT))));
5753 clearPreviousFloat = false;
5755 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
5756 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) {
5757 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5761 // If we're supposed to clear the previous float, then terminate maxwidth as well.
5762 if (clearPreviousFloat) {
5763 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5767 // Add in text-indent. This is added in only once.
5769 if (!addedTextIndent) {
5775 textIndent = childMin;
5777 addedTextIndent = true;
5780 // Add our width to the max.
5781 inlineMax += max<float>(0, childMax);
5783 if (!autoWrap || !canBreakReplacedElement) {
5784 if (child->isFloating())
5785 updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
5787 inlineMin += childMin;
5789 // Now check our line.
5790 updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
5792 // Now start a new line.
5796 // We are no longer stripping whitespace at the start of
5798 if (!child->isFloating()) {
5799 stripFrontSpaces = false;
5800 trailingSpaceChild = 0;
5802 } else if (child->isText()) {
5804 RenderText* t = toRenderText(child);
5806 if (t->isWordBreak()) {
5807 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5812 if (t->style()->hasTextCombine() && t->isCombineText())
5813 toRenderCombineText(t)->combineText();
5815 // Determine if we have a breakable character. Pass in
5816 // whether or not we should ignore any spaces at the front
5817 // of the string. If those are going to be stripped out,
5818 // then they shouldn't be considered in the breakable char
5820 bool hasBreakableChar, hasBreak;
5821 float beginMin, endMin;
5822 bool beginWS, endWS;
5823 float beginMax, endMax;
5824 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
5825 hasBreakableChar, hasBreak, beginMax, endMax,
5826 childMin, childMax, stripFrontSpaces);
5828 // This text object will not be rendered, but it may still provide a breaking opportunity.
5829 if (!hasBreak && childMax == 0) {
5830 if (autoWrap && (beginWS || endWS)) {
5831 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5837 if (stripFrontSpaces)
5838 trailingSpaceChild = child;
5840 trailingSpaceChild = 0;
5842 // Add in text-indent. This is added in only once.
5844 if (!addedTextIndent) {
5846 childMin+=ti; beginMin += ti;
5847 childMax+=ti; beginMax += ti;
5850 textIndent = childMin;
5852 addedTextIndent = true;
5855 // If we have no breakable characters at all,
5856 // then this is the easy case. We add ourselves to the current
5857 // min and max and continue.
5858 if (!hasBreakableChar) {
5859 inlineMin += childMin;
5861 // We have a breakable character. Now we need to know if
5862 // we start and end with whitespace.
5864 // Go ahead and end the current line.
5865 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5867 inlineMin += beginMin;
5868 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5872 inlineMin = childMin;
5875 // We end in whitespace, which means we can go ahead
5876 // and end our current line.
5877 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5880 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5886 inlineMax += beginMax;
5887 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5888 updatePreferredWidth(m_maxPreferredLogicalWidth, childMax);
5890 addedTextIndent = true;
5892 inlineMax += max<float>(0, childMax);
5895 // Ignore spaces after a list marker.
5896 if (child->isListMarker())
5897 stripFrontSpaces = true;
5899 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5900 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5901 inlineMin = inlineMax = 0;
5902 stripFrontSpaces = true;
5903 trailingSpaceChild = 0;
5904 addedTextIndent = true;
5907 oldAutoWrap = autoWrap;
5910 if (styleToUse->collapseWhiteSpace())
5911 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
5913 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5914 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5917 void RenderBlock::computeBlockPreferredLogicalWidths()
5919 RenderStyle* styleToUse = style();
5920 bool nowrap = styleToUse->whiteSpace() == NOWRAP;
5922 RenderObject* child = firstChild();
5923 RenderBlock* containingBlock = this->containingBlock();
5924 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
5926 // Positioned children don't affect the min/max width
5927 if (child->isOutOfFlowPositioned()) {
5928 child = child->nextSibling();
5932 RenderStyle* childStyle = child->style();
5933 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
5934 LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
5935 if (childStyle->clear() & CLEFT) {
5936 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
5939 if (childStyle->clear() & CRIGHT) {
5940 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
5941 floatRightWidth = 0;
5945 // A margin basically has three types: fixed, percentage, and auto (variable).
5946 // Auto and percentage margins simply become 0 when computing min/max width.
5947 // Fixed margins can be added in as is.
5948 Length startMarginLength = childStyle->marginStartUsing(styleToUse);
5949 Length endMarginLength = childStyle->marginEndUsing(styleToUse);
5950 LayoutUnit margin = 0;
5951 LayoutUnit marginStart = 0;
5952 LayoutUnit marginEnd = 0;
5953 if (startMarginLength.isFixed())
5954 marginStart += startMarginLength.value();
5955 if (endMarginLength.isFixed())
5956 marginEnd += endMarginLength.value();
5957 margin = marginStart + marginEnd;
5959 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
5960 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
5961 RenderBox* childBox = toRenderBox(child);
5962 LayoutUnit oldHeight = childBox->logicalHeight();
5963 childBox->setLogicalHeight(childBox->borderAndPaddingLogicalHeight());
5964 childBox->computeLogicalHeight();
5965 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = childBox->logicalHeight();
5966 childBox->setLogicalHeight(oldHeight);
5968 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
5969 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
5972 LayoutUnit w = childMinPreferredLogicalWidth + margin;
5973 m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth);
5975 // IE ignores tables for calculation of nowrap. Makes some sense.
5976 if (nowrap && !child->isTable())
5977 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
5979 w = childMaxPreferredLogicalWidth + margin;
5981 if (!child->isFloating()) {
5982 if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
5983 // Determine a left and right max value based off whether or not the floats can fit in the
5984 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
5985 // is smaller than the float width.
5986 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse->isLeftToRightDirection();
5987 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
5988 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
5989 LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
5990 LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
5991 w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
5992 w = max(w, floatLeftWidth + floatRightWidth);
5995 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
5996 floatLeftWidth = floatRightWidth = 0;
5999 if (child->isFloating()) {
6000 if (styleToUse->floating() == LeftFloat)
6001 floatLeftWidth += w;
6003 floatRightWidth += w;
6005 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
6007 child = child->nextSibling();
6010 // Always make sure these values are non-negative.
6011 m_minPreferredLogicalWidth = max(ZERO_LAYOUT_UNIT, m_minPreferredLogicalWidth);
6012 m_maxPreferredLogicalWidth = max(ZERO_LAYOUT_UNIT, m_maxPreferredLogicalWidth);
6014 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
6017 bool RenderBlock::hasLineIfEmpty() const
6022 if (node()->isRootEditableElement())
6025 if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
6031 LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
6033 // Inline blocks are replaced elements. Otherwise, just pass off to
6034 // the base class. If we're being queried as though we're the root line
6035 // box, then the fact that we're an inline-block is irrelevant, and we behave
6036 // just like a block.
6037 if (isReplaced() && linePositionMode == PositionOnContainingLine)
6038 return RenderBox::lineHeight(firstLine, direction, linePositionMode);
6040 if (firstLine && document()->usesFirstLineRules()) {
6041 RenderStyle* s = style(firstLine);
6043 return s->computedLineHeight(view());
6046 if (m_lineHeight == -1)
6047 m_lineHeight = style()->computedLineHeight(view());
6049 return m_lineHeight;
6052 LayoutUnit RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
6054 // Inline blocks are replaced elements. Otherwise, just pass off to
6055 // the base class. If we're being queried as though we're the root line
6056 // box, then the fact that we're an inline-block is irrelevant, and we behave
6057 // just like a block.
6058 if (isReplaced() && linePositionMode == PositionOnContainingLine) {
6059 // For "leaf" theme objects, let the theme decide what the baseline position is.
6060 // FIXME: Might be better to have a custom CSS property instead, so that if the theme
6061 // is turned off, checkboxes/radios will still have decent baselines.
6062 // FIXME: Need to patch form controls to deal with vertical lines.
6063 if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
6064 return theme()->baselinePosition(this);
6066 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
6067 // the normal flow. We make an exception for marquees, since their baselines are meaningless
6068 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
6069 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
6070 // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
6071 // of our content box.
6072 bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)
6073 : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || (isWritingModeRoot() && !isRubyRun());
6075 LayoutUnit baselinePos = ignoreBaseline ? static_cast<LayoutUnit>(-1) : lastLineBoxBaseline();
6077 LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
6078 if (baselinePos != -1 && baselinePos <= bottomOfContent)
6079 return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos;
6081 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
6084 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
6085 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
6088 LayoutUnit RenderBlock::firstLineBoxBaseline() const
6090 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
6093 if (childrenInline()) {
6095 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
6100 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
6101 if (!curr->isFloatingOrOutOfFlowPositioned()) {
6102 LayoutUnit result = curr->firstLineBoxBaseline();
6104 return curr->logicalTop() + result; // Translate to our coordinate space.
6112 LayoutUnit RenderBlock::lastLineBoxBaseline() const
6114 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
6117 LineDirectionMode lineDirection = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
6119 if (childrenInline()) {
6120 if (!firstLineBox() && hasLineIfEmpty()) {
6121 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
6122 return fontMetrics.ascent()
6123 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
6124 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
6127 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
6130 bool haveNormalFlowChild = false;
6131 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
6132 if (!curr->isFloatingOrOutOfFlowPositioned()) {
6133 haveNormalFlowChild = true;
6134 LayoutUnit result = curr->lastLineBoxBaseline();
6136 return curr->logicalTop() + result; // Translate to our coordinate space.
6139 if (!haveNormalFlowChild && hasLineIfEmpty()) {
6140 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
6141 return fontMetrics.ascent()
6142 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
6143 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
6150 bool RenderBlock::containsNonZeroBidiLevel() const
6152 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
6153 for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
6154 if (box->bidiLevel())
6161 RenderBlock* RenderBlock::firstLineBlock() const
6163 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
6164 bool hasPseudo = false;
6166 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
6169 RenderObject* parentBlock = firstLineBlock->parent();
6170 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
6171 !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
6173 ASSERT(parentBlock->isRenderBlock());
6174 firstLineBlock = toRenderBlock(parentBlock);
6180 return firstLineBlock;
6183 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
6185 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
6186 // Force inline display (except for floating first-letters).
6187 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
6188 // CSS2 says first-letter can't be positioned.
6189 pseudoStyle->setPosition(StaticPosition);
6193 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
6194 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
6195 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
6196 static inline bool isPunctuationForFirstLetter(UChar c)
6198 CharCategory charCategory = category(c);
6199 return charCategory == Punctuation_Open
6200 || charCategory == Punctuation_Close
6201 || charCategory == Punctuation_InitialQuote
6202 || charCategory == Punctuation_FinalQuote
6203 || charCategory == Punctuation_Other;
6206 static inline bool shouldSkipForFirstLetter(UChar c)
6208 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
6211 static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
6213 RenderObject* firstLetterBlock = start;
6215 bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
6216 && firstLetterBlock->canHaveGeneratedChildren();
6217 if (canHaveFirstLetterRenderer)
6218 return firstLetterBlock;
6220 RenderObject* parentBlock = firstLetterBlock->parent();
6221 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
6222 !parentBlock->isBlockFlow())
6224 firstLetterBlock = parentBlock;
6230 void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild)
6232 RenderObject* firstLetter = currentChild->parent();
6233 RenderObject* firstLetterContainer = firstLetter->parent();
6234 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
6235 ASSERT(firstLetter->isFloating() || firstLetter->isInline());
6237 if (Node::diff(firstLetter->style(), pseudoStyle, document()) == Node::Detach) {
6238 // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
6239 RenderObject* newFirstLetter;
6240 if (pseudoStyle->display() == INLINE)
6241 newFirstLetter = new (renderArena()) RenderInline(document());
6243 newFirstLetter = new (renderArena()) RenderBlock(document());
6244 newFirstLetter->setStyle(pseudoStyle);
6246 // Move the first letter into the new renderer.
6247 LayoutStateDisabler layoutStateDisabler(view());
6248 while (RenderObject* child = firstLetter->firstChild()) {
6249 if (child->isText())
6250 toRenderText(child)->removeAndDestroyTextBoxes();
6251 firstLetter->removeChild(child);
6252 newFirstLetter->addChild(child, 0);
6255 RenderTextFragment* remainingText = 0;
6256 RenderObject* nextSibling = firstLetter->nextSibling();
6257 RenderObject* remainingTextObject = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText();
6258 if (remainingTextObject && remainingTextObject->isText() && toRenderText(remainingTextObject)->isTextFragment())
6259 remainingText = toRenderTextFragment(remainingTextObject);
6260 if (remainingText) {
6261 ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText);
6262 // Replace the old renderer with the new one.
6263 remainingText->setFirstLetter(newFirstLetter);
6264 toRenderBoxModelObject(newFirstLetter)->setFirstLetterRemainingText(remainingText);
6266 // To prevent removal of single anonymous block in RenderBlock::removeChild and causing
6267 // |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
6268 firstLetterContainer->virtualChildren()->removeChildNode(firstLetterContainer, firstLetter);
6269 firstLetter->destroy();
6270 firstLetter = newFirstLetter;
6271 firstLetterContainer->addChild(firstLetter, nextSibling);
6273 firstLetter->setStyle(pseudoStyle);
6275 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
6276 if (genChild->isText())
6277 genChild->setStyle(pseudoStyle);
6281 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild)
6283 RenderObject* firstLetterContainer = currentChild->parent();
6284 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
6285 RenderObject* firstLetter = 0;
6286 if (pseudoStyle->display() == INLINE)
6287 firstLetter = new (renderArena()) RenderInline(document());
6289 firstLetter = new (renderArena()) RenderBlock(document());
6290 firstLetter->setStyle(pseudoStyle);
6291 firstLetterContainer->addChild(firstLetter, currentChild);
6293 RenderText* textObj = toRenderText(currentChild);
6295 // The original string is going to be either a generated content string or a DOM node's
6296 // string. We want the original string before it got transformed in case first-letter has
6297 // no text-transform or a different text-transform applied to it.
6298 RefPtr<StringImpl> oldText = textObj->originalText();
6301 if (oldText && oldText->length() > 0) {
6302 unsigned length = 0;
6304 // Account for leading spaces and punctuation.
6305 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length]))
6308 // Account for first letter.
6311 // Keep looking for whitespace and allowed punctuation, but avoid
6312 // accumulating just whitespace into the :first-letter.
6313 for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) {
6314 UChar c = (*oldText)[scanLength];
6316 if (!shouldSkipForFirstLetter(c))
6319 if (isPunctuationForFirstLetter(c))
6320 length = scanLength + 1;
6323 // Construct a text fragment for the text after the first letter.
6324 // This text fragment might be empty.
6325 RenderTextFragment* remainingText =
6326 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
6327 remainingText->setStyle(textObj->style());
6328 if (remainingText->node())
6329 remainingText->node()->setRenderer(remainingText);
6331 firstLetterContainer->addChild(remainingText, textObj);
6332 firstLetterContainer->removeChild(textObj);
6333 remainingText->setFirstLetter(firstLetter);
6334 toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText);
6336 // construct text fragment for the first letter
6337 RenderTextFragment* letter =
6338 new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
6339 letter->setStyle(pseudoStyle);
6340 firstLetter->addChild(letter);
6346 void RenderBlock::updateFirstLetter()
6348 if (!document()->usesFirstLetterRules())
6351 if (style()->styleType() == FIRST_LETTER)
6354 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
6355 // an efficient way to check for that situation though before implementing anything.
6356 RenderObject* firstLetterBlock = findFirstLetterBlock(this);
6357 if (!firstLetterBlock)
6360 // Drill into inlines looking for our first text child.
6361 RenderObject* currChild = firstLetterBlock->firstChild();
6363 if (currChild->isText())
6365 if (currChild->isListMarker())
6366 currChild = currChild->nextSibling();
6367 else if (currChild->isFloatingOrOutOfFlowPositioned()) {
6368 if (currChild->style()->styleType() == FIRST_LETTER) {
6369 currChild = currChild->firstChild();
6372 currChild = currChild->nextSibling();
6373 } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList())
6375 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) {
6376 // We found a lower-level node with first-letter, which supersedes the higher-level style
6377 firstLetterBlock = currChild;
6378 currChild = currChild->firstChild();
6380 currChild = currChild->firstChild();
6386 // If the child already has style, then it has already been created, so we just want
6388 if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
6389 updateFirstLetterStyle(firstLetterBlock, currChild);
6393 if (!currChild->isText() || currChild->isBR())
6396 // Our layout state is not valid for the repaints we are going to trigger by
6397 // adding and removing children of firstLetterContainer.
6398 LayoutStateDisabler layoutStateDisabler(view());
6400 createFirstLetterRenderer(firstLetterBlock, currChild);
6403 // Helper methods for obtaining the last line, computing line counts and heights for line counts
6404 // (crawling into blocks).
6405 static bool shouldCheckLines(RenderObject* obj)
6407 return !obj->isFloatingOrOutOfFlowPositioned() && !obj->isRunIn()
6408 && obj->isBlockFlow() && obj->style()->height().isAuto()
6409 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
6412 static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
6414 if (block->style()->visibility() == VISIBLE) {
6415 if (block->childrenInline()) {
6416 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
6422 for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
6423 if (shouldCheckLines(obj)) {
6424 RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
6434 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
6436 if (block->style()->visibility() == VISIBLE) {
6437 if (block->childrenInline()) {
6438 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
6440 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : ZERO_LAYOUT_UNIT);
6444 RenderBox* normalFlowChildWithoutLines = 0;
6445 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
6446 if (shouldCheckLines(obj)) {
6447 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
6449 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : ZERO_LAYOUT_UNIT);
6450 } else if (!obj->isFloatingOrOutOfFlowPositioned() && !obj->isRunIn())
6451 normalFlowChildWithoutLines = obj;
6453 if (normalFlowChildWithoutLines && l == 0)
6454 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
6461 RootInlineBox* RenderBlock::lineAtIndex(int i)
6464 return getLineAtIndex(this, i, count);
6467 int RenderBlock::lineCount()
6470 if (style()->visibility() == VISIBLE) {
6471 if (childrenInline())
6472 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
6475 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
6476 if (shouldCheckLines(obj))
6477 count += toRenderBlock(obj)->lineCount();
6482 int RenderBlock::heightForLineCount(int l)
6485 return getHeightForLineCount(this, l, true, count);
6488 void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
6490 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
6491 // for either overflow or translations via relative positioning.
6492 if (style()->visibility() == VISIBLE) {
6493 if (childrenInline()) {
6494 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
6495 if (box->firstChild())
6496 left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
6497 if (box->lastChild())
6498 right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight())));
6502 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
6503 if (!obj->isFloatingOrOutOfFlowPositioned()) {
6504 if (obj->isBlockFlow() && !obj->hasOverflowClip())
6505 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
6506 else if (obj->style()->visibility() == VISIBLE) {
6507 // We are a replaced element or some kind of non-block-flow object.
6508 left = min(left, x + obj->x());
6509 right = max(right, x + obj->x() + obj->width());
6515 if (m_floatingObjects) {
6516 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
6517 FloatingObjectSetIterator end = floatingObjectSet.end();
6518 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
6519 FloatingObject* r = *it;
6520 // Only examine the object if our m_shouldPaint flag is set.
6521 if (r->shouldPaint()) {
6522 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x();
6523 LayoutUnit floatRight = floatLeft + r->m_renderer->width();
6524 left = min(left, floatLeft);
6525 right = max(right, floatRight);
6532 void RenderBlock::borderFitAdjust(LayoutRect& rect) const
6534 if (style()->borderFit() == BorderFitBorder)
6537 // Walk any normal flow lines to snugly fit.
6538 LayoutUnit left = MAX_LAYOUT_UNIT;
6539 LayoutUnit right = MIN_LAYOUT_UNIT;
6540 LayoutUnit oldWidth = rect.width();
6541 adjustForBorderFit(0, left, right);
6542 if (left != MAX_LAYOUT_UNIT) {
6543 left = min(left, oldWidth - (borderRight() + paddingRight()));
6545 left -= (borderLeft() + paddingLeft());
6548 rect.expand(-left, 0);
6551 if (right != MIN_LAYOUT_UNIT) {
6552 right = max(right, borderLeft() + paddingLeft());
6554 right += (borderRight() + paddingRight());
6555 if (right < oldWidth)
6556 rect.expand(-(oldWidth - right), 0);
6560 void RenderBlock::clearTruncation()
6562 if (style()->visibility() == VISIBLE) {
6563 if (childrenInline() && hasMarkupTruncation()) {
6564 setHasMarkupTruncation(false);
6565 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
6566 box->clearTruncation();
6568 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
6569 if (shouldCheckLines(obj))
6570 toRenderBlock(obj)->clearTruncation();
6576 void RenderBlock::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
6579 if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this))
6581 m_rareData = adoptPtr(new RenderBlockRareData(this));
6583 m_rareData->m_margins.setPositiveMarginBefore(pos);
6584 m_rareData->m_margins.setNegativeMarginBefore(neg);
6587 void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
6590 if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this))
6592 m_rareData = adoptPtr(new RenderBlockRareData(this));
6594 m_rareData->m_margins.setPositiveMarginAfter(pos);
6595 m_rareData->m_margins.setNegativeMarginAfter(neg);
6598 void RenderBlock::setPaginationStrut(LayoutUnit strut)
6603 m_rareData = adoptPtr(new RenderBlockRareData(this));
6605 m_rareData->m_paginationStrut = strut;
6608 void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
6613 m_rareData = adoptPtr(new RenderBlockRareData(this));
6615 m_rareData->m_pageLogicalOffset = logicalOffset;
6618 void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
6620 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
6621 // inline boxes above and below us (thus getting merged with them to form a single irregular
6623 if (isAnonymousBlockContinuation()) {
6624 // FIXME: This is wrong for block-flows that are horizontal.
6625 // https://bugs.webkit.org/show_bug.cgi?id=46781
6626 rects.append(pixelSnappedIntRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(),
6627 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
6628 continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
6629 inlineElementContinuation()->containingBlock()->location()));
6631 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
6634 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
6636 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
6637 // inline boxes above and below us (thus getting merged with them to form a single irregular
6639 if (isAnonymousBlockContinuation()) {
6640 // FIXME: This is wrong for block-flows that are horizontal.
6641 // https://bugs.webkit.org/show_bug.cgi?id=46781
6642 FloatRect localRect(0, -collapsedMarginBefore(),
6643 width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
6644 quads.append(localToAbsoluteQuad(localRect, false, wasFixed));
6645 continuation()->absoluteQuads(quads, wasFixed);
6647 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), false, wasFixed));
6650 LayoutRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const
6652 LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
6653 if (isAnonymousBlockContinuation())
6654 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
6658 RenderObject* RenderBlock::hoverAncestor() const
6660 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
6663 void RenderBlock::updateDragState(bool dragOn)
6665 RenderBox::updateDragState(dragOn);
6667 continuation()->updateDragState(dragOn);
6670 RenderStyle* RenderBlock::outlineStyleForRepaint() const
6672 return isAnonymousBlockContinuation() ? continuation()->style() : style();
6675 void RenderBlock::childBecameNonInline(RenderObject*)
6677 makeChildrenNonInline();
6678 if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
6679 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
6680 // |this| may be dead here
6683 void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
6685 if (result.innerNode())
6689 if (isAnonymousBlockContinuation())
6690 // We are in the margins of block elements that are part of a continuation. In
6691 // this case we're actually still inside the enclosing element that was
6692 // split. Go ahead and set our inner node accordingly.
6693 n = continuation()->node();
6696 result.setInnerNode(n);
6697 if (!result.innerNonSharedNode())
6698 result.setInnerNonSharedNode(n);
6699 result.setLocalPoint(point);
6703 LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
6705 // Do the normal calculation in most cases.
6707 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
6709 LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
6711 if (extraWidthToEndOfLine) {
6712 if (isRenderBlock()) {
6713 *extraWidthToEndOfLine = width() - caretRect.maxX();
6715 // FIXME: This code looks wrong.
6716 // myRight and containerRight are set up, but then clobbered.
6717 // So *extraWidthToEndOfLine will always be 0 here.
6719 LayoutUnit myRight = caretRect.maxX();
6720 // FIXME: why call localToAbsoluteForContent() twice here, too?
6721 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
6723 LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
6724 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
6726 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
6733 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
6735 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
6736 // inline boxes above and below us (thus getting merged with them to form a single irregular
6738 if (inlineElementContinuation()) {
6739 // FIXME: This check really isn't accurate.
6740 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
6741 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
6742 // FIXME: This is wrong for block-flows that are horizontal.
6743 // https://bugs.webkit.org/show_bug.cgi?id=46781
6744 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
6745 float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : ZERO_LAYOUT_UNIT;
6746 float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : ZERO_LAYOUT_UNIT;
6747 LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin);
6748 if (!rect.isEmpty())
6749 rects.append(pixelSnappedIntRect(rect));
6750 } else if (width() && height())
6751 rects.append(pixelSnappedIntRect(additionalOffset, size()));
6753 if (!hasOverflowClip() && !hasControlClip()) {
6754 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
6755 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
6756 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
6757 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
6758 if (!rect.isEmpty())
6759 rects.append(pixelSnappedIntRect(rect));
6762 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
6763 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
6764 RenderBox* box = toRenderBox(curr);
6766 // FIXME: This doesn't work correctly with transforms.
6768 pos = curr->localToAbsolute();
6770 pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
6771 box->addFocusRingRects(rects, flooredLayoutPoint(pos));
6776 if (inlineElementContinuation())
6777 inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()));
6780 RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
6782 if (isAnonymousColumnsBlock())
6783 return createAnonymousColumnsWithParentRenderer(parent);
6784 if (isAnonymousColumnSpanBlock())
6785 return createAnonymousColumnSpanWithParentRenderer(parent);
6786 return createAnonymousWithParentRendererAndDisplay(parent, style()->display());
6789 bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
6791 ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
6793 if (!inRenderFlowThread())
6794 return true; // Printing and multi-column both make new pages to accommodate content.
6796 // See if we're in the last region.
6797 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
6798 RenderRegion* region = enclosingRenderFlowThread()->renderRegionForLine(pageOffset, this);
6801 if (region->isLastRegion())
6802 return region->style()->regionOverflow() == BreakRegionOverflow
6803 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->offsetFromLogicalTopOfFirstPage());
6807 LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
6809 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6810 if (!pageLogicalHeight)
6811 return logicalOffset;
6813 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
6814 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
6815 if (pageBoundaryRule == ExcludePageBoundary)
6816 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
6817 return logicalOffset + remainingLogicalHeight;
6820 static bool inNormalFlow(RenderBox* child)
6822 RenderBlock* curr = child->containingBlock();
6823 RenderView* renderView = child->view();
6824 while (curr && curr != renderView) {
6825 if (curr->hasColumns() || curr->isRenderFlowThread())
6827 if (curr->isFloatingOrOutOfFlowPositioned())
6829 curr = curr->containingBlock();
6834 ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const
6836 return ColumnInfo::Column;
6839 LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
6841 // FIXME: Add page break checking here when we support printing.
6842 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6843 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
6844 bool checkRegionBreaks = inRenderFlowThread();
6845 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
6846 || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
6847 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
6848 if (checkColumnBreaks)
6849 view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
6850 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
6852 return logicalOffset;
6855 LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
6857 // FIXME: Add page break checking here when we support printing.
6858 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6859 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
6860 bool checkRegionBreaks = inRenderFlowThread();
6861 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
6862 || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
6863 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
6864 marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content.
6865 if (checkColumnBreaks)
6866 view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
6867 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
6869 return logicalOffset;
6872 LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
6874 RenderView* renderView = view();
6875 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
6876 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
6878 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
6879 if (!inRenderFlowThread()) {
6880 LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
6881 if (!pageLogicalHeight)
6883 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
6885 return enclosingRenderFlowThread()->regionLogicalTopForLine(cumulativeOffset);
6888 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
6890 RenderView* renderView = view();
6891 if (!inRenderFlowThread())
6892 return renderView->layoutState()->m_pageLogicalHeight;
6893 return enclosingRenderFlowThread()->regionLogicalHeightForLine(offset + offsetFromLogicalTopOfFirstPage());
6896 LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
6898 RenderView* renderView = view();
6899 offset += offsetFromLogicalTopOfFirstPage();
6901 if (!inRenderFlowThread()) {
6902 LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
6903 LayoutUnit remainingHeight = pageLogicalHeight - layoutMod(offset, pageLogicalHeight);
6904 if (pageBoundaryRule == IncludePageBoundary) {
6905 // If includeBoundaryPoint is true the line exactly on the top edge of a
6906 // column will act as being part of the previous column.
6907 remainingHeight = layoutMod(remainingHeight, pageLogicalHeight);
6909 return remainingHeight;
6912 return enclosingRenderFlowThread()->regionRemainingLogicalHeightForLine(offset, pageBoundaryRule);
6915 LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
6917 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6918 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
6919 bool checkRegionBreaks = inRenderFlowThread();
6920 bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
6921 || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
6922 || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
6923 if (!isUnsplittable)
6924 return logicalOffset;
6925 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : ZERO_LAYOUT_UNIT);
6926 LayoutState* layoutState = view()->layoutState();
6927 if (layoutState->m_columnInfo)
6928 layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
6929 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6930 bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
6931 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
6932 || !hasNextPage(logicalOffset))
6933 return logicalOffset;
6934 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
6935 if (remainingLogicalHeight < childLogicalHeight) {
6936 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
6937 return logicalOffset;
6938 return logicalOffset + remainingLogicalHeight;
6940 return logicalOffset;
6943 bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
6945 bool checkRegion = false;
6946 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
6947 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
6948 if (minimumLogicalHeight <= pageLogicalHeight)
6950 if (!hasNextPage(logicalOffset + adjustment))
6952 adjustment += pageLogicalHeight;
6955 return !checkRegion;
6958 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta)
6960 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
6961 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
6962 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
6963 // of the first column.
6965 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
6966 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
6967 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
6968 // for overflow to occur), and then cache visible overflow for each column rect.
6970 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
6971 // content that paints in a previous column (and content that paints in the following column).
6973 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
6974 // at least make positive leading work in typical cases.
6976 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
6977 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
6978 // line and all following lines.
6979 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
6980 LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
6981 LayoutUnit lineHeight = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()) - logicalOffset;
6982 RenderView* renderView = view();
6983 LayoutState* layoutState = renderView->layoutState();
6984 if (layoutState->m_columnInfo)
6985 layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
6986 logicalOffset += delta;
6987 lineBox->setPaginationStrut(0);
6988 lineBox->setIsFirstAfterPageBreak(false);
6989 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6990 bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
6991 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
6992 // still going to add a strut, so that the visible overflow fits on a single page.
6993 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
6994 || !hasNextPage(logicalOffset))
6996 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
6997 if (remainingLogicalHeight < lineHeight) {
6998 // If we have a non-uniform page height, then we have to shift further possibly.
6999 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
7001 if (lineHeight > pageLogicalHeight) {
7002 // Split the top margin in order to avoid splitting the visible part of the line.
7003 remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max(ZERO_LAYOUT_UNIT, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
7005 LayoutUnit totalLogicalHeight = lineHeight + max(ZERO_LAYOUT_UNIT, logicalOffset);
7006 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
7007 if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isOutOfFlowPositioned() && !isTableCell())
7008 setPaginationStrut(remainingLogicalHeight + max(ZERO_LAYOUT_UNIT, logicalOffset));
7010 delta += remainingLogicalHeight;
7011 lineBox->setPaginationStrut(remainingLogicalHeight);
7012 lineBox->setIsFirstAfterPageBreak(true);
7014 } else if (remainingLogicalHeight == pageLogicalHeight && lineBox != firstRootBox())
7015 lineBox->setIsFirstAfterPageBreak(true);
7018 LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
7020 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
7022 if (estimateWithoutPagination != logicalTopAfterClear) {
7023 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
7025 setLogicalHeight(logicalTopAfterClear);
7026 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
7028 if (child->shrinkToAvoidFloats()) {
7029 // The child's width depends on the line width.
7030 // When the child shifts to clear an item, its width can
7031 // change (because it has more available line width).
7032 // So go ahead and mark the item as dirty.
7033 child->setChildNeedsLayout(true, MarkOnlyThis);
7036 if (childRenderBlock) {
7037 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
7038 childRenderBlock->markAllDescendantsWithFloatsForLayout();
7039 if (!child->needsLayout())
7040 child->markForPaginationRelayoutIfNeeded();
7043 // Our guess was wrong. Make the child lay itself out again.
7044 child->layoutIfNeeded();
7047 LayoutUnit oldTop = logicalTopAfterClear;
7049 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
7050 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
7052 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
7053 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
7054 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
7056 LayoutUnit paginationStrut = 0;
7057 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
7058 if (unsplittableAdjustmentDelta)
7059 paginationStrut = unsplittableAdjustmentDelta;
7060 else if (childRenderBlock && childRenderBlock->paginationStrut())
7061 paginationStrut = childRenderBlock->paginationStrut();
7063 if (paginationStrut) {
7064 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
7065 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
7066 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
7067 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
7068 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
7069 // and pushes to the next page anyway, so not too concerned about it.
7070 setPaginationStrut(result + paginationStrut);
7071 if (childRenderBlock)
7072 childRenderBlock->setPaginationStrut(0);
7074 result += paginationStrut;
7077 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
7078 setLogicalHeight(logicalHeight() + (result - oldTop));
7080 // Return the final adjusted logical top.
7084 bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta) const
7086 if (!inRenderFlowThread())
7089 return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(rootBox->lineTopWithLeading() + lineDelta);
7092 LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
7094 // FIXME: This function needs to work without layout state. It's fine to use the layout state as a cache
7095 // for speed, but we need a slow implementation that will walk up the containing block chain and figure
7096 // out our offset from the top of the page.
7097 LayoutState* layoutState = view()->layoutState();
7098 if (!layoutState || !layoutState->isPaginated())
7101 // FIXME: Sanity check that the renderer in the layout state is ours, since otherwise the computation will be off.
7102 // Right now this assert gets hit inside computeLogicalHeight for percentage margins, since they're computed using
7103 // widths which can vary in each region. Until we patch that, we can't have this assert.
7104 // ASSERT(layoutState->m_renderer == this);
7106 LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
7107 return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
7110 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
7112 if (!inRenderFlowThread())
7115 RenderFlowThread* flowThread = enclosingRenderFlowThread();
7116 if (!flowThread || !flowThread->hasValidRegionInfo())
7119 return flowThread->renderRegionForLine(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
7122 void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
7124 if (inRenderFlowThread()) {
7125 // Shift the inline position to exclude the region offset.
7126 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
7128 child->layer()->setStaticInlinePosition(inlinePosition);
7131 bool RenderBlock::logicalWidthChangedInRegions() const
7133 if (!inRenderFlowThread())
7136 RenderFlowThread* flowThread = enclosingRenderFlowThread();
7137 if (!flowThread || !flowThread->hasValidRegionInfo())
7140 return flowThread->logicalWidthChangedInRegions(this, offsetFromLogicalTopOfFirstPage());
7143 RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
7145 ASSERT(region && inRenderFlowThread());
7147 // We need to clamp to the block, since we want any lines or blocks that overflow out of the
7148 // logical top or logical bottom of the block to size as though the border box in the first and
7149 // last regions extended infinitely. Otherwise the lines are going to size according to the regions
7150 // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
7151 RenderRegion* startRegion;
7152 RenderRegion* endRegion;
7153 enclosingRenderFlowThread()->getRegionRangeForBox(this, startRegion, endRegion);
7155 if (startRegion && region->offsetFromLogicalTopOfFirstPage() < startRegion->offsetFromLogicalTopOfFirstPage())
7157 if (endRegion && region->offsetFromLogicalTopOfFirstPage() > endRegion->offsetFromLogicalTopOfFirstPage())
7163 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
7165 // If the child has the same directionality as we do, then we can just return its
7166 // collapsed margin.
7167 if (!child->isWritingModeRoot())
7168 return child->collapsedMarginBefore();
7170 // The child has a different directionality. If the child is parallel, then it's just
7171 // flipped relative to us. We can use the collapsed margin for the opposite edge.
7172 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
7173 return child->collapsedMarginAfter();
7175 // The child is perpendicular to us, which means its margins don't collapse but are on the
7176 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
7177 return marginBeforeForChild(child);
7180 LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) const
7182 // If the child has the same directionality as we do, then we can just return its
7183 // collapsed margin.
7184 if (!child->isWritingModeRoot())
7185 return child->collapsedMarginAfter();
7187 // The child has a different directionality. If the child is parallel, then it's just
7188 // flipped relative to us. We can use the collapsed margin for the opposite edge.
7189 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
7190 return child->collapsedMarginBefore();
7192 // The child is perpendicular to us, which means its margins don't collapse but are on the
7193 // "logical left/right" side of the child box. We can just return the raw margin in this case.
7194 return marginAfterForChild(child);
7197 RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) const
7199 LayoutUnit childBeforePositive = 0;
7200 LayoutUnit childBeforeNegative = 0;
7201 LayoutUnit childAfterPositive = 0;
7202 LayoutUnit childAfterNegative = 0;
7204 LayoutUnit beforeMargin = 0;
7205 LayoutUnit afterMargin = 0;
7207 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
7209 // If the child has the same directionality as we do, then we can just return its
7210 // margins in the same direction.
7211 if (!child->isWritingModeRoot()) {
7212 if (childRenderBlock) {
7213 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
7214 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
7215 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
7216 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
7218 beforeMargin = child->marginBefore();
7219 afterMargin = child->marginAfter();
7221 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
7222 // The child has a different directionality. If the child is parallel, then it's just
7223 // flipped relative to us. We can use the margins for the opposite edges.
7224 if (childRenderBlock) {
7225 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
7226 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
7227 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
7228 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
7230 beforeMargin = child->marginAfter();
7231 afterMargin = child->marginBefore();
7234 // The child is perpendicular to us, which means its margins don't collapse but are on the
7235 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
7236 beforeMargin = marginBeforeForChild(child);
7237 afterMargin = marginAfterForChild(child);
7240 // Resolve uncollapsing margins into their positive/negative buckets.
7242 if (beforeMargin > 0)
7243 childBeforePositive = beforeMargin;
7245 childBeforeNegative = -beforeMargin;
7248 if (afterMargin > 0)
7249 childAfterPositive = afterMargin;
7251 childAfterNegative = -afterMargin;
7254 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
7257 const char* RenderBlock::renderName() const
7260 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
7263 return "RenderBlock (floating)";
7264 if (isOutOfFlowPositioned())
7265 return "RenderBlock (positioned)";
7266 if (isAnonymousColumnsBlock())
7267 return "RenderBlock (anonymous multi-column)";
7268 if (isAnonymousColumnSpanBlock())
7269 return "RenderBlock (anonymous multi-column span)";
7270 if (isAnonymousBlock())
7271 return "RenderBlock (anonymous)";
7272 else if (isAnonymous())
7273 return "RenderBlock (generated)";
7274 if (isRelPositioned())
7275 return "RenderBlock (relative positioned)";
7277 return "RenderBlock (run-in)";
7278 return "RenderBlock";
7281 inline void RenderBlock::FloatingObjects::clear()
7284 m_placedFloatsTree.clear();
7285 m_leftObjectsCount = 0;
7286 m_rightObjectsCount = 0;
7289 inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
7291 if (type == FloatingObject::FloatLeft)
7292 m_leftObjectsCount++;
7294 m_rightObjectsCount++;
7297 inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
7299 if (type == FloatingObject::FloatLeft)
7300 m_leftObjectsCount--;
7302 m_rightObjectsCount--;
7305 inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
7307 if (m_horizontalWritingMode)
7308 return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
7309 return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
7312 void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
7314 ASSERT(!floatingObject->isInPlacedTree());
7316 floatingObject->setIsPlaced(true);
7317 if (m_placedFloatsTree.isInitialized())
7318 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
7321 floatingObject->setIsInPlacedTree(true);
7325 void RenderBlock::FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
7327 ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
7329 if (m_placedFloatsTree.isInitialized()) {
7330 bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
7331 ASSERT_UNUSED(removed, removed);
7334 floatingObject->setIsPlaced(false);
7336 floatingObject->setIsInPlacedTree(false);
7340 inline void RenderBlock::FloatingObjects::add(FloatingObject* floatingObject)
7342 increaseObjectsCount(floatingObject->type());
7343 m_set.add(floatingObject);
7344 if (floatingObject->isPlaced())
7345 addPlacedObject(floatingObject);
7348 inline void RenderBlock::FloatingObjects::remove(FloatingObject* floatingObject)
7350 decreaseObjectsCount(floatingObject->type());
7351 m_set.remove(floatingObject);
7352 ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree());
7353 if (floatingObject->isPlaced())
7354 removePlacedObject(floatingObject);
7357 void RenderBlock::FloatingObjects::computePlacedFloatsTree()
7359 ASSERT(!m_placedFloatsTree.isInitialized());
7360 if (m_set.isEmpty())
7362 m_placedFloatsTree.initIfNeeded(m_renderer->view()->intervalArena());
7363 FloatingObjectSetIterator it = m_set.begin();
7364 FloatingObjectSetIterator end = m_set.end();
7365 for (; it != end; ++it) {
7366 FloatingObject* floatingObject = *it;
7367 if (floatingObject->isPlaced())
7368 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
7372 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const UChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags)
7376 TextDirection textDirection = LTR;
7377 bool directionalOverride = style->rtlOrdering() == VisualOrder;
7378 if (flags != DefaultTextRunFlags) {
7379 if (flags & RespectDirection)
7380 textDirection = style->direction();
7381 if (flags & RespectDirectionOverride)
7382 directionalOverride |= isOverride(style->unicodeBidi());
7385 TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride);
7386 if (textRunNeedsRenderingContext(font))
7387 run.setRenderingContext(SVGTextRunRenderingContext::create(context));
7392 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags)
7394 return constructTextRun(context, font, string.characters(), string.length(), style, expansion, flags);
7397 RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
7399 // FIXME: Do we need to cover the new flex box here ?
7400 // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
7401 EDisplay newDisplay;
7402 RenderBlock* newBox = 0;
7403 if (display == BOX || display == INLINE_BOX) {
7404 newBox = new (parent->renderArena()) RenderDeprecatedFlexibleBox(parent->document() /* anonymous box */);
7407 newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
7411 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay);
7412 newBox->setStyle(newStyle.release());
7416 RenderBlock* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent)
7418 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
7419 newStyle->inheritColumnPropertiesFrom(parent->style());
7421 RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
7422 newBox->setStyle(newStyle.release());
7426 RenderBlock* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent)
7428 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
7429 newStyle->setColumnSpan(ColumnSpanAll);
7431 RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
7432 newBox->setStyle(newStyle.release());
7437 void RenderBlock::checkPositionedObjectsNeedLayout()
7439 if (PositionedObjectsListHashSet* positionedObjects = this->positionedObjects()) {
7440 PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
7441 for (PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
7442 RenderBox* currBox = *it;
7443 ASSERT(!currBox->needsLayout());
7448 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const
7451 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
7452 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
7455 // These helpers are only used by the PODIntervalTree for debugging purposes.
7456 String ValueToString<int>::string(const int value)
7458 return String::number(value);
7461 String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject)
7463 return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
7468 } // namespace WebCore