summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/rendering/RenderBlock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/RenderBlock.cpp')
-rw-r--r--Source/WebCore/rendering/RenderBlock.cpp373
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