diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderBlock.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderBlock.cpp | 373 |
1 files changed, 217 insertions, 156 deletions
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 3ffdef97d..bf1a78a7f 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -92,11 +92,136 @@ struct SameSizeAsRenderBlock : public RenderBox { COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); -static TrackedDescendantsMap* gPositionedDescendantsMap; -static TrackedDescendantsMap* gPercentHeightDescendantsMap; +typedef HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>> TrackedDescendantsMap; +typedef HashMap<const RenderBox*, std::unique_ptr<HashSet<const RenderBlock*>>> TrackedContainerMap; -static TrackedContainerMap* gPositionedContainerMap; -static TrackedContainerMap* gPercentHeightContainerMap; +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<TrackedRendererListHashSet>(); + }).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<HashSet<const RenderBlock*>>(); + }).iterator->value; + + ASSERT(!containerSet->contains(&container)); + containerSet->add(&container); +} + +static void removeFromTrackedRendererMaps(RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) + return; + + std::unique_ptr<HashSet<const RenderBlock*>> 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<TrackedRendererListHashSet>(); + }).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<RenderBox*>(&positionedDescendant))); + + descendants->remove(const_cast<RenderBox*>(&positionedDescendant)); + if (descendants->isEmpty()) + m_descendantsMap.remove(descendantsIterator); + } + + void removeContainingBlock(const RenderBlock& containingBlock) + { + auto descendants = m_descendantsMap.take(&containingBlock); + if (!descendants) + return; + + for (auto* renderer : *descendants) + m_containerMap.remove(renderer); + } + + TrackedRendererListHashSet* positionedRenderers(const RenderBlock& containingBlock) const + { + return m_descendantsMap.get(&containingBlock); + } + +private: + using DescendantsMap = HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>>; + using ContainerMap = HashMap<const RenderBox*, const RenderBlock*>; + + DescendantsMap m_descendantsMap; + ContainerMap m_containerMap; +}; + +static PositionedDescendantsMap& positionedDescendantsMap() +{ + static NeverDestroyed<PositionedDescendantsMap> mapForPositionedDescendants; + return mapForPositionedDescendants; +} typedef HashMap<RenderBlock*, std::unique_ptr<ListHashSet<RenderInline*>>> ContinuationOutlineTableMap; @@ -192,21 +317,24 @@ RenderBlock::RenderBlock(Document& document, Ref<RenderStyle>&& style, BaseTypeF { } -static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap) +static void removeBlockFromPercentageDescendantAndContainerMaps(RenderBlock* block) { - if (std::unique_ptr<TrackedRendererListHashSet> 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<RenderBlock*>* containerSet = it->value.get(); - ASSERT(containerSet->contains(block)); - containerSet->remove(block); - if (containerSet->isEmpty()) - containerMap->remove(it); - } + if (!percentHeightDescendantsMap) + return; + std::unique_ptr<TrackedRendererListHashSet> 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); } } @@ -216,10 +344,8 @@ RenderBlock::~RenderBlock() if (gRareDataMap) gRareDataMap->remove(this); - if (gPercentHeightDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap); - if (gPositionedDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap); + removeBlockFromPercentageDescendantAndContainerMaps(this); + positionedDescendantsMap().removeContainingBlock(*this); } void RenderBlock::willBeDestroyed() @@ -244,14 +370,20 @@ void RenderBlock::removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, c if (oldStyle.position() == newStyle.position() && hadTransform == willHaveTransform) return; - // We are no longer a containing block. + // 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; + } + + // We are no longer the containing block for absolute positioned descendants. if (newStyle.position() == StaticPosition && !willHaveTransform) { - // Clear our positioned objects list. Our absolutely positioned descendants will be - // inserted into our containing block's positioned objects list during layout. + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. removePositionedObjects(nullptr, NewContainingBlock); return; } - + // We are a new containing block. if (oldStyle.position() == StaticPosition && !hadTransform) { // Remove our absolutely positioned descendants from their current containing block. @@ -1157,10 +1289,10 @@ void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, R void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants() { - if (!gPercentHeightDescendantsMap) + if (!percentHeightDescendantsMap) return; - TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this); + TrackedRendererListHashSet* descendants = percentHeightDescendantsMap->get(this); if (!descendants) return; @@ -1264,34 +1396,33 @@ bool RenderBlock::simplifiedLayout() return true; } -void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject& child) +void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderBox& positionedChild) { - if (child.style().position() != FixedPosition) + if (positionedChild.style().position() != FixedPosition) return; - bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontalWritingMode()); - bool hasStaticInlinePosition = child.style().hasStaticInlinePosition(isHorizontalWritingMode()); + bool hasStaticBlockPosition = positionedChild.style().hasStaticBlockPosition(isHorizontalWritingMode()); + bool hasStaticInlinePosition = positionedChild.style().hasStaticInlinePosition(isHorizontalWritingMode()); if (!hasStaticBlockPosition && !hasStaticInlinePosition) return; - auto o = child.parent(); - while (o && !is<RenderView>(*o) && o->style().position() != AbsolutePosition) - o = o->parent(); - if (o->style().position() != AbsolutePosition) + auto* parent = positionedChild.parent(); + while (parent && !is<RenderView>(*parent) && parent->style().position() != AbsolutePosition) + parent = parent->parent(); + if (!parent || parent->style().position() != AbsolutePosition) return; - auto& box = downcast<RenderBox>(child); if (hasStaticInlinePosition) { LogicalExtentComputedValues computedValues; - box.computeLogicalWidthInRegion(computedValues); + positionedChild.computeLogicalWidthInRegion(computedValues); LayoutUnit newLeft = computedValues.m_position; - if (newLeft != box.logicalLeft()) - box.setChildNeedsLayout(MarkOnlyThis); + if (newLeft != positionedChild.logicalLeft()) + positionedChild.setChildNeedsLayout(MarkOnlyThis); } else if (hasStaticBlockPosition) { - LayoutUnit oldTop = box.logicalTop(); - box.updateLogicalHeight(); - if (box.logicalTop() != oldTop) - box.setChildNeedsLayout(MarkOnlyThis); + LayoutUnit oldTop = positionedChild.logicalTop(); + positionedChild.updateLogicalHeight(); + if (positionedChild.logicalTop() != oldTop) + positionedChild.setChildNeedsLayout(MarkOnlyThis); } } @@ -2049,6 +2180,8 @@ LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock& rootBlock, Layou ASSERT(currentCache); auto info = currentCache->containingBlockInfo(*cb); cb = info.block(); + if (!cb) + break; currentCache = info.cache(); } return logicalLeft; @@ -2071,6 +2204,8 @@ LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock& rootBlock, Layo ASSERT(currentCache); auto info = currentCache->containingBlockInfo(*cb); cb = info.block(); + if (!cb) + break; currentCache = info.cache(); } return logicalRight; @@ -2108,148 +2243,79 @@ RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) con return beforeBlock; } -void RenderBlock::insertIntoTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap, bool forceNewEntry) -{ - if (!descendantsMap) { - descendantsMap = new TrackedDescendantsMap; - containerMap = new TrackedContainerMap; - } - - TrackedRendererListHashSet* descendantSet = descendantsMap->get(this); - if (!descendantSet) { - descendantSet = new TrackedRendererListHashSet; - descendantsMap->set(this, std::unique_ptr<TrackedRendererListHashSet>(descendantSet)); - } - - if (forceNewEntry) { - descendantSet->remove(&descendant); - containerMap->remove(&descendant); - } - - bool added = descendantSet->add(&descendant).isNewEntry; - if (!added) { - ASSERT(containerMap->get(&descendant)); - ASSERT(containerMap->get(&descendant)->contains(this)); - return; - } - - HashSet<RenderBlock*>* containerSet = containerMap->get(&descendant); - if (!containerSet) { - containerSet = new HashSet<RenderBlock*>; - containerMap->set(&descendant, std::unique_ptr<HashSet<RenderBlock*>>(containerSet)); - } - ASSERT(!containerSet->contains(this)); - containerSet->add(this); -} - -void RenderBlock::removeFromTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap) -{ - if (!descendantsMap) - return; - - std::unique_ptr<HashSet<RenderBlock*>> containerSet = containerMap->take(&descendant); - if (!containerSet) - return; - - for (auto it = containerSet->begin(), end = containerSet->end(); it != end; ++it) { - RenderBlock* container = *it; - - // 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)); - - TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container); - ASSERT(descendantsMapIterator != descendantsMap->end()); - if (descendantsMapIterator == descendantsMap->end()) - continue; - TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get(); - ASSERT(descendantSet->contains(&descendant)); - descendantSet->remove(&descendant); - if (descendantSet->isEmpty()) - descendantsMap->remove(descendantsMapIterator); - } -} - TrackedRendererListHashSet* RenderBlock::positionedObjects() const { - if (gPositionedDescendantsMap) - return gPositionedDescendantsMap->get(this); - return nullptr; + return positionedDescendantsMap().positionedRenderers(*this); } -void RenderBlock::insertPositionedObject(RenderBox& o) +void RenderBlock::insertPositionedObject(RenderBox& positioned) { ASSERT(!isAnonymousBlock()); - if (o.isRenderFlowThread()) + if (positioned.isRenderFlowThread()) return; - - insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap, isRenderView()); + + positionedDescendantsMap().addDescendant(*this, positioned, isRenderView() ? PositionedDescendantsMap::MoveDescendantToEnd::Yes + : PositionedDescendantsMap::MoveDescendantToEnd::No); } -void RenderBlock::removePositionedObject(RenderBox& o) +void RenderBlock::removePositionedObject(const RenderBox& rendererToRemove) { - removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap); + positionedDescendantsMap().removeDescendant(rendererToRemove); } -void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState) +void RenderBlock::removePositionedObjects(const RenderBlock* newContainingBlockCandidate, ContainingBlockState containingBlockState) { - TrackedRendererListHashSet* positionedDescendants = positionedObjects(); + auto* positionedDescendants = positionedObjects(); if (!positionedDescendants) return; - Vector<RenderBox*, 16> deadObjects; - - for (auto it = positionedDescendants->begin(), end = positionedDescendants->end(); it != end; ++it) { - RenderBox* r = *it; - if (!o || r->isDescendantOf(o)) { - if (containingBlockState == NewContainingBlock) - r->setChildNeedsLayout(MarkOnlyThis); - - // It is parent blocks job to add positioned child to positioned objects list of its containing block - // Parent layout needs to be invalidated to ensure this happens. - RenderElement* p = r->parent(); - while (p && !p->isRenderBlock()) - p = p->parent(); - if (p) - p->setChildNeedsLayout(); - - deadObjects.append(r); - } + Vector<RenderBox*, 16> renderersToRemove; + for (auto* renderer : *positionedDescendants) { + if (newContainingBlockCandidate && !renderer->isDescendantOf(newContainingBlockCandidate)) + continue; + renderersToRemove.append(renderer); + if (containingBlockState == NewContainingBlock) + renderer->setChildNeedsLayout(MarkOnlyThis); + // It is the parent block's job to add positioned children to positioned objects list of its containing block. + // Dirty the parent to ensure this happens. + auto* parent = renderer->parent(); + while (parent && !parent->isRenderBlock()) + parent = parent->parent(); + if (parent) + parent->setChildNeedsLayout(); } - - for (unsigned i = 0; i < deadObjects.size(); i++) - removePositionedObject(*deadObjects.at(i)); + for (auto* renderer : renderersToRemove) + removePositionedObject(*renderer); } void RenderBlock::addPercentHeightDescendant(RenderBox& descendant) { - insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); + insertIntoTrackedRendererMaps(*this, descendant); } void RenderBlock::removePercentHeightDescendant(RenderBox& descendant) { - removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); + removeFromTrackedRendererMaps(descendant); } TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const { - return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; + return percentHeightDescendantsMap ? percentHeightDescendantsMap->get(this) : nullptr; } bool RenderBlock::hasPercentHeightContainerMap() { - return gPercentHeightContainerMap; + return percentHeightContainerMap; } bool RenderBlock::hasPercentHeightDescendant(RenderBox& descendant) { - // We don't null check gPercentHeightContainerMap since the caller + // We don't null check percentHeightContainerMap since the caller // already ensures this and we need to call this function on every // descendant in clearPercentHeightDescendantsFrom(). - ASSERT(gPercentHeightContainerMap); - return gPercentHeightContainerMap->contains(&descendant); + ASSERT(percentHeightContainerMap); + return percentHeightContainerMap->contains(&descendant); } void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox& descendant) @@ -2268,7 +2334,7 @@ void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox& descendant) void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox& parent) { - ASSERT(gPercentHeightContainerMap); + ASSERT(percentHeightContainerMap); for (RenderObject* child = parent.firstChild(); child; child = child->nextInPreOrder(&parent)) { if (!is<RenderBox>(*child)) continue; @@ -3768,17 +3834,12 @@ RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const Rend #ifndef NDEBUG void RenderBlock::checkPositionedObjectsNeedLayout() { - if (!gPositionedDescendantsMap) - return; - - TrackedRendererListHashSet* positionedDescendantSet = positionedObjects(); - if (!positionedDescendantSet) + auto* positionedDescendants = positionedObjects(); + if (!positionedDescendants) return; - for (auto it = positionedDescendantSet->begin(), end = positionedDescendantSet->end(); it != end; ++it) { - RenderBox* currBox = *it; - ASSERT(!currBox->needsLayout()); - } + for (auto* renderer : *positionedDescendants) + ASSERT(!renderer->needsLayout()); } #endif |