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/RenderFlowThread.h"
53 #include "core/rendering/RenderInline.h"
54 #include "core/rendering/RenderLayer.h"
55 #include "core/rendering/RenderMarquee.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();
1064 void RenderBlock::removeChild(RenderObject* oldChild)
1066 // No need to waste time in merging or removing empty anonymous blocks.
1067 // We can just bail out if our document is getting destroyed.
1068 if (documentBeingDestroyed()) {
1069 RenderBox::removeChild(oldChild);
1073 // This protects against column split flows when anonymous blocks are getting merged.
1074 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
1076 // If this child is a block, and if our previous and next siblings are
1077 // both anonymous blocks with inline content, then we can go ahead and
1078 // fold the inline content back together.
1079 RenderObject* prev = oldChild->previousSibling();
1080 RenderObject* next = oldChild->nextSibling();
1081 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1082 if (canMergeAnonymousBlocks && prev && next) {
1083 prev->setNeedsLayoutAndPrefWidthsRecalc();
1084 RenderBlockFlow* nextBlock = toRenderBlockFlow(next);
1085 RenderBlockFlow* prevBlock = toRenderBlockFlow(prev);
1087 if (prev->childrenInline() != next->childrenInline()) {
1088 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1089 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1091 // Place the inline children block inside of the block children block instead of deleting it.
1092 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1093 // to clear out inherited column properties by just making a new style, and to also clear the
1094 // column span flag if it is set.
1095 ASSERT(!inlineChildrenBlock->continuation());
1096 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
1097 // Cache this value as it might get changed in setStyle() call.
1098 bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer();
1099 inlineChildrenBlock->setStyle(newStyle);
1100 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlockHasLayer);
1102 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1103 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1104 inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer());
1105 next->setNeedsLayoutAndPrefWidthsRecalc();
1107 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1108 // of "this". we null out prev or next so that is not used later in the function.
1109 if (inlineChildrenBlock == prevBlock)
1114 // Take all the children out of the |next| block and put them in
1115 // the |prev| block.
1116 nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1118 // Delete the now-empty block's lines and nuke it.
1119 nextBlock->deleteLineBoxTree();
1120 nextBlock->destroy();
1125 RenderBox::removeChild(oldChild);
1127 RenderObject* child = prev ? prev : next;
1128 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) {
1129 // The removal has knocked us down to containing only a single anonymous
1130 // box. We can go ahead and pull the content right back up into our
1132 collapseAnonymousBlockChild(this, toRenderBlock(child));
1133 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
1134 // It's possible that the removal has knocked us down to a single anonymous
1135 // block with pseudo-style element siblings (e.g. first-letter). If these
1136 // are floating, then we need to pull the content up also.
1137 RenderBlock* anonymousBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1138 if ((anonymousBlock->previousSibling() || anonymousBlock->nextSibling())
1139 && (!anonymousBlock->previousSibling() || (anonymousBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->previousSibling()->isFloating() && !anonymousBlock->previousSibling()->previousSibling()))
1140 && (!anonymousBlock->nextSibling() || (anonymousBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->nextSibling()->isFloating() && !anonymousBlock->nextSibling()->nextSibling()))) {
1141 collapseAnonymousBlockChild(this, anonymousBlock);
1145 if (!firstChild()) {
1146 // If this was our last child be sure to clear out our line boxes.
1147 if (childrenInline())
1148 deleteLineBoxTree();
1150 // If we are an empty anonymous block in the continuation chain,
1151 // we need to remove ourself and fix the continuation chain.
1152 if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) {
1153 RenderObject* containingBlockIgnoringAnonymous = containingBlock();
1154 while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock())
1155 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
1156 for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
1157 if (curr->virtualContinuation() != this)
1160 // Found our previous continuation. We just need to point it to
1161 // |this|'s next continuation.
1162 RenderBoxModelObject* nextContinuation = continuation();
1163 if (curr->isRenderInline())
1164 toRenderInline(curr)->setContinuation(nextContinuation);
1165 else if (curr->isRenderBlock())
1166 toRenderBlock(curr)->setContinuation(nextContinuation);
1168 ASSERT_NOT_REACHED();
1178 bool RenderBlock::isSelfCollapsingBlock() const
1180 // Placeholder elements are not laid out until the dimensions of their parent text control are known, so they
1181 // don't get layout until their parent has had layout - this is unique in the layout tree and means
1182 // when we call isSelfCollapsingBlock on them we find that they still need layout.
1183 ASSERT(!needsLayout() || (node() && node()->isElementNode() && toElement(node())->shadowPseudoId() == "-webkit-input-placeholder"));
1185 // We are not self-collapsing if we
1186 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1188 // (c) have border/padding,
1189 // (d) have a min-height
1190 // (e) have specified that one of our margins can't collapse using a CSS extension
1191 // (f) establish a new block formatting context.
1193 if (createsBlockFormattingContext())
1196 if (logicalHeight() > 0
1197 || isTable() || borderAndPaddingLogicalHeight()
1198 || style()->logicalMinHeight().isPositive()
1199 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1202 Length logicalHeightLength = style()->logicalHeight();
1203 bool hasAutoHeight = logicalHeightLength.isAuto();
1204 if (logicalHeightLength.isPercent() && !document().inQuirksMode()) {
1205 hasAutoHeight = true;
1206 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1207 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1208 hasAutoHeight = false;
1212 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1213 // on whether we have content that is all self-collapsing or not.
1214 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1215 // If the block has inline children, see if we generated any line boxes. If we have any
1216 // line boxes, then we can't be self-collapsing, since we have content.
1217 if (childrenInline())
1218 return !firstLineBox();
1220 // Whether or not we collapse is dependent on whether all our normal flow children
1221 // are also self-collapsing.
1222 if (m_hasOnlySelfCollapsingChildren)
1224 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1225 if (child->isFloatingOrOutOfFlowPositioned())
1227 if (!child->isSelfCollapsingBlock())
1235 void RenderBlock::startDelayUpdateScrollInfo()
1237 if (gDelayUpdateScrollInfo == 0) {
1238 ASSERT(!gDelayedUpdateScrollInfoSet);
1239 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1241 ASSERT(gDelayedUpdateScrollInfoSet);
1242 ++gDelayUpdateScrollInfo;
1245 void RenderBlock::finishDelayUpdateScrollInfo()
1247 --gDelayUpdateScrollInfo;
1248 ASSERT(gDelayUpdateScrollInfo >= 0);
1249 if (gDelayUpdateScrollInfo == 0) {
1250 ASSERT(gDelayedUpdateScrollInfoSet);
1252 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1253 gDelayedUpdateScrollInfoSet = 0;
1255 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1256 RenderBlock* block = *it;
1257 if (block->hasOverflowClip()) {
1258 block->layer()->scrollableArea()->updateAfterLayout();
1264 void RenderBlock::updateScrollInfoAfterLayout()
1266 if (hasOverflowClip()) {
1267 if (style()->isFlippedBlocksWritingMode()) {
1268 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
1269 // Workaround for now. We cannot delay the scroll info for overflow
1270 // for items with opposite writing directions, as the contents needs
1271 // to overflow in that direction
1272 layer()->scrollableArea()->updateAfterLayout();
1276 if (gDelayUpdateScrollInfo)
1277 gDelayedUpdateScrollInfoSet->add(this);
1279 layer()->scrollableArea()->updateAfterLayout();
1283 void RenderBlock::layout()
1285 OverflowEventDispatcher dispatcher(this);
1286 LayoutRectRecorder recorder(*this);
1288 // Update our first letter info now.
1289 updateFirstLetter();
1291 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1295 if (frameView()->partialLayout().isStopping())
1298 // It's safe to check for control clip here, since controls can never be table cells.
1299 // If we have a lightweight clip, there can never be any overflow from children.
1300 if (hasControlClip() && m_overflow)
1301 clearLayoutOverflow();
1303 invalidateBackgroundObscurationStatus();
1306 bool RenderBlock::updateImageLoadingPriorities()
1308 Vector<ImageResource*> images;
1309 appendImagesFromStyle(images, *style());
1311 if (images.isEmpty())
1314 LayoutRect viewBounds = viewRect();
1315 LayoutRect objectBounds = absoluteContentBox();
1316 // The object bounds might be empty right now, so intersects will fail since it doesn't deal
1317 // with empty rects. Use LayoutRect::contains in that case.
1319 if (!objectBounds.isEmpty())
1320 isVisible = viewBounds.intersects(objectBounds);
1322 isVisible = viewBounds.contains(objectBounds);
1324 ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ?
1325 ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible;
1327 for (Vector<ImageResource*>::iterator it = images.begin(), end = images.end(); it != end; ++it)
1328 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(*it, status);
1333 void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset)
1335 LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height();
1336 if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo())
1338 // Propagate layout markers only up to the child, as we are still in the middle
1340 child->setNormalChildNeedsLayout(true);
1341 child->markShapeInsideDescendantsForLayout();
1342 child->layoutIfNeeded();
1345 ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
1347 if (ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo())
1348 return shapeInsideInfo;
1350 RenderFlowThread* flowThread = flowThreadContainingBlock();
1351 if (allowsShapeInsideInfoSharing(flowThread)) {
1352 LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
1353 // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ...
1354 LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1);
1355 RenderRegion* region = regionAtBlockOffset(offset);
1356 if (region && region->logicalHeight())
1357 return region->shapeInsideInfo();
1363 LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const
1365 const RenderBlock* currentBlock = this;
1366 LayoutRect blockRect(currentBlock->borderBoxRect());
1367 while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) {
1368 RenderBlock* containerBlock = currentBlock->containingBlock();
1369 ASSERT(containerBlock);
1370 if (!containerBlock)
1371 return LayoutSize();
1373 if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
1374 // We have to put the block rect in container coordinates
1375 // and we have to take into account both the container and current block flipping modes
1376 // Bug: Flipping inline and block directions at the same time will not work,
1377 // as one of the flipped dimensions will not yet have been set to its final size
1378 if (containerBlock->style()->isFlippedBlocksWritingMode()) {
1379 if (containerBlock->isHorizontalWritingMode())
1380 blockRect.setY(currentBlock->height() - blockRect.maxY());
1382 blockRect.setX(currentBlock->width() - blockRect.maxX());
1384 currentBlock->flipForWritingMode(blockRect);
1387 blockRect.moveBy(currentBlock->location());
1388 currentBlock = containerBlock;
1391 LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x());
1395 void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*)
1397 RenderBox::imageChanged(image);
1399 if (!parent() || !everHadLayout())
1402 ShapeValue* shapeValue = style()->shapeInside();
1403 if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) {
1404 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1405 shapeInsideInfo->dirtyShapeSize();
1406 markShapeInsideDescendantsForLayout();
1410 void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
1412 // FIXME: A future optimization would do a deep comparison for equality.
1413 if (shapeInside == oldShapeInside)
1417 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1418 shapeInsideInfo->dirtyShapeSize();
1420 setShapeInsideInfo(nullptr);
1421 markShapeInsideDescendantsForLayout();
1425 static inline bool shapeInfoRequiresRelayout(const RenderBlock* block)
1427 ShapeInsideInfo* info = block->shapeInsideInfo();
1429 info->setNeedsLayout(info->shapeSizeDirty());
1431 info = block->layoutShapeInsideInfo();
1432 return info && info->needsLayout();
1435 bool RenderBlock::updateRegionsAndShapesLogicalSize(RenderFlowThread* flowThread)
1437 if (!flowThread && !shapeInsideInfo())
1438 return shapeInfoRequiresRelayout(this);
1440 LayoutUnit oldHeight = logicalHeight();
1441 LayoutUnit oldTop = logicalTop();
1443 // Compute the maximum logical height content may cause this block to expand to
1444 // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
1445 setLogicalHeight(RenderFlowThread::maxLogicalHeight());
1446 updateLogicalHeight();
1450 // Set our start and end regions. No regions above or below us will be considered by our children. They are
1451 // effectively clamped to our region range.
1452 computeRegionRangeForBlock(flowThread);
1454 setLogicalHeight(oldHeight);
1455 setLogicalTop(oldTop);
1457 return shapeInfoRequiresRelayout(this);
1460 void RenderBlock::computeShapeSize()
1462 ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
1463 if (!shapeInsideInfo)
1466 bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
1467 shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
1470 void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged)
1472 // A previous sibling has changed dimension, so we need to relayout the shape with the content
1473 ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
1474 if (heightChanged && shapeInsideInfo)
1475 shapeInsideInfo->dirtyShapeSize();
1477 computeRegionRangeForBlock(flowThread);
1480 void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread)
1483 flowThread->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1486 bool RenderBlock::updateLogicalWidthAndColumnWidth()
1488 LayoutUnit oldWidth = logicalWidth();
1489 LayoutUnit oldColumnWidth = desiredColumnWidth();
1491 updateLogicalWidth();
1494 bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged;
1495 m_hasBorderOrPaddingLogicalWidthChanged = false;
1497 return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
1500 void RenderBlock::layoutBlock(bool)
1502 ASSERT_NOT_REACHED();
1506 void RenderBlock::addOverflowFromChildren()
1508 if (!hasColumns()) {
1509 if (childrenInline())
1510 toRenderBlockFlow(this)->addOverflowFromInlineChildren();
1512 addOverflowFromBlockChildren();
1514 ColumnInfo* colInfo = columnInfo();
1515 if (columnCount(colInfo)) {
1516 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1517 addLayoutOverflow(lastRect);
1518 addContentsVisualOverflow(lastRect);
1523 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool)
1527 // Add overflow from children.
1528 addOverflowFromChildren();
1530 // Add in the overflow from positioned objects.
1531 addOverflowFromPositionedObjects();
1533 if (hasOverflowClip()) {
1534 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1535 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1536 // be considered reachable.
1537 LayoutRect clientRect(noOverflowRect());
1538 LayoutRect rectToApply;
1539 if (isHorizontalWritingMode())
1540 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1542 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1543 addLayoutOverflow(rectToApply);
1544 if (hasRenderOverflow())
1545 m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
1548 // Add visual overflow from box-shadow and border-image-outset.
1549 addVisualEffectOverflow();
1551 // Add visual overflow from theme.
1552 addVisualOverflowFromTheme();
1555 void RenderBlock::addOverflowFromBlockChildren()
1557 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1558 if (!child->isFloatingOrOutOfFlowPositioned())
1559 addOverflowFromChild(child);
1563 void RenderBlock::addOverflowFromPositionedObjects()
1565 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1566 if (!positionedDescendants)
1569 RenderBox* positionedObject;
1570 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1571 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1572 positionedObject = *it;
1574 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1575 if (positionedObject->style()->position() != FixedPosition)
1576 addOverflowFromChild(positionedObject, LayoutSize(positionedObject->x(), positionedObject->y()));
1580 void RenderBlock::addVisualOverflowFromTheme()
1582 if (!style()->hasAppearance())
1585 IntRect inflatedRect = pixelSnappedBorderBoxRect();
1586 RenderTheme::theme().adjustRepaintRect(this, inflatedRect);
1587 addVisualOverflow(inflatedRect);
1590 bool RenderBlock::createsBlockFormattingContext() const
1592 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
1593 || style()->specifiesColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot() || style()->columnSpan();
1596 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
1598 LayoutUnit startPosition = borderStart() + paddingStart();
1599 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1600 startPosition -= verticalScrollbarWidth();
1601 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1603 // Add in our start margin.
1604 LayoutUnit childMarginStart = marginStartForChild(child);
1605 LayoutUnit newPosition = startPosition + childMarginStart;
1607 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1608 // to shift over as necessary to dodge any floats that might get in the way.
1609 if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
1610 newPosition += toRenderBlockFlow(this)->computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
1612 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
1615 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
1617 if (isHorizontalWritingMode()) {
1618 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1619 view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
1620 child->setX(logicalLeft);
1622 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1623 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
1624 child->setY(logicalLeft);
1628 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
1630 if (isHorizontalWritingMode()) {
1631 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1632 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
1633 child->setY(logicalTop);
1635 if (applyDelta == ApplyLayoutDelta && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
1636 view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
1637 child->setX(logicalTop);
1641 void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child)
1643 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1644 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1645 if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
1646 child->setChildNeedsLayout(MarkOnlyThis);
1648 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1649 if (relayoutChildren && child->needsPreferredWidthsRecalculation())
1650 child->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1653 void RenderBlock::simplifiedNormalFlowLayout()
1655 if (childrenInline()) {
1656 ListHashSet<RootInlineBox*> lineBoxes;
1657 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1658 RenderObject* o = walker.current();
1659 if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
1660 o->layoutIfNeeded();
1661 if (toRenderBox(o)->inlineBoxWrapper()) {
1662 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
1665 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
1666 o->clearNeedsLayout();
1670 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
1671 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1672 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
1673 RootInlineBox* box = *it;
1674 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
1677 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
1678 if (!box->isOutOfFlowPositioned())
1679 box->layoutIfNeeded();
1684 bool RenderBlock::simplifiedLayout()
1686 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
1689 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
1691 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
1694 FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(document(), this);
1696 // Lay out positioned descendants or objects that just need to recompute overflow.
1697 if (needsSimplifiedNormalFlowLayout())
1698 simplifiedNormalFlowLayout();
1700 // Make sure a forced break is applied after the content if we are a flow thread in a simplified layout.
1701 // This ensures the size information is correctly computed for the last auto-height region receiving content.
1702 if (isRenderFlowThread())
1703 toRenderFlowThread(this)->applyBreakAfterContent(clientLogicalBottom());
1705 // Lay out our positioned objects if our positioned child bit is set.
1706 // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
1707 // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
1708 // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
1709 // are statically positioned and thus need to move with their absolute ancestors.
1710 bool canContainFixedPosObjects = canContainFixedPositionObjects();
1711 if (posChildNeedsLayout() || canContainFixedPosObjects)
1712 layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects);
1714 // Recompute our overflow information.
1715 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
1716 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
1717 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
1718 // lowestPosition on every relayout so it's not a regression.
1719 // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
1720 // simplifiedLayout, we cache the value in m_overflow.
1721 LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
1722 computeOverflow(oldClientAfterEdge, true);
1726 updateLayerTransform();
1728 updateScrollInfoAfterLayout();
1734 void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child, SubtreeLayoutScope& layoutScope)
1736 if (child->style()->position() != FixedPosition)
1739 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
1740 bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
1741 if (!hasStaticBlockPosition && !hasStaticInlinePosition)
1744 RenderObject* o = child->parent();
1745 while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition)
1747 if (o->style()->position() != AbsolutePosition)
1750 RenderBox* box = toRenderBox(child);
1751 if (hasStaticInlinePosition) {
1752 LogicalExtentComputedValues computedValues;
1753 box->computeLogicalWidth(computedValues);
1754 LayoutUnit newLeft = computedValues.m_position;
1755 if (newLeft != box->logicalLeft())
1756 layoutScope.setChildNeedsLayout(child);
1757 } else if (hasStaticBlockPosition) {
1758 LayoutUnit oldTop = box->logicalTop();
1759 box->updateLogicalHeight();
1760 if (box->logicalTop() != oldTop)
1761 layoutScope.setChildNeedsLayout(child);
1765 LayoutUnit RenderBlock::marginIntrinsicLogicalWidthForChild(RenderBox* child) const
1767 // A margin has three types: fixed, percentage, and auto (variable).
1768 // Auto and percentage margins become 0 when computing min/max width.
1769 // Fixed margins can be added in as is.
1770 Length marginLeft = child->style()->marginStartUsing(style());
1771 Length marginRight = child->style()->marginEndUsing(style());
1772 LayoutUnit margin = 0;
1773 if (marginLeft.isFixed())
1774 margin += marginLeft.value();
1775 if (marginRight.isFixed())
1776 margin += marginRight.value();
1780 void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly)
1782 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1783 if (!positionedDescendants)
1787 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
1790 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1791 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1794 SubtreeLayoutScope layoutScope(r);
1795 // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
1796 // 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.
1797 // it has static position.
1798 markFixedPositionObjectForLayoutIfNeeded(r, layoutScope);
1799 if (fixedPositionObjectsOnly) {
1800 r->layoutIfNeeded();
1804 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
1805 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
1806 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
1807 // positioned explicitly) this should not incur a performance penalty.
1808 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
1809 layoutScope.setChildNeedsLayout(r);
1811 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1812 if (relayoutChildren && r->needsPreferredWidthsRecalculation())
1813 r->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1815 if (!r->needsLayout())
1816 r->markForPaginationRelayoutIfNeeded(layoutScope);
1818 // 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
1819 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
1820 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
1821 r->clearNeedsLayout();
1823 // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
1824 // If it's wrong we'll lay out again.
1825 LayoutUnit oldLogicalTop = 0;
1826 bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
1827 if (needsBlockDirectionLocationSetBeforeLayout) {
1828 if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
1829 r->updateLogicalHeight();
1831 r->updateLogicalWidth();
1832 oldLogicalTop = logicalTopForChild(r);
1835 r->layoutIfNeeded();
1837 // Lay out again if our estimate was wrong.
1838 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop)
1839 r->forceChildLayout();
1843 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
1846 void RenderBlock::markPositionedObjectsForLayout()
1848 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1849 if (positionedDescendants) {
1851 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1852 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1854 r->setChildNeedsLayout();
1859 void RenderBlock::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
1861 ASSERT(!needsLayout());
1865 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
1866 layoutScope.setChildNeedsLayout(this);
1869 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1871 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
1873 LayoutPoint adjustedPaintOffset = paintOffset + location();
1875 PaintPhase phase = paintInfo.phase;
1877 // Check if we need to do anything at all.
1878 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
1879 // paints the root's background.
1881 LayoutRect overflowBox = overflowRectForPaintRejection();
1882 flipForWritingMode(overflowBox);
1883 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
1884 overflowBox.moveBy(adjustedPaintOffset);
1885 if (!overflowBox.intersects(paintInfo.rect))
1889 // There are some cases where not all clipped visual overflow is accounted for.
1890 // FIXME: reduce the number of such cases.
1891 ContentsClipBehavior contentsClipBehavior = ForceContentsClip;
1892 if (hasOverflowClip() && !hasControlClip() && !(shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !hasCaret())
1893 contentsClipBehavior = SkipContentsClipIfPossible;
1895 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior);
1896 paintObject(paintInfo, adjustedPaintOffset);
1898 popContentsClip(paintInfo, phase, adjustedPaintOffset);
1900 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1901 // z-index. We paint after we painted the background/border, so that the scrollbars will
1902 // sit above the background/border.
1903 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly())
1904 layer()->scrollableArea()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect, false /* paintingOverlayControls */);
1907 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1909 if (paintInfo.context->paintingDisabled())
1912 const Color& ruleColor = resolveColor(CSSPropertyWebkitColumnRuleColor);
1913 bool ruleTransparent = style()->columnRuleIsTransparent();
1914 EBorderStyle ruleStyle = style()->columnRuleStyle();
1915 LayoutUnit ruleThickness = style()->columnRuleWidth();
1916 LayoutUnit colGap = columnGap();
1917 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
1921 ColumnInfo* colInfo = columnInfo();
1922 unsigned colCount = columnCount(colInfo);
1924 bool antialias = shouldAntialiasLines(paintInfo.context);
1926 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
1927 bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed();
1928 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
1929 LayoutUnit ruleAdd = logicalLeftOffsetForContent();
1930 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
1931 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
1932 BoxSide boxSide = isHorizontalWritingMode()
1933 ? leftToRight ? BSLeft : BSRight
1934 : leftToRight ? BSTop : BSBottom;
1936 for (unsigned i = 0; i < colCount; i++) {
1937 // Move to the next position.
1939 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
1940 currLogicalLeftOffset += inlineDirectionSize + colGap;
1942 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
1943 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
1946 // Now paint the column rule.
1947 if (i < colCount - 1) {
1948 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
1949 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
1950 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
1951 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
1952 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
1953 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
1956 ruleLogicalLeft = currLogicalLeftOffset;
1959 bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
1960 LayoutUnit ruleLeft = isHorizontalWritingMode()
1961 ? borderLeft() + paddingLeft()
1962 : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
1963 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
1964 LayoutUnit ruleTop = isHorizontalWritingMode()
1965 ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
1966 : borderStart() + paddingStart();
1967 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
1968 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
1971 if (isHorizontalWritingMode())
1972 ruleRect.setY(height() - ruleRect.maxY());
1974 ruleRect.setX(width() - ruleRect.maxX());
1977 ruleRect.moveBy(paintOffset);
1979 BoxSide boxSide = isHorizontalWritingMode()
1980 ? topToBottom ? BSTop : BSBottom
1981 : topToBottom ? BSLeft : BSRight;
1983 LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
1984 if (!isHorizontalWritingMode())
1985 step = step.transposedSize();
1987 for (unsigned i = 1; i < colCount; i++) {
1988 ruleRect.move(step);
1989 IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
1990 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
1995 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
1997 // We need to do multiple passes, breaking up our child painting into strips.
1998 GraphicsContext* context = paintInfo.context;
1999 ColumnInfo* colInfo = columnInfo();
2000 unsigned colCount = columnCount(colInfo);
2003 LayoutUnit currLogicalTopOffset = 0;
2004 LayoutUnit colGap = columnGap();
2005 for (unsigned i = 0; i < colCount; i++) {
2006 // For each rect, we clip to the rect, and then we adjust our coords.
2007 LayoutRect colRect = columnRectAt(colInfo, i);
2008 flipForWritingMode(colRect);
2009 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2010 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2011 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2012 if (isHorizontalWritingMode())
2013 offset.expand(0, colRect.y() - borderTop() - paddingTop());
2015 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2017 colRect.moveBy(paintOffset);
2018 PaintInfo info(paintInfo);
2019 info.rect.intersect(pixelSnappedIntRect(colRect));
2021 if (!info.rect.isEmpty()) {
2022 GraphicsContextStateSaver stateSaver(*context);
2023 LayoutRect clipRect(colRect);
2025 if (i < colCount - 1) {
2026 if (isHorizontalWritingMode())
2027 clipRect.expand(colGap / 2, 0);
2029 clipRect.expand(0, colGap / 2);
2031 // Each strip pushes a clip, since column boxes are specified as being
2032 // like overflow:hidden.
2033 // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
2034 // are clipped according to the 'overflow' property.
2035 context->clip(pixelSnappedIntRect(clipRect));
2037 // Adjust our x and y when painting.
2038 LayoutPoint adjustedPaintOffset = paintOffset + offset;
2040 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2042 paintContents(info, adjustedPaintOffset);
2045 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2046 if (style()->isFlippedBlocksWritingMode())
2047 currLogicalTopOffset += blockDelta;
2049 currLogicalTopOffset -= blockDelta;
2053 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2055 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2056 // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
2057 // will do a full repaint.
2058 if (document().didLayoutWithPendingStylesheets() && !isRenderView())
2061 if (childrenInline())
2062 m_lineBoxes.paint(this, paintInfo, paintOffset);
2064 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2065 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2067 // We don't paint our own background, but we do let the kids paint their backgrounds.
2068 PaintInfo paintInfoForChild(paintInfo);
2069 paintInfoForChild.phase = newPhase;
2070 paintInfoForChild.updatePaintingRootForChildren(this);
2071 paintChildren(paintInfoForChild, paintOffset);
2075 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2077 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox())
2078 paintChild(child, paintInfo, paintOffset);
2081 void RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2083 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2084 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2085 child->paint(paintInfo, childPoint);
2088 void RenderBlock::paintChildAsInlineBlock(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2090 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2091 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2092 paintAsInlineBlock(child, paintInfo, childPoint);
2095 void RenderBlock::paintAsInlineBlock(RenderObject* renderer, PaintInfo& paintInfo, const LayoutPoint& childPoint)
2097 if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)
2100 // Paint all phases atomically, as though the element established its own
2101 // stacking context. (See Appendix E.2, section 7.2.1.4 on
2102 // inline block/table/replaced elements in the CSS2.1 specification.)
2103 // This is also used by other elements (e.g. flex items and grid items).
2104 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
2105 PaintInfo info(paintInfo);
2106 info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2107 renderer->paint(info, childPoint);
2108 if (!preservePhase) {
2109 info.phase = PaintPhaseChildBlockBackgrounds;
2110 renderer->paint(info, childPoint);
2111 info.phase = PaintPhaseFloat;
2112 renderer->paint(info, childPoint);
2113 info.phase = PaintPhaseForeground;
2114 renderer->paint(info, childPoint);
2115 info.phase = PaintPhaseOutline;
2116 renderer->paint(info, childPoint);
2120 bool RenderBlock::hasCaret(CaretType type) const
2122 // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2123 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2124 RenderObject* caretPainter;
2125 bool isContentEditable;
2126 if (type == CursorCaret) {
2127 caretPainter = frame()->selection().caretRenderer();
2128 isContentEditable = frame()->selection().rendererIsEditable();
2130 caretPainter = frame()->page()->dragCaretController().caretRenderer();
2131 isContentEditable = frame()->page()->dragCaretController().isContentEditable();
2133 return caretPainter == this && (isContentEditable || caretBrowsing);
2136 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2138 if (!hasCaret(type))
2141 if (type == CursorCaret)
2142 frame()->selection().paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2144 frame()->page()->dragCaretController().paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
2147 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2149 PaintPhase paintPhase = paintInfo.phase;
2151 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2152 LayoutPoint scrolledOffset = paintOffset;
2153 if (hasOverflowClip())
2154 scrolledOffset.move(-scrolledContentOffset());
2156 // 1. paint background, borders etc
2157 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2158 if (hasBoxDecorations())
2159 paintBoxDecorations(paintInfo, paintOffset);
2160 if (hasColumns() && !paintInfo.paintRootBackgroundOnly())
2161 paintColumnRules(paintInfo, scrolledOffset);
2164 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2165 paintMask(paintInfo, paintOffset);
2169 if (paintPhase == PaintPhaseClippingMask && style()->visibility() == VISIBLE) {
2170 paintClippingMask(paintInfo, paintOffset);
2174 // We're done. We don't bother painting any children.
2175 if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
2178 // 2. paint contents
2179 if (paintPhase != PaintPhaseSelfOutline) {
2181 paintColumnContents(paintInfo, scrolledOffset);
2183 paintContents(paintInfo, scrolledOffset);
2186 // 3. paint selection
2187 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2188 bool isPrinting = document().printing();
2189 if (!isPrinting && !hasColumns())
2190 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2193 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2195 paintColumnContents(paintInfo, scrolledOffset, true);
2197 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2200 // 5. paint outline.
2201 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2202 paintOutline(paintInfo, LayoutRect(paintOffset, size()));
2204 // 6. paint continuation outlines.
2205 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2206 RenderInline* inlineCont = inlineElementContinuation();
2207 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2208 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2209 RenderBlock* cb = containingBlock();
2211 bool inlineEnclosedInSelfPaintingLayer = false;
2212 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2213 if (box->hasSelfPaintingLayer()) {
2214 inlineEnclosedInSelfPaintingLayer = true;
2219 // Do not add continuations for outline painting by our containing block if we are a relative positioned
2220 // 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
2221 // in the same layer.
2222 if (!inlineEnclosedInSelfPaintingLayer && !hasLayer())
2223 cb->addContinuationWithOutline(inlineRenderer);
2224 else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer()))
2225 inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2227 paintContinuationOutlines(paintInfo, paintOffset);
2231 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2232 // then paint the caret.
2233 if (paintPhase == PaintPhaseForeground) {
2234 paintCaret(paintInfo, paintOffset, CursorCaret);
2235 paintCaret(paintInfo, paintOffset, DragCaret);
2239 RenderInline* RenderBlock::inlineElementContinuation() const
2241 RenderBoxModelObject* continuation = this->continuation();
2242 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2245 RenderBlock* RenderBlock::blockElementContinuation() const
2247 RenderBoxModelObject* currentContinuation = continuation();
2248 if (!currentContinuation || currentContinuation->isInline())
2250 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2251 if (nextContinuation->isAnonymousBlock())
2252 return nextContinuation->blockElementContinuation();
2253 return nextContinuation;
2256 static ContinuationOutlineTableMap* continuationOutlineTable()
2258 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2262 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2264 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2266 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2268 ContinuationOutlineTableMap* table = continuationOutlineTable();
2269 ListHashSet<RenderInline*>* continuations = table->get(this);
2270 if (!continuations) {
2271 continuations = new ListHashSet<RenderInline*>;
2272 table->set(this, adoptPtr(continuations));
2275 continuations->add(flow);
2278 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2280 ContinuationOutlineTableMap* table = continuationOutlineTable();
2281 if (table->isEmpty())
2284 ListHashSet<RenderInline*>* continuations = table->get(this);
2288 return continuations->contains(flow);
2291 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2293 ContinuationOutlineTableMap* table = continuationOutlineTable();
2294 if (table->isEmpty())
2297 OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this);
2301 LayoutPoint accumulatedPaintOffset = paintOffset;
2302 // Paint each continuation outline.
2303 ListHashSet<RenderInline*>::iterator end = continuations->end();
2304 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2305 // Need to add in the coordinates of the intervening blocks.
2306 RenderInline* flow = *it;
2307 RenderBlock* block = flow->containingBlock();
2308 for ( ; block && block != this; block = block->containingBlock())
2309 accumulatedPaintOffset.moveBy(block->location());
2311 flow->paintOutline(info, accumulatedPaintOffset);
2315 bool RenderBlock::shouldPaintSelectionGaps() const
2317 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2320 bool RenderBlock::isSelectionRoot() const
2322 if (isPseudoElement())
2324 ASSERT(node() || isAnonymous());
2326 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2330 if (isBody() || isRoot() || hasOverflowClip()
2331 || isPositioned() || isFloating()
2332 || isTableCell() || isInlineBlockOrInlineTable()
2333 || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot()
2334 || isRenderFlowThread())
2337 if (view() && view()->selectionStart()) {
2338 Node* startElement = view()->selectionStart()->node();
2339 if (startElement && startElement->rootEditableElement() == node())
2346 GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer)
2348 ASSERT(!needsLayout());
2350 if (!shouldPaintSelectionGaps())
2353 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2354 mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms);
2355 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
2357 if (hasOverflowClip())
2358 offsetFromRepaintContainer -= scrolledContentOffset();
2360 LayoutUnit lastTop = 0;
2361 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2362 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2364 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2367 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2369 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2370 LayoutUnit lastTop = 0;
2371 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2372 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2373 GraphicsContextStateSaver stateSaver(*paintInfo.context);
2375 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
2376 if (!gapRectsBounds.isEmpty()) {
2377 if (RenderLayer* layer = enclosingLayer()) {
2378 gapRectsBounds.moveBy(-paintOffset);
2380 LayoutRect localBounds(gapRectsBounds);
2381 flipForWritingMode(localBounds);
2382 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2383 if (layer->renderer()->hasOverflowClip())
2384 gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
2386 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2392 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, TrackedRendererListHashSet* positionedObjects)
2394 if (!positionedObjects)
2397 TrackedRendererListHashSet::const_iterator end = positionedObjects->end();
2398 for (TrackedRendererListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2400 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2404 LayoutUnit RenderBlock::blockDirectionOffset(const LayoutSize& offsetFromBlock) const
2406 return isHorizontalWritingMode() ? offsetFromBlock.height() : offsetFromBlock.width();
2409 LayoutUnit RenderBlock::inlineDirectionOffset(const LayoutSize& offsetFromBlock) const
2411 return isHorizontalWritingMode() ? offsetFromBlock.width() : offsetFromBlock.height();
2414 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
2417 if (isHorizontalWritingMode())
2418 result = logicalRect;
2420 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2421 flipForWritingMode(result);
2422 result.moveBy(rootBlockPhysicalPosition);
2426 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2427 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2429 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2430 // Clip out floating and positioned objects when painting selection gaps.
2432 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2433 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2434 rootBlock->flipForWritingMode(flippedBlockRect);
2435 flippedBlockRect.moveBy(rootBlockPhysicalPosition);
2436 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects());
2437 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2438 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2439 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes.
2440 clipOutFloatingObjects(rootBlock, paintInfo, rootBlockPhysicalPosition, offsetFromRootBlock);
2443 // 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
2446 if (!isRenderBlockFlow() && !isFlexibleBoxIncludingDeprecated()) // FIXME: Make multi-column selection gap filling work someday.
2449 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2450 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2451 lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalHeight();
2452 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2453 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2457 if (childrenInline())
2458 result = toRenderBlockFlow(this)->inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2460 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2462 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2463 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2464 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2465 logicalHeight(), paintInfo));
2469 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2470 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2474 // Go ahead and jump right to the first block child that contains some selected objects.
2476 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2478 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2479 SelectionState childState = curr->selectionState();
2480 if (childState == SelectionBoth || childState == SelectionEnd)
2481 sawSelectionEnd = true;
2483 if (curr->isFloatingOrOutOfFlowPositioned())
2484 continue; // We must be a normal flow object in order to even be considered.
2486 if (curr->isInFlowPositioned() && curr->hasLayer()) {
2487 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2488 // Just disregard it completely.
2489 LayoutSize relOffset = curr->layer()->offsetForInFlowPosition();
2490 if (relOffset.width() || relOffset.height())
2494 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2495 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2496 if (fillBlockGaps) {
2497 // We need to fill the vertical gap above this object.
2498 if (childState == SelectionEnd || childState == SelectionInside)
2499 // Fill the gap above the object.
2500 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2501 curr->logicalTop(), paintInfo));
2503 // 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*
2504 // our object. We know this if the selection did not end inside our object.
2505 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2506 childState = SelectionNone;
2508 // Fill side gaps on this object based off its state.
2509 bool leftGap, rightGap;
2510 getSelectionGapInfo(childState, leftGap, rightGap);
2513 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2515 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2517 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
2518 // they can without bumping into floating or positioned objects. Ideally they will go right up
2519 // to the border of the root selection block.
2520 lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + curr->logicalBottom();
2521 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
2522 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
2523 } else if (childState != SelectionNone)
2524 // We must be a block that has some selected object inside it. Go ahead and recur.
2525 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
2526 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
2531 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2532 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
2534 LayoutUnit logicalTop = lastLogicalTop;
2535 LayoutUnit logicalHeight = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalBottom - logicalTop;
2536 if (logicalHeight <= 0)
2537 return LayoutRect();
2539 // Get the selection offsets for the bottom of the gap
2540 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
2541 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
2542 LayoutUnit logicalWidth = logicalRight - logicalLeft;
2543 if (logicalWidth <= 0)
2544 return LayoutRect();
2546 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
2548 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor());
2552 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2553 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
2555 LayoutUnit rootBlockLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalTop;
2556 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
2557 LayoutUnit rootBlockLogicalRight = min(rootBlock->inlineDirectionOffset(offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2558 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2559 if (rootBlockLogicalWidth <= 0)
2560 return LayoutRect();
2562 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2564 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor());
2568 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2569 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
2571 LayoutUnit rootBlockLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalTop;
2572 LayoutUnit rootBlockLogicalLeft = max(rootBlock->inlineDirectionOffset(offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2573 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
2574 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2575 if (rootBlockLogicalWidth <= 0)
2576 return LayoutRect();
2578 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2580 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor());
2584 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
2586 bool ltr = style()->isLeftToRightDirection();
2587 leftGap = (state == RenderObject::SelectionInside) ||
2588 (state == RenderObject::SelectionEnd && ltr) ||
2589 (state == RenderObject::SelectionStart && !ltr);
2590 rightGap = (state == RenderObject::SelectionInside) ||
2591 (state == RenderObject::SelectionStart && ltr) ||
2592 (state == RenderObject::SelectionEnd && !ltr);
2595 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
2597 // The border can potentially be further extended by our containingBlock().
2598 if (rootBlock != this)
2599 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
2600 return logicalLeftOffsetForContent();
2603 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
2605 // The border can potentially be further extended by our containingBlock().
2606 if (rootBlock != this)
2607 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
2608 return logicalRightOffsetForContent();
2611 RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
2613 if (isSelectionRoot())
2616 const RenderObject* object = this;
2617 RenderObject* sibling;
2619 sibling = object->previousSibling();
2620 while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot()))
2621 sibling = sibling->previousSibling();
2623 offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop());
2624 object = object->parent();
2625 } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot());
2630 RenderBlock* beforeBlock = toRenderBlock(sibling);
2632 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
2634 RenderObject* child = beforeBlock->lastChild();
2635 while (child && child->isRenderBlock()) {
2636 beforeBlock = toRenderBlock(child);
2637 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
2638 child = beforeBlock->lastChild();
2643 void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
2645 if (!descendantsMap) {
2646 descendantsMap = new TrackedDescendantsMap;
2647 containerMap = new TrackedContainerMap;
2650 TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
2651 if (!descendantSet) {
2652 descendantSet = new TrackedRendererListHashSet;
2653 descendantsMap->set(this, adoptPtr(descendantSet));
2655 bool added = descendantSet->add(descendant).isNewEntry;
2657 ASSERT(containerMap->get(descendant));
2658 ASSERT(containerMap->get(descendant)->contains(this));
2662 HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
2663 if (!containerSet) {
2664 containerSet = new HashSet<RenderBlock*>;
2665 containerMap->set(descendant, adoptPtr(containerSet));
2667 ASSERT(!containerSet->contains(this));
2668 containerSet->add(this);
2671 void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
2673 if (!descendantsMap)
2676 OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant);
2680 HashSet<RenderBlock*>::iterator end = containerSet->end();
2681 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
2682 RenderBlock* container = *it;
2684 // FIXME: Disabling this assert temporarily until we fix the layout
2685 // bugs associated with positioned objects not properly cleared from
2686 // their ancestor chain before being moved. See webkit bug 93766.
2687 // ASSERT(descendant->isDescendantOf(container));
2689 TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
2690 ASSERT(descendantsMapIterator != descendantsMap->end());
2691 if (descendantsMapIterator == descendantsMap->end())
2693 TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get();
2694 ASSERT(descendantSet->contains(descendant));
2695 descendantSet->remove(descendant);
2696 if (descendantSet->isEmpty())
2697 descendantsMap->remove(descendantsMapIterator);
2701 TrackedRendererListHashSet* RenderBlock::positionedObjects() const
2703 if (gPositionedDescendantsMap)
2704 return gPositionedDescendantsMap->get(this);
2708 void RenderBlock::insertPositionedObject(RenderBox* o)
2710 ASSERT(!isAnonymousBlock());
2712 if (o->isRenderFlowThread())
2715 insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
2718 void RenderBlock::removePositionedObject(RenderBox* o)
2720 removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
2723 void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState)
2725 TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2726 if (!positionedDescendants)
2731 TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2733 Vector<RenderBox*, 16> deadObjects;
2735 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2737 if (!o || r->isDescendantOf(o)) {
2738 if (containingBlockState == NewContainingBlock)
2739 r->setChildNeedsLayout(MarkOnlyThis);
2741 // It is parent blocks job to add positioned child to positioned objects list of its containing block
2742 // Parent layout needs to be invalidated to ensure this happens.
2743 RenderObject* p = r->parent();
2744 while (p && !p->isRenderBlock())
2747 p->setChildNeedsLayout();
2749 deadObjects.append(r);
2753 for (unsigned i = 0; i < deadObjects.size(); i++)
2754 removePositionedObject(deadObjects.at(i));
2757 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
2759 insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
2762 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
2764 removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
2767 TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const
2769 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
2772 bool RenderBlock::hasPercentHeightContainerMap()
2774 return gPercentHeightContainerMap;
2777 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
2779 // We don't null check gPercentHeightContainerMap since the caller
2780 // already ensures this and we need to call this function on every
2781 // descendant in clearPercentHeightDescendantsFrom().
2782 ASSERT(gPercentHeightContainerMap);
2783 return gPercentHeightContainerMap->contains(descendant);
2786 void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope& layoutScope)
2788 if (!gPercentHeightDescendantsMap)
2791 TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
2795 TrackedRendererListHashSet::iterator end = descendants->end();
2796 for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
2797 RenderBox* box = *it;
2798 while (box != this) {
2799 if (box->normalChildNeedsLayout())
2801 layoutScope.setChildNeedsLayout(box);
2802 box = box->containingBlock();
2810 void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant)
2812 // We query the map directly, rather than looking at style's
2813 // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
2814 // can change with writing mode/directional changes.
2815 if (!hasPercentHeightContainerMap())
2818 if (!hasPercentHeightDescendant(descendant))
2821 removePercentHeightDescendant(descendant);
2824 void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent)
2826 ASSERT(gPercentHeightContainerMap);
2827 for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) {
2831 RenderBox* box = toRenderBox(curr);
2832 if (!hasPercentHeightDescendant(box))
2835 removePercentHeightDescendant(box);
2839 LayoutUnit RenderBlock::textIndentOffset() const
2842 if (style()->textIndent().isPercent())
2843 cw = containingBlock()->availableLogicalWidth();
2844 return minimumValueForLength(style()->textIndent(), cw);
2847 void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2849 if (logicalTop >= logicalBottom)
2852 RootInlineBox* lowestDirtyLine = lastRootBox();
2853 RootInlineBox* afterLowest = lowestDirtyLine;
2854 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2855 afterLowest = lowestDirtyLine;
2856 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2859 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2860 afterLowest->markDirty();
2861 afterLowest = afterLowest->prevRootBox();
2865 bool RenderBlock::avoidsFloats() const
2867 // Floats can't intrude into our box if we have a non-auto column count or width.
2868 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
2871 void RenderBlock::markShapeInsideDescendantsForLayout()
2873 if (!everHadLayout())
2875 if (childrenInline()) {
2879 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
2880 if (!child->isRenderBlock())
2882 RenderBlock* childBlock = toRenderBlock(child);
2883 childBlock->markShapeInsideDescendantsForLayout();
2887 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
2889 if (!scrollsOverflow())
2892 return layer()->scrollableArea()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset)));
2895 Node* RenderBlock::nodeForHitTest() const
2897 // If we are in the margins of block elements that are part of a
2898 // continuation we're actually still inside the enclosing element
2899 // that was split. Use the appropriate inner node.
2900 return isAnonymousBlockContinuation() ? continuation()->node() : node();
2903 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2905 LayoutPoint adjustedLocation(accumulatedOffset + location());
2906 LayoutSize localOffset = toLayoutSize(adjustedLocation);
2908 if (!isRenderView()) {
2909 // Check if we need to do anything at all.
2910 LayoutRect overflowBox = visualOverflowRect();
2911 flipForWritingMode(overflowBox);
2912 overflowBox.moveBy(adjustedLocation);
2913 if (!locationInContainer.intersects(overflowBox))
2917 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)
2918 && visibleToHitTestRequest(request)
2919 && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) {
2920 updateHitTestResult(result, locationInContainer.point() - localOffset);
2921 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
2922 if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer))
2926 // If we have clipping, then we can't have any spillout.
2927 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
2928 bool useClip = (hasControlClip() || useOverflowClip);
2929 bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, IncludeOverlayScrollbarSize)));
2930 if (checkChildren) {
2931 // Hit test descendants first.
2932 LayoutSize scrolledOffset(localOffset);
2933 if (hasOverflowClip())
2934 scrolledOffset -= scrolledContentOffset();
2936 // Hit test contents if we don't have columns.
2937 if (!hasColumns()) {
2938 if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
2939 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
2942 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset)))
2944 } else if (hitTestColumns(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
2945 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
2950 // Check if the point is outside radii.
2951 if (!isRenderView() && style()->hasBorderRadius()) {
2952 LayoutRect borderRect = borderBoxRect();
2953 borderRect.moveBy(adjustedLocation);
2954 RoundedRect border = style()->getRoundedBorderFor(borderRect);
2955 if (!locationInContainer.intersects(border))
2959 // Now hit test our background
2960 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
2961 LayoutRect boundsRect(adjustedLocation, size());
2962 if (visibleToHitTestRequest(request) && locationInContainer.intersects(boundsRect)) {
2963 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
2964 if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer, boundsRect))
2972 class ColumnRectIterator {
2973 WTF_MAKE_NONCOPYABLE(ColumnRectIterator);
2975 ColumnRectIterator(const RenderBlock& block)
2977 , m_colInfo(block.columnInfo())
2978 , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1)
2979 , m_isHorizontal(block.isHorizontalWritingMode())
2980 , m_logicalLeft(block.logicalLeftOffsetForContent())
2982 int colCount = m_colInfo->columnCount();
2983 m_colIndex = colCount - 1;
2984 m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
2995 LayoutRect columnRect() const { return m_colRect; }
2996 bool hasMore() const { return m_colIndex >= 0; }
2998 void adjust(LayoutSize& offset) const
3000 LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
3001 offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
3002 if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
3004 offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
3006 offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
3016 m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
3017 m_block.flipForWritingMode(m_colRect);
3018 m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
3021 const RenderBlock& m_block;
3022 const ColumnInfo* const m_colInfo;
3023 const int m_direction;
3024 const bool m_isHorizontal;
3025 const LayoutUnit m_logicalLeft;
3027 LayoutUnit m_currLogicalTopOffset;
3028 LayoutRect m_colRect;
3031 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3033 // We need to do multiple passes, breaking up our hit testing into strips.
3037 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
3038 LayoutRect hitRect = locationInContainer.boundingBox();
3039 LayoutRect colRect = it.columnRect();
3040 colRect.moveBy(accumulatedOffset);
3041 if (locationInContainer.intersects(colRect)) {
3042 // The point is inside this column.
3043 // Adjust accumulatedOffset to change where we hit test.
3046 LayoutPoint finalLocation = accumulatedOffset + offset;
3047 if (!result.isRectBasedTest() || colRect.contains(hitRect))
3048 return hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, finalLocation));
3050 hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction);
3057 void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const
3059 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
3060 LayoutRect colRect = it.columnRect();
3061 if (colRect.contains(locationInContainer)) {
3068 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3070 if (childrenInline() && !isTable()) {
3071 // We have to hit-test our line boxes.
3072 if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction))
3075 // Hit test our children.
3076 HitTestAction childHitTest = hitTestAction;
3077 if (hitTestAction == HitTestChildBlockBackgrounds)
3078 childHitTest = HitTestChildBlockBackground;
3079 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
3080 LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
3081 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, locationInContainer, childPoint, childHitTest))
3089 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
3094 if (!box->renderer()->nonPseudoNode())
3095 return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset());
3097 if (!box->isInlineTextBox())
3098 return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
3100 InlineTextBox* textBox = toInlineTextBox(box);
3101 return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
3104 static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
3106 ASSERT(!ancestor || ancestor->nonPseudoNode());
3107 ASSERT(child && child->nonPseudoNode());
3108 return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
3109 || ancestor->nonPseudoNode()->rendererIsEditable() == child->nonPseudoNode()->rendererIsEditable();
3112 // FIXME: This function should go on RenderObject as an instance method. Then
3113 // all cases in which positionForPoint recurs could call this instead to
3114 // prevent crossing editable boundaries. This would require many tests.
3115 static PositionWithAffinity positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates)
3117 LayoutPoint childLocation = child->location();
3118 if (child->isInFlowPositioned())
3119 childLocation += child->offsetForInFlowPosition();
3121 // FIXME: This is wrong if the child's writing-mode is different from the parent's.
3122 LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
3124 // If this is an anonymous renderer, we just recur normally
3125 Node* childNode = child->nonPseudoNode();
3127 return child->positionForPoint(pointInChildCoordinates);
3129 // Otherwise, first make sure that the editability of the parent and child agree.
3130 // If they don't agree, then we return a visible position just before or after the child
3131 RenderObject* ancestor = parent;
3132 while (ancestor && !ancestor->nonPseudoNode())
3133 ancestor = ancestor->parent();
3135 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
3136 if (isEditingBoundary(ancestor, child))
3137 return child->positionForPoint(pointInChildCoordinates);
3139 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
3140 LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2;
3141 LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
3142 if (logicalLeft < childMiddle)
3143 return ancestor->createPositionWithAffinity(childNode->nodeIndex(), DOWNSTREAM);
3144 return ancestor->createPositionWithAffinity(childNode->nodeIndex() + 1, UPSTREAM);
3147 PositionWithAffinity RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
3149 ASSERT(childrenInline());
3151 if (!firstRootBox())
3152 return createPositionWithAffinity(0, DOWNSTREAM);
3154 bool linesAreFlipped = style()->isFlippedLinesWritingMode();
3155 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
3157 // look for the closest line box in the root box which is at the passed-in y coordinate
3158 InlineBox* closestBox = 0;
3159 RootInlineBox* firstRootBoxWithChildren = 0;
3160 RootInlineBox* lastRootBoxWithChildren = 0;
3161 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
3162 if (!root->firstLeafChild())
3164 if (!firstRootBoxWithChildren)
3165 firstRootBoxWithChildren = root;
3167 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3168 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3171 lastRootBoxWithChildren = root;
3173 // check if this root line box is located at this y coordinate
3174 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3175 if (linesAreFlipped) {
3176 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3177 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3178 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3180 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3181 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3184 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3190 bool moveCaretToBoundary = document().frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3192 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3193 // y coordinate is below last root line box, pretend we hit it
3194 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3198 if (moveCaretToBoundary) {
3199 LayoutUnit firstRootBoxWithChildrenTop = min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
3200 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3201 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3202 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3203 if (box->isLineBreak()) {
3204 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3207 // y coordinate is above first root line box, so return the start of the first
3208 return PositionWithAffinity(positionForBox(box, true), DOWNSTREAM);
3212 // pass the box a top position that is inside it
3213 LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine());
3214 if (!isHorizontalWritingMode())
3215 point = point.transposedPoint();
3216 if (closestBox->renderer()->isReplaced())
3217 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
3218 return closestBox->renderer()->positionForPoint(point);
3221 if (lastRootBoxWithChildren) {
3222 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3223 ASSERT(moveCaretToBoundary);
3224 InlineBox* logicallyLastBox;
3225 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3226 return PositionWithAffinity(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3229 // Can't reach this. We have a root line box, but it has no kids.
3230 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3231 // seems to hit this code path.
3232 return createPositionWithAffinity(0, DOWNSTREAM);
3235 static inline bool isChildHitTestCandidate(RenderBox* box)
3237 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned();
3240 PositionWithAffinity RenderBlock::positionForPoint(const LayoutPoint& point)
3243 return RenderBox::positionForPoint(point);
3246 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
3247 LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
3248 LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
3250 if (pointLogicalLeft < 0)
3251 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
3252 if (pointLogicalLeft >= logicalWidth())
3253 return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM);
3254 if (pointLogicalTop < 0)
3255 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
3256 if (pointLogicalTop >= logicalHeight())
3257 return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM);
3260 LayoutPoint pointInContents = point;
3261 offsetForContents(pointInContents);
3262 LayoutPoint pointInLogicalContents(pointInContents);
3263 if (!isHorizontalWritingMode())
3264 pointInLogicalContents = pointInLogicalContents.transposedPoint();
3266 if (childrenInline())
3267 return positionForPointWithInlineChildren(pointInLogicalContents);
3269 RenderBox* lastCandidateBox = lastChildBox();
3270 while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
3271 lastCandidateBox = lastCandidateBox->previousSiblingBox();
3273 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
3274 if (lastCandidateBox) {
3275 if (pointInLogicalContents.y() > logicalTopForChild(lastCandidateBox)
3276 || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(lastCandidateBox)))
3277 return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
3279 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
3280 if (!isChildHitTestCandidate(childBox))
3282 LayoutUnit childLogicalBottom = logicalTopForChild(childBox) + logicalHeightForChild(childBox);
3283 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
3284 if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
3285 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
3286 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
3290 // We only get here if there are no hit test candidate children below the click.
3291 return RenderBox::positionForPoint(point);
3294 void RenderBlock::offsetForContents(LayoutPoint& offset) const
3296 offset = flipForWritingMode(offset);
3298 if (hasOverflowClip())
3299 offset += scrolledContentOffset();
3302 adjustPointToColumnContents(offset);
3304 offset = flipForWritingMode(offset);
3307 LayoutUnit RenderBlock::availableLogicalWidth() const
3309 // If we have multiple columns, then the available logical width is reduced to our column width.
3311 return desiredColumnWidth();
3312 return RenderBox::availableLogicalWidth();
3315 int RenderBlock::columnGap() const
3317 if (style()->hasNormalColumnGap())
3318 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
3319 return static_cast<int>(style()->columnGap());
3322 void RenderBlock::calcColumnWidth()
3324 if (document().regionBasedColumnsEnabled())
3327 // Calculate our column width and column count.
3328 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
3329 unsigned desiredColumnCount = 1;
3330 LayoutUnit desiredColumnWidth = contentLogicalWidth();
3332 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
3333 if (document().paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) {
3334 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3338 LayoutUnit availWidth = desiredColumnWidth;
3339 LayoutUnit colGap = columnGap();
3340 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
3341 int colCount = max<int>(1, style()->columnCount());
3343 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
3344 desiredColumnCount = colCount;
3345 desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
3346 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
3347 desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
3348 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
3350 desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
3351 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
3353 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3356 bool RenderBlock::requiresColumns(int desiredColumnCount) const
3358 // Paged overflow is treated as multicol here, unless this element was the one that got its
3359 // overflow propagated to the viewport.
3360 bool isPaginated = style()->isOverflowPaged() && node() != document().viewportDefiningElement();
3363 && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated)
3364 && !firstChild()->isAnonymousColumnsBlock()
3365 && !firstChild()->isAnonymousColumnSpanBlock();
3368 void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
3370 bool destroyColumns = !requiresColumns(count);
3371 if (destroyColumns) {
3373 gColumnInfoMap->take(this);
3374 setHasColumns(false);
3379 info = gColumnInfoMap->get(this);
3381 if (!gColumnInfoMap)
3382 gColumnInfoMap = new ColumnInfoMap;
3383 info = new ColumnInfo;
3384 gColumnInfoMap->add(this, adoptPtr(info));
3385 setHasColumns(true);
3387 info->setDesiredColumnWidth(width);
3388 if (style()->isOverflowPaged()) {
3389 info->setProgressionAxis(style()->hasInlinePaginationAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
3391 info->setDesiredColumnCount(count);
3392 info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
3393 info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
3398 LayoutUnit RenderBlock::desiredColumnWidth() const
3401 return contentLogicalWidth();
3402 return gColumnInfoMap->get(this)->desiredColumnWidth();
3405 ColumnInfo* RenderBlock::columnInfo() const
3409 return gColumnInfoMap->get(this);
3412 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
3414 ASSERT(hasColumns());
3415 ASSERT(gColumnInfoMap->get(this) == colInfo);
3416 return colInfo->columnCount();
3419 LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
3421 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
3423 // Compute the appropriate rect based off our information.
3424 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
3425 LayoutUnit colLogicalHeight = colInfo->columnHeight();
3426 LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
3427 LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
3428 LayoutUnit colGap = columnGap();
3429 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3430 if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
3431 colLogicalLeft += index * (colLogicalWidth + colGap);
3433 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
3435 if (!colInfo->progressionIsReversed())
3436 colLogicalTop += index * (colLogicalHeight + colGap);
3438 colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap);
3441 if (isHorizontalWritingMode())
3442 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
3443 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
3446 void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
3448 // Just bail if we have no columns.
3452 ColumnInfo* colInfo = columnInfo();
3453 if (!columnCount(colInfo))
3456 // Determine which columns we intersect.
3457 LayoutUnit colGap = columnGap();
3458 LayoutUnit halfColGap = colGap / 2;
3459 LayoutPoint columnPoint(columnRectAt(colInfo, 0).location());
3460 LayoutUnit logicalOffset = 0;
3461 for (unsigned i = 0; i < colInfo->columnCount(); i++) {
3462 // Add in half the column gap to the left and right of the rect.
3463 LayoutRect colRect = columnRectAt(colInfo, i);
3464 flipForWritingMode(colRect);
3465 if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) {
3466 LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
3467 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
3468 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3469 // FIXME: The clamping that follows is not completely right for right-to-left
3471 // Clamp everything above the column to its top left.
3472 if (point.y() < gapAndColumnRect.y())
3473 point = gapAndColumnRect.location();
3474 // Clamp everything below the column to the next column's top left. If there is
3475 // no next column, this still maps to just after this column.
3476 else if (point.y() >= gapAndColumnRect.maxY()) {
3477 point = gapAndColumnRect.location();
3478 point.move(0, gapAndColumnRect.height());
3481 if (point.x() < colRect.x())
3482 point.setX(colRect.x());
3483 else if (point.x() >= colRect.maxX())
3484 point.setX(colRect.maxX() - 1);
3487 // We're inside the column. Translate the x and y into our column coordinate space.
3488 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3489 point.move(columnPoint.x() - colRect.x(), (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset));
3491 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0);
3495 // Move to the next position.
3496 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width();
3498 LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
3499 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
3500 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3501 // FIXME: The clamping that follows is not completely right for right-to-left
3503 // Clamp everything above the column to its top left.
3504 if (point.x() < gapAndColumnRect.x())
3505 point = gapAndColumnRect.location();
3506 // Clamp everything below the column to the next column's top left. If there is
3507 // no next column, this still maps to just after this column.
3508 else if (point.x() >= gapAndColumnRect.maxX()) {
3509 point = gapAndColumnRect.location();
3510 point.move(gapAndColumnRect.width(), 0);
3513 if (point.y() < colRect.y())
3514 point.setY(colRect.y());
3515 else if (point.y() >= colRect.maxY())
3516 point.setY(colRect.maxY() - 1);
3519 // We're inside the column. Translate the x and y into our column coordinate space.
3520 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3521 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset), columnPoint.y() - colRect.y());
3523 point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop());
3527 // Move to the next position.
3528 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height();
3533 void RenderBlock::adjustRectForColumns(LayoutRect& r) const
3535 // Just bail if we have no columns.
3539 ColumnInfo* colInfo = columnInfo();
3541 // Determine which columns we intersect.
3542 unsigned colCount = columnCount(colInfo);
3546 // Begin with a result rect that is empty.
3549 bool isHorizontal = isHorizontalWritingMode();
3550 LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
3551 LayoutUnit colHeight = colInfo->columnHeight();
3555 LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
3556 LayoutUnit endOffset = max(min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding);
3558 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
3559 unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
3560 unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight;
3562 if (startColumn == endColumn) {
3563 // The rect is fully contained within one column. Adjust for our offsets
3564 // and repaint only that portion.
3565 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent();
3566 LayoutRect colRect = columnRectAt(colInfo, startColumn);
3567 LayoutRect repaintRect = r;
3569 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3571 repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight);
3573 repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset);
3576 repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding);
3578 repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0);
3580 repaintRect.intersect(colRect);
3581 result.unite(repaintRect);
3583 // We span multiple columns. We can just unite the start and end column to get the final
3585 result.unite(columnRectAt(colInfo, startColumn));
3586 result.unite(columnRectAt(colInfo, endColumn));
3592 LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
3594 ASSERT(hasColumns());
3595 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3597 ColumnInfo* colInfo = columnInfo();
3598 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
3599 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
3600 if (isHorizontalWritingMode())
3601 return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
3602 return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
3605 void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const
3607 ASSERT(hasColumns());
3608 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3611 ColumnInfo* colInfo = columnInfo();
3612 LayoutUnit columnLogicalHeight = colInfo->columnHeight();
3613 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
3615 if (isHorizontalWritingMode())
3616 rect.setY(expandedLogicalHeight - rect.maxY());
3618 rect.setX(expandedLogicalHeight - rect.maxX());
3621 void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const
3626 ColumnInfo* colInfo = columnInfo();
3628 LayoutUnit logicalLeft = logicalLeftOffsetForContent();
3629 unsigned colCount = columnCount(colInfo);
3630 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
3631 LayoutUnit colLogicalHeight = colInfo->columnHeight();
3633 for (unsigned i = 0; i < colCount; ++i) {
3634 // Compute the edges for a given column in the block progression direction.
3635 LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
3636 if (!isHorizontalWritingMode())
3637 sliceRect = sliceRect.transposedRect();
3639 LayoutUnit logicalOffset = i * colLogicalHeight;
3641 // Now we're in the same coordinate space as the point. See if it is inside the rectangle.
3642 if (isHorizontalWritingMode()) {
3643 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
3644 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3645 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
3647 offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
3651 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
3652 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3653 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
3655 offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
3662 void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3664 if (childrenInline()) {
3665 // FIXME: Remove this const_cast.
3666 const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
3668 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
3670 maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
3672 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
3674 // A horizontal marquee with inline children has no minimum width.
3675 if (childrenInline() && isMarquee() && toRenderMarquee(this)->isHorizontal())
3676 minLogicalWidth = 0;
3678 if (isTableCell()) {
3679 Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth();
3680 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
3681 maxLogicalWidth = max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
3684 int scrollbarWidth = instrinsicScrollbarLogicalWidth();
3685 maxLogicalWidth += scrollbarWidth;
3686 minLogicalWidth += scrollbarWidth;
3689 void RenderBlock::computePreferredLogicalWidths()
3691 ASSERT(preferredLogicalWidthsDirty());
3693 updateFirstLetter();
3695 m_minPreferredLogicalWidth = 0;
3696 m_maxPreferredLogicalWidth = 0;
3698 // FIXME: The isFixed() calls here should probably be checking for isSpecified since you
3699 // should be able to use percentage, calc or viewport relative values for width.
3700 RenderStyle* styleToUse = style();
3701 if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
3702 && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
3703 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
3705 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
3707 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
3708 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
3709 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
3712 if (styleToUse->logicalMaxWidth().isFixed()) {
3713 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
3714 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
3717 // Table layout uses integers, ceil the preferred widths to ensure that they can contain the contents.
3718 if (isTableCell()) {
3719 m_minPreferredLogicalWidth = m_minPreferredLogicalWidth.ceil();
3720 m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil();
3723 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
3724 m_minPreferredLogicalWidth += borderAndPadding;
3725 m_maxPreferredLogicalWidth += borderAndPadding;
3727 clearPreferredLogicalWidthsDirty();
3730 void RenderBlock::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3732 // FIXME: make this method virtual and move the code to RenderMultiColumnBlock once the old
3733 // multicol code is gone.
3735 if (!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()) {
3736 // The min/max intrinsic widths calculated really tell how much space elements need when
3737 // laid out inside the columns. In order to eventually end up with the desired column width,
3738 // we need to convert them to values pertaining to the multicol container.
3739 int columnCount = style()->hasAutoColumnCount() ? 1 : style()->columnCount();
3740 LayoutUnit columnWidth;
3741 LayoutUnit gapExtra = (columnCount - 1) * columnGap();
3742 if (style()->hasAutoColumnWidth()) {
3743 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
3745 columnWidth = style()->columnWidth();
3746 minLogicalWidth = min(minLogicalWidth, columnWidth);
3748 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
3749 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
3750 // performing a layout pass, but this is not an appropriate time or place for layout. The
3751 // good news is that if height is unconstrained and there are no explicit breaks, the
3752 // resolved column-count really should be 1.
3753 maxLogicalWidth = max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
3757 struct InlineMinMaxIterator {
3758 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3759 inline min/max width calculations. Note the following about the way it walks:
3760 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3761 (2) We do not drill into the children of floats or replaced elements, since you can't break
3762 in the middle of such an element.
3763 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3764 distinct borders/margin/padding that contribute to the min/max width.
3766 RenderObject* parent;
3767 RenderObject* current;
3770 InlineMinMaxIterator(RenderObject* p, bool end = false)
3771 :parent(p), current(p), endOfInline(end) {}
3773 RenderObject* next();
3776 RenderObject* InlineMinMaxIterator::next()
3778 RenderObject* result = 0;
3779 bool oldEndOfInline = endOfInline;
3780 endOfInline = false;
3781 while (current || current == parent) {
3782 if (!oldEndOfInline &&
3783 (current == parent ||
3784 (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
3785 result = current->firstChild();
3787 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3788 if (!oldEndOfInline && current->isRenderInline()) {
3794 while (current && current != parent) {
3795 result = current->nextSibling();
3797 current = current->parent();
3798 if (current && current != parent && current->isRenderInline()) {
3809 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3816 // Update our position.
3821 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3823 if (cssUnit.type() != Auto)
3824 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
3828 static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
3830 RenderStyle* childStyle = child->style();
3832 return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
3833 getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
3835 return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
3836 getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
3837 child->borderStart();
3840 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
3841 RenderObject* trailingSpaceChild)
3843 if (trailingSpaceChild && trailingSpaceChild->isText()) {
3844 // Collapse away the trailing space at the end of a block.
3845 RenderText* t = toRenderText(trailingSpaceChild);
3846 const UChar space = ' ';
3847 const Font& font = t->style()->font(); // FIXME: This ignores first-line.
3848 float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style(), LTR));
3849 inlineMax -= spaceWidth + font.fontDescription().wordSpacing();
3850 if (inlineMin > inlineMax)
3851 inlineMin = inlineMax;
3855 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
3857 LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result);
3858 preferredWidth = max(snappedResult, preferredWidth);
3861 // When converting between floating point and LayoutUnits we risk losing precision
3862 // with each conversion. When this occurs while accumulating our preferred widths,
3863 // we can wind up with a line width that's larger than our maxPreferredWidth due to
3864 // pure float accumulation.
3865 static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
3867 return LayoutUnit::fromFloatCeil(value);
3871 void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
3873 float inlineMax = 0;
3874 float inlineMin = 0;
3876 RenderStyle* styleToUse = style();
3877 RenderBlock* containingBlock = this->containingBlock();
3878 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
3880 // If we are at the start of a line, we want to ignore all white-space.
3881 // Also strip spaces if we previously had text that ended in a trailing space.
3882 bool stripFrontSpaces = true;
3883 RenderObject* trailingSpaceChild = 0;
3885 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
3886 // very specific cirucumstances (in order to match common WinIE renderings).
3887 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
3888 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto();
3890 bool autoWrap, oldAutoWrap;
3891 autoWrap = oldAutoWrap = styleToUse->autoWrap();
3893 InlineMinMaxIterator childIterator(this);
3895 // Only gets added to the max preffered width once.
3896 bool addedTextIndent = false;
3897 // Signals the text indent was more negative than the min preferred width
3898 bool hasRemainingNegativeTextIndent = false;
3900 LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw);
3901 RenderObject* prevFloat = 0;
3902 bool isPrevChildInlineFlow = false;
3903 bool shouldBreakLineAfterText = false;
3904 while (RenderObject* child = childIterator.next()) {
3905 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
3906 child->style()->autoWrap();
3908 if (!child->isBR()) {
3909 // Step One: determine whether or not we need to go ahead and
3910 // terminate our current line. Each discrete chunk can become
3911 // the new min-width, if it is the widest chunk seen so far, and
3912 // it can also become the max-width.
3914 // Children fall into three categories:
3915 // (1) An inline flow object. These objects always have a min/max of 0,
3916 // and are included in the iteration solely so that their margins can
3919 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
3920 // These objects can always be on a line by themselves, so in this situation
3921 // we need to go ahead and break the current line, and then add in our own
3922 // margins and min/max width on its own line, and then terminate the line.
3924 // (3) A text object. Text runs can have breakable characters at the start,
3925 // the middle or the end. They may also lose whitespace off the front if
3926 // we're already ignoring whitespace. In order to compute accurate min-width
3927 // information, we need three pieces of information.
3928 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
3929 // starts with whitespace.
3930 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
3931 // ends with whitespace.
3932 // (c) the min/max width of the string (trimmed for whitespace).
3934 // If the text string starts with whitespace, then we need to go ahead and
3935 // terminate our current line (unless we're already in a whitespace stripping
3938 // If the text string has a breakable character in the middle, but didn't start
3939 // with whitespace, then we add the width of the first non-breakable run and
3940 // then end the current line. We then need to use the intermediate min/max width
3941 // values (if any of them are larger than our current min/max). We then look at
3942 // the width of the last non-breakable run and use that to start a new line
3943 // (unless we end in whitespace).
3944 RenderStyle* childStyle = child->style();
3948 if (!child->isText()) {
3949 // Case (1) and (2). Inline replaced and inline flow elements.
3950 if (child->isRenderInline()) {
3951 // Add in padding/border/margin from the appropriate side of
3953 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
3957 inlineMin += childMin;
3958 inlineMax += childMax;
3960 child->clearPreferredLogicalWidthsDirty();
3962 // Inline replaced elts add in their margins to their min/max values.
3963 LayoutUnit margins = 0;
3964 Length startMargin = childStyle->marginStart();
3965 Length endMargin = childStyle->marginEnd();
3966 if (startMargin.isFixed())
3967 margins += adjustFloatForSubPixelLayout(startMargin.value());
3968 if (endMargin.isFixed())
3969 margins += adjustFloatForSubPixelLayout(endMargin.value());
3970 childMin += margins.ceilToFloat();
3971 childMax += margins.ceilToFloat();
3975 if (!child->isRenderInline() && !child->isText()) {
3976 // Case (2). Inline replaced elements and floats.
3977 // Go ahead and terminate the current line as far as
3978 // minwidth is concerned.
3979 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
3980 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
3981 RenderBox* childBox = toRenderBox(child);
3982 LogicalExtentComputedValues computedValues;
3983 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
3984 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
3986 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
3987 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
3989 childMin += childMinPreferredLogicalWidth.ceilToFloat();
3990 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
3992 bool clearPreviousFloat;
3993 if (child->isFloating()) {
3994 clearPreviousFloat = (prevFloat
3995 && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT))
3996 || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT))));
3999 clearPreviousFloat = false;
4001 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4002 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
4003 updatePreferredWidth(minLogicalWidth, inlineMin);
4007 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4008 if (clearPreviousFloat) {
4009 updatePreferredWidth(maxLogicalWidth, inlineMax);
4013 // Add in text-indent. This is added in only once.
4014 if (!addedTextIndent && !child->isFloating()) {
4015 float ceiledTextIndent = textIndent.ceilToFloat();
4016 childMin += ceiledTextIndent;
4017 childMax += ceiledTextIndent;
4020 textIndent = adjustFloatForSubPixelLayout(childMin);
4022 addedTextIndent = true;
4025 // Add our width to the max.
4026 inlineMax += max<float>(0, childMax);
4028 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
4029 if (child->isFloating())
4030 updatePreferredWidth(minLogicalWidth, childMin);
4032 inlineMin += childMin;
4034 // Now check our line.
4035 updatePreferredWidth(minLogicalWidth, childMin);
4037 // Now start a new line.
4041 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4042 updatePreferredWidth(minLogicalWidth, inlineMin);
4046 // We are no longer stripping whitespace at the start of
4048 if (!child->isFloating()) {
4049 stripFrontSpaces = false;
4050 trailingSpaceChild = 0;
4052 } else if (child->isText()) {
4054 RenderText* t = toRenderText(child);
4056 if (t->isWordBreak()) {
4057 updatePreferredWidth(minLogicalWidth, inlineMin);
4062 if (t->style()->hasTextCombine() && t->isCombineText())
4063 toRenderCombineText(t)->combineText();
4065 // Determine if we have a breakable character. Pass in
4066 // whether or not we should ignore any spaces at the front
4067 // of the string. If those are going to be stripped out,
4068 // then they shouldn't be considered in the breakable char
4070 bool hasBreakableChar, hasBreak;
4071 float firstLineMinWidth, lastLineMinWidth;
4072 bool hasBreakableStart, hasBreakableEnd;
4073 float firstLineMaxWidth, lastLineMaxWidth;
4074 t->trimmedPrefWidths(inlineMax,
4075 firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd,
4076 hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
4077 childMin, childMax, stripFrontSpaces, styleToUse->direction());
4079 // This text object will not be rendered, but it may still provide a breaking opportunity.
4080 if (!hasBreak && childMax == 0) {
4081 if (autoWrap && (hasBreakableStart || hasBreakableEnd)) {
4082 updatePreferredWidth(minLogicalWidth, inlineMin);
4088 if (stripFrontSpaces)
4089 trailingSpaceChild = child;
4091 trailingSpaceChild = 0;
4093 // Add in text-indent. This is added in only once.
4095 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4096 ti = textIndent.ceilToFloat();
4098 firstLineMinWidth += ti;
4100 // It the text indent negative and larger than the child minimum, we re-use the remainder
4101 // in future minimum calculations, but using the negative value again on the maximum
4102 // will lead to under-counting the max pref width.
4103 if (!addedTextIndent) {
4105 firstLineMaxWidth += ti;
4106 addedTextIndent = true;
4110 textIndent = childMin;
4111 hasRemainingNegativeTextIndent = true;
4115 // If we have no breakable characters at all,
4116 // then this is the easy case. We add ourselves to the current
4117 // min and max and continue.
4118 if (!hasBreakableChar) {
4119 inlineMin += childMin;
4121 if (hasBreakableStart) {
4122 updatePreferredWidth(minLogicalWidth, inlineMin);
4124 inlineMin += firstLineMinWidth;
4125 updatePreferredWidth(minLogicalWidth, inlineMin);
4129 inlineMin = childMin;
4131 if (hasBreakableEnd) {
4132 updatePreferredWidth(minLogicalWidth, inlineMin);
4134 shouldBreakLineAfterText = false;
4136 updatePreferredWidth(minLogicalWidth, inlineMin);
4137 inlineMin = lastLineMinWidth;
4138 shouldBreakLineAfterText = true;
4143 inlineMax += firstLineMaxWidth;
4144 updatePreferredWidth(maxLogicalWidth, inlineMax);
4145 updatePreferredWidth(maxLogicalWidth, childMax);
4146 inlineMax = lastLineMaxWidth;
4147 addedTextIndent = true;
4149 inlineMax += max<float>(0, childMax);
4153 // Ignore spaces after a list marker.
4154 if (child->isListMarker())
4155 stripFrontSpaces = true;
4157 updatePreferredWidth(minLogicalWidth, inlineMin);
4158 updatePreferredWidth(maxLogicalWidth, inlineMax);
4159 inlineMin = inlineMax = 0;
4160 stripFrontSpaces = true;
4161 trailingSpaceChild = 0;
4162 addedTextIndent = true;
4165 if (!child->isText() && child->isRenderInline())
4166 isPrevChildInlineFlow = true;
4168 isPrevChildInlineFlow = false;
4170 oldAutoWrap = autoWrap;
4173 if (styleToUse->collapseWhiteSpace())
4174 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4176 updatePreferredWidth(minLogicalWidth, inlineMin);
4177 updatePreferredWidth(maxLogicalWidth, inlineMax);
4180 void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4182 RenderStyle* styleToUse = style();
4183 bool nowrap = styleToUse->whiteSpace() == NOWRAP;
4185 RenderObject* child = firstChild();
4186 RenderBlock* containingBlock = this->containingBlock();
4187 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
4189 // Positioned children don't affect the min/max width
4190 if (child->isOutOfFlowPositioned()) {
4191 child = child->nextSibling();
4195 RenderStyle* childStyle = child->style();
4196 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
4197 LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
4198 if (childStyle->clear() & CLEFT) {
4199 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
4202 if (childStyle->clear() & CRIGHT) {
4203 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
4204 floatRightWidth = 0;
4208 // A margin basically has three types: fixed, percentage, and auto (variable).
4209 // Auto and percentage margins simply become 0 when computing min/max width.
4210 // Fixed margins can be added in as is.
4211 Length startMarginLength = childStyle->marginStartUsing(styleToUse);
4212 Length endMarginLength = childStyle->marginEndUsing(styleToUse);
4213 LayoutUnit margin = 0;
4214 LayoutUnit marginStart = 0;
4215 LayoutUnit marginEnd = 0;
4216 if (startMarginLength.isFixed())
4217 marginStart += startMarginLength.value();
4218 if (endMarginLength.isFixed())
4219 marginEnd += endMarginLength.value();
4220 margin = marginStart + marginEnd;
4222 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4223 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
4224 RenderBox* childBox = toRenderBox(child);
4225 LogicalExtentComputedValues computedValues;
4226 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
4227 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
4229 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
4230 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
4233 LayoutUnit w = childMinPreferredLogicalWidth + margin;
4234 minLogicalWidth = max(w, minLogicalWidth);
4236 // IE ignores tables for calculation of nowrap. Makes some sense.
4237 if (nowrap && !child->isTable())
4238 maxLogicalWidth = max(w, maxLogicalWidth);
4240 w = childMaxPreferredLogicalWidth + margin;
4242 if (!child->isFloating()) {
4243 if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
4244 // Determine a left and right max value based off whether or not the floats can fit in the
4245 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
4246 // is smaller than the float width.
4247 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse->isLeftToRightDirection();
4248 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
4249 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
4250 LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
4251 LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
4252 w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
4253 w = max(w, floatLeftWidth + floatRightWidth);
4256 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
4257 floatLeftWidth = floatRightWidth = 0;
4260 if (child->isFloating()) {
4261 if (childStyle->floating() == LeftFloat)
4262 floatLeftWidth += w;
4264 floatRightWidth += w;
4266 maxLogicalWidth = max(w, maxLogicalWidth);
4268 child = child->nextSibling();
4271 // Always make sure these values are non-negative.
4272 minLogicalWidth = max<LayoutUnit>(0, minLogicalWidth);
4273 maxLogicalWidth = max<LayoutUnit>(0, maxLogicalWidth);
4275 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
4278 bool RenderBlock::hasLineIfEmpty() const
4283 if (node()->isRootEditableElement())
4286 if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
4292 LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
4294 // Inline blocks are replaced elements. Otherwise, just pass off to
4295 // the base class. If we're being queried as though we're the root line
4296 // box, then the fact that we're an inline-block is irrelevant, and we behave
4297 // just like a block.
4298 if (isReplaced() && linePositionMode == PositionOnContainingLine)
4299 return RenderBox::lineHeight(firstLine, direction, linePositionMode);
4301 if (firstLine && document().styleEngine()->usesFirstLineRules()) {
4302 RenderStyle* s = style(firstLine);
4304 return s->computedLineHeight();
4307 if (m_lineHeight == -1)
4308 m_lineHeight = style()->computedLineHeight();
4310 return m_lineHeight;
4313 int RenderBlock::beforeMarginInLineDirection(LineDirectionMode direction) const
4315 return direction == HorizontalLine ? marginTop() : marginRight();
4318 int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
4320 // Inline blocks are replaced elements. Otherwise, just pass off to
4321 // the base class. If we're being queried as though we're the root line
4322 // box, then the fact that we're an inline-block is irrelevant, and we behave
4323 // just like a block.
4324 if (isInline() && linePositionMode == PositionOnContainingLine) {
4325 // For "leaf" theme objects, let the theme decide what the baseline position is.
4326 // FIXME: Might be better to have a custom CSS property instead, so that if the theme
4327 // is turned off, checkboxes/radios will still have decent baselines.
4328 // FIXME: Need to patch form controls to deal with vertical lines.
4329 if (style()->hasAppearance() && !RenderTheme::theme().isControlContainer(style()->appearance()))
4330 return RenderTheme::theme().baselinePosition(this);
4332 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
4333 // the normal flow. We make an exception for marquees, since their baselines are meaningless
4334 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
4335 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
4336 // vertically (e.g., an overflow:hidden block that has had scrollTop moved).
4337 bool ignoreBaseline = (layer() && layer()->scrollableArea() && (isMarquee() || (direction == HorizontalLine ? (layer()->scrollableArea()->verticalScrollbar() || layer()->scrollableArea()->scrollYOffset())
4338 : (layer()->scrollableArea()->horizontalScrollbar() || layer()->scrollableArea()->scrollXOffset())))) || (isWritingModeRoot() && !isRubyRun());
4340 int baselinePos = ignoreBaseline ? -1 : inlineBlockBaseline(direction);
4342 if (isDeprecatedFlexibleBox()) {
4343 // Historically, we did this check for all baselines. But we can't
4344 // remove this code from deprecated flexbox, because it effectively
4345 // breaks -webkit-line-clamp, which is used in the wild -- we would
4346 // calculate the baseline as if -webkit-line-clamp wasn't used.
4347 // For simplicity, we use this for all uses of deprecated flexbox.
4348 LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
4349 if (baselinePos > bottomOfContent)
4352 if (baselinePos != -1)
4353 return beforeMarginInLineDirection(direction) + baselinePos;
4355 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
4358 // If we're not replaced, we'll only get called with PositionOfInteriorLineBoxes.
4359 // Note that inline-block counts as replaced here.
4360 ASSERT(linePositionMode == PositionOfInteriorLineBoxes);
4362 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
4363 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
4366 LayoutUnit RenderBlock::minLineHeightForReplacedRenderer(bool isFirstLine, LayoutUnit replacedHeight) const
4368 if (!document().inNoQuirksMode() && replacedHeight)
4369 return replacedHeight;
4371 if (!(style(isFirstLine)->lineBoxContain() & LineBoxContainBlock))
4374 return std::max<LayoutUnit>(replacedHeight, lineHeight(isFirstLine, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
4377 int RenderBlock::firstLineBoxBaseline() const
4379 if (isWritingModeRoot() && !isRubyRun())
4382 if (childrenInline()) {
4384 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
4389 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
4390 if (!curr->isFloatingOrOutOfFlowPositioned()) {
4391 int result = curr->firstLineBoxBaseline();
4393 return curr->logicalTop() + result; // Translate to our coordinate space.
4401 int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const
4403 if (!style()->isOverflowVisible()) {
4404 // We are not calling RenderBox::baselinePosition here because the caller should add the margin-top/margin-right, not us.
4405 return direction == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
4408 return lastLineBoxBaseline(direction);
4411 int RenderBlock::lastLineBoxBaseline(LineDirectionMode lineDirection) const
4413 if (isWritingModeRoot() && !isRubyRun())
4416 if (childrenInline()) {
4417 if (!firstLineBox() && hasLineIfEmpty()) {
4418 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
4419 return fontMetrics.ascent()
4420 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
4421 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
4424 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
4427 bool haveNormalFlowChild = false;
4428 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
4429 if (!curr->isFloatingOrOutOfFlowPositioned()) {
4430 haveNormalFlowChild = true;
4431 int result = curr->inlineBlockBaseline(lineDirection);
4433 return curr->logicalTop() + result; // Translate to our coordinate space.
4436 if (!haveNormalFlowChild && hasLineIfEmpty()) {
4437 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
4438 return fontMetrics.ascent()
4439 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
4440 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
4447 RenderBlock* RenderBlock::firstLineBlock() const
4449 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
4450 bool hasPseudo = false;
4452 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
4455 RenderObject* parentBlock = firstLineBlock->parent();
4456 // We include isRenderButton in this check because buttons are
4457 // implemented using flex box but should still support first-line. The
4458 // flex box spec requires that flex box does not support first-line,
4460 // FIXME: Remove when buttons are implemented with align-items instead
4462 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating()
4463 || !parentBlock || parentBlock->firstChild() != firstLineBlock
4464 || (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton()))
4466 ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock());
4467 firstLineBlock = toRenderBlock(parentBlock);
4473 return firstLineBlock;
4476 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
4478 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
4479 // Force inline display (except for floating first-letters).
4480 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
4481 // CSS2 says first-letter can't be positioned.
4482 pseudoStyle->setPosition(StaticPosition);
4486 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
4487 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
4488 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
4489 static inline bool isPunctuationForFirstLetter(UChar c)
4491 CharCategory charCategory = category(c);
4492 return charCategory == Punctuation_Open
4493 || charCategory == Punctuation_Close
4494 || charCategory == Punctuation_InitialQuote
4495 || charCategory == Punctuation_FinalQuote
4496 || charCategory == Punctuation_Other;
4499 static inline bool shouldSkipForFirstLetter(UChar c)
4501 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
4504 static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
4506 RenderObject* firstLetterBlock = start;
4508 // We include isRenderButton in these two checks because buttons are
4509 // implemented using flex box but should still support first-letter.
4510 // The flex box spec requires that flex box does not support
4511 // first-letter, though.
4512 // FIXME: Remove when buttons are implemented with align-items instead
4514 bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
4515 && firstLetterBlock->canHaveGeneratedChildren()
4516 && (!firstLetterBlock->isFlexibleBox() || firstLetterBlock->isRenderButton());
4517 if (canHaveFirstLetterRenderer)
4518 return firstLetterBlock;
4520 RenderObject* parentBlock = firstLetterBlock->parent();
4521 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
4522 (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton()))
4524 firstLetterBlock = parentBlock;
4530 void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild)
4532 RenderObject* firstLetter = currentChild->parent();
4533 RenderObject* firstLetterContainer = firstLetter->parent();
4534 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
4535 ASSERT(firstLetter->isFloating() || firstLetter->isInline());
4537 if (RenderStyle::compare(firstLetter->style(), pseudoStyle) == Reattach) {
4538 // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
4539 RenderBoxModelObject* newFirstLetter;
4540 if (pseudoStyle->display() == INLINE)
4541 newFirstLetter = RenderInline::createAnonymous(&document());
4543 newFirstLetter = RenderBlockFlow::createAnonymous(&document());
4544 newFirstLetter->setStyle(pseudoStyle);
4546 // Move the first letter into the new renderer.
4547 LayoutStateDisabler layoutStateDisabler(view());
4548 while (RenderObject* child = firstLetter->firstChild()) {
4549 if (child->isText())
4550 toRenderText(child)->removeAndDestroyTextBoxes();
4551 firstLetter->removeChild(child);
4552 newFirstLetter->addChild(child, 0);
4555 RenderObject* nextSibling = firstLetter->nextSibling();
4556 if (RenderTextFragment* remainingText = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText()) {
4557 ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText);
4558 // Replace the old renderer with the new one.
4559 remainingText->setFirstLetter(newFirstLetter);
4560 newFirstLetter->setFirstLetterRemainingText(remainingText);
4562 // To prevent removal of single anonymous block in RenderBlock::removeChild and causing
4563 // |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
4564 firstLetterContainer->virtualChildren()->removeChildNode(firstLetterContainer, firstLetter);
4565 firstLetter->destroy();
4566 firstLetter = newFirstLetter;
4567 firstLetterContainer->addChild(firstLetter, nextSibling);
4569 firstLetter->setStyle(pseudoStyle);
4571 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
4572 if (genChild->isText())
4573 genChild->setStyle(pseudoStyle);
4577 static inline unsigned firstLetterLength(const String& text)
4579 unsigned length = 0;
4581 // Account for leading spaces and punctuation.
4582 while (length < text.length() && shouldSkipForFirstLetter((text)[length]))
4585 // Bail if we didn't find a letter
4586 if (text.length() && length == text.length())
4589 // Account for first letter.
4592 // Keep looking for whitespace and allowed punctuation, but avoid
4593 // accumulating just whitespace into the :first-letter.
4594 for (unsigned scanLength = length; scanLength < text.length(); ++scanLength) {
4595 UChar c = (text)[scanLength];
4597 if (!shouldSkipForFirstLetter(c))
4600 if (isPunctuationForFirstLetter(c))
4601 length = scanLength + 1;
4607 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild, unsigned length)
4609 ASSERT(length && currentChild->isText());
4611 RenderObject* firstLetterContainer = currentChild->parent();
4612 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
4613 RenderObject* firstLetter = 0;
4614 if (pseudoStyle->display() == INLINE)
4615 firstLetter = RenderInline::createAnonymous(&document());
4617 firstLetter = RenderBlockFlow::createAnonymous(&document());
4618 firstLetter->setStyle(pseudoStyle);
4619 firstLetterContainer->addChild(firstLetter, currentChild);
4621 RenderText* textObj = toRenderText(currentChild);
4623 // The original string is going to be either a generated content string or a DOM node's
4624 // string. We want the original string before it got transformed in case first-letter has
4625 // no text-transform or a different text-transform applied to it.
4626 String oldText = textObj->originalText();
4627 ASSERT(oldText.impl());
4629 // Construct a text fragment for the text after the first letter.
4630 // This text fragment might be empty.
4631 RenderTextFragment* remainingText =
4632 new RenderTextFragment(textObj->node() ? textObj->node() : &textObj->document(), oldText.impl(), length, oldText.length() - length);
4633 remainingText->setStyle(textObj->style());
4634 if (remainingText->node())
4635 remainingText->node()->setRenderer(remainingText);
4637 firstLetterContainer->addChild(remainingText, textObj);
4638 firstLetterContainer->removeChild(textObj);
4639 remainingText->setFirstLetter(firstLetter);
4640 toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText);
4642 // construct text fragment for the first letter
4643 RenderTextFragment* letter =
4644 new RenderTextFragment(remainingText->node() ? remainingText->node() : &remainingText->document(), oldText.impl(), 0, length);
4645 letter->setStyle(pseudoStyle);
4646 firstLetter->addChild(letter);
4651 void RenderBlock::updateFirstLetter()
4653 if (!document().styleEngine()->usesFirstLetterRules())
4656 if (style()->styleType() == FIRST_LETTER)
4659 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
4660 // an efficient way to check for that situation though before implementing anything.
4661 RenderObject* firstLetterBlock = findFirstLetterBlock(this);
4662 if (!firstLetterBlock)
4665 // Drill into inlines looking for our first text child.
4666 RenderObject* currChild = firstLetterBlock->firstChild();
4667 unsigned length = 0;
4669 if (currChild->isText()) {
4670 // FIXME: If there is leading punctuation in a different RenderText than
4671 // the first letter, we'll not apply the correct style to it.
4672 length = firstLetterLength(toRenderText(currChild)->originalText());
4675 currChild = currChild->nextSibling();
4676 } else if (currChild->isListMarker()) {
4677 currChild = currChild->nextSibling();
4678 } else if (currChild->isFloatingOrOutOfFlowPositioned()) {
4679 if (currChild->style()->styleType() == FIRST_LETTER) {
4680 currChild = currChild->firstChild();
4683 currChild = currChild->nextSibling();
4684 } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList())
4686 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) {
4687 // We found a lower-level node with first-letter, which supersedes the higher-level style
4688 firstLetterBlock = currChild;
4689 currChild = currChild->firstChild();
4691 currChild = currChild->firstChild();
4697 // If the child already has style, then it has already been created, so we just want
4699 if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
4700 updateFirstLetterStyle(firstLetterBlock, currChild);
4704 if (!currChild->isText() || currChild->isBR())
4707 // Our layout state is not valid for the repaints we are going to trigger by
4708 // adding and removing children of firstLetterContainer.
4709 LayoutStateDisabler layoutStateDisabler(view());
4711 createFirstLetterRenderer(firstLetterBlock, currChild, length);
4714 // Helper methods for obtaining the last line, computing line counts and heights for line counts
4715 // (crawling into blocks).
4716 static bool shouldCheckLines(RenderObject* obj)
4718 return !obj->isFloatingOrOutOfFlowPositioned()
4719 && obj->isRenderBlock() && obj->style()->height().isAuto()
4720 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
4723 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
4725 if (block->style()->visibility() == VISIBLE) {
4726 if (block->childrenInline()) {
4727 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
4729 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
4733 RenderBox* normalFlowChildWithoutLines = 0;
4734 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4735 if (shouldCheckLines(obj)) {
4736 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
4738 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
4739 } else if (!obj->isFloatingOrOutOfFlowPositioned())
4740 normalFlowChildWithoutLines = obj;
4742 if (normalFlowChildWithoutLines && l == 0)
4743 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
4750 RootInlineBox* RenderBlock::lineAtIndex(int i) const
4754 if (style()->visibility() != VISIBLE)
4757 if (childrenInline()) {
4758 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4762 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
4763 if (!shouldCheckLines(child))
4765 if (RootInlineBox* box = toRenderBlock(child)->lineAtIndex(i))
4773 int RenderBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
4777 if (style()->visibility() == VISIBLE) {
4778 if (childrenInline())
4779 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
4781 if (box == stopRootInlineBox) {
4788 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
4789 if (shouldCheckLines(obj)) {
4790 bool recursiveFound = false;
4791 count += toRenderBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound);
4792 if (recursiveFound) {
4802 int RenderBlock::heightForLineCount(int l)
4805 return getHeightForLineCount(this, l, true, count);
4808 void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
4810 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
4811 // for either overflow or translations via relative positioning.
4812 if (style()->visibility() == VISIBLE) {
4813 if (childrenInline()) {
4814 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
4815 if (box->firstChild())
4816 left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
4817 if (box->lastChild())
4818 right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight())));
4821 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4822 if (!obj->isFloatingOrOutOfFlowPositioned()) {
4823 if (obj->isRenderBlockFlow() && !obj->hasOverflowClip())
4824 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
4825 else if (obj->style()->visibility() == VISIBLE) {
4826 // We are a replaced element or some kind of non-block-flow object.
4827 left = min(left, x + obj->x());
4828 right = max(right, x + obj->x() + obj->width());
4836 void RenderBlock::fitBorderToLinesIfNeeded()
4838 if (style()->borderFit() == BorderFitBorder || hasOverrideWidth())
4841 // Walk any normal flow lines to snugly fit.
4842 LayoutUnit left = LayoutUnit::max();
4843 LayoutUnit right = LayoutUnit::min();
4844 LayoutUnit oldWidth = contentWidth();
4845 adjustForBorderFit(0, left, right);
4847 // Clamp to our existing edges. We can never grow. We only shrink.
4848 LayoutUnit leftEdge = borderLeft() + paddingLeft();
4849 LayoutUnit rightEdge = leftEdge + oldWidth;
4850 left = min(rightEdge, max(leftEdge, left));
4851 right = max(left, min(rightEdge, right));
4853 LayoutUnit newContentWidth = right - left;
4854 if (newContentWidth == oldWidth)
4857 setOverrideLogicalContentWidth(newContentWidth);
4859 clearOverrideLogicalContentWidth();
4862 void RenderBlock::clearTruncation()
4864 if (style()->visibility() == VISIBLE) {
4865 if (childrenInline() && hasMarkupTruncation()) {
4866 setHasMarkupTruncation(false);
4867 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4868 box->clearTruncation();
4870 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
4871 if (shouldCheckLines(obj))
4872 toRenderBlock(obj)->clearTruncation();
4878 void RenderBlock::setPaginationStrut(LayoutUnit strut)
4883 m_rareData = adoptPtr(new RenderBlockRareData());
4885 m_rareData->m_paginationStrut = strut;
4888 void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
4893 m_rareData = adoptPtr(new RenderBlockRareData());
4895 m_rareData->m_pageLogicalOffset = logicalOffset;
4898 void RenderBlock::setBreakAtLineToAvoidWidow(int lineToBreak)
4900 ASSERT(lineToBreak >= 0);
4902 m_rareData = adoptPtr(new RenderBlockRareData());
4904 ASSERT(!m_rareData->m_didBreakAtLineToAvoidWidow);
4905 m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
4908 void RenderBlock::setDidBreakAtLineToAvoidWidow()
4910 ASSERT(!shouldBreakAtLineToAvoidWidow());
4912 // This function should be called only after a break was applied to avoid widows
4913 // so assert |m_rareData| exists.
4916 m_rareData->m_didBreakAtLineToAvoidWidow = true;
4919 void RenderBlock::clearDidBreakAtLineToAvoidWidow()
4924 m_rareData->m_didBreakAtLineToAvoidWidow = false;
4927 void RenderBlock::clearShouldBreakAtLineToAvoidWidow() const
4929 ASSERT(shouldBreakAtLineToAvoidWidow());
4933 m_rareData->m_lineBreakToAvoidWidow = -1;
4936 void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
4938 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
4939 // inline boxes above and below us (thus getting merged with them to form a single irregular
4941 if (isAnonymousBlockContinuation()) {
4942 // FIXME: This is wrong for block-flows that are horizontal.
4943 // https://bugs.webkit.org/show_bug.cgi?id=46781
4944 rects.append(pixelSnappedIntRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(),
4945 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
4946 continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
4947 inlineElementContinuation()->containingBlock()->location()));
4949 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
4952 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
4954 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
4955 // inline boxes above and below us (thus getting merged with them to form a single irregular
4957 if (isAnonymousBlockContinuation()) {
4958 // FIXME: This is wrong for block-flows that are horizontal.
4959 // https://bugs.webkit.org/show_bug.cgi?id=46781
4960 FloatRect localRect(0, -collapsedMarginBefore(),
4961 width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
4962 quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed));
4963 continuation()->absoluteQuads(quads, wasFixed);
4965 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
4968 LayoutRect RenderBlock::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
4970 LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
4971 if (isAnonymousBlockContinuation())
4972 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
4976 RenderObject* RenderBlock::hoverAncestor() const
4978 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
4981 void RenderBlock::updateDragState(bool dragOn)
4983 RenderBox::updateDragState(dragOn);
4985 continuation()->updateDragState(dragOn);
4988 RenderStyle* RenderBlock::outlineStyleForRepaint() const
4990 return isAnonymousBlockContinuation() ? continuation()->style() : style();
4993 void RenderBlock::childBecameNonInline(RenderObject*)
4995 makeChildrenNonInline();
4996 if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
4997 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
4998 // |this| may be dead here
5001 void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
5003 if (result.innerNode())
5006 if (Node* n = nodeForHitTest()) {
5007 result.setInnerNode(n);
5008 if (!result.innerNonSharedNode())
5009 result.setInnerNonSharedNode(n);
5010 result.setLocalPoint(point);
5014 LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
5016 // Do the normal calculation in most cases.
5018 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
5020 LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
5022 if (extraWidthToEndOfLine) {
5023 if (isRenderBlock()) {
5024 *extraWidthToEndOfLine = width() - caretRect.maxX();
5026 // FIXME: This code looks wrong.
5027 // myRight and containerRight are set up, but then clobbered.
5028 // So *extraWidthToEndOfLine will always be 0 here.
5030 LayoutUnit myRight = caretRect.maxX();
5031 // FIXME: why call localToAbsoluteForContent() twice here, too?
5032 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
5034 LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
5035 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
5037 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
5044 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
5046 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5047 // inline boxes above and below us (thus getting merged with them to form a single irregular
5049 if (inlineElementContinuation()) {
5050 // FIXME: This check really isn't accurate.
5051 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
5052 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
5053 // FIXME: This is wrong for block-flows that are horizontal.
5054 // https://bugs.webkit.org/show_bug.cgi?id=46781
5055 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
5056 float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit();
5057 float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit();
5058 LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin);
5059 if (!rect.isEmpty())
5060 rects.append(pixelSnappedIntRect(rect));
5061 } else if (width() && height())
5062 rects.append(pixelSnappedIntRect(additionalOffset, size()));
5064 if (!hasOverflowClip() && !hasControlClip()) {
5065 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5066 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
5067 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
5068 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
5069 if (!rect.isEmpty())
5070 rects.append(pixelSnappedIntRect(rect));
5073 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
5074 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
5075 RenderBox* box = toRenderBox(curr);
5077 // FIXME: This doesn't work correctly with transforms.
5079 pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
5081 pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
5082 box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer);
5087 if (inlineElementContinuation())
5088 inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()), paintContainer);
5091 void RenderBlock::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
5093 RenderBox::computeSelfHitTestRects(rects, layerOffset);
5095 if (hasHorizontalLayoutOverflow() || hasVerticalLayoutOverflow()) {
5096 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5097 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
5098 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
5099 LayoutRect rect(layerOffset.x() + curr->x(), layerOffset.y() + top, curr->width(), bottom - top);
5100 // It's common for this rect to be entirely contained in our box, so exclude that simple case.
5101 if (!rect.isEmpty() && (rects.isEmpty() || !rects[0].contains(rect)))
5107 RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
5109 if (isAnonymousColumnsBlock())
5110 return createAnonymousColumnsWithParentRenderer(parent);
5111 if (isAnonymousColumnSpanBlock())
5112 return createAnonymousColumnSpanWithParentRenderer(parent);
5113 return createAnonymousWithParentRendererAndDisplay(parent, style()->display());
5116 LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
5118 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5119 if (!pageLogicalHeight)
5120 return logicalOffset;
5122 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
5123 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
5124 if (pageBoundaryRule == ExcludePageBoundary)
5125 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
5126 return logicalOffset + remainingLogicalHeight;
5129 LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
5131 RenderView* renderView = view();
5132 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
5133 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
5135 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
5136 RenderFlowThread* flowThread = flowThreadContainingBlock();
5138 LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
5139 if (!pageLogicalHeight)
5141 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
5143 return flowThread->pageLogicalTopForOffset(cumulativeOffset);
5146 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
5148 RenderView* renderView = view();
5149 RenderFlowThread* flowThread = flowThreadContainingBlock();
5151 return renderView->layoutState()->m_pageLogicalHeight;
5152 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
5155 LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
5157 RenderView* renderView = view();
5158 offset += offsetFromLogicalTopOfFirstPage();
5160 RenderFlowThread* flowThread = flowThreadContainingBlock();
5162 LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
5163 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
5164 if (pageBoundaryRule == IncludePageBoundary) {
5165 // If includeBoundaryPoint is true the line exactly on the top edge of a
5166 // column will act as being part of the previous column.
5167 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
5169 return remainingHeight;
5172 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
5175 LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
5177 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
5178 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
5179 bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
5180 || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID);
5181 if (!isUnsplittable)
5182 return logicalOffset;
5183 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
5184 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5185 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
5186 if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight)
5187 return logicalOffset;
5188 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
5189 if (remainingLogicalHeight < childLogicalHeight)
5190 return logicalOffset + remainingLogicalHeight;
5191 return logicalOffset;
5194 bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
5196 // FIXME: multicol will need to do some work here, when we implement support for multiple rows.
5200 void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
5202 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
5203 flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
5206 void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
5208 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
5209 flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight);
5210 else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo)
5211 colInfo->updateMinimumColumnHeight(minHeight);
5214 static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
5216 // We may require a certain minimum number of lines per page in order to satisfy
5217 // orphans and widows, and that may affect the minimum page height.
5218 unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
5219 if (lineCount > 1) {
5220 RootInlineBox* line = lastLine;
5221 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
5222 line = line->prevRootBox();
5224 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
5225 // adjustLinePositionForPagination() for more details.
5226 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
5227 lineTop = min(line->lineTopWithLeading(), overflow.y());
5229 return lineBottom - lineTop;
5232 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread)
5234 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
5235 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
5236 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
5237 // of the first column.
5239 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
5240 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
5241 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
5242 // for overflow to occur), and then cache visible overflow for each column rect.
5244 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
5245 // content that paints in a previous column (and content that paints in the following column).
5247 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
5248 // at least make positive leading work in typical cases.
5250 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
5251 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
5252 // line and all following lines.
5253 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
5254 LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
5255 LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
5256 LayoutUnit lineHeight = logicalBottom - logicalOffset;
5257 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom));
5258 logicalOffset += delta;
5259 lineBox->setPaginationStrut(0);
5260 lineBox->setIsFirstAfterPageBreak(false);
5261 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5262 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
5263 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
5264 // still going to add a strut, so that the visible overflow fits on a single page.
5265 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight))
5266 // 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.
5267 // 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.
5269 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
5271 int lineIndex = lineCount(lineBox);
5272 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
5273 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
5274 clearShouldBreakAtLineToAvoidWidow();
5275 setDidBreakAtLineToAvoidWidow();
5277 // If we have a non-uniform page height, then we have to shift further possibly.
5278 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
5280 if (lineHeight > pageLogicalHeight) {
5281 // Split the top margin in order to avoid splitting the visible part of the line.
5282 remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
5284 LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
5285 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
5286 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
5287 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineIndex))
5288 && !isOutOfFlowPositioned() && !isTableCell())
5289 setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
5291 delta += remainingLogicalHeight;
5292 lineBox->setPaginationStrut(remainingLogicalHeight);
5293 lineBox->setIsFirstAfterPageBreak(true);
5295 } else if (remainingLogicalHeight == pageLogicalHeight) {
5296 // We're at the very top of a page or column.
5297 if (lineBox != firstRootBox())
5298 lineBox->setIsFirstAfterPageBreak(true);
5299 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
5300 setPageBreak(logicalOffset, lineHeight);
5304 LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
5306 LayoutState* layoutState = view()->layoutState();
5307 if (layoutState && !layoutState->isPaginated())
5310 RenderFlowThread* flowThread = flowThreadContainingBlock();
5312 return flowThread->offsetFromLogicalTopOfFirstRegion(this);
5315 ASSERT(layoutState->renderer() == this);
5317 LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
5318 return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
5321 ASSERT_NOT_REACHED();
5325 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
5327 RenderFlowThread* flowThread = flowThreadContainingBlock();
5328 if (!flowThread || !flowThread->hasValidRegionInfo())
5331 return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
5334 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
5336 // If the child has the same directionality as we do, then we can just return its
5337 // collapsed margin.
5338 if (!child->isWritingModeRoot())
5339 return child->collapsedMarginBefore();
5341 // The child has a different directionality. If the child is parallel, then it's just
5342 // flipped relative to us. We can use the collapsed margin for the opposite edge.
5343 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5344 return child->collapsedMarginAfter();
5346 // The child is perpendicular to us, which means its margins don't collapse but are on the
5347 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
5348 return marginBeforeForChild(child);
5351 LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) const
5353 // If the child has the same directionality as we do, then we can just return its
5354 // collapsed margin.
5355 if (!child->isWritingModeRoot())
5356 return child->collapsedMarginAfter();
5358 // The child has a different directionality. If the child is parallel, then it's just
5359 // flipped relative to us. We can use the collapsed margin for the opposite edge.
5360 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5361 return child->collapsedMarginBefore();
5363 // The child is perpendicular to us, which means its margins don't collapse but are on the
5364 // "logical left/right" side of the child box. We can just return the raw margin in this case.
5365 return marginAfterForChild(child);
5368 bool RenderBlock::hasMarginBeforeQuirk(const RenderBox* child) const
5370 // If the child has the same directionality as we do, then we can just return its
5372 if (!child->isWritingModeRoot())
5373 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
5375 // The child has a different directionality. If the child is parallel, then it's just
5376 // flipped relative to us. We can use the opposite edge.
5377 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5378 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
5380 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
5381 // whether or not authors specified quirky ems, since they're an implementation detail.
5385 bool RenderBlock::hasMarginAfterQuirk(const RenderBox* child) const
5387 // If the child has the same directionality as we do, then we can just return its
5389 if (!child->isWritingModeRoot())
5390 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
5392 // The child has a different directionality. If the child is parallel, then it's just
5393 // flipped relative to us. We can use the opposite edge.
5394 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5395 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
5397 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
5398 // whether or not authors specified quirky ems, since they're an implementation detail.
5402 const char* RenderBlock::renderName() const
5405 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
5408 return "RenderBlock (floating)";
5409 if (isOutOfFlowPositioned())
5410 return "RenderBlock (positioned)";
5411 if (isAnonymousColumnsBlock())
5412 return "RenderBlock (anonymous multi-column)";
5413 if (isAnonymousColumnSpanBlock())
5414 return "RenderBlock (anonymous multi-column span)";
5415 if (isAnonymousBlock())
5416 return "RenderBlock (anonymous)";
5417 // FIXME: Temporary hack while the new generated content system is being implemented.
5418 if (isPseudoElement())
5419 return "RenderBlock (generated)";
5421 return "RenderBlock (generated)";
5422 if (isRelPositioned())
5423 return "RenderBlock (relative positioned)";
5424 if (isStickyPositioned())
5425 return "RenderBlock (sticky positioned)";
5426 return "RenderBlock";
5429 RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
5431 // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
5432 EDisplay newDisplay;
5433 RenderBlock* newBox = 0;
5434 if (display == BOX || display == INLINE_BOX) {
5435 // FIXME: Remove this case once we have eliminated all internal users of old flexbox
5436 newBox = RenderDeprecatedFlexibleBox::createAnonymous(&parent->document());
5438 } else if (display == FLEX || display == INLINE_FLEX) {
5439 newBox = RenderFlexibleBox::createAnonymous(&parent->document());
5442 newBox = RenderBlockFlow::createAnonymous(&parent->document());
5446 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay);
5447 newBox->setStyle(newStyle.release());
5451 RenderBlockFlow* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent)
5453 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
5454 newStyle->inheritColumnPropertiesFrom(parent->style());
5456 RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&parent->document());
5457 newBox->setStyle(newStyle.release());
5461 RenderBlockFlow* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent)
5463 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
5464 newStyle->setColumnSpan(ColumnSpanAll);
5466 RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&parent->document());
5467 newBox->setStyle(newStyle.release());
5472 void RenderBlock::checkPositionedObjectsNeedLayout()
5474 if (!gPositionedDescendantsMap)
5477 if (TrackedRendererListHashSet* positionedDescendantSet = positionedObjects()) {
5478 TrackedRendererListHashSet::const_iterator end = positionedDescendantSet->end();
5479 for (TrackedRendererListHashSet::const_iterator it = positionedDescendantSet->begin(); it != end; ++it) {
5480 RenderBox* currBox = *it;
5481 ASSERT(!currBox->needsLayout());
5486 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const
5489 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
5490 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
5495 } // namespace WebCore