From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WebCore/rendering/RenderBlock.cpp | 4070 +++++++++--------------------- 1 file changed, 1194 insertions(+), 2876 deletions(-) (limited to 'Source/WebCore/rendering/RenderBlock.cpp') diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 27ee2c9bf..90c3b8f4a 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -25,7 +25,6 @@ #include "RenderBlock.h" #include "AXObjectCache.h" -#include "ColumnInfo.h" #include "Document.h" #include "Editor.h" #include "Element.h" @@ -34,7 +33,6 @@ #include "FrameSelection.h" #include "FrameView.h" #include "GraphicsContext.h" -#include "HTMLInputElement.h" #include "HTMLNames.h" #include "HitTestLocation.h" #include "HitTestResult.h" @@ -48,31 +46,34 @@ #include "PaintInfo.h" #include "RenderBlockFlow.h" #include "RenderBoxRegionInfo.h" +#include "RenderButton.h" +#include "RenderChildIterator.h" #include "RenderCombineText.h" #include "RenderDeprecatedFlexibleBox.h" #include "RenderFlexibleBox.h" #include "RenderInline.h" #include "RenderIterator.h" #include "RenderLayer.h" -#include "RenderMarquee.h" +#include "RenderListMarker.h" +#include "RenderMenuList.h" #include "RenderNamedFlowFragment.h" #include "RenderNamedFlowThread.h" #include "RenderRegion.h" +#include "RenderSVGResourceClipper.h" #include "RenderTableCell.h" #include "RenderTextFragment.h" #include "RenderTheme.h" +#include "RenderTreePosition.h" #include "RenderView.h" -#include "SVGTextRunRenderingContext.h" #include "Settings.h" #include "ShadowRoot.h" +#include "ShapeOutsideInfo.h" #include "TransformState.h" -#include -#include -#if ENABLE(CSS_SHAPES) -#include "ShapeInsideInfo.h" -#include "ShapeOutsideInfo.h" -#endif +#include +#include +#include +#include using namespace WTF; using namespace Unicode; @@ -82,49 +83,182 @@ namespace WebCore { using namespace HTMLNames; struct SameSizeAsRenderBlock : public RenderBox { - uint32_t bitfields; }; COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); -typedef WTF::HashMap> ColumnInfoMap; -static ColumnInfoMap* gColumnInfoMap = 0; +typedef HashMap> TrackedDescendantsMap; +typedef HashMap>> TrackedContainerMap; + +static TrackedDescendantsMap* percentHeightDescendantsMap; +static TrackedContainerMap* percentHeightContainerMap; + +static void insertIntoTrackedRendererMaps(const RenderBlock& container, RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) { + percentHeightDescendantsMap = new TrackedDescendantsMap; + percentHeightContainerMap = new TrackedContainerMap; + } + + auto& descendantSet = percentHeightDescendantsMap->ensure(&container, [] { + return std::make_unique(); + }).iterator->value; + + bool added = descendantSet->add(&descendant).isNewEntry; + if (!added) { + ASSERT(percentHeightContainerMap->get(&descendant)); + ASSERT(percentHeightContainerMap->get(&descendant)->contains(&container)); + return; + } + + auto& containerSet = percentHeightContainerMap->ensure(&descendant, [] { + return std::make_unique>(); + }).iterator->value; + + ASSERT(!containerSet->contains(&container)); + containerSet->add(&container); +} + +static void removeFromTrackedRendererMaps(RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) + return; + + std::unique_ptr> containerSet = percentHeightContainerMap->take(&descendant); + if (!containerSet) + return; + + for (auto* container : *containerSet) { + // FIXME: Disabling this assert temporarily until we fix the layout + // bugs associated with positioned objects not properly cleared from + // their ancestor chain before being moved. See webkit bug 93766. + // ASSERT(descendant->isDescendantOf(container)); + auto descendantsMapIterator = percentHeightDescendantsMap->find(container); + ASSERT(descendantsMapIterator != percentHeightDescendantsMap->end()); + if (descendantsMapIterator == percentHeightDescendantsMap->end()) + continue; + auto& descendantSet = descendantsMapIterator->value; + ASSERT(descendantSet->contains(&descendant)); + descendantSet->remove(&descendant); + if (descendantSet->isEmpty()) + percentHeightDescendantsMap->remove(descendantsMapIterator); + } +} + +class PositionedDescendantsMap { +public: + enum class MoveDescendantToEnd { No, Yes }; + void addDescendant(const RenderBlock& containingBlock, RenderBox& positionedDescendant, MoveDescendantToEnd moveDescendantToEnd) + { + // Protect against double insert where a descendant would end up with multiple containing blocks. + auto* previousContainingBlock = m_containerMap.get(&positionedDescendant); + if (previousContainingBlock && previousContainingBlock != &containingBlock) { + if (auto* descendants = m_descendantsMap.get(previousContainingBlock)) + descendants->remove(&positionedDescendant); + } + + auto& descendants = m_descendantsMap.ensure(&containingBlock, [] { + return std::make_unique(); + }).iterator->value; + + bool isNewEntry = moveDescendantToEnd == MoveDescendantToEnd::Yes ? descendants->appendOrMoveToLast(&positionedDescendant).isNewEntry + : descendants->add(&positionedDescendant).isNewEntry; + if (!isNewEntry) { + ASSERT(m_containerMap.contains(&positionedDescendant)); + return; + } + m_containerMap.set(&positionedDescendant, &containingBlock); + } + + void removeDescendant(const RenderBox& positionedDescendant) + { + auto* containingBlock = m_containerMap.take(&positionedDescendant); + if (!containingBlock) + return; + + auto descendantsIterator = m_descendantsMap.find(containingBlock); + ASSERT(descendantsIterator != m_descendantsMap.end()); + if (descendantsIterator == m_descendantsMap.end()) + return; + + auto& descendants = descendantsIterator->value; + ASSERT(descendants->contains(const_cast(&positionedDescendant))); + + descendants->remove(const_cast(&positionedDescendant)); + if (descendants->isEmpty()) + m_descendantsMap.remove(descendantsIterator); + } + + void removeContainingBlock(const RenderBlock& containingBlock) + { + auto descendants = m_descendantsMap.take(&containingBlock); + if (!descendants) + return; -static TrackedDescendantsMap* gPositionedDescendantsMap = 0; -static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0; + for (auto* renderer : *descendants) + m_containerMap.remove(renderer); + } + + TrackedRendererListHashSet* positionedRenderers(const RenderBlock& containingBlock) const + { + return m_descendantsMap.get(&containingBlock); + } -static TrackedContainerMap* gPositionedContainerMap = 0; -static TrackedContainerMap* gPercentHeightContainerMap = 0; +private: + using DescendantsMap = HashMap>; + using ContainerMap = HashMap; -typedef WTF::HashMap>> ContinuationOutlineTableMap; + DescendantsMap m_descendantsMap; + ContainerMap m_containerMap; +}; + +static PositionedDescendantsMap& positionedDescendantsMap() +{ + static NeverDestroyed mapForPositionedDescendants; + return mapForPositionedDescendants; +} -typedef WTF::HashSet DelayedUpdateScrollInfoSet; -static int gDelayUpdateScrollInfo = 0; -static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; +typedef HashMap>> ContinuationOutlineTableMap; -static bool gColumnFlowSplitEnabled = true; +struct UpdateScrollInfoAfterLayoutTransaction { + UpdateScrollInfoAfterLayoutTransaction(const RenderView& view) + : nestedCount(0) + , view(&view) + { + } + + int nestedCount; + const RenderView* view; + HashSet blocks; +}; + +typedef Vector DelayedUpdateScrollInfoStack; +static std::unique_ptr& updateScrollInfoAfterLayoutTransactionStack() +{ + static NeverDestroyed> delayedUpdatedScrollInfoStack; + return delayedUpdatedScrollInfoStack; +} // Allocated only when some of these fields have non-default values struct RenderBlockRareData { WTF_MAKE_NONCOPYABLE(RenderBlockRareData); WTF_MAKE_FAST_ALLOCATED; public: - RenderBlockRareData() + RenderBlockRareData() : m_paginationStrut(0) , m_pageLogicalOffset(0) - { + , m_flowThreadContainingBlock(std::nullopt) + { } LayoutUnit m_paginationStrut; LayoutUnit m_pageLogicalOffset; -#if ENABLE(CSS_SHAPES) - std::unique_ptr m_shapeInsideInfo; -#endif + std::optional m_flowThreadContainingBlock; }; typedef HashMap> RenderBlockRareDataMap; -static RenderBlockRareDataMap* gRareDataMap = 0; +static RenderBlockRareDataMap* gRareDataMap; // This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code // only works on RenderBlocks. If this change, this class should be shared with other RenderBoxes. @@ -156,9 +290,9 @@ public: if (!horizontalLayoutOverflowChanged && !verticalLayoutOverflowChanged) return; - RefPtr overflowEvent = OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow); + Ref overflowEvent = OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow); overflowEvent->setTarget(m_block->element()); - m_block->document().enqueueOverflowEvent(overflowEvent.release()); + m_block->document().enqueueOverflowEvent(WTFMove(overflowEvent)); } private: @@ -168,58 +302,65 @@ private: bool m_hadVerticalLayoutOverflow; }; -RenderBlock::RenderBlock(Element& element, PassRef style, unsigned baseTypeFlags) - : RenderBox(element, std::move(style), baseTypeFlags | RenderBlockFlag) - , m_lineHeight(-1) - , m_hasMarginBeforeQuirk(false) - , m_hasMarginAfterQuirk(false) - , m_beingDestroyed(false) - , m_hasMarkupTruncation(false) - , m_hasBorderOrPaddingLogicalWidthChanged(false) - , m_lineLayoutPath(UndeterminedPath) +RenderBlock::RenderBlock(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags) + : RenderBox(element, WTFMove(style), baseTypeFlags | RenderBlockFlag) { } -RenderBlock::RenderBlock(Document& document, PassRef style, unsigned baseTypeFlags) - : RenderBox(document, std::move(style), baseTypeFlags | RenderBlockFlag) - , m_lineHeight(-1) - , m_hasMarginBeforeQuirk(false) - , m_hasMarginAfterQuirk(false) - , m_beingDestroyed(false) - , m_hasMarkupTruncation(false) - , m_hasBorderOrPaddingLogicalWidthChanged(false) - , m_lineLayoutPath(UndeterminedPath) +RenderBlock::RenderBlock(Document& document, RenderStyle&& style, BaseTypeFlags baseTypeFlags) + : RenderBox(document, WTFMove(style), baseTypeFlags | RenderBlockFlag) { } -static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap) +static void removeBlockFromPercentageDescendantAndContainerMaps(RenderBlock* block) { - if (OwnPtr descendantSet = descendantMap->take(block)) { - TrackedRendererListHashSet::iterator end = descendantSet->end(); - for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { - TrackedContainerMap::iterator it = containerMap->find(*descendant); - ASSERT(it != containerMap->end()); - if (it == containerMap->end()) - continue; - HashSet* containerSet = it->value.get(); - ASSERT(containerSet->contains(block)); - containerSet->remove(block); - if (containerSet->isEmpty()) - containerMap->remove(it); - } + if (!percentHeightDescendantsMap) + return; + std::unique_ptr descendantSet = percentHeightDescendantsMap->take(block); + if (!descendantSet) + return; + + for (auto* descendant : *descendantSet) { + auto it = percentHeightContainerMap->find(descendant); + ASSERT(it != percentHeightContainerMap->end()); + if (it == percentHeightContainerMap->end()) + continue; + auto* containerSet = it->value.get(); + ASSERT(containerSet->contains(block)); + containerSet->remove(block); + if (containerSet->isEmpty()) + percentHeightContainerMap->remove(it); } } RenderBlock::~RenderBlock() { - if (hasColumns()) - gColumnInfoMap->take(this); + // Blocks can be added to gRareDataMap during willBeDestroyed(), so this code can't move there. if (gRareDataMap) gRareDataMap->remove(this); - if (gPercentHeightDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap); - if (gPositionedDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap); + + // Do not add any more code here. Add it to willBeDestroyed() instead. +} + +// Note that this is not called for RenderBlockFlows. +void RenderBlock::willBeDestroyed() +{ + if (!renderTreeBeingDestroyed()) { + if (parent()) + parent()->dirtyLinesFromChangedChild(*this); + } + + blockWillBeDestroyed(); + + RenderBox::willBeDestroyed(); +} + +void RenderBlock::blockWillBeDestroyed() +{ + removeFromUpdateScrollInfoAfterLayoutTransaction(); + + removeBlockFromPercentageDescendantAndContainerMaps(this); + positionedDescendantsMap().removeContainingBlock(*this); } bool RenderBlock::hasRareData() const @@ -227,67 +368,51 @@ bool RenderBlock::hasRareData() const return gRareDataMap ? gRareDataMap->contains(this) : false; } -void RenderBlock::willBeDestroyed() +void RenderBlock::removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, const RenderStyle& newStyle) { - // Mark as being destroyed to avoid trouble with merges in removeChild(). - m_beingDestroyed = true; + bool hadTransform = oldStyle.hasTransformRelatedProperty(); + bool willHaveTransform = newStyle.hasTransformRelatedProperty(); + if (oldStyle.position() == newStyle.position() && hadTransform == willHaveTransform) + return; - if (!documentBeingDestroyed()) { - if (firstChild() && firstChild()->isRunIn()) - moveRunInToOriginalPosition(*firstChild()); + // We are no longer the containing block for fixed descendants. + if (hadTransform && !willHaveTransform) { + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. + removePositionedObjects(nullptr, NewContainingBlock); + return; } - // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will - // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. - destroyLeftoverChildren(); - - // Destroy our continuation before anything other than anonymous children. - // The reason we don't destroy it before anonymous children is that they may - // have continuations of their own that are anonymous children of our continuation. - RenderBoxModelObject* continuation = this->continuation(); - if (continuation) { - continuation->destroy(); - setContinuation(0); - } - - if (!documentBeingDestroyed()) { - if (parent()) - parent()->dirtyLinesFromChangedChild(this); + // We are no longer the containing block for absolute positioned descendants. + if (newStyle.position() == StaticPosition && !willHaveTransform) { + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. + removePositionedObjects(nullptr, NewContainingBlock); + return; } - removeFromDelayedUpdateScrollInfoSet(); - - RenderBox::willBeDestroyed(); + // We are a new containing block. + if (oldStyle.position() == StaticPosition && !hadTransform) { + // Remove our absolutely positioned descendants from their current containing block. + // They will be inserted into our positioned objects list during layout. + auto* containingBlock = parent(); + while (containingBlock && !is(*containingBlock) + && (containingBlock->style().position() == StaticPosition || (containingBlock->isInline() && !containingBlock->isReplaced()))) { + if (containingBlock->style().position() == RelativePosition && containingBlock->isInline() && !containingBlock->isReplaced()) { + containingBlock = containingBlock->containingBlock(); + break; + } + containingBlock = containingBlock->parent(); + } + if (containingBlock && is(*containingBlock)) + downcast(*containingBlock).removePositionedObjects(this, NewContainingBlock); + } } void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) { const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr; - setReplaced(newStyle.isDisplayInlineType()); - - if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle.position()) { - if (newStyle.position() == StaticPosition) - // Clear our positioned objects list. Our absolutely positioned descendants will be - // inserted into our containing block's positioned objects list during layout. - removePositionedObjects(0, NewContainingBlock); - else if (oldStyle->position() == StaticPosition) { - // Remove our absolutely positioned descendants from their current containing block. - // They will be inserted into our positioned objects list during layout. - auto cb = parent(); - while (cb && (cb->style().position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { - if (cb->style().position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { - cb = cb->containingBlock(); - break; - } - cb = cb->parent(); - } - - if (cb->isRenderBlock()) - toRenderBlock(cb)->removePositionedObjects(this, NewContainingBlock); - } - } - + if (oldStyle) + removePositionedObjectsIfNeeded(*oldStyle, newStyle); RenderBox::styleWillChange(diff, newStyle); } @@ -307,30 +432,28 @@ static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, cons void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { + bool hadTransform = hasTransform(); RenderBox::styleDidChange(diff, oldStyle); - - RenderStyle& newStyle = style(); - -#if ENABLE(CSS_SHAPES) - updateShapeInsideInfoAfterStyleChange(newStyle.resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : 0); -#endif + if (hadTransform != hasTransform()) + adjustFlowThreadStateOnContainingBlockChangeIfNeeded(); + + auto& newStyle = style(); if (!isAnonymousBlock()) { // Ensure that all of our continuation blocks pick up the new style. for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) { RenderBoxModelObject* nextCont = currCont->continuation(); currCont->setContinuation(0); - currCont->setStyle(newStyle); + currCont->setStyle(RenderStyle::clone(newStyle)); currCont->setContinuation(nextCont); } } propagateStyleToAnonymousChildren(PropagateToBlockChildrenOnly); - m_lineHeight = -1; - + // It's possible for our border/padding to change, but for the overall logical width of the block to // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true. - m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, &newStyle); + setShouldForceRelayoutChildren(oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, &newStyle)); } RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild) @@ -338,19 +461,17 @@ RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild) if (beforeChild && beforeChild->parent() == this) return this; - RenderBlock* curr = toRenderBlock(continuation()); RenderBlock* nextToLast = this; RenderBlock* last = this; - while (curr) { - if (beforeChild && beforeChild->parent() == curr) { - if (curr->firstChild() == beforeChild) + for (auto* current = downcast(continuation()); current; current = downcast(current->continuation())) { + if (beforeChild && beforeChild->parent() == current) { + if (current->firstChild() == beforeChild) return last; - return curr; + return current; } nextToLast = last; - last = curr; - curr = toRenderBlock(curr->continuation()); + last = current; } if (!beforeChild && !last->firstChild()) @@ -361,14 +482,14 @@ RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild) void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild) { RenderBlock* flow = continuationBefore(beforeChild); - ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock()); - RenderBoxModelObject* beforeChildParent = 0; + ASSERT(!beforeChild || is(*beforeChild->parent())); + RenderBoxModelObject* beforeChildParent = nullptr; if (beforeChild) - beforeChildParent = toRenderBoxModelObject(beforeChild->parent()); + beforeChildParent = downcast(beforeChild->parent()); else { - RenderBoxModelObject* cont = flow->continuation(); - if (cont) - beforeChildParent = cont; + RenderBoxModelObject* continuation = flow->continuation(); + if (continuation) + beforeChildParent = continuation; else beforeChildParent = flow; } @@ -378,8 +499,6 @@ void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* b return; } - // A continuation always consists of two potential candidates: a block or an anonymous - // column span box holding column span children. bool childIsNormal = newChild->isInline() || !newChild->style().columnSpan(); bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style().columnSpan(); bool flowIsNormal = flow->isInline() || !flow->style().columnSpan(); @@ -402,96 +521,6 @@ void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* b beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); } - -void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild) -{ - ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block. - - // The goal is to locate a suitable box in which to place our child. - RenderBlock* beforeChildParent = 0; - if (beforeChild) { - RenderObject* curr = beforeChild; - while (curr && curr->parent() != this) - curr = curr->parent(); - beforeChildParent = toRenderBlock(curr); - ASSERT(beforeChildParent); - ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock()); - } else - beforeChildParent = toRenderBlock(lastChild()); - - // If the new child is floating or positioned it can just go in that block. - if (newChild->isFloatingOrOutOfFlowPositioned()) { - beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); - return; - } - - // See if the child can be placed in the box. - bool newChildHasColumnSpan = !newChild->isInline() && newChild->style().columnSpan(); - bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock(); - - if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) { - beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); - return; - } - - if (!beforeChild) { - // Create a new block of the correct type. - RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock(); - insertChildInternal(newBox, nullptr, NotifyChildren); - newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0); - return; - } - - RenderObject* immediateChild = beforeChild; - bool isPreviousBlockViable = true; - while (immediateChild->parent() != this) { - if (isPreviousBlockViable) - isPreviousBlockViable = !immediateChild->previousSibling(); - immediateChild = immediateChild->parent(); - } - if (isPreviousBlockViable && immediateChild->previousSibling()) { - toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append. - return; - } - - // Split our anonymous blocks. - RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild); - - - // Create a new anonymous box of the appropriate type. - RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock(); - insertChildInternal(newBox, newBeforeChild, NotifyChildren); - newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0); - return; -} - -RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock) -{ - RenderBlock* firstChildIgnoringAnonymousWrappers = 0; - for (RenderElement* curr = this; curr; curr = curr->parent()) { - if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip() - || curr->isInlineBlockOrInlineTable()) - return 0; - - // FIXME: Tables, RenderButtons, and RenderListItems all do special management - // of their children that breaks when the flow is split through them. Disabling - // multi-column for them to avoid this problem. - if (curr->isTable() || curr->isRenderButton() || curr->isListItem()) - return 0; - - RenderBlock* currBlock = toRenderBlock(curr); - if (!currBlock->createsAnonymousWrapper()) - firstChildIgnoringAnonymousWrappers = currBlock; - - if (currBlock->style().specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock())) - return firstChildIgnoringAnonymousWrappers; - - if (currBlock->isAnonymousColumnSpanBlock()) - return 0; - } - return 0; -} - RenderPtr RenderBlock::clone() const { RenderPtr cloneBlock; @@ -499,7 +528,8 @@ RenderPtr RenderBlock::clone() const cloneBlock = RenderPtr(createAnonymousBlock()); cloneBlock->setChildrenInline(childrenInline()); } else { - cloneBlock = static_pointer_cast(element()->createElementRenderer(style())); + RenderTreePosition insertionPosition(*parent()); + cloneBlock = static_pointer_cast(element()->createElementRenderer(RenderStyle::clone(style()), insertionPosition)); cloneBlock->initializeStyle(); // This takes care of setting the right value of childrenInline in case @@ -511,218 +541,15 @@ RenderPtr RenderBlock::clone() const return cloneBlock; } -void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock, - RenderBlock* middleBlock, - RenderObject* beforeChild, RenderBoxModelObject* oldCont) -{ - // Create a clone of this inline. - RenderPtr cloneBlock = clone(); - if (!isAnonymousBlock()) - cloneBlock->setContinuation(oldCont); - - if (!beforeChild && isAfterContent(lastChild())) - beforeChild = lastChild(); - - // If we are moving inline children from |this| to cloneBlock, then we need - // to clear our line box tree. - if (beforeChild && childrenInline()) - deleteLines(); - - // Now take all of the children from beforeChild to the end and remove - // them from |this| and place them in the clone. - moveChildrenTo(cloneBlock.get(), beforeChild, 0, true); - - // Hook |clone| up as the continuation of the middle block. - if (!cloneBlock->isAnonymousBlock()) - middleBlock->setContinuation(cloneBlock.get()); - - // We have been reparented and are now under the fromBlock. We need - // to walk up our block parent chain until we hit the containing anonymous columns block. - // Once we hit the anonymous columns block we're done. - RenderBoxModelObject* curr = toRenderBoxModelObject(parent()); - RenderBoxModelObject* currChild = this; - RenderObject* currChildNextSibling = currChild->nextSibling(); - - while (curr && curr->isDescendantOf(fromBlock) && curr != fromBlock) { - RenderBlock* blockCurr = toRenderBlock(curr); - - // Create a new clone. - RenderPtr cloneChild = std::move(cloneBlock); - cloneBlock = blockCurr->clone(); - - // Insert our child clone as the first child. - cloneBlock->addChildIgnoringContinuation(cloneChild.leakPtr(), 0); - - // Hook the clone up as a continuation of |curr|. Note we do encounter - // anonymous blocks possibly as we walk up the block chain. When we split an - // anonymous block, there's no need to do any continuation hookup, since we haven't - // actually split a real element. - if (!blockCurr->isAnonymousBlock()) { - oldCont = blockCurr->continuation(); - blockCurr->setContinuation(cloneBlock.get()); - cloneBlock->setContinuation(oldCont); - } - - // Now we need to take all of the children starting from the first child - // *after* currChild and append them all to the clone. - blockCurr->moveChildrenTo(cloneBlock.get(), currChildNextSibling, 0, true); - - // Keep walking up the chain. - currChild = curr; - currChildNextSibling = currChild->nextSibling(); - curr = toRenderBoxModelObject(curr->parent()); - } - - // Now we are at the columns block level. We need to put the clone into the toBlock. - toBlock->insertChildInternal(cloneBlock.leakPtr(), nullptr, NotifyChildren); - - // Now take all the children after currChild and remove them from the fromBlock - // and put them in the toBlock. - if (currChildNextSibling && currChildNextSibling->parent() == fromBlock) - fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true); -} - -void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, - RenderObject* newChild, RenderBoxModelObject* oldCont) -{ - RenderBlock* pre = 0; - RenderBlock* block = containingColumnsBlock(); - - // Delete our line boxes before we do the inline split into continuations. - block->deleteLines(); - - bool madeNewBeforeBlock = false; - if (block->isAnonymousColumnsBlock()) { - // We can reuse this block and make it the preBlock of the next continuation. - pre = block; - pre->removePositionedObjects(0); - // FIXME-BLOCKFLOW remove this when splitFlow is moved to RenderBlockFlow. - if (pre->isRenderBlockFlow()) - toRenderBlockFlow(pre)->removeFloatingObjects(); - block = toRenderBlock(block->parent()); - } else { - // No anonymous block available for use. Make one. - pre = block->createAnonymousColumnsBlock(); - pre->setChildrenInline(false); - madeNewBeforeBlock = true; - } - - RenderBlock* post = block->createAnonymousColumnsBlock(); - post->setChildrenInline(false); - - RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); - if (madeNewBeforeBlock) - block->insertChildInternal(pre, boxFirst, NotifyChildren); - block->insertChildInternal(newBlockBox, boxFirst, NotifyChildren); - block->insertChildInternal(post, boxFirst, NotifyChildren); - block->setChildrenInline(false); - - if (madeNewBeforeBlock) - block->moveChildrenTo(pre, boxFirst, 0, true); - - splitBlocks(pre, post, newBlockBox, beforeChild, oldCont); - - // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting - // time in makeChildrenNonInline by just setting this explicitly up front. - newBlockBox->setChildrenInline(false); - - // We delayed adding the newChild until now so that the |newBlockBox| would be fully - // connected, thus allowing newChild access to a renderArena should it need - // to wrap itself in additional boxes (e.g., table construction). - newBlockBox->addChild(newChild); - - // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) - // get deleted properly. Because objects moves from the pre block into the post block, we want to - // make new line boxes instead of leaving the old line boxes around. - pre->setNeedsLayoutAndPrefWidthsRecalc(); - block->setNeedsLayoutAndPrefWidthsRecalc(); - post->setNeedsLayoutAndPrefWidthsRecalc(); -} - -void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild) +void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) { - RenderBlock* pre = 0; - RenderBlock* post = 0; - RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable - // so that we don't have to patch all of the rest of the code later on. - - // Delete the block's line boxes before we do the split. - block->deleteLines(); - - if (beforeChild && beforeChild->parent() != this) - beforeChild = splitAnonymousBoxesAroundChild(beforeChild); - - if (beforeChild != firstChild()) { - pre = block->createAnonymousColumnsBlock(); - pre->setChildrenInline(block->childrenInline()); - } - - if (beforeChild) { - post = block->createAnonymousColumnsBlock(); - post->setChildrenInline(block->childrenInline()); - } - - RenderObject* boxFirst = block->firstChild(); - if (pre) - block->insertChildInternal(pre, boxFirst, NotifyChildren); - block->insertChildInternal(newBlockBox, boxFirst, NotifyChildren); - if (post) - block->insertChildInternal(post, boxFirst, NotifyChildren); - block->setChildrenInline(false); - - // 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). - block->moveChildrenTo(pre, boxFirst, beforeChild, true); - block->moveChildrenTo(post, beforeChild, 0, true); - - // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting - // time in makeChildrenNonInline by just setting this explicitly up front. - newBlockBox->setChildrenInline(false); - - // We delayed adding the newChild until now so that the |newBlockBox| would be fully - // connected, thus allowing newChild access to a renderArena should it need - // to wrap itself in additional boxes (e.g., table construction). - newBlockBox->addChild(newChild); - - // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) - // get deleted properly. Because objects moved from the pre block into the post block, we want to - // make new line boxes instead of leaving the old line boxes around. - if (pre) - pre->setNeedsLayoutAndPrefWidthsRecalc(); - block->setNeedsLayoutAndPrefWidthsRecalc(); - if (post) - post->setNeedsLayoutAndPrefWidthsRecalc(); -} - -RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild) -{ - // FIXME: This function is the gateway for the addition of column-span support. It will - // be added to in three stages: - // (1) Immediate children of a multi-column block can span. - // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span. - // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we - // cross the streams and have to cope with both types of continuations mixed together). - // This function currently supports (1) and (2). - RenderBlock* columnsBlockAncestor = 0; - if (!newChild->isText() && newChild->style().columnSpan() && !newChild->isBeforeOrAfterContent() - && !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) { - columnsBlockAncestor = containingColumnsBlock(false); - if (columnsBlockAncestor) { - // Make sure that none of the parent ancestors have a continuation. - // If yes, we do not want split the block into continuations. - RenderElement* curr = this; - while (curr && curr != columnsBlockAncestor) { - if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) { - columnsBlockAncestor = 0; - break; - } - curr = curr->parent(); - } - } - } - return columnsBlockAncestor; + if (continuation() && !isAnonymousBlock()) + addChildToContinuation(newChild, beforeChild); + else + addChildIgnoringContinuation(newChild, beforeChild); } -void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild) +void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) { if (beforeChild && beforeChild->parent() != this) { RenderElement* beforeChildContainer = beforeChild->parent(); @@ -764,47 +591,6 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, // safe fallback to use the topmost beforeChild container. beforeChild = beforeChildContainer; } - } else { - // We will reach here when beforeChild is a run-in element. - // If run-in element precedes a block-level element, it becomes the - // the first inline child of that block level element. The insertion - // point will be before that block-level element. - ASSERT(beforeChild->isRunIn()); - beforeChild = beforeChildContainer; - } - } - - // Nothing goes before the intruded run-in. - if (beforeChild && beforeChild->isRunIn() && runInIsPlacedIntoSiblingBlock(*beforeChild)) - beforeChild = beforeChild->nextSibling(); - - // Check for a spanning element in columns. - if (gColumnFlowSplitEnabled) { - RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild); - if (columnsBlockAncestor) { - TemporaryChange columnFlowSplitEnabled(gColumnFlowSplitEnabled, false); - // We are placing a column-span element inside a block. - RenderBlock* newBox = createAnonymousColumnSpanBlock(); - - if (columnsBlockAncestor != this && !isRenderFlowThread()) { - // We are nested inside a multi-column element and are being split by the span. We have to break up - // our block into continuations. - RenderBoxModelObject* oldContinuation = continuation(); - - // When we split an anonymous block, there's no need to do any continuation hookup, - // since we haven't actually split a real element. - if (!isAnonymousBlock()) - setContinuation(newBox); - - splitFlow(beforeChild, newBox, newChild, oldContinuation); - return; - } - - // We have to perform a split of this block's children. This involves creating an anonymous block box to hold - // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into - // one anonymous columns block, and all of the children after |newChild| go into another anonymous block. - makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild); - return; } } @@ -830,7 +616,7 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild(); if (afterChild && afterChild->isAnonymousBlock()) { - toRenderBlock(afterChild)->addChild(newChild); + downcast(*afterChild).addChild(newChild); return; } @@ -847,30 +633,11 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderBox::addChild(newChild, beforeChild); - // Handle placement of run-ins. - placeRunInIfNeeded(*newChild); - - if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) - toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); + if (madeBoxesNonInline && is(parent()) && isAnonymousBlock()) + downcast(*parent()).removeLeftoverAnonymousBlock(this); // this object may be dead here } -void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) -{ - if (continuation() && !isAnonymousBlock()) - addChildToContinuation(newChild, beforeChild); - else - addChildIgnoringContinuation(newChild, beforeChild); -} - -void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) -{ - if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock())) - addChildToAnonymousColumnBlocks(newChild, beforeChild); - else - addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); -} - static void getInlineRun(RenderObject* start, RenderObject* boundary, RenderObject*& inlineRunStart, RenderObject*& inlineRunEnd) @@ -914,14 +681,7 @@ static void getInlineRun(RenderObject* start, RenderObject* boundary, void RenderBlock::deleteLines() { if (AXObjectCache* cache = document().existingAXObjectCache()) - cache->recomputeIsIgnored(this); -} - -void RenderBlock::invalidateLineLayoutPath() -{ - if (m_lineLayoutPath == ForceLineBoxesPath) - return; - m_lineLayoutPath = UndeterminedPath; + cache->recomputeDeferredIsIgnored(*this); } void RenderBlock::makeChildrenNonInline(RenderObject* insertionPoint) @@ -944,13 +704,6 @@ void RenderBlock::makeChildrenNonInline(RenderObject* insertionPoint) deleteLines(); - // Since we are going to have block children, we have to move - // back the run-in to its original place. - if (child->isRunIn()) { - moveRunInToOriginalPosition(*child); - child = firstChild(); - } - while (child) { RenderObject* inlineRunStart; RenderObject* inlineRunEnd; @@ -979,7 +732,7 @@ void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) ASSERT(child->isAnonymousBlock()); ASSERT(!child->childrenInline()); - if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock()))) + if (child->continuation()) return; RenderObject* firstAnChild = child->firstChild(); @@ -1017,7 +770,7 @@ void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) child->m_next = 0; // Remove all the information in the flow thread associated with the leftover anonymous block. - child->removeFromRenderFlowThread(); + child->resetFlowThreadStateOnRemoval(); child->setParent(0); child->setPreviousSibling(0); @@ -1026,122 +779,103 @@ void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) child->destroy(); } -static bool canMergeAnonymousBlock(RenderBlock* anonymousBlock) +static bool canDropAnonymousBlock(const RenderBlock& anonymousBlock) { - if (anonymousBlock->beingDestroyed() || anonymousBlock->continuation()) + if (anonymousBlock.beingDestroyed() || anonymousBlock.continuation()) return false; - if (anonymousBlock->isRubyRun() || anonymousBlock->isRubyBase()) + if (anonymousBlock.isRubyRun() || anonymousBlock.isRubyBase()) return false; return true; } static bool canMergeContiguousAnonymousBlocks(RenderObject& oldChild, RenderObject* previous, RenderObject* next) { - if (oldChild.documentBeingDestroyed() || oldChild.isInline() || oldChild.virtualContinuation()) + if (oldChild.renderTreeBeingDestroyed() || oldChild.isInline() || oldChild.virtualContinuation()) return false; if (previous) { if (!previous->isAnonymousBlock()) return false; - RenderBlock* previousAnonymousBlock = toRenderBlock(previous); - if (!canMergeAnonymousBlock(previousAnonymousBlock)) - return false; - // FIXME: This check isn't required when inline run-ins can't be split into continuations. - RenderObject* child = previousAnonymousBlock->firstChild(); - if (child && child->isInline() && child->isRunIn()) + RenderBlock& previousAnonymousBlock = downcast(*previous); + if (!canDropAnonymousBlock(previousAnonymousBlock)) return false; } if (next) { if (!next->isAnonymousBlock()) return false; - RenderBlock* nextAnonymousBlock = toRenderBlock(next); - if (!canMergeAnonymousBlock(nextAnonymousBlock)) + RenderBlock& nextAnonymousBlock = downcast(*next); + if (!canDropAnonymousBlock(nextAnonymousBlock)) return false; } - if (!previous || !next) - return true; - - // Make sure the types of the anonymous blocks match up. - return previous->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock() - && previous->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock(); + return true; } -void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderBlock* child) +void RenderBlock::dropAnonymousBoxChild(RenderBlock& parent, RenderBlock& child) { - parent->setNeedsLayoutAndPrefWidthsRecalc(); - parent->setChildrenInline(child->childrenInline()); - RenderObject* nextSibling = child->nextSibling(); - - RenderFlowThread* childFlowThread = child->flowThreadContainingBlock(); - CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread); - - parent->removeChildInternal(*child, child->hasLayer() ? NotifyChildren : DontNotifyChildren); - child->moveAllChildrenTo(parent, nextSibling, child->hasLayer()); + parent.setNeedsLayoutAndPrefWidthsRecalc(); + parent.setChildrenInline(child.childrenInline()); + RenderObject* nextSibling = child.nextSibling(); + parent.removeChildInternal(child, child.hasLayer() ? NotifyChildren : DontNotifyChildren); + child.moveAllChildrenTo(&parent, nextSibling, child.hasLayer()); // Delete the now-empty block's lines and nuke it. - child->deleteLines(); - if (childFlowThread && childFlowThread->isRenderNamedFlowThread()) - toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child); - child->destroy(); + child.deleteLines(); + child.destroy(); } void RenderBlock::removeChild(RenderObject& oldChild) { // No need to waste time in merging or removing empty anonymous blocks. // We can just bail out if our document is getting destroyed. - if (documentBeingDestroyed()) { + if (renderTreeBeingDestroyed()) { RenderBox::removeChild(oldChild); return; } - // This protects against column split flows when anonymous blocks are getting merged. - TemporaryChange columnFlowSplitEnabled(gColumnFlowSplitEnabled, false); - - // If this child is a block, and if our previous and next siblings are - // both anonymous blocks with inline content, then we can go ahead and - // fold the inline content back together. + // If this child is a block, and if our previous and next siblings are both anonymous blocks + // with inline content, then we can fold the inline content back together. RenderObject* prev = oldChild.previousSibling(); RenderObject* next = oldChild.nextSibling(); bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next); if (canMergeAnonymousBlocks && prev && next) { prev->setNeedsLayoutAndPrefWidthsRecalc(); - RenderBlock* nextBlock = toRenderBlock(next); - RenderBlock* prevBlock = toRenderBlock(prev); + RenderBlock& nextBlock = downcast(*next); + RenderBlock& prevBlock = downcast(*prev); if (prev->childrenInline() != next->childrenInline()) { - RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock; - RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock; + RenderBlock& inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock; + RenderBlock& blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock; // Place the inline children block inside of the block children block instead of deleting it. // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure // to clear out inherited column properties by just making a new style, and to also clear the // column span flag if it is set. - ASSERT(!inlineChildrenBlock->continuation()); + ASSERT(!inlineChildrenBlock.continuation()); // Cache this value as it might get changed in setStyle() call. - bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer(); - inlineChildrenBlock->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK)); - removeChildInternal(*inlineChildrenBlock, inlineChildrenBlockHasLayer ? NotifyChildren : DontNotifyChildren); + bool inlineChildrenBlockHasLayer = inlineChildrenBlock.hasLayer(); + inlineChildrenBlock.setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK)); + removeChildInternal(inlineChildrenBlock, inlineChildrenBlockHasLayer ? NotifyChildren : DontNotifyChildren); // Now just put the inlineChildrenBlock inside the blockChildrenBlock. - RenderObject* beforeChild = prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : nullptr; - blockChildrenBlock->insertChildInternal(inlineChildrenBlock, beforeChild, - (inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer()) ? NotifyChildren : DontNotifyChildren); + RenderObject* beforeChild = prev == &inlineChildrenBlock ? blockChildrenBlock.firstChild() : nullptr; + blockChildrenBlock.insertChildInternal(&inlineChildrenBlock, beforeChild, + (inlineChildrenBlockHasLayer || blockChildrenBlock.hasLayer()) ? NotifyChildren : DontNotifyChildren); next->setNeedsLayoutAndPrefWidthsRecalc(); // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child // of "this". we null out prev or next so that is not used later in the function. - if (inlineChildrenBlock == prevBlock) - prev = 0; + if (&inlineChildrenBlock == &prevBlock) + prev = nullptr; else - next = 0; + next = nullptr; } else { // Take all the children out of the |next| block and put them in // the |prev| block. - nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer()); + nextBlock.moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock.hasLayer() || prevBlock.hasLayer()); // Delete the now-empty block's lines and nuke it. - nextBlock->deleteLines(); - nextBlock->destroy(); - next = 0; + nextBlock.deleteLines(); + nextBlock.destroy(); + next = nullptr; } } @@ -1150,20 +884,26 @@ void RenderBlock::removeChild(RenderObject& oldChild) RenderBox::removeChild(oldChild); RenderObject* child = prev ? prev : next; - if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) { + if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canDropAnonymousBlockChild()) { // The removal has knocked us down to containing only a single anonymous - // box. We can go ahead and pull the content right back up into our - // box. - collapseAnonymousBoxChild(this, toRenderBlock(child)); - } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) { + // box. We can pull the content right back up into our box. + dropAnonymousBoxChild(*this, downcast(*child)); + } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canDropAnonymousBlockChild()) { // It's possible that the removal has knocked us down to a single anonymous - // block with pseudo-style element siblings (e.g. first-letter). If these - // are floating, then we need to pull the content up also. - RenderBlock* anonBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next); - if ((anonBlock->previousSibling() || anonBlock->nextSibling()) - && (!anonBlock->previousSibling() || (anonBlock->previousSibling()->style().styleType() != NOPSEUDO && anonBlock->previousSibling()->isFloating() && !anonBlock->previousSibling()->previousSibling())) - && (!anonBlock->nextSibling() || (anonBlock->nextSibling()->style().styleType() != NOPSEUDO && anonBlock->nextSibling()->isFloating() && !anonBlock->nextSibling()->nextSibling()))) { - collapseAnonymousBoxChild(this, anonBlock); + // block with floating siblings. + RenderBlock& anonBlock = downcast((prev && prev->isAnonymousBlock()) ? *prev : *next); + if (canDropAnonymousBlock(anonBlock)) { + bool dropAnonymousBlock = true; + for (auto& sibling : childrenOfType(*this)) { + if (&sibling == &anonBlock) + continue; + if (!sibling.isFloating()) { + dropAnonymousBlock = false; + break; + } + } + if (dropAnonymousBlock) + dropAnonymousBoxChild(*this, anonBlock); } } @@ -1178,28 +918,41 @@ void RenderBlock::removeChild(RenderObject& oldChild) auto containingBlockIgnoringAnonymous = containingBlock(); while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock()) containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock(); - for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) { - if (curr->virtualContinuation() != this) + for (RenderObject* current = this; current; current = current->previousInPreOrder(containingBlockIgnoringAnonymous)) { + if (current->virtualContinuation() != this) continue; // Found our previous continuation. We just need to point it to // |this|'s next continuation. RenderBoxModelObject* nextContinuation = continuation(); - if (curr->isRenderInline()) - toRenderInline(curr)->setContinuation(nextContinuation); - else if (curr->isRenderBlock()) - toRenderBlock(curr)->setContinuation(nextContinuation); + if (is(*current)) + downcast(*current).setContinuation(nextContinuation); + else if (is(*current)) + downcast(*current).setContinuation(nextContinuation); else ASSERT_NOT_REACHED(); break; } - setContinuation(0); + setContinuation(nullptr); destroy(); } } } +bool RenderBlock::childrenPreventSelfCollapsing() const +{ + // Whether or not we collapse is dependent on whether all our normal flow children + // are also self-collapsing. + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { + if (child->isFloatingOrOutOfFlowPositioned()) + continue; + if (!child->isSelfCollapsingBlock()) + return true; + } + return false; +} + bool RenderBlock::isSelfCollapsingBlock() const { // We are not self-collapsing if we @@ -1216,9 +969,9 @@ bool RenderBlock::isSelfCollapsingBlock() const Length logicalHeightLength = style().logicalHeight(); bool hasAutoHeight = logicalHeightLength.isAuto(); - if (logicalHeightLength.isPercent() && !document().inQuirksMode()) { + if (logicalHeightLength.isPercentOrCalculated() && !document().inQuirksMode()) { hasAutoHeight = true; - for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { + for (RenderBlock* cb = containingBlock(); cb && !is(*cb); cb = cb->containingBlock()) { if (cb->style().logicalHeight().isFixed() || cb->isTableCell()) hasAutoHeight = false; } @@ -1226,78 +979,82 @@ bool RenderBlock::isSelfCollapsingBlock() const // If the height is 0 or auto, then whether or not we are a self-collapsing block depends // on whether we have content that is all self-collapsing or not. - if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) { - // If the block has inline children, see if we generated any line boxes. If we have any - // line boxes, then we can't be self-collapsing, since we have content. - if (childrenInline()) - return !hasLines(); - - // Whether or not we collapse is dependent on whether all our normal flow children - // are also self-collapsing. - for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { - if (child->isFloatingOrOutOfFlowPositioned()) - continue; - if (!child->isSelfCollapsingBlock()) - return false; - } - return true; - } + if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercentOrCalculated()) && logicalHeightLength.isZero())) + return !childrenPreventSelfCollapsing(); + return false; } -void RenderBlock::startDelayUpdateScrollInfo() +static inline UpdateScrollInfoAfterLayoutTransaction* currentUpdateScrollInfoAfterLayoutTransaction() { - if (gDelayUpdateScrollInfo == 0) { - ASSERT(!gDelayedUpdateScrollInfoSet); - gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; - } - ASSERT(gDelayedUpdateScrollInfoSet); - ++gDelayUpdateScrollInfo; + if (!updateScrollInfoAfterLayoutTransactionStack()) + return nullptr; + return &updateScrollInfoAfterLayoutTransactionStack()->last(); } -void RenderBlock::finishDelayUpdateScrollInfo() +void RenderBlock::beginUpdateScrollInfoAfterLayoutTransaction() { - --gDelayUpdateScrollInfo; - ASSERT(gDelayUpdateScrollInfo >= 0); - if (gDelayUpdateScrollInfo == 0) { - ASSERT(gDelayedUpdateScrollInfoSet); + if (!updateScrollInfoAfterLayoutTransactionStack()) + updateScrollInfoAfterLayoutTransactionStack() = std::make_unique(); + if (updateScrollInfoAfterLayoutTransactionStack()->isEmpty() || currentUpdateScrollInfoAfterLayoutTransaction()->view != &view()) + updateScrollInfoAfterLayoutTransactionStack()->append(UpdateScrollInfoAfterLayoutTransaction(view())); + ++currentUpdateScrollInfoAfterLayoutTransaction()->nestedCount; +} - OwnPtr infoSet(adoptPtr(gDelayedUpdateScrollInfoSet)); - gDelayedUpdateScrollInfoSet = 0; +void RenderBlock::endAndCommitUpdateScrollInfoAfterLayoutTransaction() +{ + UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction(); + ASSERT(transaction); + ASSERT(transaction->view == &view()); + if (--transaction->nestedCount) + return; - for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { - RenderBlock* block = *it; - if (block->hasOverflowClip()) { - block->layer()->updateScrollInfoAfterLayout(); - block->clearLayoutOverflow(); - } - } + // Calling RenderLayer::updateScrollInfoAfterLayout() may cause its associated block to layout again and + // updates its scroll info (i.e. call RenderBlock::updateScrollInfoAfterLayout()). We remove |transaction| + // from the transaction stack to ensure that all subsequent calls to RenderBlock::updateScrollInfoAfterLayout() + // are dispatched immediately. That is, to ensure that such subsequent calls aren't added to |transaction| + // while we are processing it. + Vector blocksToUpdate; + copyToVector(transaction->blocks, blocksToUpdate); + updateScrollInfoAfterLayoutTransactionStack()->removeLast(); + if (updateScrollInfoAfterLayoutTransactionStack()->isEmpty()) + updateScrollInfoAfterLayoutTransactionStack() = nullptr; + + for (auto* block : blocksToUpdate) { + ASSERT(block->hasOverflowClip()); + block->layer()->updateScrollInfoAfterLayout(); + block->clearLayoutOverflow(); } } -void RenderBlock::removeFromDelayedUpdateScrollInfoSet() +void RenderBlock::removeFromUpdateScrollInfoAfterLayoutTransaction() { - if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0)) - gDelayedUpdateScrollInfoSet->remove(this); + if (UNLIKELY(updateScrollInfoAfterLayoutTransactionStack().get() != 0)) { + UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction(); + ASSERT(transaction); + if (transaction->view == &view()) + transaction->blocks.remove(this); + } } void RenderBlock::updateScrollInfoAfterLayout() { - if (hasOverflowClip()) { - if (style().isFlippedBlocksWritingMode()) { - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937 - // Workaround for now. We cannot delay the scroll info for overflow - // for items with opposite writing directions, as the contents needs - // to overflow in that direction - layer()->updateScrollInfoAfterLayout(); + if (!hasOverflowClip()) + return; + + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937 + // Workaround for now. We cannot delay the scroll info for overflow + // for items with opposite writing directions, as the contents needs + // to overflow in that direction + if (!style().isFlippedBlocksWritingMode()) { + UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction(); + if (transaction && transaction->view == &view()) { + transaction->blocks.add(this); return; } - - if (gDelayUpdateScrollInfo) - gDelayedUpdateScrollInfoSet->add(this); - else - layer()->updateScrollInfoAfterLayout(); } + if (layer()) + layer()->updateScrollInfoAfterLayout(); } void RenderBlock::layout() @@ -1314,247 +1071,48 @@ void RenderBlock::layout() // It's safe to check for control clip here, since controls can never be table cells. // If we have a lightweight clip, there can never be any overflow from children. - if (hasControlClip() && m_overflow && !gDelayUpdateScrollInfo) + UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction(); + bool isDelayingUpdateScrollInfoAfterLayoutInView = transaction && transaction->view == &view(); + if (hasControlClip() && m_overflow && !isDelayingUpdateScrollInfoAfterLayoutInView) clearLayoutOverflow(); invalidateBackgroundObscurationStatus(); } -static RenderBlockRareData* getRareData(const RenderBlock* block) +static RenderBlockRareData* getBlockRareData(const RenderBlock& block) { - return gRareDataMap ? gRareDataMap->get(block) : 0; + return gRareDataMap ? gRareDataMap->get(&block) : nullptr; } -static RenderBlockRareData& ensureRareData(const RenderBlock* block) +static RenderBlockRareData& ensureBlockRareData(const RenderBlock& block) { if (!gRareDataMap) gRareDataMap = new RenderBlockRareDataMap; - auto& rareData = gRareDataMap->add(block, nullptr).iterator->value; + auto& rareData = gRareDataMap->add(&block, nullptr).iterator->value; if (!rareData) rareData = std::make_unique(); return *rareData.get(); } -#if ENABLE(CSS_SHAPES) -void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset) -{ - LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height(); - if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo()) - return; - // Propagate layout markers only up to the child, as we are still in the middle - // of a layout pass - child->setNormalChildNeedsLayoutBit(true); - child->markShapeInsideDescendantsForLayout(); - child->layoutIfNeeded(); -} - -LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const -{ - const RenderBlock* currentBlock = this; - LayoutRect blockRect(currentBlock->borderBoxRect()); - while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) { - RenderBlock* containerBlock = currentBlock->containingBlock(); - ASSERT(containerBlock); - if (!containerBlock) - return LayoutSize(); - - if (containerBlock->style().writingMode() != currentBlock->style().writingMode()) { - // We have to put the block rect in container coordinates - // and we have to take into account both the container and current block flipping modes - // Bug 118073: Flipping inline and block directions at the same time will not work, - // as one of the flipped dimensions will not yet have been set to its final size - if (containerBlock->style().isFlippedBlocksWritingMode()) { - if (containerBlock->isHorizontalWritingMode()) - blockRect.setY(currentBlock->height() - blockRect.maxY()); - else - blockRect.setX(currentBlock->width() - blockRect.maxX()); - } - currentBlock->flipForWritingMode(blockRect); - } - - blockRect.moveBy(currentBlock->location()); - currentBlock = containerBlock; - } - - LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x()); - return result; -} - -void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*) -{ - RenderBox::imageChanged(image); - - if (!parent() || !everHadLayout()) - return; - - ShapeValue* shapeValue = style().shapeInside(); - if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) { - ShapeInsideInfo& shapeInsideInfo = ensureShapeInsideInfo(); - shapeInsideInfo.dirtyShapeSize(); - markShapeInsideDescendantsForLayout(); - } - - ShapeValue* shapeOutsideValue = style().shapeOutside(); - if (isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) - parent()->setNeedsLayoutAndPrefWidthsRecalc(); -} - -void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside) -{ - // FIXME: A future optimization would do a deep comparison for equality. - if (shapeInside == oldShapeInside) - return; - - if (shapeInside) { - ShapeInsideInfo& shapeInsideInfo = ensureShapeInsideInfo(); - shapeInsideInfo.dirtyShapeSize(); - } else - setShapeInsideInfo(nullptr); - markShapeInsideDescendantsForLayout(); -} - -ShapeInsideInfo& RenderBlock::ensureShapeInsideInfo() -{ - RenderBlockRareData& rareData = ensureRareData(this); - if (!rareData.m_shapeInsideInfo) - setShapeInsideInfo(std::make_unique(*this)); - return *rareData.m_shapeInsideInfo; -} - -ShapeInsideInfo* RenderBlock::shapeInsideInfo() const -{ - RenderBlockRareData* rareData = getRareData(this); - if (!rareData || !rareData->m_shapeInsideInfo) - return nullptr; - return ShapeInsideInfo::isEnabledFor(*this) ? rareData->m_shapeInsideInfo.get() : nullptr; -} - -void RenderBlock::setShapeInsideInfo(std::unique_ptr value) -{ - ensureRareData(this).m_shapeInsideInfo = std::move(value); -} - -void RenderBlock::markShapeInsideDescendantsForLayout() -{ - if (!everHadLayout()) - return; - if (childrenInline()) { - setNeedsLayout(); - invalidateLineLayoutPath(); - return; - } - - for (auto& childBlock : childrenOfType(*this)) - childBlock.markShapeInsideDescendantsForLayout(); -} - -ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const -{ - // This may be called outside layout when switching from SimpleLineLayout to line boxes. This case never has shape info. - if (!view().layoutState()) - return nullptr; - - ShapeInsideInfo* shapeInsideInfo = view().layoutState()->shapeInsideInfo(); - - if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfoSharing()) { - LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); - // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ... - LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit::fromPixel(1); - RenderRegion* region = regionAtBlockOffset(offset); - if (region && region->logicalHeight()) - shapeInsideInfo = region->shapeInsideInfo(); - } - - return shapeInsideInfo; -} - -static inline bool shapeInfoRequiresRelayout(const RenderBlock* block) -{ - ShapeInsideInfo* info = block->shapeInsideInfo(); - if (info) - info->setNeedsLayout(info->shapeSizeDirty()); - else - info = block->layoutShapeInsideInfo(); - return info && info->needsLayout(); -} - -void RenderBlock::computeShapeSize() -{ - ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo(); - if (!shapeInsideInfo) - return; - - if (isRenderNamedFlowFragment()) { - ShapeInsideInfo* parentShapeInsideInfo = toRenderBlock(parent())->shapeInsideInfo(); - ASSERT(parentShapeInsideInfo); - shapeInsideInfo->setShapeSize(parentShapeInsideInfo->shapeSize().width(), parentShapeInsideInfo->shapeSize().height()); - } else { - bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false); - shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit()); - } -} -#endif - -bool RenderBlock::updateShapesBeforeBlockLayout() -{ -#if ENABLE(CSS_SHAPES) - if (!flowThreadContainingBlock() && !shapeInsideInfo()) - return shapeInfoRequiresRelayout(this); - - LayoutUnit oldHeight = logicalHeight(); - LayoutUnit oldTop = logicalTop(); - - // Compute the maximum logical height content may cause this block to expand to - // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight - setLogicalHeight(RenderFlowThread::maxLogicalHeight()); - updateLogicalHeight(); - - computeShapeSize(); - - setLogicalHeight(oldHeight); - setLogicalTop(oldTop); - - return shapeInfoRequiresRelayout(this); -#else - return false; -#endif -} - -void RenderBlock::updateShapesAfterBlockLayout(bool heightChanged) -{ -#if ENABLE(CSS_SHAPES) - // A previous sibling has changed dimension, so we need to relayout the shape with the content - ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo(); - if (heightChanged && shapeInsideInfo) - shapeInsideInfo->dirtyShapeSize(); -#else - UNUSED_PARAM(heightChanged); -#endif -} - -void RenderBlock::prepareShapesAndPaginationBeforeBlockLayout(bool& relayoutChildren) +void RenderBlock::preparePaginationBeforeBlockLayout(bool& relayoutChildren) { // Regions changing widths can force us to relayout our children. RenderFlowThread* flowThread = flowThreadContainingBlock(); - if (updateShapesBeforeBlockLayout()) - relayoutChildren = true; if (flowThread) flowThread->logicalWidthChangedInRegionsForBlock(this, relayoutChildren); } -bool RenderBlock::updateLogicalWidthAndColumnWidth() +bool RenderBlock::recomputeLogicalWidth() { LayoutUnit oldWidth = logicalWidth(); - LayoutUnit oldColumnWidth = computedColumnWidth(); - + updateLogicalWidth(); - computeColumnCountAndWidth(); - - bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged; - m_hasBorderOrPaddingLogicalWidthChanged = false; + + bool hasBorderOrPaddingLogicalWidthChanged = this->hasBorderOrPaddingLogicalWidthChanged(); + setShouldForceRelayoutChildren(false); - return oldWidth != logicalWidth() || oldColumnWidth != computedColumnWidth() || hasBorderOrPaddingLogicalWidthChanged; + return oldWidth != logicalWidth() || hasBorderOrPaddingLogicalWidthChanged; } void RenderBlock::layoutBlock(bool, LayoutUnit) @@ -1565,43 +1123,32 @@ void RenderBlock::layoutBlock(bool, LayoutUnit) void RenderBlock::addOverflowFromChildren() { - if (!hasColumns()) { - if (childrenInline()) - addOverflowFromInlineChildren(); - else - addOverflowFromBlockChildren(); - - // If this block is flowed inside a flow thread, make sure its overflow is propagated to the containing regions. - if (m_overflow) { - if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock()) - containingFlowThread->addRegionsVisualOverflow(this, m_overflow->visualOverflowRect()); - } - } else { - ColumnInfo* colInfo = columnInfo(); - if (columnCount(colInfo)) { - LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); - addLayoutOverflow(lastRect); - if (!hasOverflowClip()) - addVisualOverflow(lastRect); - } + if (childrenInline()) + addOverflowFromInlineChildren(); + else + addOverflowFromBlockChildren(); + + // If this block is flowed inside a flow thread, make sure its overflow is propagated to the containing regions. + if (m_overflow) { + if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock()) + containingFlowThread->addRegionsVisualOverflow(this, m_overflow->visualOverflowRect()); } } +// Overflow is always relative to the border-box of the element in question. +// Therefore, if the element has a vertical scrollbar placed on the left, an overflow rect at x=2px would conceptually intersect the scrollbar. void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool) { clearOverflow(); - - // Add overflow from children. addOverflowFromChildren(); - // Add in the overflow from positioned objects. addOverflowFromPositionedObjects(); if (hasOverflowClip()) { // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always // be considered reachable. - LayoutRect clientRect(clientBoxRect()); + LayoutRect clientRect(flippedClientBoxRect()); LayoutRect rectToApply; if (isHorizontalWritingMode()) rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, std::max(0, oldClientAfterEdge - clientRect.y())); @@ -1612,14 +1159,11 @@ void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool) m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge); } - // Add visual overflow from box-shadow and border-image-outset. + // Add visual overflow from box-shadow, border-image-outset and outline. addVisualEffectOverflow(); // Add visual overflow from theme. addVisualOverflowFromTheme(); - - if (isRenderNamedFlowThread()) - toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge); } void RenderBlock::clearLayoutOverflow() @@ -1638,7 +1182,7 @@ void RenderBlock::clearLayoutOverflow() void RenderBlock::addOverflowFromBlockChildren() { - for (auto child = firstChildBox(); child; child = child->nextSiblingBox()) { + for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (!child->isFloatingOrOutOfFlowPositioned()) addOverflowFromChild(child); } @@ -1654,12 +1198,8 @@ void RenderBlock::addOverflowFromPositionedObjects() RenderBox* positionedObject = *it; // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content. - if (positionedObject->style().position() != FixedPosition) { - LayoutUnit x = positionedObject->x(); - if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - x -= verticalScrollbarWidth(); - addOverflowFromChild(positionedObject, LayoutSize(x, positionedObject->y())); - } + if (positionedObject->style().position() != FixedPosition) + addOverflowFromChild(positionedObject, { positionedObject->x(), positionedObject->y() }); } } @@ -1668,183 +1208,14 @@ void RenderBlock::addVisualOverflowFromTheme() if (!style().hasAppearance()) return; - IntRect inflatedRect = pixelSnappedBorderBoxRect(); - theme().adjustRepaintRect(this, inflatedRect); - addVisualOverflow(inflatedRect); + FloatRect inflatedRect = borderBoxRect(); + theme().adjustRepaintRect(*this, inflatedRect); + addVisualOverflow(snappedIntRect(LayoutRect(inflatedRect))); if (RenderFlowThread* flowThread = flowThreadContainingBlock()) flowThread->addRegionsVisualOverflowFromTheme(this); } -bool RenderBlock::isTopLayoutOverflowAllowed() const -{ - bool hasTopOverflow = RenderBox::isTopLayoutOverflowAllowed(); - if (!hasColumns() || style().columnProgression() == NormalColumnProgression) - return hasTopOverflow; - - if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())) - hasTopOverflow = !hasTopOverflow; - - return hasTopOverflow; -} - -bool RenderBlock::isLeftLayoutOverflowAllowed() const -{ - bool hasLeftOverflow = RenderBox::isLeftLayoutOverflowAllowed(); - if (!hasColumns() || style().columnProgression() == NormalColumnProgression) - return hasLeftOverflow; - - if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()) - hasLeftOverflow = !hasLeftOverflow; - - return hasLeftOverflow; -} - -bool RenderBlock::expandsToEncloseOverhangingFloats() const -{ - return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated()) - || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot(); -} - -static void destroyRunIn(RenderBoxModelObject& runIn) -{ - ASSERT(runIn.isRunIn()); - ASSERT(!runIn.firstChild()); - - // Delete our line box tree. This is needed as our children got moved - // and our line box tree is no longer valid. - if (runIn.isRenderBlock()) - toRenderBlock(runIn).deleteLines(); - else if (runIn.isRenderInline()) - toRenderInline(runIn).deleteLines(); - else - ASSERT_NOT_REACHED(); - - runIn.destroy(); -} - -void RenderBlock::placeRunInIfNeeded(RenderObject& newChild) -{ - if (newChild.isRunIn()) - moveRunInUnderSiblingBlockIfNeeded(newChild); - else if (RenderObject* prevSibling = newChild.previousSibling()) { - if (prevSibling->isRunIn()) - moveRunInUnderSiblingBlockIfNeeded(*prevSibling); - } -} - -RenderBoxModelObject& RenderBlock::createReplacementRunIn(RenderBoxModelObject& runIn) -{ - ASSERT(runIn.isRunIn()); - ASSERT(runIn.element()); - - RenderBoxModelObject* newRunIn = 0; - if (!runIn.isRenderBlockFlow()) - newRunIn = new RenderBlockFlow(*runIn.element(), runIn.style()); - else - newRunIn = new RenderInline(*runIn.element(), runIn.style()); - - runIn.element()->setRenderer(newRunIn); - newRunIn->initializeStyle(); - - runIn.moveAllChildrenTo(newRunIn, true); - - return *newRunIn; -} - -void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject& runIn) -{ - ASSERT(runIn.isRunIn()); - - // See if we have inline children. If the children aren't inline, - // then just treat the run-in as a normal block. - if (!runIn.childrenInline()) - return; - - // FIXME: We don't handle non-block elements with run-in for now. - if (!runIn.isRenderBlockFlow()) - return; - - // FIXME: We don't support run-ins with or as part of a continuation - // as it makes the back-and-forth placing complex. - if (runIn.isElementContinuation() || runIn.virtualContinuation()) - return; - - // Check if this node is allowed to run-in. E.g.