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 "core/rendering/RenderBlock.h"
27 #include "HTMLNames.h"
28 #include "core/accessibility/AXObjectCache.h"
29 #include "core/dom/Document.h"
30 #include "core/dom/Element.h"
31 #include "core/events/OverflowEvent.h"
32 #include "core/dom/shadow/ShadowRoot.h"
33 #include "core/editing/Editor.h"
34 #include "core/editing/FrameSelection.h"
35 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
36 #include "core/frame/Frame.h"
37 #include "core/frame/FrameView.h"
38 #include "core/page/Page.h"
39 #include "core/frame/Settings.h"
40 #include "core/rendering/FastTextAutosizer.h"
41 #include "core/rendering/GraphicsContextAnnotator.h"
42 #include "core/rendering/HitTestLocation.h"
43 #include "core/rendering/HitTestResult.h"
44 #include "core/rendering/InlineIterator.h"
45 #include "core/rendering/InlineTextBox.h"
46 #include "core/rendering/LayoutRectRecorder.h"
47 #include "core/rendering/LayoutRepainter.h"
48 #include "core/rendering/PaintInfo.h"
49 #include "core/rendering/RenderCombineText.h"
50 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
51 #include "core/rendering/RenderFlexibleBox.h"
52 #include "core/rendering/RenderInline.h"
53 #include "core/rendering/RenderLayer.h"
54 #include "core/rendering/RenderMarquee.h"
55 #include "core/rendering/RenderNamedFlowThread.h"
56 #include "core/rendering/RenderRegion.h"
57 #include "core/rendering/RenderTableCell.h"
58 #include "core/rendering/RenderTextControl.h"
59 #include "core/rendering/RenderTextFragment.h"
60 #include "core/rendering/RenderTheme.h"
61 #include "core/rendering/RenderView.h"
62 #include "core/rendering/shapes/ShapeOutsideInfo.h"
63 #include "core/rendering/style/ContentData.h"
64 #include "core/rendering/style/RenderStyle.h"
65 #include "platform/geometry/FloatQuad.h"
66 #include "platform/geometry/TransformState.h"
67 #include "platform/graphics/GraphicsContextStateSaver.h"
68 #include "wtf/StdLibExtras.h"
69 #include "wtf/TemporaryChange.h"
73 using namespace Unicode;
77 using namespace HTMLNames;
79 struct SameSizeAsRenderBlock : public RenderBox {
81 RenderObjectChildList children;
82 RenderLineBoxList lineBoxes;
86 struct SameSizeAsRenderBlockRareData {
88 int pageLogicalOffset;
93 COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small);
94 COMPILE_ASSERT(sizeof(RenderBlock::RenderBlockRareData) == sizeof(SameSizeAsRenderBlockRareData), RenderBlockRareData_should_stay_small);
96 typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap;
97 static ColumnInfoMap* gColumnInfoMap = 0;
99 static TrackedDescendantsMap* gPositionedDescendantsMap = 0;
100 static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0;
102 static TrackedContainerMap* gPositionedContainerMap = 0;
103 static TrackedContainerMap* gPercentHeightContainerMap = 0;
105 typedef WTF::HashMap<RenderBlock*, OwnPtr<ListHashSet<RenderInline*> > > ContinuationOutlineTableMap;
107 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
108 static int gDelayUpdateScrollInfo = 0;
109 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
111 static bool gColumnFlowSplitEnabled = true;
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 changes, this class should be shared with other RenderBoxes.
115 class OverflowEventDispatcher {
116 WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher);
118 OverflowEventDispatcher(const RenderBlock* block)
121 m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document().hasListenerType(Document::OVERFLOWCHANGED_LISTENER);
122 if (m_shouldDispatchEvent) {
123 m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
124 m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
128 ~OverflowEventDispatcher()
130 if (!m_shouldDispatchEvent)
133 bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
134 bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
136 bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow;
137 bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow;
139 if (!horizontalLayoutOverflowChanged && !verticalLayoutOverflowChanged)
142 RefPtr<OverflowEvent> event = OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow);
143 event->setTarget(m_block->node());
144 m_block->document().enqueueAnimationFrameEvent(event.release());
148 const RenderBlock* m_block;
149 bool m_shouldDispatchEvent;
150 bool m_hadHorizontalLayoutOverflow;
151 bool m_hadVerticalLayoutOverflow;
154 RenderBlock::RenderBlock(ContainerNode* node)
157 , m_hasMarginBeforeQuirk(false)
158 , m_hasMarginAfterQuirk(false)
159 , m_beingDestroyed(false)
160 , m_hasMarkupTruncation(false)
161 , m_hasBorderOrPaddingLogicalWidthChanged(false)
162 , m_hasOnlySelfCollapsingChildren(false)
164 setChildrenInline(true);
167 static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
169 if (OwnPtr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) {
170 TrackedRendererListHashSet::iterator end = descendantSet->end();
171 for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
172 TrackedContainerMap::iterator it = containerMap->find(*descendant);
173 ASSERT(it != containerMap->end());
174 if (it == containerMap->end())
176 HashSet<RenderBlock*>* containerSet = it->value.get();
177 ASSERT(containerSet->contains(block));
178 containerSet->remove(block);
179 if (containerSet->isEmpty())
180 containerMap->remove(it);
185 static void appendImageIfNotNull(Vector<ImageResource*>& imageResources, const StyleImage* styleImage)
187 if (styleImage && styleImage->cachedImage()) {
188 ImageResource* imageResource = styleImage->cachedImage();
189 if (imageResource && !imageResource->isLoaded())
190 imageResources.append(styleImage->cachedImage());
194 static void appendLayers(Vector<ImageResource*>& images, const FillLayer* styleLayer)
196 for (const FillLayer* layer = styleLayer; layer; layer = layer->next()) {
197 appendImageIfNotNull(images, layer->image());
201 static void appendImagesFromStyle(Vector<ImageResource*>& images, RenderStyle& blockStyle)
203 appendLayers(images, blockStyle.backgroundLayers());
204 appendLayers(images, blockStyle.maskLayers());
206 const ContentData* contentData = blockStyle.contentData();
207 if (contentData && contentData->isImage()) {
208 const ImageContentData* imageContentData = static_cast<const ImageContentData*>(contentData);
209 appendImageIfNotNull(images, imageContentData->image());
211 if (blockStyle.boxReflect())
212 appendImageIfNotNull(images, blockStyle.boxReflect()->mask().image());
213 appendImageIfNotNull(images, blockStyle.listStyleImage());
214 appendImageIfNotNull(images, blockStyle.borderImageSource());
215 appendImageIfNotNull(images, blockStyle.maskBoxImageSource());
218 RenderBlock::~RenderBlock()
220 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this);
222 gColumnInfoMap->take(this);
223 if (gPercentHeightDescendantsMap)
224 removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
225 if (gPositionedDescendantsMap)
226 removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
229 void RenderBlock::willBeDestroyed()
231 // Mark as being destroyed to avoid trouble with merges in removeChild().
232 m_beingDestroyed = true;
234 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
235 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
236 children()->destroyLeftoverChildren();
238 // Destroy our continuation before anything other than anonymous children.
239 // The reason we don't destroy it before anonymous children is that they may
240 // have continuations of their own that are anonymous children of our continuation.
241 RenderBoxModelObject* continuation = this->continuation();
243 continuation->destroy();
247 if (!documentBeingDestroyed()) {
248 if (firstLineBox()) {
249 // We can't wait for RenderBox::destroy to clear the selection,
250 // because by then we will have nuked the line boxes.
251 // FIXME: The FrameSelection should be responsible for this when it
252 // is notified of DOM mutations.
253 if (isSelectionBorder())
254 view()->clearSelection();
256 // If we are an anonymous block, then our line boxes might have children
257 // that will outlast this block. In the non-anonymous block case those
258 // children will be destroyed by the time we return from this function.
259 if (isAnonymousBlock()) {
260 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
261 while (InlineBox* childBox = box->firstChild())
266 parent()->dirtyLinesFromChangedChild(this);
269 m_lineBoxes.deleteLineBoxes();
271 if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
272 gDelayedUpdateScrollInfoSet->remove(this);
274 if (FastTextAutosizer* textAutosizer = document().fastTextAutosizer())
275 textAutosizer->destroy(this);
277 RenderBox::willBeDestroyed();
280 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
282 RenderStyle* oldStyle = style();
284 setReplaced(newStyle->isDisplayInlineType());
286 if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
287 if (newStyle->position() == StaticPosition)
288 // Clear our positioned objects list. Our absolutely positioned descendants will be
289 // inserted into our containing block's positioned objects list during layout.
290 removePositionedObjects(0, NewContainingBlock);
291 else if (oldStyle->position() == StaticPosition) {
292 // Remove our absolutely positioned descendants from their current containing block.
293 // They will be inserted into our positioned objects list during layout.
294 RenderObject* cb = parent();
295 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
296 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
297 cb = cb->containingBlock();
303 if (cb->isRenderBlock())
304 toRenderBlock(cb)->removePositionedObjects(this, NewContainingBlock);
308 RenderBox::styleWillChange(diff, newStyle);
311 static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
313 if (newStyle->isHorizontalWritingMode())
314 return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
315 || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
316 || oldStyle->paddingLeft() != newStyle->paddingLeft()
317 || oldStyle->paddingRight() != newStyle->paddingRight();
319 return oldStyle->borderTopWidth() != newStyle->borderTopWidth()
320 || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth()
321 || oldStyle->paddingTop() != newStyle->paddingTop()
322 || oldStyle->paddingBottom() != newStyle->paddingBottom();
325 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
327 RenderBox::styleDidChange(diff, oldStyle);
329 RenderStyle* newStyle = style();
331 updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : RenderStyle::initialShapeInside());
333 if (!isAnonymousBlock()) {
334 // Ensure that all of our continuation blocks pick up the new style.
335 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
336 RenderBoxModelObject* nextCont = currCont->continuation();
337 currCont->setContinuation(0);
338 currCont->setStyle(newStyle);
339 currCont->setContinuation(nextCont);
343 if (FastTextAutosizer* textAutosizer = document().fastTextAutosizer())
344 textAutosizer->record(this);
346 propagateStyleToAnonymousChildren(true);
349 // It's possible for our border/padding to change, but for the overall logical width of the block to
350 // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true.
351 m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle);
353 // If the style has unloaded images, want to notify the ResourceLoadPriorityOptimizer so that
354 // network priorities can be set.
355 Vector<ImageResource*> images;
356 appendImagesFromStyle(images, *newStyle);
357 if (images.isEmpty())
358 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this);
360 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addRenderObject(this);
363 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
365 if (beforeChild && beforeChild->parent() == this)
368 RenderBlock* curr = toRenderBlock(continuation());
369 RenderBlock* nextToLast = this;
370 RenderBlock* last = this;
372 if (beforeChild && beforeChild->parent() == curr) {
373 if (curr->firstChild() == beforeChild)
380 curr = toRenderBlock(curr->continuation());
383 if (!beforeChild && !last->firstChild())
388 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
390 RenderBlock* flow = continuationBefore(beforeChild);
391 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
392 RenderBoxModelObject* beforeChildParent = 0;
394 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
396 RenderBoxModelObject* cont = flow->continuation();
398 beforeChildParent = cont;
400 beforeChildParent = flow;
403 if (newChild->isFloatingOrOutOfFlowPositioned()) {
404 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
408 // A continuation always consists of two potential candidates: a block or an anonymous
409 // column span box holding column span children.
410 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
411 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
412 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
414 if (flow == beforeChildParent) {
415 flow->addChildIgnoringContinuation(newChild, beforeChild);
419 // The goal here is to match up if we can, so that we can coalesce and create the
420 // minimal # of continuations needed for the inline.
421 if (childIsNormal == bcpIsNormal) {
422 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
425 if (flowIsNormal == childIsNormal) {
426 flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
429 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
433 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
435 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
437 // The goal is to locate a suitable box in which to place our child.
438 RenderBlock* beforeChildParent = 0;
440 RenderObject* curr = beforeChild;
441 while (curr && curr->parent() != this)
442 curr = curr->parent();
443 beforeChildParent = toRenderBlock(curr);
444 ASSERT(beforeChildParent);
445 ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock());
447 beforeChildParent = toRenderBlock(lastChild());
449 // If the new child is floating or positioned it can just go in that block.
450 if (newChild->isFloatingOrOutOfFlowPositioned()) {
451 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
455 // See if the child can be placed in the box.
456 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
457 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
459 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
460 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
465 // Create a new block of the correct type.
466 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
467 children()->appendChildNode(this, newBox);
468 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
472 RenderObject* immediateChild = beforeChild;
473 bool isPreviousBlockViable = true;
474 while (immediateChild->parent() != this) {
475 if (isPreviousBlockViable)
476 isPreviousBlockViable = !immediateChild->previousSibling();
477 immediateChild = immediateChild->parent();
479 if (isPreviousBlockViable && immediateChild->previousSibling()) {
480 toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
484 // Split our anonymous blocks.
485 RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild);
488 // Create a new anonymous box of the appropriate type.
489 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
490 children()->insertChildNode(this, newBox, newBeforeChild);
491 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
495 RenderBlockFlow* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
497 RenderBlock* firstChildIgnoringAnonymousWrappers = 0;
498 for (RenderObject* curr = this; curr; curr = curr->parent()) {
499 if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
500 || curr->isInlineBlockOrInlineTable())
503 // FIXME: Renderers that do special management of their children (tables, buttons,
504 // lists, flexboxes, etc.) breaks when the flow is split through them. Disabling
505 // multi-column for them to avoid this problem.)
506 if (!curr->isRenderBlockFlow() || curr->isListItem())
509 RenderBlockFlow* currBlock = toRenderBlockFlow(curr);
510 if (!currBlock->createsAnonymousWrapper())
511 firstChildIgnoringAnonymousWrappers = currBlock;
513 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
514 return toRenderBlockFlow(firstChildIgnoringAnonymousWrappers);
516 if (currBlock->isAnonymousColumnSpanBlock())
522 RenderBlock* RenderBlock::clone() const
524 RenderBlock* cloneBlock;
525 if (isAnonymousBlock()) {
526 cloneBlock = createAnonymousBlock();
527 cloneBlock->setChildrenInline(childrenInline());
530 RenderObject* cloneRenderer = toElement(node())->createRenderer(style());
531 cloneBlock = toRenderBlock(cloneRenderer);
532 cloneBlock->setStyle(style());
534 // This takes care of setting the right value of childrenInline in case
535 // generated content is added to cloneBlock and 'this' does not have
536 // generated content added yet.
537 cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
539 cloneBlock->setFlowThreadState(flowThreadState());
543 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
544 RenderBlock* middleBlock,
545 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
547 // Create a clone of this inline.
548 RenderBlock* cloneBlock = clone();
549 if (!isAnonymousBlock())
550 cloneBlock->setContinuation(oldCont);
552 if (!beforeChild && isAfterContent(lastChild()))
553 beforeChild = lastChild();
555 // If we are moving inline children from |this| to cloneBlock, then we need
556 // to clear our line box tree.
557 if (beforeChild && childrenInline())
560 // Now take all of the children from beforeChild to the end and remove
561 // them from |this| and place them in the clone.
562 moveChildrenTo(cloneBlock, beforeChild, 0, true);
564 // Hook |clone| up as the continuation of the middle block.
565 if (!cloneBlock->isAnonymousBlock())
566 middleBlock->setContinuation(cloneBlock);
568 // We have been reparented and are now under the fromBlock. We need
569 // to walk up our block parent chain until we hit the containing anonymous columns block.
570 // Once we hit the anonymous columns block we're done.
571 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
572 RenderBoxModelObject* currChild = this;
573 RenderObject* currChildNextSibling = currChild->nextSibling();
575 while (curr && curr->isDescendantOf(fromBlock) && curr != fromBlock) {
576 ASSERT_WITH_SECURITY_IMPLICATION(curr->isRenderBlock());
578 RenderBlock* blockCurr = toRenderBlock(curr);
580 // Create a new clone.
581 RenderBlock* cloneChild = cloneBlock;
582 cloneBlock = blockCurr->clone();
584 // Insert our child clone as the first child.
585 cloneBlock->addChildIgnoringContinuation(cloneChild, 0);
587 // Hook the clone up as a continuation of |curr|. Note we do encounter
588 // anonymous blocks possibly as we walk up the block chain. When we split an
589 // anonymous block, there's no need to do any continuation hookup, since we haven't
590 // actually split a real element.
591 if (!blockCurr->isAnonymousBlock()) {
592 oldCont = blockCurr->continuation();
593 blockCurr->setContinuation(cloneBlock);
594 cloneBlock->setContinuation(oldCont);
597 // Now we need to take all of the children starting from the first child
598 // *after* currChild and append them all to the clone.
599 blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
601 // Keep walking up the chain.
603 currChildNextSibling = currChild->nextSibling();
604 curr = toRenderBoxModelObject(curr->parent());
607 // Now we are at the columns block level. We need to put the clone into the toBlock.
608 toBlock->children()->appendChildNode(toBlock, cloneBlock);
610 // Now take all the children after currChild and remove them from the fromBlock
611 // and put them in the toBlock.
612 fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true);
615 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
616 RenderObject* newChild, RenderBoxModelObject* oldCont)
618 RenderBlock* pre = 0;
619 RenderBlock* block = containingColumnsBlock();
621 // Delete our line boxes before we do the inline split into continuations.
622 block->deleteLineBoxTree();
624 bool madeNewBeforeBlock = false;
625 if (block->isAnonymousColumnsBlock()) {
626 // We can reuse this block and make it the preBlock of the next continuation.
628 pre->removePositionedObjects(0);
629 if (block->isRenderBlockFlow())
630 toRenderBlockFlow(pre)->removeFloatingObjects();
631 block = toRenderBlock(block->parent());
633 // No anonymous block available for use. Make one.
634 pre = block->createAnonymousColumnsBlock();
635 pre->setChildrenInline(false);
636 madeNewBeforeBlock = true;
639 RenderBlock* post = block->createAnonymousColumnsBlock();
640 post->setChildrenInline(false);
642 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
643 if (madeNewBeforeBlock)
644 block->children()->insertChildNode(block, pre, boxFirst);
645 block->children()->insertChildNode(block, newBlockBox, boxFirst);
646 block->children()->insertChildNode(block, post, boxFirst);
647 block->setChildrenInline(false);
649 if (madeNewBeforeBlock)
650 block->moveChildrenTo(pre, boxFirst, 0, true);
652 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
654 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
655 // time in makeChildrenNonInline by just setting this explicitly up front.
656 newBlockBox->setChildrenInline(false);
658 newBlockBox->addChild(newChild);
660 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
661 // get deleted properly. Because objects moves from the pre block into the post block, we want to
662 // make new line boxes instead of leaving the old line boxes around.
663 pre->setNeedsLayoutAndPrefWidthsRecalc();
664 block->setNeedsLayoutAndPrefWidthsRecalc();
665 post->setNeedsLayoutAndPrefWidthsRecalc();
668 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlockFlow* newBlockBox, RenderObject* newChild)
670 RenderBlockFlow* pre = 0;
671 RenderBlockFlow* post = 0;
672 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
673 // so that we don't have to patch all of the rest of the code later on.
675 // Delete the block's line boxes before we do the split.
676 block->deleteLineBoxTree();
678 if (beforeChild && beforeChild->parent() != this)
679 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
681 if (beforeChild != firstChild()) {
682 pre = block->createAnonymousColumnsBlock();
683 pre->setChildrenInline(block->childrenInline());
687 post = block->createAnonymousColumnsBlock();
688 post->setChildrenInline(block->childrenInline());
691 RenderObject* boxFirst = block->firstChild();
693 block->children()->insertChildNode(block, pre, boxFirst);
694 block->children()->insertChildNode(block, newBlockBox, boxFirst);
696 block->children()->insertChildNode(block, post, boxFirst);
697 block->setChildrenInline(false);
699 // 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).
700 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
701 block->moveChildrenTo(post, beforeChild, 0, true);
703 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
704 // time in makeChildrenNonInline by just setting this explicitly up front.
705 newBlockBox->setChildrenInline(false);
707 newBlockBox->addChild(newChild);
709 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
710 // get deleted properly. Because objects moved from the pre block into the post block, we want to
711 // make new line boxes instead of leaving the old line boxes around.
713 pre->setNeedsLayoutAndPrefWidthsRecalc();
714 block->setNeedsLayoutAndPrefWidthsRecalc();
716 post->setNeedsLayoutAndPrefWidthsRecalc();
719 RenderBlockFlow* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
721 // FIXME: This function is the gateway for the addition of column-span support. It will
722 // be added to in three stages:
723 // (1) Immediate children of a multi-column block can span.
724 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
725 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
726 // cross the streams and have to cope with both types of continuations mixed together).
727 // This function currently supports (1) and (2).
728 RenderBlockFlow* columnsBlockAncestor = 0;
729 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent()
730 && !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
731 columnsBlockAncestor = containingColumnsBlock(false);
732 if (columnsBlockAncestor) {
733 // Make sure that none of the parent ancestors have a continuation.
734 // If yes, we do not want split the block into continuations.
735 RenderObject* curr = this;
736 while (curr && curr != columnsBlockAncestor) {
737 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
738 columnsBlockAncestor = 0;
741 curr = curr->parent();
745 return columnsBlockAncestor;
748 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
750 if (beforeChild && beforeChild->parent() != this) {
751 RenderObject* beforeChildContainer = beforeChild->parent();
752 while (beforeChildContainer->parent() != this)
753 beforeChildContainer = beforeChildContainer->parent();
754 ASSERT(beforeChildContainer);
756 if (beforeChildContainer->isAnonymous()) {
757 // If the requested beforeChild is not one of our children, then this is because
758 // there is an anonymous container within this object that contains the beforeChild.
759 RenderObject* beforeChildAnonymousContainer = beforeChildContainer;
760 if (beforeChildAnonymousContainer->isAnonymousBlock()
761 // Full screen renderers and full screen placeholders act as anonymous blocks, not tables:
762 || beforeChildAnonymousContainer->isRenderFullScreen()
763 || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder()
765 // Insert the child into the anonymous block box instead of here.
766 if (newChild->isInline() || newChild->isFloatingOrOutOfFlowPositioned() || beforeChild->parent()->firstChild() != beforeChild)
767 beforeChild->parent()->addChild(newChild, beforeChild);
769 addChild(newChild, beforeChild->parent());
773 ASSERT(beforeChildAnonymousContainer->isTable());
774 if (newChild->isTablePart()) {
775 // Insert into the anonymous table.
776 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
780 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
782 ASSERT(beforeChild->parent() == this);
783 if (beforeChild->parent() != this) {
784 // We should never reach here. If we do, we need to use the
785 // safe fallback to use the topmost beforeChild container.
786 beforeChild = beforeChildContainer;
791 // Check for a spanning element in columns.
792 if (gColumnFlowSplitEnabled) {
793 RenderBlockFlow* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
794 if (columnsBlockAncestor) {
795 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
796 // We are placing a column-span element inside a block.
797 RenderBlockFlow* newBox = createAnonymousColumnSpanBlock();
799 if (columnsBlockAncestor != this && !isRenderFlowThread()) {
800 // We are nested inside a multi-column element and are being split by the span. We have to break up
801 // our block into continuations.
802 RenderBoxModelObject* oldContinuation = continuation();
804 // When we split an anonymous block, there's no need to do any continuation hookup,
805 // since we haven't actually split a real element.
806 if (!isAnonymousBlock())
807 setContinuation(newBox);
809 splitFlow(beforeChild, newBox, newChild, oldContinuation);
813 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
814 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
815 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
816 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
821 bool madeBoxesNonInline = false;
823 // A block has to either have all of its children inline, or all of its children as blocks.
824 // So, if our children are currently inline and a block child has to be inserted, we move all our
825 // inline children into anonymous block boxes.
826 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
827 // This is a block with inline content. Wrap the inline content in anonymous blocks.
828 makeChildrenNonInline(beforeChild);
829 madeBoxesNonInline = true;
831 if (beforeChild && beforeChild->parent() != this) {
832 beforeChild = beforeChild->parent();
833 ASSERT(beforeChild->isAnonymousBlock());
834 ASSERT(beforeChild->parent() == this);
836 } else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) {
837 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
838 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
839 // a new one is created and inserted into our list of children in the appropriate position.
840 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
842 if (afterChild && afterChild->isAnonymousBlock()) {
843 afterChild->addChild(newChild);
847 if (newChild->isInline()) {
848 // No suitable existing anonymous box - create a new one.
849 RenderBlock* newBox = createAnonymousBlock();
850 RenderBox::addChild(newBox, beforeChild);
851 newBox->addChild(newChild);
856 RenderBox::addChild(newChild, beforeChild);
858 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
859 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
860 // this object may be dead here
863 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
865 if (continuation() && !isAnonymousBlock())
866 addChildToContinuation(newChild, beforeChild);
868 addChildIgnoringContinuation(newChild, beforeChild);
871 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
873 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
874 addChildToAnonymousColumnBlocks(newChild, beforeChild);
876 addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
879 static void getInlineRun(RenderObject* start, RenderObject* boundary,
880 RenderObject*& inlineRunStart,
881 RenderObject*& inlineRunEnd)
883 // Beginning at |start| we find the largest contiguous run of inlines that
884 // we can. We denote the run with start and end points, |inlineRunStart|
885 // and |inlineRunEnd|. Note that these two values may be the same if
886 // we encounter only one inline.
888 // We skip any non-inlines we encounter as long as we haven't found any
891 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
892 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
895 // Start by skipping as many non-inlines as we can.
896 RenderObject * curr = start;
899 while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()))
900 curr = curr->nextSibling();
902 inlineRunStart = inlineRunEnd = curr;
905 return; // No more inline children to be found.
907 sawInline = curr->isInline();
909 curr = curr->nextSibling();
910 while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) {
912 if (curr->isInline())
914 curr = curr->nextSibling();
916 } while (!sawInline);
919 void RenderBlock::deleteLineBoxTree()
921 m_lineBoxes.deleteLineBoxTree();
923 if (AXObjectCache* cache = document().existingAXObjectCache())
924 cache->recomputeIsIgnored(this);
927 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
929 // makeChildrenNonInline takes a block whose children are *all* inline and it
930 // makes sure that inline children are coalesced under anonymous
931 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
932 // the new block child that is causing us to have to wrap all the inlines. This
933 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
934 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
936 ASSERT(isInlineBlockOrInlineTable() || !isInline());
937 ASSERT(!insertionPoint || insertionPoint->parent() == this);
939 setChildrenInline(false);
941 RenderObject *child = firstChild();
948 RenderObject *inlineRunStart, *inlineRunEnd;
949 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
954 child = inlineRunEnd->nextSibling();
956 RenderBlock* block = createAnonymousBlock();
957 children()->insertChildNode(this, block, inlineRunStart);
958 moveChildrenTo(block, inlineRunStart, child);
962 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
963 ASSERT(!c->isInline());
969 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
971 ASSERT(child->isAnonymousBlock());
972 ASSERT(!child->childrenInline());
974 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
977 RenderObject* firstAnChild = child->m_children.firstChild();
978 RenderObject* lastAnChild = child->m_children.lastChild();
980 RenderObject* o = firstAnChild;
983 o = o->nextSibling();
985 firstAnChild->setPreviousSibling(child->previousSibling());
986 lastAnChild->setNextSibling(child->nextSibling());
987 if (child->previousSibling())
988 child->previousSibling()->setNextSibling(firstAnChild);
989 if (child->nextSibling())
990 child->nextSibling()->setPreviousSibling(lastAnChild);
992 if (child == m_children.firstChild())
993 m_children.setFirstChild(firstAnChild);
994 if (child == m_children.lastChild())
995 m_children.setLastChild(lastAnChild);
997 if (child == m_children.firstChild())
998 m_children.setFirstChild(child->nextSibling());
999 if (child == m_children.lastChild())
1000 m_children.setLastChild(child->previousSibling());
1002 if (child->previousSibling())
1003 child->previousSibling()->setNextSibling(child->nextSibling());
1004 if (child->nextSibling())
1005 child->nextSibling()->setPreviousSibling(child->previousSibling());
1008 child->children()->setFirstChild(0);
1011 // Remove all the information in the flow thread associated with the leftover anonymous block.
1012 child->removeFromRenderFlowThread();
1014 child->setParent(0);
1015 child->setPreviousSibling(0);
1016 child->setNextSibling(0);
1021 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
1023 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
1026 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
1027 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
1030 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
1031 || (next && (next->isRubyRun() || next->isRubyBase())))
1037 // Make sure the types of the anonymous blocks match up.
1038 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1039 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1042 void RenderBlock::collapseAnonymousBlockChild(RenderBlock* parent, RenderBlock* child)
1044 // It's possible that this block's destruction may have been triggered by the
1045 // child's removal. Just bail if the anonymous child block is already being
1046 // destroyed. See crbug.com/282088
1047 if (child->beingDestroyed())
1049 parent->setNeedsLayoutAndPrefWidthsRecalc();
1050 parent->setChildrenInline(child->childrenInline());
1051 RenderObject* nextSibling = child->nextSibling();
1053 RenderFlowThread* childFlowThread = child->flowThreadContainingBlock();
1054 CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread);
1056 parent->children()->removeChildNode(parent, child, child->hasLayer());
1057 child->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
1058 // Explicitly delete the child's line box tree, or the special anonymous
1059 // block handling in willBeDestroyed will cause problems.
1060 child->deleteLineBoxTree();
1061 if (childFlowThread && childFlowThread->isRenderNamedFlowThread())
1062 toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child);
1066 void RenderBlock::removeChild(RenderObject* oldChild)
1068 // No need to waste time in merging or removing empty anonymous blocks.
1069 // We can just bail out if our document is getting destroyed.
1070 if (documentBeingDestroyed()) {
1071 RenderBox::removeChild(oldChild);
1075 // This protects against column split flows when anonymous blocks are getting merged.
1076 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
1078 // If this child is a block, and if our previous and next siblings are
1079 // both anonymous blocks with inline content, then we can go ahead and
1080 // fold the inline content back together.
1081 RenderObject* prev = oldChild->previousSibling();
1082 RenderObject* next = oldChild->nextSibling();
1083 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1084 if (canMergeAnonymousBlocks && prev && next) {
1085 prev->setNeedsLayoutAndPrefWidthsRecalc();
1086 RenderBlockFlow* nextBlock = toRenderBlockFlow(next);
1087 RenderBlockFlow* prevBlock = toRenderBlockFlow(prev);
1089 if (prev->childrenInline() != next->childrenInline()) {
1090 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1091 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1093 // Place the inline children block inside of the block children block instead of deleting it.
1094 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1095 // to clear out inherited column properties by just making a new style, and to also clear the
1096 // column span flag if it is set.
1097 ASSERT(!inlineChildrenBlock->continuation());
1098 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
1099 // Cache this value as it might get changed in setStyle() call.
1100 bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer();
1101 inlineChildrenBlock->setStyle(newStyle);
1102 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlockHasLayer);
1104 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1105 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1106 inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer());
1107 next->setNeedsLayoutAndPrefWidthsRecalc();
1109 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1110 // of "this". we null out prev or next so that is not used later in the function.
1111 if (inlineChildrenBlock == prevBlock)
1116 // Take all the children out of the |next| block and put them in
1117 // the |prev| block.
1118 nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1120 // Delete the now-empty block's lines and nuke it.
1121 nextBlock->deleteLineBoxTree();
1122 nextBlock->destroy();
1127 RenderBox::removeChild(oldChild);
1129 RenderObject* child = prev ? prev : next;
1130 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) {
1131 // The removal has knocked us down to containing only a single anonymous
1132 // box. We can go ahead and pull the content right back up into our
1134 collapseAnonymousBlockChild(this, toRenderBlock(child));
1135 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
1136 // It's possible that the removal has knocked us down to a single anonymous
1137 // block with pseudo-style element siblings (e.g. first-letter). If these
1138 // are floating, then we need to pull the content up also.
1139 RenderBlock* anonymousBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1140 if ((anonymousBlock->previousSibling() || anonymousBlock->nextSibling())
1141 && (!anonymousBlock->previousSibling() || (anonymousBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->previousSibling()->isFloating() && !anonymousBlock->previousSibling()->previousSibling()))
1142 && (!anonymousBlock->nextSibling() || (anonymousBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->nextSibling()->isFloating() && !anonymousBlock->nextSibling()->nextSibling()))) {
1143 collapseAnonymousBlockChild(this, anonymousBlock);
1147 if (!firstChild()) {
1148 // If this was our last child be sure to clear out our line boxes.
1149 if (childrenInline())
1150 deleteLineBoxTree();
1152 // If we are an empty anonymous block in the continuation chain,
1153 // we need to remove ourself and fix the continuation chain.
1154 if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) {
1155 RenderObject* containingBlockIgnoringAnonymous = containingBlock();
1156 while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock())
1157 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
1158 for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
1159 if (curr->virtualContinuation() != this)
1162 // Found our previous continuation. We just need to point it to
1163 // |this|'s next continuation.
1164 RenderBoxModelObject* nextContinuation = continuation();
1165 if (curr->isRenderInline())
1166 toRenderInline(curr)->setContinuation(nextContinuation);
1167 else if (curr->isRenderBlock())
1168 toRenderBlock(curr)->setContinuation(nextContinuation);
1170 ASSERT_NOT_REACHED();
1180 bool RenderBlock::isSelfCollapsingBlock() const
1182 ASSERT(!needsLayout());
1184 // We are not self-collapsing if we
1185 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1187 // (c) have border/padding,
1188 // (d) have a min-height
1189 // (e) have specified that one of our margins can't collapse using a CSS extension
1190 if (logicalHeight() > 0
1191 || isTable() || borderAndPaddingLogicalHeight()
1192 || style()->logicalMinHeight().isPositive()
1193 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1196 Length logicalHeightLength = style()->logicalHeight();
1197 bool hasAutoHeight = logicalHeightLength.isAuto();
1198 if (logicalHeightLength.isPercent() && !document().inQuirksMode()) {
1199 hasAutoHeight = true;
1200 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1201 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1202 hasAutoHeight = false;
1206 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1207 // on whether we have content that is all self-collapsing or not.
1208 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1209 // If the block has inline children, see if we generated any line boxes. If we have any
1210 // line boxes, then we can't be self-collapsing, since we have content.
1211 if (childrenInline())
1212 return !firstLineBox();
1214 // Whether or not we collapse is dependent on whether all our normal flow children
1215 // are also self-collapsing.
1216 if (m_hasOnlySelfCollapsingChildren)
1218 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1219 if (child->isFloatingOrOutOfFlowPositioned())
1221 if (!child->isSelfCollapsingBlock())
1229 void RenderBlock::startDelayUpdateScrollInfo()
1231 if (gDelayUpdateScrollInfo == 0) {
1232 ASSERT(!gDelayedUpdateScrollInfoSet);
1233 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1235 ASSERT(gDelayedUpdateScrollInfoSet);
1236 ++gDelayUpdateScrollInfo;
1239 void RenderBlock::finishDelayUpdateScrollInfo()
1241 --gDelayUpdateScrollInfo;
1242 ASSERT(gDelayUpdateScrollInfo >= 0);
1243 if (gDelayUpdateScrollInfo == 0) {
1244 ASSERT(gDelayedUpdateScrollInfoSet);
1246 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1247 gDelayedUpdateScrollInfoSet = 0;
1249 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1250 RenderBlock* block = *it;
1251 if (block->hasOverflowClip()) {
1252 block->layer()->scrollableArea()->updateAfterLayout();
1258 void RenderBlock::updateScrollInfoAfterLayout()
1260 if (hasOverflowClip()) {
1261 if (style()->isFlippedBlocksWritingMode()) {
1262 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
1263 // Workaround for now. We cannot delay the scroll info for overflow
1264 // for items with opposite writing directions, as the contents needs
1265 // to overflow in that direction
1266 layer()->scrollableArea()->updateAfterLayout();
1270 if (gDelayUpdateScrollInfo)
1271 gDelayedUpdateScrollInfoSet->add(this);
1273 layer()->scrollableArea()->updateAfterLayout();
1277 void RenderBlock::layout()
1279 OverflowEventDispatcher dispatcher(this);
1280 LayoutRectRecorder recorder(*this);
1282 // Update our first letter info now.
1283 updateFirstLetter();
1285 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1289 if (frameView()->partialLayout().isStopping())
1292 // It's safe to check for control clip here, since controls can never be table cells.
1293 // If we have a lightweight clip, there can never be any overflow from children.
1294 if (hasControlClip() && m_overflow)
1295 clearLayoutOverflow();
1297 invalidateBackgroundObscurationStatus();
1300 bool RenderBlock::updateImageLoadingPriorities()
1302 Vector<ImageResource*> images;
1303 appendImagesFromStyle(images, *style());
1305 if (images.isEmpty())
1308 LayoutRect viewBounds = viewRect();
1309 LayoutRect objectBounds = absoluteContentBox();
1310 // The object bounds might be empty right now, so intersects will fail since it doesn't deal
1311 // with empty rects. Use LayoutRect::contains in that case.
1313 if (!objectBounds.isEmpty())
1314 isVisible = viewBounds.intersects(objectBounds);
1316 isVisible = viewBounds.contains(objectBounds);
1318 ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ?
1319 ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible;
1321 for (Vector<ImageResource*>::iterator it = images.begin(), end = images.end(); it != end; ++it)
1322 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(*it, status);
1327 void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset)
1329 LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height();
1330 if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo())
1332 // Propagate layout markers only up to the child, as we are still in the middle
1334 child->setNormalChildNeedsLayout(true);
1335 child->markShapeInsideDescendantsForLayout();
1336 child->layoutIfNeeded();
1339 ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
1341 if (ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo())
1342 return shapeInsideInfo;
1344 RenderFlowThread* flowThread = flowThreadContainingBlock();
1345 if (allowsShapeInsideInfoSharing(flowThread)) {
1346 LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
1347 // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ...
1348 LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1);
1349 RenderRegion* region = regionAtBlockOffset(offset);
1350 if (region && region->logicalHeight())
1351 return region->shapeInsideInfo();
1357 LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const
1359 const RenderBlock* currentBlock = this;
1360 LayoutRect blockRect(currentBlock->borderBoxRect());
1361 while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) {
1362 RenderBlock* containerBlock = currentBlock->containingBlock();
1363 ASSERT(containerBlock);
1364 if (!containerBlock)
1365 return LayoutSize();
1367 if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
1368 // We have to put the block rect in container coordinates
1369 // and we have to take into account both the container and current block flipping modes
1370 // Bug: Flipping inline and block directions at the same time will not work,
1371 // as one of the flipped dimensions will not yet have been set to its final size
1372 if (containerBlock->style()->isFlippedBlocksWritingMode()) {
1373 if (containerBlock->isHorizontalWritingMode())
1374 blockRect.setY(currentBlock->height() - blockRect.maxY());
1376 blockRect.setX(currentBlock->width() - blockRect.maxX());
1378 currentBlock->flipForWritingMode(blockRect);
1381 blockRect.moveBy(currentBlock->location());
1382 currentBlock = containerBlock;
1385 LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x());
1389 void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*)
1391 RenderBox::imageChanged(image);
1393 if (!parent() || !everHadLayout())
1396 ShapeValue* shapeValue = style()->shapeInside();
1397 if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) {
1398 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1399 shapeInsideInfo->dirtyShapeSize();
1400 markShapeInsideDescendantsForLayout();
1403 ShapeValue* shapeOutsideValue = style()->shapeOutside();
1404 if (isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image)
1405 parent()->setNeedsLayoutAndPrefWidthsRecalc();
1408 void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
1410 // FIXME: A future optimization would do a deep comparison for equality.
1411 if (shapeInside == oldShapeInside)
1415 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1416 shapeInsideInfo->dirtyShapeSize();
1418 setShapeInsideInfo(nullptr);
1419 markShapeInsideDescendantsForLayout();
1423 static inline bool shapeInfoRequiresRelayout(const RenderBlock* block)
1425 ShapeInsideInfo* info = block->shapeInsideInfo();
1427 info->setNeedsLayout(info->shapeSizeDirty());
1429 info = block->layoutShapeInsideInfo();
1430 return info && info->needsLayout();
1433 bool RenderBlock::updateRegionsAndShapesLogicalSize(RenderFlowThread* flowThread)
1435 if (!flowThread && !shapeInsideInfo())
1436 return shapeInfoRequiresRelayout(this);
1438 LayoutUnit oldHeight = logicalHeight();
1439 LayoutUnit oldTop = logicalTop();
1441 // Compute the maximum logical height content may cause this block to expand to
1442 // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
1443 setLogicalHeight(RenderFlowThread::maxLogicalHeight());
1444 updateLogicalHeight();
1448 // Set our start and end regions. No regions above or below us will be considered by our children. They are
1449 // effectively clamped to our region range.
1450 computeRegionRangeForBlock(flowThread);
1452 setLogicalHeight(oldHeight);
1453 setLogicalTop(oldTop);
1455 return shapeInfoRequiresRelayout(this);
1458 void RenderBlock::computeShapeSize()
1460 ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
1461 if (!shapeInsideInfo)
1464 if (isRenderNamedFlowFragment()) {
1465 ShapeInsideInfo* parentShapeInsideInfo = toRenderBlock(parent())->shapeInsideInfo();
1466 ASSERT(parentShapeInsideInfo);
1467 shapeInsideInfo->setShapeSize(parentShapeInsideInfo->shapeSize().width(), parentShapeInsideInfo->shapeSize().height());
1469 bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
1470 shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
1474 void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged)
1476 // A previous sibling has changed dimension, so we need to relayout the shape with the content
1477 ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
1478 if (heightChanged && shapeInsideInfo)
1479 shapeInsideInfo->dirtyShapeSize();
1481 computeRegionRangeForBlock(flowThread);
1484 void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread)
1487 flowThread->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1490 bool RenderBlock::updateLogicalWidthAndColumnWidth()
1492 LayoutUnit oldWidth = logicalWidth();
1493 LayoutUnit oldColumnWidth = desiredColumnWidth();
1495 updateLogicalWidth();
1498 bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged;
1499 m_hasBorderOrPaddingLogicalWidthChanged = false;
1501 return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
1504 void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
1506 ColumnInfo* colInfo = columnInfo();
1508 if (!pageLogicalHeight) {
1509 LayoutUnit oldLogicalHeight = logicalHeight();
1510 setLogicalHeight(0);
1511 // We need to go ahead and set our explicit page height if one exists, so that we can
1512 // avoid doing two layout passes.
1513 updateLogicalHeight();
1514 LayoutUnit columnHeight = contentLogicalHeight();
1515 if (columnHeight > 0) {
1516 pageLogicalHeight = columnHeight;
1517 hasSpecifiedPageLogicalHeight = true;
1519 setLogicalHeight(oldLogicalHeight);
1521 if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
1522 colInfo->setColumnHeight(pageLogicalHeight);
1523 pageLogicalHeightChanged = true;
1526 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1527 colInfo->clearForcedBreaks();
1529 colInfo->setPaginationUnit(paginationUnit());
1530 } else if (isRenderFlowThread()) {
1531 pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
1532 pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged();
1536 void RenderBlock::layoutBlock(bool)
1538 ASSERT_NOT_REACHED();
1542 void RenderBlock::addOverflowFromChildren()
1544 if (!hasColumns()) {
1545 if (childrenInline())
1546 toRenderBlockFlow(this)->addOverflowFromInlineChildren();
1548 addOverflowFromBlockChildren();
1550 ColumnInfo* colInfo = columnInfo();
1551 if (columnCount(colInfo)) {
1552 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1553 addLayoutOverflow(lastRect);
1554 addContentsVisualOverflow(lastRect);
1559 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool)
1563 // Add overflow from children.
1564 addOverflowFromChildren();
1566 // Add in the overflow from positioned objects.
1567 addOverflowFromPositionedObjects();
1569 if (hasOverflowClip()) {
1570 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1571 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1572 // be considered reachable.
1573 LayoutRect clientRect(noOverflowRect());
1574 LayoutRect rectToApply;
1575 if (isHorizontalWritingMode())
1576 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1578 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1579 addLayoutOverflow(rectToApply);
1580 if (hasRenderOverflow())
1581 m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
1584 // Add visual overflow from box-shadow and border-image-outset.
1585 addVisualEffectOverflow();
1587 // Add visual overflow from theme.
1588 addVisualOverflowFromTheme();
1590 if (isRenderNamedFlowThread())
1591 toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge);
1594 void RenderBlock::addOverflowFromBlockChildren()
1596 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1597 if (!child->isFloatingOrOutOfFlowPositioned())
1598 addOverflowFromChild(child);
1602 void RenderBlock::addOverflowFromPositionedObjects()
1604 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1605 if (!positionedDescendants)
1608 RenderBox* positionedObject;
1609 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1610 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1611 positionedObject = *it;
1613 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1614 if (positionedObject->style()->position() != FixedPosition)
1615 addOverflowFromChild(positionedObject, LayoutSize(positionedObject->x(), positionedObject->y()));
1619 void RenderBlock::addVisualOverflowFromTheme()
1621 if (!style()->hasAppearance())
1624 IntRect inflatedRect = pixelSnappedBorderBoxRect();
1625 RenderTheme::theme().adjustRepaintRect(this, inflatedRect);
1626 addVisualOverflow(inflatedRect);
1629 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1631 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
1632 || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
1635 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
1637 LayoutUnit startPosition = borderStart() + paddingStart();
1638 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1639 startPosition -= verticalScrollbarWidth();
1640 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1642 // Add in our start margin.
1643 LayoutUnit childMarginStart = marginStartForChild(child);
1644 LayoutUnit newPosition = startPosition + childMarginStart;
1646 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1647 // to shift over as necessary to dodge any floats that might get in the way.
1648 if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
1649 newPosition += toRenderBlockFlow(this)->computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
1651 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
1654 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
1656 if (isHorizontalWritingMode()) {
1657 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1658 view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
1659 child->setX(logicalLeft);
1661 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1662 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
1663 child->setY(logicalLeft);
1667 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
1669 if (isHorizontalWritingMode()) {
1670 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1671 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
1672 child->setY(logicalTop);
1674 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1675 view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
1676 child->setX(logicalTop);
1680 void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child)
1682 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1683 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1684 if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
1685 child->setChildNeedsLayout(MarkOnlyThis);
1687 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1688 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
1689 child->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1692 void RenderBlock::simplifiedNormalFlowLayout()
1694 if (childrenInline()) {
1695 ListHashSet<RootInlineBox*> lineBoxes;
1696 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1697 RenderObject* o = walker.current();
1698 if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
1699 o->layoutIfNeeded();
1700 if (toRenderBox(o)->inlineBoxWrapper()) {
1701 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
1704 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
1705 o->clearNeedsLayout();
1709 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
1710 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1711 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
1712 RootInlineBox* box = *it;
1713 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
1716 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
1717 if (!box->isOutOfFlowPositioned())
1718 box->layoutIfNeeded();
1723 bool RenderBlock::simplifiedLayout()
1725 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
1728 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
1730 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
1733 // Lay out positioned descendants or objects that just need to recompute overflow.
1734 if (needsSimplifiedNormalFlowLayout())
1735 simplifiedNormalFlowLayout();
1737 // Make sure a forced break is applied after the content if we are a flow thread in a simplified layout.
1738 // This ensures the size information is correctly computed for the last auto-height region receiving content.
1739 if (isRenderFlowThread())
1740 toRenderFlowThread(this)->applyBreakAfterContent(clientLogicalBottom());
1742 // Lay out our positioned objects if our positioned child bit is set.
1743 // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
1744 // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
1745 // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
1746 // are statically positioned and thus need to move with their absolute ancestors.
1747 bool canContainFixedPosObjects = canContainFixedPositionObjects();
1748 if (posChildNeedsLayout() || canContainFixedPosObjects)
1749 layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects);
1751 // Recompute our overflow information.
1752 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
1753 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
1754 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
1755 // lowestPosition on every relayout so it's not a regression.
1756 // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
1757 // simplifiedLayout, we cache the value in m_overflow.
1758 LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
1759 computeOverflow(oldClientAfterEdge, true);
1763 updateLayerTransform();
1765 updateScrollInfoAfterLayout();
1771 void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child, SubtreeLayoutScope& layoutScope)
1773 if (child->style()->position() != FixedPosition)
1776 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
1777 bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
1778 if (!hasStaticBlockPosition && !hasStaticInlinePosition)
1781 RenderObject* o = child->parent();
1782 while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition)
1784 if (o->style()->position() != AbsolutePosition)
1787 RenderBox* box = toRenderBox(child);
1788 if (hasStaticInlinePosition) {
1789 LayoutUnit oldLeft = box->logicalLeft();
1790 box->updateLogicalWidth();
1791 if (box->logicalLeft() != oldLeft)
1792 layoutScope.setChildNeedsLayout(child);
1793 } else if (hasStaticBlockPosition) {
1794 LayoutUnit oldTop = box->logicalTop();
1795 box->updateLogicalHeight();
1796 if (box->logicalTop() != oldTop)
1797 layoutScope.setChildNeedsLayout(child);
1801 LayoutUnit RenderBlock::marginIntrinsicLogicalWidthForChild(RenderBox* child) const
1803 // A margin has three types: fixed, percentage, and auto (variable).
1804 // Auto and percentage margins become 0 when computing min/max width.
1805 // Fixed margins can be added in as is.
1806 Length marginLeft = child->style()->marginStartUsing(style());
1807 Length marginRight = child->style()->marginEndUsing(style());
1808 LayoutUnit margin = 0;
1809 if (marginLeft.isFixed())
1810 margin += marginLeft.value();
1811 if (marginRight.isFixed())
1812 margin += marginRight.value();
1816 void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly)
1818 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1819 if (!positionedDescendants)
1823 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
1826 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1827 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1830 SubtreeLayoutScope layoutScope(r);
1831 // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
1832 // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e.
1833 // it has static position.
1834 markFixedPositionObjectForLayoutIfNeeded(r, layoutScope);
1835 if (fixedPositionObjectsOnly) {
1836 r->layoutIfNeeded();
1840 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
1841 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
1842 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
1843 // positioned explicitly) this should not incur a performance penalty.
1844 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
1845 layoutScope.setChildNeedsLayout(r);
1847 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1848 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
1849 r->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1851 if (!r->needsLayout())
1852 r->markForPaginationRelayoutIfNeeded(layoutScope);
1854 // 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
1855 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
1856 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
1857 r->clearNeedsLayout();
1859 // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
1860 // If it's wrong we'll lay out again.
1861 LayoutUnit oldLogicalTop = 0;
1862 bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
1863 if (needsBlockDirectionLocationSetBeforeLayout) {
1864 if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
1865 r->updateLogicalHeight();
1867 r->updateLogicalWidth();
1868 oldLogicalTop = logicalTopForChild(r);
1871 r->layoutIfNeeded();
1873 // Lay out again if our estimate was wrong.
1874 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop)
1875 r->forceChildLayout();
1879 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
1882 void RenderBlock::markPositionedObjectsForLayout()
1884 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1885 if (positionedDescendants) {
1887 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1888 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1890 r->setChildNeedsLayout();
1895 void RenderBlock::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
1897 ASSERT(!needsLayout());
1901 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
1902 layoutScope.setChildNeedsLayout(this);
1905 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1907 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
1909 LayoutPoint adjustedPaintOffset = paintOffset + location();
1911 PaintPhase phase = paintInfo.phase;
1913 // Check if we need to do anything at all.
1914 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
1915 // paints the root's background.
1917 LayoutRect overflowBox = overflowRectForPaintRejection();
1918 flipForWritingMode(overflowBox);
1919 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
1920 overflowBox.moveBy(adjustedPaintOffset);
1921 if (!overflowBox.intersects(paintInfo.rect))
1925 // There are some cases where not all clipped visual overflow is accounted for.
1926 // FIXME: reduce the number of such cases.
1927 ContentsClipBehavior contentsClipBehavior = ForceContentsClip;
1928 if (hasOverflowClip() && !hasControlClip() && !(shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !hasCaret())
1929 contentsClipBehavior = SkipContentsClipIfPossible;
1931 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior);
1932 paintObject(paintInfo, adjustedPaintOffset);
1934 popContentsClip(paintInfo, phase, adjustedPaintOffset);
1936 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1937 // z-index. We paint after we painted the background/border, so that the scrollbars will
1938 // sit above the background/border.
1939 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly())
1940 layer()->scrollableArea()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect, false /* paintingOverlayControls */);
1943 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1945 if (paintInfo.context->paintingDisabled())
1948 const Color& ruleColor = resolveColor(CSSPropertyWebkitColumnRuleColor);
1949 bool ruleTransparent = style()->columnRuleIsTransparent();
1950 EBorderStyle ruleStyle = style()->columnRuleStyle();
1951 LayoutUnit ruleThickness = style()->columnRuleWidth();
1952 LayoutUnit colGap = columnGap();
1953 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
1957 ColumnInfo* colInfo = columnInfo();
1958 unsigned colCount = columnCount(colInfo);
1960 bool antialias = shouldAntialiasLines(paintInfo.context);
1962 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
1963 bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed();
1964 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
1965 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
1966 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
1967 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
1968 BoxSide boxSide = isHorizontalWritingMode()
1969 ? leftToRight ? BSLeft : BSRight
1970 : leftToRight ? BSTop : BSBottom;
1972 for (unsigned i = 0; i < colCount; i++) {
1973 // Move to the next position.
1975 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
1976 currLogicalLeftOffset += inlineDirectionSize + colGap;
1978 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
1979 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
1982 // Now paint the column rule.
1983 if (i < colCount - 1) {
1984 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
1985 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
1986 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
1987 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
1988 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
1989 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
1992 ruleLogicalLeft = currLogicalLeftOffset;
1995 bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
1996 LayoutUnit ruleLeft = isHorizontalWritingMode()
1997 ? borderLeft() + paddingLeft()
1998 : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
1999 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2000 LayoutUnit ruleTop = isHorizontalWritingMode()
2001 ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
2002 : borderStart() + paddingStart();
2003 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2004 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2007 if (isHorizontalWritingMode())
2008 ruleRect.setY(height() - ruleRect.maxY());
2010 ruleRect.setX(width() - ruleRect.maxX());
2013 ruleRect.moveBy(paintOffset);
2015 BoxSide boxSide = isHorizontalWritingMode()
2016 ? topToBottom ? BSTop : BSBottom
2017 : topToBottom ? BSLeft : BSRight;
2019 LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2020 if (!isHorizontalWritingMode())
2021 step = step.transposedSize();
2023 for (unsigned i = 1; i < colCount; i++) {
2024 ruleRect.move(step);
2025 IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
2026 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2031 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2033 // We need to do multiple passes, breaking up our child painting into strips.
2034 GraphicsContext* context = paintInfo.context;
2035 ColumnInfo* colInfo = columnInfo();
2036 unsigned colCount = columnCount(colInfo);
2039 LayoutUnit currLogicalTopOffset = 0;
2040 LayoutUnit colGap = columnGap();
2041 for (unsigned i = 0; i < colCount; i++) {
2042 // For each rect, we clip to the rect, and then we adjust our coords.
2043 LayoutRect colRect = columnRectAt(colInfo, i);
2044 flipForWritingMode(colRect);
2045 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2046 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2047 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2048 if (isHorizontalWritingMode())
2049 offset.expand(0, colRect.y() - borderTop() - paddingTop());
2051 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2053 colRect.moveBy(paintOffset);
2054 PaintInfo info(paintInfo);
2055 info.rect.intersect(pixelSnappedIntRect(colRect));
2057 if (!info.rect.isEmpty()) {
2058 GraphicsContextStateSaver stateSaver(*context);
2059 LayoutRect clipRect(colRect);
2061 if (i < colCount - 1) {
2062 if (isHorizontalWritingMode())
2063 clipRect.expand(colGap / 2, 0);
2065 clipRect.expand(0, colGap / 2);
2067 // Each strip pushes a clip, since column boxes are specified as being
2068 // like overflow:hidden.
2069 // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
2070 // are clipped according to the 'overflow' property.
2071 context->clip(pixelSnappedIntRect(clipRect));
2073 // Adjust our x and y when painting.
2074 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2076 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2078 paintContents(info, adjustedPaintOffset);
2081 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2082 if (style()->isFlippedBlocksWritingMode())
2083 currLogicalTopOffset += blockDelta;
2085 currLogicalTopOffset -= blockDelta;
2089 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2091 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2092 // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
2093 // will do a full repaint.
2094 if (document().didLayoutWithPendingStylesheets() && !isRenderView())
2097 if (childrenInline())
2098 m_lineBoxes.paint(this, paintInfo, paintOffset);
2100 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2101 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2103 // We don't paint our own background, but we do let the kids paint their backgrounds.
2104 PaintInfo paintInfoForChild(paintInfo);
2105 paintInfoForChild.phase = newPhase;
2106 paintInfoForChild.updatePaintingRootForChildren(this);
2107 paintChildren(paintInfoForChild, paintOffset);
2111 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2113 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox())
2114 paintChild(child, paintInfo, paintOffset);
2117 void RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2119 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2120 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2121 child->paint(paintInfo, childPoint);
2124 void RenderBlock::paintChildAsInlineBlock(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2126 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2127 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2128 paintAsInlineBlock(child, paintInfo, childPoint);
2131 void RenderBlock::paintAsInlineBlock(RenderObject* renderer, PaintInfo& paintInfo, const LayoutPoint& childPoint)
2133 if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)
2136 // Paint all phases atomically, as though the element established its own
2137 // stacking context. (See Appendix E.2, section 7.2.1.4 on
2138 // inline block/table/replaced elements in the CSS2.1 specification.)
2139 // This is also used by other elements (e.g. flex items and grid items).
2140 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
2141 PaintInfo info(paintInfo);
2142 info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2143 renderer->paint(info, childPoint);
2144 if (!preservePhase) {
2145 info.phase = PaintPhaseChildBlockBackgrounds;
2146 renderer->paint(info, childPoint);
2147 info.phase = PaintPhaseFloat;
2148 renderer->paint(info, childPoint);
2149 info.phase = PaintPhaseForeground;
2150 renderer->paint(info, childPoint);
2151 info.phase = PaintPhaseOutline;
2152 renderer->paint(info, childPoint);
2156 bool RenderBlock::hasCaret(CaretType type) const
2158 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2159 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2160 RenderObject* caretPainter;
2161 bool isContentEditable;
2162 if (type == CursorCaret) {
2163 caretPainter = frame()->selection().caretRenderer();
2164 isContentEditable = frame()->selection().rendererIsEditable();
2166 caretPainter = frame()->page()->dragCaretController().caretRenderer();
2167 isContentEditable = frame()->page()->dragCaretController().isContentEditable();
2169 return caretPainter == this && (isContentEditable || caretBrowsing);
2172 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2174 if (!hasCaret(type))
2177 if (type == CursorCaret)
2178 frame()->selection().paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2180 frame()->page()->dragCaretController().paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
2183 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2185 PaintPhase paintPhase = paintInfo.phase;
2187 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2188 LayoutPoint scrolledOffset = paintOffset;
2189 if (hasOverflowClip())
2190 scrolledOffset.move(-scrolledContentOffset());
2192 // 1. paint background, borders etc
2193 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2194 if (hasBoxDecorations())
2195 paintBoxDecorations(paintInfo, paintOffset);
2196 if (hasColumns() && !paintInfo.paintRootBackgroundOnly())
2197 paintColumnRules(paintInfo, scrolledOffset);
2200 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2201 paintMask(paintInfo, paintOffset);
2205 if (paintPhase == PaintPhaseClippingMask && style()->visibility() == VISIBLE) {
2206 paintClippingMask(paintInfo, paintOffset);
2210 // We're done. We don't bother painting any children.
2211 if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
2214 // 2. paint contents
2215 if (paintPhase != PaintPhaseSelfOutline) {
2217 paintColumnContents(paintInfo, scrolledOffset);
2219 paintContents(paintInfo, scrolledOffset);
2222 // 3. paint selection
2223 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2224 bool isPrinting = document().printing();
2225 if (!isPrinting && !hasColumns())
2226 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2229 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2231 paintColumnContents(paintInfo, scrolledOffset, true);
2233 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2236 // 5. paint outline.
2237 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2238 paintOutline(paintInfo, LayoutRect(paintOffset, size()));
2240 // 6. paint continuation outlines.
2241 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2242 RenderInline* inlineCont = inlineElementContinuation();
2243 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2244 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2245 RenderBlock* cb = containingBlock();
2247 bool inlineEnclosedInSelfPaintingLayer = false;
2248 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2249 if (box->hasSelfPaintingLayer()) {
2250 inlineEnclosedInSelfPaintingLayer = true;
2255 // Do not add continuations for outline painting by our containing block if we are a relative positioned
2256 // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being
2257 // in the same layer.
2258 if (!inlineEnclosedInSelfPaintingLayer && !hasLayer())
2259 cb->addContinuationWithOutline(inlineRenderer);
2260 else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer()))
2261 inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2263 paintContinuationOutlines(paintInfo, paintOffset);
2267 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2268 // then paint the caret.
2269 if (paintPhase == PaintPhaseForeground) {
2270 paintCaret(paintInfo, paintOffset, CursorCaret);
2271 paintCaret(paintInfo, paintOffset, DragCaret);
2275 RenderInline* RenderBlock::inlineElementContinuation() const
2277 RenderBoxModelObject* continuation = this->continuation();
2278 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2281 RenderBlock* RenderBlock::blockElementContinuation() const
2283 RenderBoxModelObject* currentContinuation = continuation();
2284 if (!currentContinuation || currentContinuation->isInline())
2286 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2287 if (nextContinuation->isAnonymousBlock())
2288 return nextContinuation->blockElementContinuation();
2289 return nextContinuation;
2292 static ContinuationOutlineTableMap* continuationOutlineTable()
2294 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2298 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2300 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2302 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2304 ContinuationOutlineTableMap* table = continuationOutlineTable();
2305 ListHashSet<RenderInline*>* continuations = table->get(this);
2306 if (!continuations) {
2307 continuations = new ListHashSet<RenderInline*>;
2308 table->set(this, adoptPtr(continuations));
2311 continuations->add(flow);
2314 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2316 ContinuationOutlineTableMap* table = continuationOutlineTable();
2317 if (table->isEmpty())
2320 ListHashSet<RenderInline*>* continuations = table->get(this);
2324 return continuations->contains(flow);
2327 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2329 ContinuationOutlineTableMap* table = continuationOutlineTable();
2330 if (table->isEmpty())
2333 OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this);
2337 LayoutPoint accumulatedPaintOffset = paintOffset;
2338 // Paint each continuation outline.
2339 ListHashSet<RenderInline*>::iterator end = continuations->end();
2340 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2341 // Need to add in the coordinates of the intervening blocks.
2342 RenderInline* flow = *it;
2343 RenderBlock* block = flow->containingBlock();
2344 for ( ; block && block != this; block = block->containingBlock())
2345 accumulatedPaintOffset.moveBy(block->location());
2347 flow->paintOutline(info, accumulatedPaintOffset);
2351 bool RenderBlock::shouldPaintSelectionGaps() const
2353 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2356 bool RenderBlock::isSelectionRoot() const
2358 if (isPseudoElement())
2360 ASSERT(node() || isAnonymous());
2362 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2366 if (isBody() || isRoot() || hasOverflowClip()
2367 || isPositioned() || isFloating()
2368 || isTableCell() || isInlineBlockOrInlineTable()
2369 || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot()
2370 || isRenderFlowThread())
2373 if (view() && view()->selectionStart()) {
2374 Node* startElement = view()->selectionStart()->node();
2375 if (startElement && startElement->rootEditableElement() == node())
2382 GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer)
2384 ASSERT(!needsLayout());
2386 if (!shouldPaintSelectionGaps())
2389 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2390 mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms);
2391 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
2393 if (hasOverflowClip())
2394 offsetFromRepaintContainer -= scrolledContentOffset();
2396 LayoutUnit lastTop = 0;
2397 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2398 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2400 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2403 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2405 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2406 LayoutUnit lastTop = 0;
2407 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2408 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2409 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2411 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
2412 if (!gapRectsBounds.isEmpty()) {
2413 if (RenderLayer* layer = enclosingLayer()) {
2414 gapRectsBounds.moveBy(-paintOffset);
2416 LayoutRect localBounds(gapRectsBounds);
2417 flipForWritingMode(localBounds);
2418 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2419 if (layer->renderer()->hasOverflowClip())
2420 gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
2422 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2428 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, TrackedRendererListHashSet* positionedObjects)
2430 if (!positionedObjects)
2433 TrackedRendererListHashSet::const_iterator end = positionedObjects->end();
2434 for (TrackedRendererListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2436 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2440 LayoutUnit RenderBlock::blockDirectionOffset(const LayoutSize& offsetFromBlock) const
2442 return isHorizontalWritingMode() ? offsetFromBlock.height() : offsetFromBlock.width();
2445 LayoutUnit RenderBlock::inlineDirectionOffset(const LayoutSize& offsetFromBlock) const
2447 return isHorizontalWritingMode() ? offsetFromBlock.width() : offsetFromBlock.height();
2450 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
2453 if (isHorizontalWritingMode())
2454 result = logicalRect;
2456 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2457 flipForWritingMode(result);
2458 result.moveBy(rootBlockPhysicalPosition);
2462 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2463 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2465 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2466 // Clip out floating and positioned objects when painting selection gaps.
2468 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2469 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2470 rootBlock->flipForWritingMode(flippedBlockRect);
2471 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
2472 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects());
2473 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2474 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2475 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes.
2476 clipOutFloatingObjects(rootBlock, paintInfo, rootBlockPhysicalPosition, offsetFromRootBlock);
2479 // 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
2482 if (!isRenderBlockFlow() && !isFlexibleBoxIncludingDeprecated()) // FIXME: Make multi-column selection gap filling work someday.
2485 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2486 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2487 lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalHeight();
2488 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2489 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2493 if (childrenInline())
2494 result = toRenderBlockFlow(this)->inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2496 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2498 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2499 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2500 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2501 logicalHeight(), paintInfo));
2505 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2506 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2510 // Go ahead and jump right to the first block child that contains some selected objects.
2512 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2514 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2515 SelectionState childState = curr->selectionState();
2516 if (childState == SelectionBoth || childState == SelectionEnd)
2517 sawSelectionEnd = true;
2519 if (curr->isFloatingOrOutOfFlowPositioned())
2520 continue; // We must be a normal flow object in order to even be considered.
2522 if (curr->isInFlowPositioned() && curr->hasLayer()) {
2523 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2524 // Just disregard it completely.
2525 LayoutSize relOffset = curr->layer()->offsetForInFlowPosition();
2526 if (relOffset.width() || relOffset.height())
2530 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2531 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2532 if (fillBlockGaps) {
2533 // We need to fill the vertical gap above this object.
2534 if (childState == SelectionEnd || childState == SelectionInside)
2535 // Fill the gap above the object.
2536 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2537 curr->logicalTop(), paintInfo));
2539 // 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*
2540 // our object. We know this if the selection did not end inside our object.
2541 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2542 childState = SelectionNone;
2544 // Fill side gaps on this object based off its state.
2545 bool leftGap, rightGap;
2546 getSelectionGapInfo(childState, leftGap, rightGap);
2549 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2551 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2553 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
2554 // they can without bumping into floating or positioned objects. Ideally they will go right up
2555 // to the border of the root selection block.
2556 lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + curr->logicalBottom();
2557 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
2558 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
2559 } else if (childState != SelectionNone)
2560 // We must be a block that has some selected object inside it. Go ahead and recur.
2561 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
2562 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
2567 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2568 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
2570 LayoutUnit logicalTop = lastLogicalTop;
2571 LayoutUnit logicalHeight = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalBottom - logicalTop;
2572 if (logicalHeight <= 0)
2573 return LayoutRect();
2575 // Get the selection offsets for the bottom of the gap
2576 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
2577 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
2578 LayoutUnit logicalWidth = logicalRight - logicalLeft;
2579 if (logicalWidth <= 0)
2580 return LayoutRect();
2582 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
2584 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor());
2588 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2589 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
2591 LayoutUnit rootBlockLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalTop;
2592 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
2593 LayoutUnit rootBlockLogicalRight = min(rootBlock->inlineDirectionOffset(offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2594 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2595 if (rootBlockLogicalWidth <= 0)
2596 return LayoutRect();
2598 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2600 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor());
2604 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2605 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
2607 LayoutUnit rootBlockLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalTop;
2608 LayoutUnit rootBlockLogicalLeft = max(rootBlock->inlineDirectionOffset(offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2609 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
2610 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2611 if (rootBlockLogicalWidth <= 0)
2612 return LayoutRect();
2614 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2616 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor());
2620 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
2622 bool ltr = style()->isLeftToRightDirection();
2623 leftGap = (state == RenderObject::SelectionInside) ||
2624 (state == RenderObject::SelectionEnd && ltr) ||
2625 (state == RenderObject::SelectionStart && !ltr);
2626 rightGap = (state == RenderObject::SelectionInside) ||
2627 (state == RenderObject::SelectionStart && ltr) ||
2628 (state == RenderObject::SelectionEnd && !ltr);
2631 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
2633 // The border can potentially be further extended by our containingBlock().
2634 if (rootBlock != this)
2635 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
2636 return logicalLeftOffsetForContent();
2639 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
2641 // The border can potentially be further extended by our containingBlock().
2642 if (rootBlock != this)
2643 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
2644 return logicalRightOffsetForContent();
2647 RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
2649 if (isSelectionRoot())
2652 const RenderObject* object = this;
2653 RenderObject* sibling;
2655 sibling = object->previousSibling();
2656 while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot()))
2657 sibling = sibling->previousSibling();
2659 offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop());
2660 object = object->parent();
2661 } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot());
2666 RenderBlock* beforeBlock = toRenderBlock(sibling);
2668 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
2670 RenderObject* child = beforeBlock->lastChild();
2671 while (child && child->isRenderBlock()) {
2672 beforeBlock = toRenderBlock(child);
2673 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
2674 child = beforeBlock->lastChild();
2679 void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
2681 if (!descendantsMap) {
2682 descendantsMap = new TrackedDescendantsMap;
2683 containerMap = new TrackedContainerMap;
2686 TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
2687 if (!descendantSet) {
2688 descendantSet = new TrackedRendererListHashSet;
2689 descendantsMap->set(this, adoptPtr(descendantSet));
2691 bool added = descendantSet->add(descendant).isNewEntry;
2693 ASSERT(containerMap->get(descendant));
2694 ASSERT(containerMap->get(descendant)->contains(this));
2698 HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
2699 if (!containerSet) {
2700 containerSet = new HashSet<RenderBlock*>;
2701 containerMap->set(descendant, adoptPtr(containerSet));
2703 ASSERT(!containerSet->contains(this));
2704 containerSet->add(this);
2707 void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
2709 if (!descendantsMap)
2712 OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant);
2716 HashSet<RenderBlock*>::iterator end = containerSet->end();
2717 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
2718 RenderBlock* container = *it;
2720 // FIXME: Disabling this assert temporarily until we fix the layout
2721 // bugs associated with positioned objects not properly cleared from
2722 // their ancestor chain before being moved. See webkit bug 93766.
2723 // ASSERT(descendant->isDescendantOf(container));
2725 TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
2726 ASSERT(descendantsMapIterator != descendantsMap->end());
2727 if (descendantsMapIterator == descendantsMap->end())
2729 TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get();
2730 ASSERT(descendantSet->contains(descendant));
2731 descendantSet->remove(descendant);
2732 if (descendantSet->isEmpty())
2733 descendantsMap->remove(descendantsMapIterator);
2737 TrackedRendererListHashSet* RenderBlock::positionedObjects() const
2739 if (gPositionedDescendantsMap)
2740 return gPositionedDescendantsMap->get(this);
2744 void RenderBlock::insertPositionedObject(RenderBox* o)
2746 ASSERT(!isAnonymousBlock());
2748 if (o->isRenderFlowThread())
2751 insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
2754 void RenderBlock::removePositionedObject(RenderBox* o)
2756 removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
2759 void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState)
2761 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2762 if (!positionedDescendants)
2767 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2769 Vector<RenderBox*, 16> deadObjects;
2771 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2773 if (!o || r->isDescendantOf(o)) {
2774 if (containingBlockState == NewContainingBlock)
2775 r->setChildNeedsLayout(MarkOnlyThis);
2777 // It is parent blocks job to add positioned child to positioned objects list of its containing block
2778 // Parent layout needs to be invalidated to ensure this happens.
2779 RenderObject* p = r->parent();
2780 while (p && !p->isRenderBlock())
2783 p->setChildNeedsLayout();
2785 deadObjects.append(r);
2789 for (unsigned i = 0; i < deadObjects.size(); i++)
2790 removePositionedObject(deadObjects.at(i));
2793 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
2795 insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
2798 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
2800 removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
2803 TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const
2805 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
2808 bool RenderBlock::hasPercentHeightContainerMap()
2810 return gPercentHeightContainerMap;
2813 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
2815 // We don't null check gPercentHeightContainerMap since the caller
2816 // already ensures this and we need to call this function on every
2817 // descendant in clearPercentHeightDescendantsFrom().
2818 ASSERT(gPercentHeightContainerMap);
2819 return gPercentHeightContainerMap->contains(descendant);
2822 void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope& layoutScope)
2824 if (!gPercentHeightDescendantsMap)
2827 TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
2831 TrackedRendererListHashSet::iterator end = descendants->end();
2832 for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
2833 RenderBox* box = *it;
2834 while (box != this) {
2835 if (box->normalChildNeedsLayout())
2837 layoutScope.setChildNeedsLayout(box);
2838 box = box->containingBlock();
2846 void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant)
2848 // We query the map directly, rather than looking at style's
2849 // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
2850 // can change with writing mode/directional changes.
2851 if (!hasPercentHeightContainerMap())
2854 if (!hasPercentHeightDescendant(descendant))
2857 removePercentHeightDescendant(descendant);
2860 void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent)
2862 ASSERT(gPercentHeightContainerMap);
2863 for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) {
2867 RenderBox* box = toRenderBox(curr);
2868 if (!hasPercentHeightDescendant(box))
2871 removePercentHeightDescendant(box);
2875 LayoutUnit RenderBlock::textIndentOffset() const
2878 if (style()->textIndent().isPercent())
2879 cw = containingBlock()->availableLogicalWidth();
2880 return minimumValueForLength(style()->textIndent(), cw);
2883 LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const
2885 LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
2887 return logicalLeftOffset;
2888 LayoutRect boxRect = borderBoxRectInRegion(region);
2889 return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
2892 LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const
2894 LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
2895 logicalRightOffset += availableLogicalWidth();
2897 return logicalRightOffset;
2898 LayoutRect boxRect = borderBoxRectInRegion(region);
2899 return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
2902 void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2904 if (logicalTop >= logicalBottom)
2907 RootInlineBox* lowestDirtyLine = lastRootBox();
2908 RootInlineBox* afterLowest = lowestDirtyLine;
2909 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2910 afterLowest = lowestDirtyLine;
2911 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2914 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2915 afterLowest->markDirty();
2916 afterLowest = afterLowest->prevRootBox();
2920 bool RenderBlock::avoidsFloats() const
2922 // Floats can't intrude into our box if we have a non-auto column count or width.
2923 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
2926 void RenderBlock::markShapeInsideDescendantsForLayout()
2928 if (!everHadLayout())
2930 if (childrenInline()) {
2934 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
2935 if (!child->isRenderBlock())
2937 RenderBlock* childBlock = toRenderBlock(child);
2938 childBlock->markShapeInsideDescendantsForLayout();
2942 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
2944 if (!scrollsOverflow())
2947 return layer()->scrollableArea()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset)));
2950 Node* RenderBlock::nodeForHitTest() const
2952 // If we are in the margins of block elements that are part of a
2953 // continuation we're actually still inside the enclosing element
2954 // that was split. Use the appropriate inner node.
2955 return isAnonymousBlockContinuation() ? continuation()->node() : node();
2958 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2960 LayoutPoint adjustedLocation(accumulatedOffset + location());
2961 LayoutSize localOffset = toLayoutSize(adjustedLocation);
2963 if (!isRenderView()) {
2964 // Check if we need to do anything at all.
2965 LayoutRect overflowBox = visualOverflowRect();
2966 flipForWritingMode(overflowBox);
2967 overflowBox.moveBy(adjustedLocation);
2968 if (!locationInContainer.intersects(overflowBox))
2972 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)
2973 && visibleToHitTestRequest(request)
2974 && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) {
2975 updateHitTestResult(result, locationInContainer.point() - localOffset);
2976 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
2977 if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer))
2981 // If we have clipping, then we can't have any spillout.
2982 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
2983 bool useClip = (hasControlClip() || useOverflowClip);
2984 bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize)));
2985 if (checkChildren) {
2986 // Hit test descendants first.
2987 LayoutSize scrolledOffset(localOffset);
2988 if (hasOverflowClip())
2989 scrolledOffset -= scrolledContentOffset();
2991 // Hit test contents if we don't have columns.
2992 if (!hasColumns()) {
2993 if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
2994 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
2997 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset)))
2999 } else if (hitTestColumns(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
3000 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
3005 // Check if the point is outside radii.
3006 if (!isRenderView() && style()->hasBorderRadius()) {
3007 LayoutRect borderRect = borderBoxRect();
3008 borderRect.moveBy(adjustedLocation);
3009 RoundedRect border = style()->getRoundedBorderFor(borderRect);
3010 if (!locationInContainer.intersects(border))
3014 // Now hit test our background
3015 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
3016 LayoutRect boundsRect(adjustedLocation, size());
3017 if (visibleToHitTestRequest(request) && locationInContainer.intersects(boundsRect)) {
3018 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
3019 if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer, boundsRect))
3027 class ColumnRectIterator {
3028 WTF_MAKE_NONCOPYABLE(ColumnRectIterator);
3030 ColumnRectIterator(const RenderBlock& block)
3032 , m_colInfo(block.columnInfo())
3033 , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1)
3034 , m_isHorizontal(block.isHorizontalWritingMode())
3035 , m_logicalLeft(block.logicalLeftOffsetForContent())
3037 int colCount = m_colInfo->columnCount();
3038 m_colIndex = colCount - 1;
3039 m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
3050 LayoutRect columnRect() const { return m_colRect; }
3051 bool hasMore() const { return m_colIndex >= 0; }
3053 void adjust(LayoutSize& offset) const
3055 LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
3056 offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
3057 if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
3059 offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
3061 offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
3071 m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
3072 m_block.flipForWritingMode(m_colRect);
3073 m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
3076 const RenderBlock& m_block;
3077 const ColumnInfo* const m_colInfo;
3078 const int m_direction;
3079 const bool m_isHorizontal;
3080 const LayoutUnit m_logicalLeft;
3082 LayoutUnit m_currLogicalTopOffset;
3083 LayoutRect m_colRect;
3086 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3088 // We need to do multiple passes, breaking up our hit testing into strips.
3092 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
3093 LayoutRect hitRect = locationInContainer.boundingBox();
3094 LayoutRect colRect = it.columnRect();
3095 colRect.moveBy(accumulatedOffset);
3096 if (locationInContainer.intersects(colRect)) {
3097 // The point is inside this column.
3098 // Adjust accumulatedOffset to change where we hit test.
3101 LayoutPoint finalLocation = accumulatedOffset + offset;
3102 if (!result.isRectBasedTest() || colRect.contains(hitRect))
3103 return hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, finalLocation));
3105 hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction);
3112 void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const
3114 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
3115 LayoutRect colRect = it.columnRect();
3116 if (colRect.contains(locationInContainer)) {
3123 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3125 if (isRenderRegion())
3126 return toRenderRegion(this)->hitTestFlowThreadContents(request, result, locationInContainer, accumulatedOffset, hitTestAction);
3128 if (childrenInline() && !isTable()) {
3129 // We have to hit-test our line boxes.
3130 if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction))
3133 // Hit test our children.
3134 HitTestAction childHitTest = hitTestAction;
3135 if (hitTestAction == HitTestChildBlockBackgrounds)
3136 childHitTest = HitTestChildBlockBackground;
3137 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
3138 LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
3139 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, locationInContainer, childPoint, childHitTest))
3147 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
3152 if (!box->renderer()->nonPseudoNode())
3153 return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset());
3155 if (!box->isInlineTextBox())
3156 return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
3158 InlineTextBox* textBox = toInlineTextBox(box);
3159 return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
3162 static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
3164 ASSERT(!ancestor || ancestor->nonPseudoNode());
3165 ASSERT(child && child->nonPseudoNode());
3166 return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
3167 || ancestor->nonPseudoNode()->rendererIsEditable() == child->nonPseudoNode()->rendererIsEditable();
3170 // FIXME: This function should go on RenderObject as an instance method. Then
3171 // all cases in which positionForPoint recurs could call this instead to
3172 // prevent crossing editable boundaries. This would require many tests.
3173 static PositionWithAffinity positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates)
3175 LayoutPoint childLocation = child->location();
3176 if (child->isInFlowPositioned())
3177 childLocation += child->offsetForInFlowPosition();
3179 // FIXME: This is wrong if the child's writing-mode is different from the parent's.
3180 LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
3182 // If this is an anonymous renderer, we just recur normally
3183 Node* childNode = child->nonPseudoNode();
3185 return child->positionForPoint(pointInChildCoordinates);
3187 // Otherwise, first make sure that the editability of the parent and child agree.
3188 // If they don't agree, then we return a visible position just before or after the child
3189 RenderObject* ancestor = parent;
3190 while (ancestor && !ancestor->nonPseudoNode())
3191 ancestor = ancestor->parent();
3193 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
3194 if (isEditingBoundary(ancestor, child))
3195 return child->positionForPoint(pointInChildCoordinates);
3197 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
3198 LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2;
3199 LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
3200 if (logicalLeft < childMiddle)
3201 return ancestor->createPositionWithAffinity(childNode->nodeIndex(), DOWNSTREAM);
3202 return ancestor->createPositionWithAffinity(childNode->nodeIndex() + 1, UPSTREAM);
3205 PositionWithAffinity RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
3207 ASSERT(childrenInline());
3209 if (!firstRootBox())
3210 return createPositionWithAffinity(0, DOWNSTREAM);
3212 bool linesAreFlipped = style()->isFlippedLinesWritingMode();
3213 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
3215 // look for the closest line box in the root box which is at the passed-in y coordinate
3216 InlineBox* closestBox = 0;
3217 RootInlineBox* firstRootBoxWithChildren = 0;
3218 RootInlineBox* lastRootBoxWithChildren = 0;
3219 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
3220 if (!root->firstLeafChild())
3222 if (!firstRootBoxWithChildren)
3223 firstRootBoxWithChildren = root;
3225 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3226 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3229 lastRootBoxWithChildren = root;
3231 // check if this root line box is located at this y coordinate
3232 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3233 if (linesAreFlipped) {
3234 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3235 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3236 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3238 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3239 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3242 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3248 bool moveCaretToBoundary = document().frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3250 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3251 // y coordinate is below last root line box, pretend we hit it
3252 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3256 if (moveCaretToBoundary) {
3257 LayoutUnit firstRootBoxWithChildrenTop = min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
3258 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3259 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3260 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3261 if (box->isLineBreak()) {
3262 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3265 // y coordinate is above first root line box, so return the start of the first
3266 return PositionWithAffinity(positionForBox(box, true), DOWNSTREAM);
3270 // pass the box a top position that is inside it
3271 LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine());
3272 if (!isHorizontalWritingMode())
3273 point = point.transposedPoint();
3274 if (closestBox->renderer()->isReplaced())
3275 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
3276 return closestBox->renderer()->positionForPoint(point);
3279 if (lastRootBoxWithChildren) {
3280 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3281 ASSERT(moveCaretToBoundary);
3282 InlineBox* logicallyLastBox;
3283 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3284 return PositionWithAffinity(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3287 // Can't reach this. We have a root line box, but it has no kids.
3288 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3289 // seems to hit this code path.
3290 return createPositionWithAffinity(0, DOWNSTREAM);
3293 static inline bool isChildHitTestCandidate(RenderBox* box)
3295 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned();
3298 PositionWithAffinity RenderBlock::positionForPoint(const LayoutPoint& point)
3301 return RenderBox::positionForPoint(point);
3304 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
3305 LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
3306 LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
3308 if (pointLogicalLeft < 0)
3309 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
3310 if (pointLogicalLeft >= logicalWidth())
3311 return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM);
3312 if (pointLogicalTop < 0)
3313 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
3314 if (pointLogicalTop >= logicalHeight())
3315 return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM);
3318 LayoutPoint pointInContents = point;
3319 offsetForContents(pointInContents);
3320 LayoutPoint pointInLogicalContents(pointInContents);
3321 if (!isHorizontalWritingMode())
3322 pointInLogicalContents = pointInLogicalContents.transposedPoint();
3324 if (childrenInline())
3325 return positionForPointWithInlineChildren(pointInLogicalContents);
3327 RenderBox* lastCandidateBox = lastChildBox();
3328 while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
3329 lastCandidateBox = lastCandidateBox->previousSiblingBox();
3331 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
3332 if (lastCandidateBox) {
3333 if (pointInLogicalContents.y() > logicalTopForChild(lastCandidateBox)
3334 || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(lastCandidateBox)))
3335 return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
3337 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
3338 if (!isChildHitTestCandidate(childBox))
3340 LayoutUnit childLogicalBottom = logicalTopForChild(childBox) + logicalHeightForChild(childBox);
3341 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
3342 if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
3343 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
3344 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
3348 // We only get here if there are no hit test candidate children below the click.
3349 return RenderBox::positionForPoint(point);
3352 void RenderBlock::offsetForContents(LayoutPoint& offset) const
3354 offset = flipForWritingMode(offset);
3356 if (hasOverflowClip())
3357 offset += scrolledContentOffset();
3360 adjustPointToColumnContents(offset);
3362 offset = flipForWritingMode(offset);
3365 LayoutUnit RenderBlock::availableLogicalWidth() const
3367 // If we have multiple columns, then the available logical width is reduced to our column width.
3369 return desiredColumnWidth();
3370 return RenderBox::availableLogicalWidth();
3373 int RenderBlock::columnGap() const
3375 if (style()->hasNormalColumnGap())
3376 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
3377 return static_cast<int>(style()->columnGap());
3380 void RenderBlock::calcColumnWidth()
3382 if (document().regionBasedColumnsEnabled())
3385 // Calculate our column width and column count.
3386 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
3387 unsigned desiredColumnCount = 1;
3388 LayoutUnit desiredColumnWidth = contentLogicalWidth();
3390 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
3391 if (document().paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) {
3392 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3396 LayoutUnit availWidth = desiredColumnWidth;
3397 LayoutUnit colGap = columnGap();
3398 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
3399 int colCount = max<int>(1, style()->columnCount());
3401 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
3402 desiredColumnCount = colCount;
3403 desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
3404 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
3405 desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
3406 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
3408 desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
3409 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
3411 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3414 bool RenderBlock::requiresColumns(int desiredColumnCount) const
3416 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3417 // in the RenderView instead.
3418 bool isPaginated = (style()->overflowY() == OPAGEDX || style()->overflowY() == OPAGEDY) && !(isRoot() || isBody());
3421 && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated)
3422 && !firstChild()->isAnonymousColumnsBlock()
3423 && !firstChild()->isAnonymousColumnSpanBlock();
3426 void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
3428 bool destroyColumns = !requiresColumns(count);
3429 if (destroyColumns) {
3431 gColumnInfoMap->take(this);
3432 setHasColumns(false);
3437 info = gColumnInfoMap->get(this);
3439 if (!gColumnInfoMap)
3440 gColumnInfoMap = new ColumnInfoMap;
3441 info = new ColumnInfo;
3442 gColumnInfoMap->add(this, adoptPtr(info));
3443 setHasColumns(true);
3445 info->setDesiredColumnCount(count);
3446 info->setDesiredColumnWidth(width);
3447 info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
3448 info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
3452 void RenderBlock::updateColumnInfoFromStyle(RenderStyle* style)
3457 ColumnInfo* info = gColumnInfoMap->get(this);
3459 bool needsLayout = false;
3460 ColumnInfo::Axis oldAxis = info->progressionAxis();
3461 ColumnInfo::Axis newAxis = style->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis;
3462 if (oldAxis != newAxis) {
3463 info->setProgressionAxis(newAxis);
3467 bool oldProgressionIsReversed = info->progressionIsReversed();
3468 bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression;
3469 if (oldProgressionIsReversed != newProgressionIsReversed) {
3470 info->setProgressionIsReversed(newProgressionIsReversed);
3475 setNeedsLayoutAndPrefWidthsRecalc();
3478 LayoutUnit RenderBlock::desiredColumnWidth() const
3481 return contentLogicalWidth();
3482 return gColumnInfoMap->get(this)->desiredColumnWidth();
3485 ColumnInfo* RenderBlock::columnInfo() const
3489 return gColumnInfoMap->get(this);
3492 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
3494 ASSERT(hasColumns());
3495 ASSERT(gColumnInfoMap->get(this) == colInfo);
3496 return colInfo->columnCount();
3499 LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
3501 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
3503 // Compute the appropriate rect based off our information.
3504 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
3505 LayoutUnit colLogicalHeight = colInfo->columnHeight();
3506 LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
3507 LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
3508 LayoutUnit colGap = columnGap();
3509 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3510 if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
3511 colLogicalLeft += index * (colLogicalWidth + colGap);
3513 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
3515 if (!colInfo->progressionIsReversed())
3516 colLogicalTop += index * (colLogicalHeight + colGap);
3518 colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap);
3521 if (isHorizontalWritingMode())
3522 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
3523 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
3526 bool RenderBlock::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
3528 if (!shouldBreakAtLineToAvoidWidow())
3532 setEverHadLayout(true);
3537 void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
3539 // Just bail if we have no columns.
3543 ColumnInfo* colInfo = columnInfo();
3544 if (!columnCount(colInfo))
3547 // Determine which columns we intersect.
3548 LayoutUnit colGap = columnGap();
3549 LayoutUnit halfColGap = colGap / 2;
3550 LayoutPoint columnPoint(columnRectAt(colInfo, 0).location());
3551 LayoutUnit logicalOffset = 0;
3552 for (unsigned i = 0; i < colInfo->columnCount(); i++) {
3553 // Add in half the column gap to the left and right of the rect.
3554 LayoutRect colRect = columnRectAt(colInfo, i);
3555 flipForWritingMode(colRect);
3556 if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) {
3557 LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
3558 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
3559 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3560 // FIXME: The clamping that follows is not completely right for right-to-left
3562 // Clamp everything above the column to its top left.
3563 if (point.y() < gapAndColumnRect.y())
3564 point = gapAndColumnRect.location();
3565 // Clamp everything below the column to the next column's top left. If there is
3566 // no next column, this still maps to just after this column.
3567 else if (point.y() >= gapAndColumnRect.maxY()) {
3568 point = gapAndColumnRect.location();
3569 point.move(0, gapAndColumnRect.height());
3572 if (point.x() < colRect.x())
3573 point.setX(colRect.x());
3574 else if (point.x() >= colRect.maxX())
3575 point.setX(colRect.maxX() - 1);
3578 // We're inside the column. Translate the x and y into our column coordinate space.
3579 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3580 point.move(columnPoint.x() - colRect.x(), (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset));
3582 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0);
3586 // Move to the next position.
3587 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width();
3589 LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
3590 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
3591 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3592 // FIXME: The clamping that follows is not completely right for right-to-left
3594 // Clamp everything above the column to its top left.
3595 if (point.x() < gapAndColumnRect.x())
3596 point = gapAndColumnRect.location();
3597 // Clamp everything below the column to the next column's top left. If there is
3598 // no next column, this still maps to just after this column.
3599 else if (point.x() >= gapAndColumnRect.maxX()) {
3600 point = gapAndColumnRect.location();
3601 point.move(gapAndColumnRect.width(), 0);
3604 if (point.y() < colRect.y())
3605 point.setY(colRect.y());
3606 else if (point.y() >= colRect.maxY())
3607 point.setY(colRect.maxY() - 1);
3610 // We're inside the column. Translate the x and y into our column coordinate space.
3611 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3612 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset), columnPoint.y() - colRect.y());
3614 point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop());
3618 // Move to the next position.
3619 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height();
3624 void RenderBlock::adjustRectForColumns(LayoutRect& r) const
3626 // Just bail if we have no columns.
3630 ColumnInfo* colInfo = columnInfo();
3632 // Determine which columns we intersect.
3633 unsigned colCount = columnCount(colInfo);
3637 // Begin with a result rect that is empty.
3640 bool isHorizontal = isHorizontalWritingMode();
3641 LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
3642 LayoutUnit colHeight = colInfo->columnHeight();
3646 LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
3647 LayoutUnit endOffset = max(min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding);
3649 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
3650 unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
3651 unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight;
3653 if (startColumn == endColumn) {
3654 // The rect is fully contained within one column. Adjust for our offsets
3655 // and repaint only that portion.
3656 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent();
3657 LayoutRect colRect = columnRectAt(colInfo, startColumn);
3658 LayoutRect repaintRect = r;
3660 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3662 repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight);
3664 repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset);
3667 repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding);
3669 repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0);
3671 repaintRect.intersect(colRect);
3672 result.unite(repaintRect);
3674 // We span multiple columns. We can just unite the start and end column to get the final
3676 result.unite(columnRectAt(colInfo, startColumn));
3677 result.unite(columnRectAt(colInfo, endColumn));
3683 LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
3685 ASSERT(hasColumns());
3686 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3688 ColumnInfo* colInfo = columnInfo();
3689 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
3690 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
3691 if (isHorizontalWritingMode())
3692 return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
3693 return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
3696 void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const
3698 ASSERT(hasColumns());
3699 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3702 ColumnInfo* colInfo = columnInfo();
3703 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
3704 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
3706 if (isHorizontalWritingMode())
3707 rect.setY(expandedLogicalHeight - rect.maxY());
3709 rect.setX(expandedLogicalHeight - rect.maxX());
3712 void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const
3717 ColumnInfo* colInfo = columnInfo();
3719 LayoutUnit logicalLeft = logicalLeftOffsetForContent();
3720 unsigned colCount = columnCount(colInfo);
3721 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
3722 LayoutUnit colLogicalHeight = colInfo->columnHeight();
3724 for (unsigned i = 0; i < colCount; ++i) {
3725 // Compute the edges for a given column in the block progression direction.
3726 LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
3727 if (!isHorizontalWritingMode())
3728 sliceRect = sliceRect.transposedRect();
3730 LayoutUnit logicalOffset = i * colLogicalHeight;
3732 // Now we're in the same coordinate space as the point. See if it is inside the rectangle.
3733 if (isHorizontalWritingMode()) {
3734 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
3735 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3736 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
3738 offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
3742 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
3743 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3744 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
3746 offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
3753 void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3755 if (childrenInline()) {
3756 // FIXME: Remove this const_cast.
3757 const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
3759 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
3761 maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
3763 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
3765 // A horizontal marquee with inline children has no minimum width.
3766 if (childrenInline() && isMarquee() && toRenderMarquee(this)->isHorizontal())
3767 minLogicalWidth = 0;
3769 if (isTableCell()) {
3770 Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth();
3771 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
3772 maxLogicalWidth = max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
3775 int scrollbarWidth = instrinsicScrollbarLogicalWidth();
3776 maxLogicalWidth += scrollbarWidth;
3777 minLogicalWidth += scrollbarWidth;
3780 void RenderBlock::computePreferredLogicalWidths()
3782 ASSERT(preferredLogicalWidthsDirty());
3784 updateFirstLetter();
3786 m_minPreferredLogicalWidth = 0;
3787 m_maxPreferredLogicalWidth = 0;
3789 // FIXME: The isFixed() calls here should probably be checking for isSpecified since you
3790 // should be able to use percentage, calc or viewport relative values for width.
3791 RenderStyle* styleToUse = style();
3792 if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
3793 && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
3794 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
3796 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
3798 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
3799 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
3800 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
3803 if (styleToUse->logicalMaxWidth().isFixed()) {
3804 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
3805 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
3808 // Table layout uses integers, ceil the preferred widths to ensure that they can contain the contents.
3809 if (isTableCell()) {
3810 m_minPreferredLogicalWidth = m_minPreferredLogicalWidth.ceil();
3811 m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil();
3814 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
3815 m_minPreferredLogicalWidth += borderAndPadding;
3816 m_maxPreferredLogicalWidth += borderAndPadding;
3818 clearPreferredLogicalWidthsDirty();
3821 void RenderBlock::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3823 // FIXME: make this method virtual and move the code to RenderMultiColumnBlock once the old
3824 // multicol code is gone.
3826 if (!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()) {
3827 // The min/max intrinsic widths calculated really tell how much space elements need when
3828 // laid out inside the columns. In order to eventually end up with the desired column width,
3829 // we need to convert them to values pertaining to the multicol container.
3830 int columnCount = style()->hasAutoColumnCount() ? 1 : style()->columnCount();
3831 LayoutUnit columnWidth;
3832 LayoutUnit gapExtra = (columnCount - 1) * columnGap();
3833 if (style()->hasAutoColumnWidth()) {
3834 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
3836 columnWidth = style()->columnWidth();
3837 minLogicalWidth = min(minLogicalWidth, columnWidth);
3839 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
3840 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
3841 // performing a layout pass, but this is not an appropriate time or place for layout. The
3842 // good news is that if height is unconstrained and there are no explicit breaks, the
3843 // resolved column-count really should be 1.
3844 maxLogicalWidth = max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
3848 struct InlineMinMaxIterator {
3849 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3850 inline min/max width calculations. Note the following about the way it walks:
3851 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3852 (2) We do not drill into the children of floats or replaced elements, since you can't break
3853 in the middle of such an element.
3854 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3855 distinct borders/margin/padding that contribute to the min/max width.
3857 RenderObject* parent;
3858 RenderObject* current;
3861 InlineMinMaxIterator(RenderObject* p, bool end = false)
3862 :parent(p), current(p), endOfInline(end) {}
3864 RenderObject* next();
3867 RenderObject* InlineMinMaxIterator::next()
3869 RenderObject* result = 0;
3870 bool oldEndOfInline = endOfInline;
3871 endOfInline = false;
3872 while (current || current == parent) {
3873 if (!oldEndOfInline &&
3874 (current == parent ||
3875 (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
3876 result = current->firstChild();
3878 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3879 if (!oldEndOfInline && current->isRenderInline()) {
3885 while (current && current != parent) {
3886 result = current->nextSibling();
3888 current = current->parent();
3889 if (current && current != parent && current->isRenderInline()) {
3900 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3907 // Update our position.
3912 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3914 if (cssUnit.type() != Auto)
3915 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
3919 static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
3921 RenderStyle* childStyle = child->style();
3923 return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
3924 getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
3926 return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
3927 getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
3928 child->borderStart();
3931 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
3932 RenderObject* trailingSpaceChild)
3934 if (trailingSpaceChild && trailingSpaceChild->isText()) {
3935 // Collapse away the trailing space at the end of a block.
3936 RenderText* t = toRenderText(trailingSpaceChild);
3937 const UChar space = ' ';
3938 const Font& font = t->style()->font(); // FIXME: This ignores first-line.
3939 float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style(), LTR));
3940 inlineMax -= spaceWidth + font.wordSpacing();
3941 if (inlineMin > inlineMax)
3942 inlineMin = inlineMax;
3946 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
3948 LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result);
3949 preferredWidth = max(snappedResult, preferredWidth);
3952 // When converting between floating point and LayoutUnits we risk losing precision
3953 // with each conversion. When this occurs while accumulating our preferred widths,
3954 // we can wind up with a line width that's larger than our maxPreferredWidth due to
3955 // pure float accumulation.
3956 static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
3958 return LayoutUnit::fromFloatCeil(value);
3962 void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
3964 float inlineMax = 0;
3965 float inlineMin = 0;
3967 RenderStyle* styleToUse = style();
3968 RenderBlock* containingBlock = this->containingBlock();
3969 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
3971 // If we are at the start of a line, we want to ignore all white-space.
3972 // Also strip spaces if we previously had text that ended in a trailing space.
3973 bool stripFrontSpaces = true;
3974 RenderObject* trailingSpaceChild = 0;
3976 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
3977 // very specific cirucumstances (in order to match common WinIE renderings).
3978 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
3979 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto();
3981 bool autoWrap, oldAutoWrap;
3982 autoWrap = oldAutoWrap = styleToUse->autoWrap();
3984 InlineMinMaxIterator childIterator(this);
3986 // Only gets added to the max preffered width once.
3987 bool addedTextIndent = false;
3988 // Signals the text indent was more negative than the min preferred width
3989 bool hasRemainingNegativeTextIndent = false;
3991 LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw);
3992 RenderObject* prevFloat = 0;
3993 bool isPrevChildInlineFlow = false;
3994 bool shouldBreakLineAfterText = false;
3995 while (RenderObject* child = childIterator.next()) {
3996 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
3997 child->style()->autoWrap();
3999 if (!child->isBR()) {
4000 // Step One: determine whether or not we need to go ahead and
4001 // terminate our current line. Each discrete chunk can become
4002 // the new min-width, if it is the widest chunk seen so far, and
4003 // it can also become the max-width.
4005 // Children fall into three categories:
4006 // (1) An inline flow object. These objects always have a min/max of 0,
4007 // and are included in the iteration solely so that their margins can
4010 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4011 // These objects can always be on a line by themselves, so in this situation
4012 // we need to go ahead and break the current line, and then add in our own
4013 // margins and min/max width on its own line, and then terminate the line.
4015 // (3) A text object. Text runs can have breakable characters at the start,
4016 // the middle or the end. They may also lose whitespace off the front if
4017 // we're already ignoring whitespace. In order to compute accurate min-width
4018 // information, we need three pieces of information.
4019 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4020 // starts with whitespace.
4021 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4022 // ends with whitespace.
4023 // (c) the min/max width of the string (trimmed for whitespace).
4025 // If the text string starts with whitespace, then we need to go ahead and
4026 // terminate our current line (unless we're already in a whitespace stripping
4029 // If the text string has a breakable character in the middle, but didn't start
4030 // with whitespace, then we add the width of the first non-breakable run and
4031 // then end the current line. We then need to use the intermediate min/max width
4032 // values (if any of them are larger than our current min/max). We then look at
4033 // the width of the last non-breakable run and use that to start a new line
4034 // (unless we end in whitespace).
4035 RenderStyle* childStyle = child->style();
4039 if (!child->isText()) {
4040 // Case (1) and (2). Inline replaced and inline flow elements.
4041 if (child->isRenderInline()) {
4042 // Add in padding/border/margin from the appropriate side of
4044 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
4048 inlineMin += childMin;
4049 inlineMax += childMax;
4051 child->clearPreferredLogicalWidthsDirty();
4053 // Inline replaced elts add in their margins to their min/max values.
4054 LayoutUnit margins = 0;
4055 Length startMargin = childStyle->marginStart();
4056 Length endMargin = childStyle->marginEnd();
4057 if (startMargin.isFixed())
4058 margins += adjustFloatForSubPixelLayout(startMargin.value());
4059 if (endMargin.isFixed())
4060 margins += adjustFloatForSubPixelLayout(endMargin.value());
4061 childMin += margins.ceilToFloat();
4062 childMax += margins.ceilToFloat();
4066 if (!child->isRenderInline() && !child->isText()) {
4067 // Case (2). Inline replaced elements and floats.
4068 // Go ahead and terminate the current line as far as
4069 // minwidth is concerned.
4070 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4071 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
4072 RenderBox* childBox = toRenderBox(child);
4073 LogicalExtentComputedValues computedValues;
4074 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
4075 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
4077 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
4078 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
4080 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4081 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
4083 bool clearPreviousFloat;
4084 if (child->isFloating()) {
4085 clearPreviousFloat = (prevFloat
4086 && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT))
4087 || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT))));
4090 clearPreviousFloat = false;
4092 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4093 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
4094 updatePreferredWidth(minLogicalWidth, inlineMin);
4098 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4099 if (clearPreviousFloat) {
4100 updatePreferredWidth(maxLogicalWidth, inlineMax);
4104 // Add in text-indent. This is added in only once.
4105 if (!addedTextIndent && !child->isFloating()) {
4106 float ceiledTextIndent = textIndent.ceilToFloat();
4107 childMin += ceiledTextIndent;
4108 childMax += ceiledTextIndent;
4111 textIndent = adjustFloatForSubPixelLayout(childMin);
4113 addedTextIndent = true;
4116 // Add our width to the max.
4117 inlineMax += max<float>(0, childMax);
4119 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
4120 if (child->isFloating())
4121 updatePreferredWidth(minLogicalWidth, childMin);
4123 inlineMin += childMin;
4125 // Now check our line.
4126 updatePreferredWidth(minLogicalWidth, childMin);
4128 // Now start a new line.
4132 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4133 updatePreferredWidth(minLogicalWidth, inlineMin);
4137 // We are no longer stripping whitespace at the start of
4139 if (!child->isFloating()) {
4140 stripFrontSpaces = false;
4141 trailingSpaceChild = 0;
4143 } else if (child->isText()) {
4145 RenderText* t = toRenderText(child);
4147 if (t->isWordBreak()) {
4148 updatePreferredWidth(minLogicalWidth, inlineMin);
4153 if (t->style()->hasTextCombine() && t->isCombineText())
4154 toRenderCombineText(t)->combineText();
4156 // Determine if we have a breakable character. Pass in
4157 // whether or not we should ignore any spaces at the front
4158 // of the string. If those are going to be stripped out,
4159 // then they shouldn't be considered in the breakable char
4161 bool hasBreakableChar, hasBreak;
4162 float firstLineMinWidth, lastLineMinWidth;
4163 bool hasBreakableStart, hasBreakableEnd;
4164 float firstLineMaxWidth, lastLineMaxWidth;
4165 t->trimmedPrefWidths(inlineMax,
4166 firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd,
4167 hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
4168 childMin, childMax, stripFrontSpaces);
4170 // This text object will not be rendered, but it may still provide a breaking opportunity.
4171 if (!hasBreak && childMax == 0) {
4172 if (autoWrap && (hasBreakableStart || hasBreakableEnd)) {
4173 updatePreferredWidth(minLogicalWidth, inlineMin);
4179 if (stripFrontSpaces)
4180 trailingSpaceChild = child;
4182 trailingSpaceChild = 0;
4184 // Add in text-indent. This is added in only once.
4186 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4187 ti = textIndent.ceilToFloat();
4189 firstLineMinWidth += ti;
4191 // It the text indent negative and larger than the child minimum, we re-use the remainder
4192 // in future minimum calculations, but using the negative value again on the maximum
4193 // will lead to under-counting the max pref width.
4194 if (!addedTextIndent) {
4196 firstLineMaxWidth += ti;
4197 addedTextIndent = true;
4201 textIndent = childMin;
4202 hasRemainingNegativeTextIndent = true;
4206 // If we have no breakable characters at all,
4207 // then this is the easy case. We add ourselves to the current
4208 // min and max and continue.
4209 if (!hasBreakableChar) {
4210 inlineMin += childMin;
4212 if (hasBreakableStart) {
4213 updatePreferredWidth(minLogicalWidth, inlineMin);
4215 inlineMin += firstLineMinWidth;
4216 updatePreferredWidth(minLogicalWidth, inlineMin);
4220 inlineMin = childMin;
4222 if (hasBreakableEnd) {
4223 updatePreferredWidth(minLogicalWidth, inlineMin);
4225 shouldBreakLineAfterText = false;
4227 updatePreferredWidth(minLogicalWidth, inlineMin);
4228 inlineMin = lastLineMinWidth;
4229 shouldBreakLineAfterText = true;
4234 inlineMax += firstLineMaxWidth;
4235 updatePreferredWidth(maxLogicalWidth, inlineMax);
4236 updatePreferredWidth(maxLogicalWidth, childMax);
4237 inlineMax = lastLineMaxWidth;
4238 addedTextIndent = true;
4240 inlineMax += max<float>(0, childMax);
4244 // Ignore spaces after a list marker.
4245 if (child->isListMarker())
4246 stripFrontSpaces = true;
4248 updatePreferredWidth(minLogicalWidth, inlineMin);
4249 updatePreferredWidth(maxLogicalWidth, inlineMax);
4250 inlineMin = inlineMax = 0;
4251 stripFrontSpaces = true;
4252 trailingSpaceChild = 0;
4253 addedTextIndent = true;
4256 if (!child->isText() && child->isRenderInline())
4257 isPrevChildInlineFlow = true;
4259 isPrevChildInlineFlow = false;
4261 oldAutoWrap = autoWrap;
4264 if (styleToUse->collapseWhiteSpace())
4265 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4267 updatePreferredWidth(minLogicalWidth, inlineMin);
4268 updatePreferredWidth(maxLogicalWidth, inlineMax);
4271 void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4273 RenderStyle* styleToUse = style();
4274 bool nowrap = styleToUse->whiteSpace() == NOWRAP;
4276 RenderObject* child = firstChild();
4277 RenderBlock* containingBlock = this->containingBlock();
4278 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
4280 // Positioned children don't affect the min/max width
4281 if (child->isOutOfFlowPositioned()) {
4282 child = child->nextSibling();
4286 RenderStyle* childStyle = child->style();
4287 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
4288 LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
4289 if (childStyle->clear() & CLEFT) {
4290 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
4293 if (childStyle->clear() & CRIGHT) {
4294 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
4295 floatRightWidth = 0;
4299 // A margin basically has three types: fixed, percentage, and auto (variable).
4300 // Auto and percentage margins simply become 0 when computing min/max width.
4301 // Fixed margins can be added in as is.
4302 Length startMarginLength = childStyle->marginStartUsing(styleToUse);
4303 Length endMarginLength = childStyle->marginEndUsing(styleToUse);
4304 LayoutUnit margin = 0;
4305 LayoutUnit marginStart = 0;
4306 LayoutUnit marginEnd = 0;
4307 if (startMarginLength.isFixed())
4308 marginStart += startMarginLength.value();
4309 if (endMarginLength.isFixed())
4310 marginEnd += endMarginLength.value();
4311 margin = marginStart + marginEnd;
4313 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4314 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
4315 RenderBox* childBox = toRenderBox(child);
4316 LogicalExtentComputedValues computedValues;
4317 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
4318 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
4320 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
4321 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
4324 LayoutUnit w = childMinPreferredLogicalWidth + margin;
4325 minLogicalWidth = max(w, minLogicalWidth);
4327 // IE ignores tables for calculation of nowrap. Makes some sense.
4328 if (nowrap && !child->isTable())
4329 maxLogicalWidth = max(w, maxLogicalWidth);
4331 w = childMaxPreferredLogicalWidth + margin;
4333 if (!child->isFloating()) {
4334 if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
4335 // Determine a left and right max value based off whether or not the floats can fit in the
4336 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
4337 // is smaller than the float width.
4338 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse->isLeftToRightDirection();
4339 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
4340 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
4341 LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
4342 LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
4343 w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
4344 w = max(w, floatLeftWidth + floatRightWidth);
4347 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
4348 floatLeftWidth = floatRightWidth = 0;
4351 if (child->isFloating()) {
4352 if (childStyle->floating() == LeftFloat)
4353 floatLeftWidth += w;
4355 floatRightWidth += w;
4357 maxLogicalWidth = max(w, maxLogicalWidth);
4359 child = child->nextSibling();
4362 // Always make sure these values are non-negative.
4363 minLogicalWidth = max<LayoutUnit>(0, minLogicalWidth);
4364 maxLogicalWidth = max<LayoutUnit>(0, maxLogicalWidth);
4366 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
4369 bool RenderBlock::hasLineIfEmpty() const
4374 if (node()->isRootEditableElement())
4377 if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
4383 LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
4385 // Inline blocks are replaced elements. Otherwise, just pass off to
4386 // the base class. If we're being queried as though we're the root line
4387 // box, then the fact that we're an inline-block is irrelevant, and we behave
4388 // just like a block.
4389 if (isReplaced() && linePositionMode == PositionOnContainingLine)
4390 return RenderBox::lineHeight(firstLine, direction, linePositionMode);
4392 if (firstLine && document().styleEngine()->usesFirstLineRules()) {
4393 RenderStyle* s = style(firstLine);
4395 return s->computedLineHeight();
4398 if (m_lineHeight == -1)
4399 m_lineHeight = style()->computedLineHeight();
4401 return m_lineHeight;
4404 int RenderBlock::beforeMarginInLineDirection(LineDirectionMode direction) const
4406 return direction == HorizontalLine ? marginTop() : marginRight();
4409 int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
4411 // Inline blocks are replaced elements. Otherwise, just pass off to
4412 // the base class. If we're being queried as though we're the root line
4413 // box, then the fact that we're an inline-block is irrelevant, and we behave
4414 // just like a block.
4415 if (isInline() && linePositionMode == PositionOnContainingLine) {
4416 // For "leaf" theme objects, let the theme decide what the baseline position is.
4417 // FIXME: Might be better to have a custom CSS property instead, so that if the theme
4418 // is turned off, checkboxes/radios will still have decent baselines.
4419 // FIXME: Need to patch form controls to deal with vertical lines.
4420 if (style()->hasAppearance() && !RenderTheme::theme().isControlContainer(style()->appearance()))
4421 return RenderTheme::theme().baselinePosition(this);
4423 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
4424 // the normal flow. We make an exception for marquees, since their baselines are meaningless
4425 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
4426 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
4427 // vertically (e.g., an overflow:hidden block that has had scrollTop moved).
4428 bool ignoreBaseline = (layer() && layer()->scrollableArea() && (isMarquee() || (direction == HorizontalLine ? (layer()->scrollableArea()->verticalScrollbar() || layer()->scrollableArea()->scrollYOffset())
4429 : (layer()->scrollableArea()->horizontalScrollbar() || layer()->scrollableArea()->scrollXOffset())))) || (isWritingModeRoot() && !isRubyRun());
4431 int baselinePos = ignoreBaseline ? -1 : inlineBlockBaseline(direction);
4433 if (isDeprecatedFlexibleBox()) {
4434 // Historically, we did this check for all baselines. But we can't
4435 // remove this code from deprecated flexbox, because it effectively
4436 // breaks -webkit-line-clamp, which is used in the wild -- we would
4437 // calculate the baseline as if -webkit-line-clamp wasn't used.
4438 // For simplicity, we use this for all uses of deprecated flexbox.
4439 LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
4440 if (baselinePos > bottomOfContent)
4443 if (baselinePos != -1)
4444 return beforeMarginInLineDirection(direction) + baselinePos;
4446 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
4449 // If we're not replaced, we'll only get called with PositionOfInteriorLineBoxes.
4450 // Note that inline-block counts as replaced here.
4451 ASSERT(linePositionMode == PositionOfInteriorLineBoxes);
4453 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
4454 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
4457 LayoutUnit RenderBlock::minLineHeightForReplacedRenderer(bool isFirstLine, LayoutUnit replacedHeight) const
4459 if (!document().inNoQuirksMode() && replacedHeight)
4460 return replacedHeight;
4462 if (!(style(isFirstLine)->lineBoxContain() & LineBoxContainBlock))
4465 return std::max<LayoutUnit>(replacedHeight, lineHeight(isFirstLine, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
4468 int RenderBlock::firstLineBoxBaseline() const
4470 if (isWritingModeRoot() && !isRubyRun())
4473 if (childrenInline()) {
4475 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
4480 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
4481 if (!curr->isFloatingOrOutOfFlowPositioned()) {
4482 int result = curr->firstLineBoxBaseline();
4484 return curr->logicalTop() + result; // Translate to our coordinate space.
4492 int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const
4494 if (style()->overflowY() != OVISIBLE) {
4495 // We are not calling RenderBox::baselinePosition here because the caller should add the margin-top/margin-right, not us.
4496 return direction == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
4499 return lastLineBoxBaseline(direction);
4502 int RenderBlock::lastLineBoxBaseline(LineDirectionMode lineDirection) const
4504 if (isWritingModeRoot() && !isRubyRun())
4507 if (childrenInline()) {
4508 if (!firstLineBox() && hasLineIfEmpty()) {
4509 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
4510 return fontMetrics.ascent()
4511 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
4512 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
4515 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
4518 bool haveNormalFlowChild = false;
4519 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
4520 if (!curr->isFloatingOrOutOfFlowPositioned()) {
4521 haveNormalFlowChild = true;
4522 int result = curr->inlineBlockBaseline(lineDirection);
4524 return curr->logicalTop() + result; // Translate to our coordinate space.
4527 if (!haveNormalFlowChild && hasLineIfEmpty()) {
4528 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
4529 return fontMetrics.ascent()
4530 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
4531 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
4538 RenderBlock* RenderBlock::firstLineBlock() const
4540 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
4541 bool hasPseudo = false;
4543 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
4546 RenderObject* parentBlock = firstLineBlock->parent();
4547 // We include isRenderButton in this check because buttons are
4548 // implemented using flex box but should still support first-line. The
4549 // flex box spec requires that flex box does not support first-line,
4551 // FIXME: Remove when buttons are implemented with align-items instead
4553 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating()
4554 || !parentBlock || parentBlock->firstChild() != firstLineBlock
4555 || (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton()))
4557 ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock());
4558 firstLineBlock = toRenderBlock(parentBlock);
4564 return firstLineBlock;
4567 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
4569 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
4570 // Force inline display (except for floating first-letters).
4571 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
4572 // CSS2 says first-letter can't be positioned.
4573 pseudoStyle->setPosition(StaticPosition);
4577 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
4578 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
4579 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
4580 static inline bool isPunctuationForFirstLetter(UChar c)
4582 CharCategory charCategory = category(c);
4583 return charCategory == Punctuation_Open
4584 || charCategory == Punctuation_Close
4585 || charCategory == Punctuation_InitialQuote
4586 || charCategory == Punctuation_FinalQuote
4587 || charCategory == Punctuation_Other;
4590 static inline bool shouldSkipForFirstLetter(UChar c)
4592 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
4595 static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
4597 RenderObject* firstLetterBlock = start;
4599 // We include isRenderButton in these two checks because buttons are
4600 // implemented using flex box but should still support first-letter.
4601 // The flex box spec requires that flex box does not support
4602 // first-letter, though.
4603 // FIXME: Remove when buttons are implemented with align-items instead
4605 bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
4606 && firstLetterBlock->canHaveGeneratedChildren()
4607 && (!firstLetterBlock->isFlexibleBox() || firstLetterBlock->isRenderButton());
4608 if (canHaveFirstLetterRenderer)
4609 return firstLetterBlock;
4611 RenderObject* parentBlock = firstLetterBlock->parent();
4612 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
4613 (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton()))
4615 firstLetterBlock = parentBlock;
4621 void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild)
4623 RenderObject* firstLetter = currentChild->parent();
4624 RenderObject* firstLetterContainer = firstLetter->parent();
4625 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
4626 ASSERT(firstLetter->isFloating() || firstLetter->isInline());
4628 if (RenderStyle::compare(firstLetter->style(), pseudoStyle) == Reattach) {
4629 // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
4630 RenderBoxModelObject* newFirstLetter;
4631 if (pseudoStyle->display() == INLINE)
4632 newFirstLetter = RenderInline::createAnonymous(&document());
4634 newFirstLetter = RenderBlockFlow::createAnonymous(&document());
4635 newFirstLetter->setStyle(pseudoStyle);
4637 // Move the first letter into the new renderer.
4638 LayoutStateDisabler layoutStateDisabler(view());
4639 while (RenderObject* child = firstLetter->firstChild()) {
4640 if (child->isText())
4641 toRenderText(child)->removeAndDestroyTextBoxes();
4642 firstLetter->removeChild(child);
4643 newFirstLetter->addChild(child, 0);
4646 RenderObject* nextSibling = firstLetter->nextSibling();
4647 if (RenderTextFragment* remainingText = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText()) {
4648 ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText);
4649 // Replace the old renderer with the new one.
4650 remainingText->setFirstLetter(newFirstLetter);
4651 newFirstLetter->setFirstLetterRemainingText(remainingText);
4653 // To prevent removal of single anonymous block in RenderBlock::removeChild and causing
4654 // |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
4655 firstLetterContainer->virtualChildren()->removeChildNode(firstLetterContainer, firstLetter);
4656 firstLetter->destroy();
4657 firstLetter = newFirstLetter;
4658 firstLetterContainer->addChild(firstLetter, nextSibling);
4660 firstLetter->setStyle(pseudoStyle);
4662 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
4663 if (genChild->isText())
4664 genChild->setStyle(pseudoStyle);
4668 static inline unsigned firstLetterLength(const String& text)
4670 unsigned length = 0;
4672 // Account for leading spaces and punctuation.
4673 while (length < text.length() && shouldSkipForFirstLetter((text)[length]))
4676 // Bail if we didn't find a letter
4677 if (text.length() && length == text.length())
4680 // Account for first letter.
4683 // Keep looking for whitespace and allowed punctuation, but avoid
4684 // accumulating just whitespace into the :first-letter.
4685 for (unsigned scanLength = length; scanLength < text.length(); ++scanLength) {
4686 UChar c = (text)[scanLength];
4688 if (!shouldSkipForFirstLetter(c))
4691 if (isPunctuationForFirstLetter(c))
4692 length = scanLength + 1;
4698 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild, unsigned length)
4700 ASSERT(length && currentChild->isText());
4702 RenderObject* firstLetterContainer = currentChild->parent();
4703 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
4704 RenderObject* firstLetter = 0;
4705 if (pseudoStyle->display() == INLINE)
4706 firstLetter = RenderInline::createAnonymous(&document());
4708 firstLetter = RenderBlockFlow::createAnonymous(&document());
4709 firstLetter->setStyle(pseudoStyle);
4710 firstLetterContainer->addChild(firstLetter, currentChild);
4712 RenderText* textObj = toRenderText(currentChild);
4714 // The original string is going to be either a generated content string or a DOM node's
4715 // string. We want the original string before it got transformed in case first-letter has
4716 // no text-transform or a different text-transform applied to it.
4717 String oldText = textObj->originalText();
4718 ASSERT(oldText.impl());
4720 // Construct a text fragment for the text after the first letter.
4721 // This text fragment might be empty.
4722 RenderTextFragment* remainingText =
4723 new RenderTextFragment(textObj->node() ? textObj->node() : &textObj->document(), oldText.impl(), length, oldText.length() - length);
4724 remainingText->setStyle(textObj->style());
4725 if (remainingText->node())
4726 remainingText->node()->setRenderer(remainingText);
4728 firstLetterContainer->addChild(remainingText, textObj);
4729 firstLetterContainer->removeChild(textObj);
4730 remainingText->setFirstLetter(firstLetter);
4731 toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText);
4733 // construct text fragment for the first letter
4734 RenderTextFragment* letter =
4735 new RenderTextFragment(remainingText->node() ? remainingText->node() : &remainingText->document(), oldText.impl(), 0, length);
4736 letter->setStyle(pseudoStyle);
4737 firstLetter->addChild(letter);
4742 void RenderBlock::updateFirstLetter()
4744 if (!document().styleEngine()->usesFirstLetterRules())
4747 if (style()->styleType() == FIRST_LETTER)
4750 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
4751 // an efficient way to check for that situation though before implementing anything.
4752 RenderObject* firstLetterBlock = findFirstLetterBlock(this);
4753 if (!firstLetterBlock)
4756 // Drill into inlines looking for our first text child.
4757 RenderObject* currChild = firstLetterBlock->firstChild();
4758 unsigned length = 0;
4760 if (currChild->isText()) {
4761 // FIXME: If there is leading punctuation in a different RenderText than
4762 // the first letter, we'll not apply the correct style to it.
4763 length = firstLetterLength(toRenderText(currChild)->originalText());
4766 currChild = currChild->nextSibling();
4767 } else if (currChild->isListMarker()) {
4768 currChild = currChild->nextSibling();
4769 } else if (currChild->isFloatingOrOutOfFlowPositioned()) {
4770 if (currChild->style()->styleType() == FIRST_LETTER) {
4771 currChild = currChild->firstChild();
4774 currChild = currChild->nextSibling();
4775 } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList())
4777 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) {
4778 // We found a lower-level node with first-letter, which supersedes the higher-level style
4779 firstLetterBlock = currChild;
4780 currChild = currChild->firstChild();
4782 currChild = currChild->firstChild();
4788 // If the child already has style, then it has already been created, so we just want
4790 if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
4791 updateFirstLetterStyle(firstLetterBlock, currChild);
4795 if (!currChild->isText() || currChild->isBR())
4798 // Our layout state is not valid for the repaints we are going to trigger by
4799 // adding and removing children of firstLetterContainer.
4800 LayoutStateDisabler layoutStateDisabler(view());
4802 createFirstLetterRenderer(firstLetterBlock, currChild, length);
4805 // Helper methods for obtaining the last line, computing line counts and heights for line counts
4806 // (crawling into blocks).
4807 static bool shouldCheckLines(RenderObject* obj)
4809 return !obj->isFloatingOrOutOfFlowPositioned()
4810 && obj->isRenderBlock() && obj->style()->height().isAuto()
4811 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
4814 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
4816 if (block->style()->visibility() == VISIBLE) {
4817 if (block->childrenInline()) {
4818 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
4820 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
4824 RenderBox* normalFlowChildWithoutLines = 0;
4825 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4826 if (shouldCheckLines(obj)) {
4827 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
4829 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
4830 } else if (!obj->isFloatingOrOutOfFlowPositioned())
4831 normalFlowChildWithoutLines = obj;
4833 if (normalFlowChildWithoutLines && l == 0)
4834 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
4841 RootInlineBox* RenderBlock::lineAtIndex(int i) const
4845 if (style()->visibility() != VISIBLE)
4848 if (childrenInline()) {
4849 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4853 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
4854 if (!shouldCheckLines(child))
4856 if (RootInlineBox* box = toRenderBlock(child)->lineAtIndex(i))
4864 int RenderBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
4868 if (style()->visibility() == VISIBLE) {
4869 if (childrenInline())
4870 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
4872 if (box == stopRootInlineBox) {
4879 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
4880 if (shouldCheckLines(obj)) {
4881 bool recursiveFound = false;
4882 count += toRenderBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound);
4883 if (recursiveFound) {
4893 int RenderBlock::heightForLineCount(int l)
4896 return getHeightForLineCount(this, l, true, count);
4899 void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
4901 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
4902 // for either overflow or translations via relative positioning.
4903 if (style()->visibility() == VISIBLE) {
4904 if (childrenInline()) {
4905 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
4906 if (box->firstChild())
4907 left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
4908 if (box->lastChild())
4909 right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight())));
4912 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4913 if (!obj->isFloatingOrOutOfFlowPositioned()) {
4914 if (obj->isRenderBlockFlow() && !obj->hasOverflowClip())
4915 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
4916 else if (obj->style()->visibility() == VISIBLE) {
4917 // We are a replaced element or some kind of non-block-flow object.
4918 left = min(left, x + obj->x());
4919 right = max(right, x + obj->x() + obj->width());
4927 void RenderBlock::fitBorderToLinesIfNeeded()
4929 if (style()->borderFit() == BorderFitBorder || hasOverrideWidth())
4932 // Walk any normal flow lines to snugly fit.
4933 LayoutUnit left = LayoutUnit::max();
4934 LayoutUnit right = LayoutUnit::min();
4935 LayoutUnit oldWidth = contentWidth();
4936 adjustForBorderFit(0, left, right);
4938 // Clamp to our existing edges. We can never grow. We only shrink.
4939 LayoutUnit leftEdge = borderLeft() + paddingLeft();
4940 LayoutUnit rightEdge = leftEdge + oldWidth;
4941 left = min(rightEdge, max(leftEdge, left));
4942 right = max(leftEdge, min(rightEdge, right));
4944 LayoutUnit newContentWidth = right - left;
4945 if (newContentWidth == oldWidth)
4948 setOverrideLogicalContentWidth(newContentWidth);
4950 clearOverrideLogicalContentWidth();
4953 void RenderBlock::clearTruncation()
4955 if (style()->visibility() == VISIBLE) {
4956 if (childrenInline() && hasMarkupTruncation()) {
4957 setHasMarkupTruncation(false);
4958 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4959 box->clearTruncation();
4961 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
4962 if (shouldCheckLines(obj))
4963 toRenderBlock(obj)->clearTruncation();
4969 void RenderBlock::setPaginationStrut(LayoutUnit strut)
4974 m_rareData = adoptPtr(new RenderBlockRareData());
4976 m_rareData->m_paginationStrut = strut;
4979 void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
4984 m_rareData = adoptPtr(new RenderBlockRareData());
4986 m_rareData->m_pageLogicalOffset = logicalOffset;
4989 void RenderBlock::setBreakAtLineToAvoidWidow(int lineToBreak)
4991 ASSERT(lineToBreak >= 0);
4993 m_rareData = adoptPtr(new RenderBlockRareData());
4995 ASSERT(!m_rareData->m_didBreakAtLineToAvoidWidow);
4996 m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
4999 void RenderBlock::setDidBreakAtLineToAvoidWidow()
5001 ASSERT(!shouldBreakAtLineToAvoidWidow());
5003 // This function should be called only after a break was applied to avoid widows
5004 // so assert |m_rareData| exists.
5007 m_rareData->m_didBreakAtLineToAvoidWidow = true;
5010 void RenderBlock::clearDidBreakAtLineToAvoidWidow()
5015 m_rareData->m_didBreakAtLineToAvoidWidow = false;
5018 void RenderBlock::clearShouldBreakAtLineToAvoidWidow() const
5020 ASSERT(shouldBreakAtLineToAvoidWidow());
5024 m_rareData->m_lineBreakToAvoidWidow = -1;
5027 void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
5029 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5030 // inline boxes above and below us (thus getting merged with them to form a single irregular
5032 if (isAnonymousBlockContinuation()) {
5033 // FIXME: This is wrong for block-flows that are horizontal.
5034 // https://bugs.webkit.org/show_bug.cgi?id=46781
5035 rects.append(pixelSnappedIntRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(),
5036 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
5037 continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
5038 inlineElementContinuation()->containingBlock()->location()));
5040 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
5043 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
5045 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5046 // inline boxes above and below us (thus getting merged with them to form a single irregular
5048 if (isAnonymousBlockContinuation()) {
5049 // FIXME: This is wrong for block-flows that are horizontal.
5050 // https://bugs.webkit.org/show_bug.cgi?id=46781
5051 FloatRect localRect(0, -collapsedMarginBefore(),
5052 width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
5053 quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed));
5054 continuation()->absoluteQuads(quads, wasFixed);
5056 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
5059 LayoutRect RenderBlock::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
5061 LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
5062 if (isAnonymousBlockContinuation())
5063 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
5067 RenderObject* RenderBlock::hoverAncestor() const
5069 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
5072 void RenderBlock::updateDragState(bool dragOn)
5074 RenderBox::updateDragState(dragOn);
5076 continuation()->updateDragState(dragOn);
5079 RenderStyle* RenderBlock::outlineStyleForRepaint() const
5081 return isAnonymousBlockContinuation() ? continuation()->style() : style();
5084 void RenderBlock::childBecameNonInline(RenderObject*)
5086 makeChildrenNonInline();
5087 if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
5088 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
5089 // |this| may be dead here
5092 void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
5094 if (result.innerNode())
5097 if (Node* n = nodeForHitTest()) {
5098 result.setInnerNode(n);
5099 if (!result.innerNonSharedNode())
5100 result.setInnerNonSharedNode(n);
5101 result.setLocalPoint(point);
5105 LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
5107 // Do the normal calculation in most cases.
5109 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
5111 LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
5113 if (extraWidthToEndOfLine) {
5114 if (isRenderBlock()) {
5115 *extraWidthToEndOfLine = width() - caretRect.maxX();
5117 // FIXME: This code looks wrong.
5118 // myRight and containerRight are set up, but then clobbered.
5119 // So *extraWidthToEndOfLine will always be 0 here.
5121 LayoutUnit myRight = caretRect.maxX();
5122 // FIXME: why call localToAbsoluteForContent() twice here, too?
5123 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
5125 LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
5126 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
5128 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
5135 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
5137 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5138 // inline boxes above and below us (thus getting merged with them to form a single irregular
5140 if (inlineElementContinuation()) {
5141 // FIXME: This check really isn't accurate.
5142 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
5143 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
5144 // FIXME: This is wrong for block-flows that are horizontal.
5145 // https://bugs.webkit.org/show_bug.cgi?id=46781
5146 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
5147 float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit();
5148 float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit();
5149 LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin);
5150 if (!rect.isEmpty())
5151 rects.append(pixelSnappedIntRect(rect));
5152 } else if (width() && height())
5153 rects.append(pixelSnappedIntRect(additionalOffset, size()));
5155 if (!hasOverflowClip() && !hasControlClip()) {
5156 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5157 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
5158 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
5159 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
5160 if (!rect.isEmpty())
5161 rects.append(pixelSnappedIntRect(rect));
5164 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
5165 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
5166 RenderBox* box = toRenderBox(curr);
5168 // FIXME: This doesn't work correctly with transforms.
5170 pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
5172 pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
5173 box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer);
5178 if (inlineElementContinuation())
5179 inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()), paintContainer);
5182 void RenderBlock::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
5184 RenderBox::computeSelfHitTestRects(rects, layerOffset);
5186 if (hasHorizontalLayoutOverflow() || hasVerticalLayoutOverflow()) {
5187 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5188 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
5189 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
5190 LayoutRect rect(layerOffset.x() + curr->x(), layerOffset.y() + top, curr->width(), bottom - top);
5191 // It's common for this rect to be entirely contained in our box, so exclude that simple case.
5192 if (!rect.isEmpty() && (rects.isEmpty() || !rects[0].contains(rect)))
5198 RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
5200 if (isAnonymousColumnsBlock())
5201 return createAnonymousColumnsWithParentRenderer(parent);
5202 if (isAnonymousColumnSpanBlock())
5203 return createAnonymousColumnSpanWithParentRenderer(parent);
5204 return createAnonymousWithParentRendererAndDisplay(parent, style()->display());
5207 bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
5209 ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
5211 RenderFlowThread* flowThread = flowThreadContainingBlock();
5213 return true; // Printing and multi-column both make new pages to accommodate content.
5215 // See if we're in the last region.
5216 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
5217 RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this);
5220 if (region->isLastRegion())
5221 return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment
5222 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
5226 LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
5228 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5229 if (!pageLogicalHeight)
5230 return logicalOffset;
5232 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
5233 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
5234 if (pageBoundaryRule == ExcludePageBoundary)
5235 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
5236 return logicalOffset + remainingLogicalHeight;
5239 ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const
5241 return ColumnInfo::Column;
5244 LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
5246 RenderView* renderView = view();
5247 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
5248 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
5250 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
5251 RenderFlowThread* flowThread = flowThreadContainingBlock();
5253 LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
5254 if (!pageLogicalHeight)
5256 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
5258 return flowThread->pageLogicalTopForOffset(cumulativeOffset);
5261 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
5263 RenderView* renderView = view();
5264 RenderFlowThread* flowThread = flowThreadContainingBlock();
5266 return renderView->layoutState()->m_pageLogicalHeight;
5267 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
5270 LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
5272 RenderView* renderView = view();
5273 offset += offsetFromLogicalTopOfFirstPage();
5275 RenderFlowThread* flowThread = flowThreadContainingBlock();
5277 LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
5278 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
5279 if (pageBoundaryRule == IncludePageBoundary) {
5280 // If includeBoundaryPoint is true the line exactly on the top edge of a
5281 // column will act as being part of the previous column.
5282 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
5284 return remainingHeight;
5287 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
5290 LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
5292 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
5293 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
5294 RenderFlowThread* flowThread = flowThreadContainingBlock();
5295 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
5296 bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
5297 || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
5298 || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
5299 if (!isUnsplittable)
5300 return logicalOffset;
5301 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
5302 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5303 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
5304 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
5305 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
5306 || !hasNextPage(logicalOffset))
5307 return logicalOffset;
5308 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
5309 if (remainingLogicalHeight < childLogicalHeight) {
5310 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
5311 return logicalOffset;
5312 return logicalOffset + remainingLogicalHeight;
5314 return logicalOffset;
5317 bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
5319 bool checkRegion = false;
5320 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
5321 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
5322 if (minimumLogicalHeight <= pageLogicalHeight)
5324 if (!hasNextPage(logicalOffset + adjustment))
5326 adjustment += pageLogicalHeight;
5329 return !checkRegion;
5332 void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
5334 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
5335 flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
5338 void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
5340 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
5341 flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight);
5342 else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo)
5343 colInfo->updateMinimumColumnHeight(minHeight);
5346 static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
5348 // We may require a certain minimum number of lines per page in order to satisfy
5349 // orphans and widows, and that may affect the minimum page height.
5350 unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
5351 if (lineCount > 1) {
5352 RootInlineBox* line = lastLine;
5353 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
5354 line = line->prevRootBox();
5356 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
5357 // adjustLinePositionForPagination() for more details.
5358 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
5359 lineTop = min(line->lineTopWithLeading(), overflow.y());
5361 return lineBottom - lineTop;
5364 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread)
5366 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
5367 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
5368 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
5369 // of the first column.
5371 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
5372 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
5373 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
5374 // for overflow to occur), and then cache visible overflow for each column rect.
5376 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
5377 // content that paints in a previous column (and content that paints in the following column).
5379 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
5380 // at least make positive leading work in typical cases.
5382 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
5383 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
5384 // line and all following lines.
5385 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
5386 LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
5387 LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
5388 LayoutUnit lineHeight = logicalBottom - logicalOffset;
5389 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom));
5390 logicalOffset += delta;
5391 lineBox->setPaginationStrut(0);
5392 lineBox->setIsFirstAfterPageBreak(false);
5393 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5394 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
5395 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
5396 // still going to add a strut, so that the visible overflow fits on a single page.
5397 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
5398 || !hasNextPage(logicalOffset))
5399 // FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page.
5400 // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
5402 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
5404 int lineIndex = lineCount(lineBox);
5405 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
5406 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
5407 clearShouldBreakAtLineToAvoidWidow();
5408 setDidBreakAtLineToAvoidWidow();
5410 // If we have a non-uniform page height, then we have to shift further possibly.
5411 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
5413 if (lineHeight > pageLogicalHeight) {
5414 // Split the top margin in order to avoid splitting the visible part of the line.
5415 remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
5417 LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
5418 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
5419 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
5420 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineIndex))
5421 && !isOutOfFlowPositioned() && !isTableCell())
5422 setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
5424 delta += remainingLogicalHeight;
5425 lineBox->setPaginationStrut(remainingLogicalHeight);
5426 lineBox->setIsFirstAfterPageBreak(true);
5428 } else if (remainingLogicalHeight == pageLogicalHeight) {
5429 // We're at the very top of a page or column.
5430 if (lineBox != firstRootBox())
5431 lineBox->setIsFirstAfterPageBreak(true);
5432 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
5433 setPageBreak(logicalOffset, lineHeight);
5437 void RenderBlock::updateRegionForLine(RootInlineBox* lineBox) const
5440 lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading()));
5442 RootInlineBox* prevLineBox = lineBox->prevRootBox();
5446 // This check is more accurate than the one in |adjustLinePositionForPagination| because it takes into
5447 // account just the container changes between lines. The before mentioned function doesn't set the flag
5448 // correctly if the line is positioned at the top of the last fragment container.
5449 if (lineBox->containingRegion() != prevLineBox->containingRegion())
5450 lineBox->setIsFirstAfterPageBreak(true);
5453 bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const
5458 RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta);
5459 // Just bail if the region didn't change.
5460 if (rootBox->containingRegion() == currentRegion)
5462 return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion);
5465 LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
5467 LayoutState* layoutState = view()->layoutState();
5468 if (layoutState && !layoutState->isPaginated())
5471 RenderFlowThread* flowThread = flowThreadContainingBlock();
5473 return flowThread->offsetFromLogicalTopOfFirstRegion(this);
5476 ASSERT(layoutState->renderer() == this);
5478 LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
5479 return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
5482 ASSERT_NOT_REACHED();
5486 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
5488 RenderFlowThread* flowThread = flowThreadContainingBlock();
5489 if (!flowThread || !flowThread->hasValidRegionInfo())
5492 return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
5495 bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const
5497 if (!flowThread || !flowThread->hasValidRegionInfo())
5500 return flowThread->logicalWidthChangedInRegionsForBlock(this);
5503 RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
5505 RenderFlowThread* flowThread = flowThreadContainingBlock();
5507 ASSERT(isRenderView() || (region && flowThread));
5511 // We need to clamp to the block, since we want any lines or blocks that overflow out of the
5512 // logical top or logical bottom of the block to size as though the border box in the first and
5513 // last regions extended infinitely. Otherwise the lines are going to size according to the regions
5514 // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
5515 RenderRegion* startRegion;
5516 RenderRegion* endRegion;
5517 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
5519 if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
5521 if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent())
5527 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
5529 // If the child has the same directionality as we do, then we can just return its
5530 // collapsed margin.
5531 if (!child->isWritingModeRoot())
5532 return child->collapsedMarginBefore();
5534 // The child has a different directionality. If the child is parallel, then it's just
5535 // flipped relative to us. We can use the collapsed margin for the opposite edge.
5536 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5537 return child->collapsedMarginAfter();
5539 // The child is perpendicular to us, which means its margins don't collapse but are on the
5540 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
5541 return marginBeforeForChild(child);
5544 LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) const
5546 // If the child has the same directionality as we do, then we can just return its
5547 // collapsed margin.
5548 if (!child->isWritingModeRoot())
5549 return child->collapsedMarginAfter();
5551 // The child has a different directionality. If the child is parallel, then it's just
5552 // flipped relative to us. We can use the collapsed margin for the opposite edge.
5553 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5554 return child->collapsedMarginBefore();
5556 // The child is perpendicular to us, which means its margins don't collapse but are on the
5557 // "logical left/right" side of the child box. We can just return the raw margin in this case.
5558 return marginAfterForChild(child);
5561 bool RenderBlock::hasMarginBeforeQuirk(const RenderBox* child) const
5563 // If the child has the same directionality as we do, then we can just return its
5565 if (!child->isWritingModeRoot())
5566 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
5568 // The child has a different directionality. If the child is parallel, then it's just
5569 // flipped relative to us. We can use the opposite edge.
5570 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5571 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
5573 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
5574 // whether or not authors specified quirky ems, since they're an implementation detail.
5578 bool RenderBlock::hasMarginAfterQuirk(const RenderBox* child) const
5580 // If the child has the same directionality as we do, then we can just return its
5582 if (!child->isWritingModeRoot())
5583 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
5585 // The child has a different directionality. If the child is parallel, then it's just
5586 // flipped relative to us. We can use the opposite edge.
5587 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5588 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
5590 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
5591 // whether or not authors specified quirky ems, since they're an implementation detail.
5595 const char* RenderBlock::renderName() const
5598 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
5601 return "RenderBlock (floating)";
5602 if (isOutOfFlowPositioned())
5603 return "RenderBlock (positioned)";
5604 if (isAnonymousColumnsBlock())
5605 return "RenderBlock (anonymous multi-column)";
5606 if (isAnonymousColumnSpanBlock())
5607 return "RenderBlock (anonymous multi-column span)";
5608 if (isAnonymousBlock())
5609 return "RenderBlock (anonymous)";
5610 // FIXME: Temporary hack while the new generated content system is being implemented.
5611 if (isPseudoElement())
5612 return "RenderBlock (generated)";
5614 return "RenderBlock (generated)";
5615 if (isRelPositioned())
5616 return "RenderBlock (relative positioned)";
5617 if (isStickyPositioned())
5618 return "RenderBlock (sticky positioned)";
5619 return "RenderBlock";
5622 RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
5624 // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
5625 EDisplay newDisplay;
5626 RenderBlock* newBox = 0;
5627 if (display == BOX || display == INLINE_BOX) {
5628 // FIXME: Remove this case once we have eliminated all internal users of old flexbox
5629 newBox = RenderDeprecatedFlexibleBox::createAnonymous(&parent->document());
5631 } else if (display == FLEX || display == INLINE_FLEX) {
5632 newBox = RenderFlexibleBox::createAnonymous(&parent->document());
5635 newBox = RenderBlockFlow::createAnonymous(&parent->document());
5639 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay);
5640 newBox->setStyle(newStyle.release());
5644 RenderBlockFlow* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent)
5646 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
5647 newStyle->inheritColumnPropertiesFrom(parent->style());
5649 RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&parent->document());
5650 newBox->setStyle(newStyle.release());
5654 RenderBlockFlow* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent)
5656 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
5657 newStyle->setColumnSpan(ColumnSpanAll);
5659 RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&parent->document());
5660 newBox->setStyle(newStyle.release());
5665 void RenderBlock::checkPositionedObjectsNeedLayout()
5667 if (!gPositionedDescendantsMap)
5670 if (TrackedRendererListHashSet* positionedDescendantSet = positionedObjects()) {
5671 TrackedRendererListHashSet::const_iterator end = positionedDescendantSet->end();
5672 for (TrackedRendererListHashSet::const_iterator it = positionedDescendantSet->begin(); it != end; ++it) {
5673 RenderBox* currBox = *it;
5674 ASSERT(!currBox->needsLayout());
5679 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const
5682 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
5683 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
5688 } // namespace WebCore