Index: Source/core/rendering/FastTextAutosizer.cpp |
diff --git a/Source/core/rendering/FastTextAutosizer.cpp b/Source/core/rendering/FastTextAutosizer.cpp |
index c55ef34bbb352d36a06f61349dcdeca9e37bdc41..79ef19a3b1485270ddcec3e6596aa87a3e8e03f7 100644 |
--- a/Source/core/rendering/FastTextAutosizer.cpp |
+++ b/Source/core/rendering/FastTextAutosizer.cpp |
@@ -97,8 +97,8 @@ void FastTextAutosizer::beginLayout(RenderBlock* block) |
return; |
} |
- if (Cluster* cluster = maybeGetOrCreateCluster(block)) |
- m_clusterStack.append(cluster); |
+ if (Cluster* cluster = maybeCreateCluster(block)) |
+ m_clusterStack.append(adoptPtr(cluster)); |
if (block->childrenInline()) |
inflate(block); |
@@ -124,10 +124,12 @@ void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark |
void FastTextAutosizer::endLayout(RenderBlock* block) |
{ |
ASSERT(enabled()); |
+ if (block->isRenderView()) { |
+ m_superclusters.clear(); |
#ifndef NDEBUG |
- if (block->isRenderView()) |
m_blocksThatHaveBegunLayout.clear(); |
#endif |
+ } |
if (currentCluster()->m_root == block) |
m_clusterStack.removeLast(); |
@@ -193,6 +195,12 @@ bool FastTextAutosizer::isFingerprintingCandidate(const RenderBlock* block) |
&& TextAutosizer::isIndependentDescendant(block)); |
} |
+bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root) |
+{ |
+ Cluster hypotheticalCluster(root, true, 0); |
+ return clusterHasEnoughTextToAutosize(&hypotheticalCluster); |
+} |
+ |
bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster) |
{ |
const RenderBlock* root = cluster->m_root; |
@@ -222,12 +230,6 @@ float FastTextAutosizer::textLength(Cluster* cluster) |
// clusters-sufficient-text-except-in-root.html). This currently includes text |
// from descendant clusters. |
- if (descendant->isRenderBlock() && m_clusters.contains(toRenderBlock(descendant))) { |
- length += textLength(m_clusters.get(toRenderBlock(descendant))); |
- descendant = descendant->nextInPreOrderAfterChildren(root); |
- continue; |
- } |
- |
if (measureLocalText && descendant->isText()) { |
// Note: Using text().stripWhiteSpace().length() instead of renderedTextLength() because |
// the lineboxes will not be built until layout. These values can be different. |
@@ -245,7 +247,7 @@ AtomicString FastTextAutosizer::computeFingerprint(const RenderBlock* block) |
return nullAtom; |
} |
-FastTextAutosizer::Cluster* FastTextAutosizer::maybeGetOrCreateCluster(const RenderBlock* block) |
+FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBlock* block) |
{ |
if (!TextAutosizer::isAutosizingContainer(block)) |
return 0; |
@@ -262,32 +264,26 @@ FastTextAutosizer::Cluster* FastTextAutosizer::maybeGetOrCreateCluster(const Ren |
if (!createClusterThatMightAutosize && containerCanAutosize == parentClusterCanAutosize) |
return 0; |
- ClusterMap::AddResult addResult = m_clusters.add(block, PassOwnPtr<Cluster>()); |
- if (!addResult.isNewEntry) |
- return addResult.iterator->value.get(); |
- |
- AtomicString fingerprint = m_fingerprintMapper.get(block); |
- if (fingerprint.isNull()) { |
- addResult.iterator->value = adoptPtr(new Cluster(block, containerCanAutosize, parentCluster)); |
- return addResult.iterator->value.get(); |
- } |
- return addSupercluster(fingerprint, block); |
+ return new Cluster(block, containerCanAutosize, parentCluster, getSupercluster(block)); |
} |
-// FIXME: The supercluster logic does not work yet. |
-FastTextAutosizer::Cluster* FastTextAutosizer::addSupercluster(AtomicString fingerprint, const RenderBlock* returnFor) |
+FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const RenderBlock* block) |
{ |
- BlockSet& roots = m_fingerprintMapper.getBlocks(fingerprint); |
+ AtomicString fingerprint = m_fingerprintMapper.get(block); |
+ if (fingerprint.isNull()) |
+ return 0; |
- Cluster* result = 0; |
- for (BlockSet::iterator it = roots.begin(); it != roots.end(); ++it) { |
- Cluster* cluster = new Cluster(*it, TextAutosizer::containerShouldBeAutosized(*it), currentCluster()); |
- m_clusters.set(*it, adoptPtr(cluster)); |
+ BlockSet* roots = &m_fingerprintMapper.getBlocks(fingerprint); |
+ if (roots->size() < 2) |
+ return 0; |
- if (*it == returnFor) |
- result = cluster; |
- } |
- return result; |
+ SuperclusterMap::AddResult addResult = m_superclusters.add(fingerprint, PassOwnPtr<Supercluster>()); |
+ if (!addResult.isNewEntry) |
+ return addResult.iterator->value.get(); |
+ |
+ Supercluster* supercluster = new Supercluster(roots); |
+ addResult.iterator->value = adoptPtr(supercluster); |
+ return supercluster; |
} |
const RenderBlock* FastTextAutosizer::deepestCommonAncestor(BlockSet& blocks) |
@@ -312,16 +308,10 @@ float FastTextAutosizer::clusterMultiplier(Cluster* cluster) |
ASSERT(m_renderViewInfoPrepared); |
if (!cluster->m_multiplier) { |
if (TextAutosizer::isIndependentDescendant(cluster->m_root) || isWiderDescendant(cluster) || isNarrowerDescendant(cluster)) { |
- if (clusterHasEnoughTextToAutosize(cluster)) { |
- const RenderBlock* deepestBlockWithAllText = deepestBlockContainingAllText(cluster); |
- |
- // Ensure the deepest block containing all text has a valid contentLogicalWidth. |
- ASSERT(m_blocksThatHaveBegunLayout.contains(deepestBlockWithAllText)); |
- |
- // Block width, in CSS pixels. |
- float textBlockWidth = deepestBlockWithAllText->contentLogicalWidth(); |
- float multiplier = min(textBlockWidth, static_cast<float>(m_layoutWidth)) / m_frameWidth; |
- cluster->m_multiplier = max(m_baseMultiplier * multiplier, 1.0f); |
+ if (cluster->m_supercluster) { |
+ cluster->m_multiplier = superclusterMultiplier(cluster->m_supercluster); |
+ } else if (clusterHasEnoughTextToAutosize(cluster)) { |
+ cluster->m_multiplier = multiplierFromBlock(deepestBlockContainingAllText(cluster)); |
} else { |
cluster->m_multiplier = 1.0f; |
} |
@@ -333,20 +323,56 @@ float FastTextAutosizer::clusterMultiplier(Cluster* cluster) |
return cluster->m_multiplier; |
} |
-// FIXME: Refactor this to look more like FastTextAutosizer::deepestCommonAncestor. This is copied |
-// from TextAutosizer::findDeepestBlockContainingAllText. |
+float FastTextAutosizer::superclusterMultiplier(Supercluster* supercluster) |
+{ |
+ if (!supercluster->m_multiplier) { |
+ const BlockSet* roots = supercluster->m_roots; |
+ // Set of the deepest block containing all text (DBCAT) of every cluster. |
+ BlockSet dbcats; |
+ for (BlockSet::iterator it = roots->begin(); it != roots->end(); ++it) { |
+ dbcats.add(deepestBlockContainingAllText(*it)); |
+ supercluster->m_anyClusterHasEnoughText |= clusterWouldHaveEnoughTextToAutosize(*it); |
+ } |
+ supercluster->m_multiplier = supercluster->m_anyClusterHasEnoughText |
+ ? multiplierFromBlock(deepestCommonAncestor(dbcats)) : 1.0f; |
+ } |
+ ASSERT(supercluster->m_multiplier); |
+ return supercluster->m_multiplier; |
+} |
+ |
+float FastTextAutosizer::multiplierFromBlock(const RenderBlock* block) |
+{ |
+ // If block->needsLayout() is false, it does not need to be in m_blocksThatHaveBegunLayout. |
+ // This can happen during layout of a positioned object if the cluster's DBCAT is deeper |
+ // than the positioned object's containing block, and wasn't marked as needing layout. |
+ ASSERT(m_blocksThatHaveBegunLayout.contains(block) || !block->needsLayout()); |
+ |
+ // Block width, in CSS pixels. |
+ float textBlockWidth = block->contentLogicalWidth(); |
+ float multiplier = min(textBlockWidth, static_cast<float>(m_layoutWidth)) / m_frameWidth; |
+ |
+ return max(m_baseMultiplier * multiplier, 1.0f); |
+} |
+ |
const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* cluster) |
{ |
- if (cluster->m_deepestBlockContainingAllText) |
- return cluster->m_deepestBlockContainingAllText; |
+ if (!cluster->m_deepestBlockContainingAllText) |
+ cluster->m_deepestBlockContainingAllText = deepestBlockContainingAllText(cluster->m_root); |
+ return cluster->m_deepestBlockContainingAllText; |
+} |
+ |
+// FIXME: Refactor this to look more like FastTextAutosizer::deepestCommonAncestor. This is copied |
+// from TextAutosizer::findDeepestBlockContainingAllText. |
+const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(const RenderBlock* root) |
+{ |
size_t firstDepth = 0; |
- const RenderObject* firstTextLeaf = findTextLeaf(cluster->m_root, firstDepth, First); |
+ const RenderObject* firstTextLeaf = findTextLeaf(root, firstDepth, First); |
if (!firstTextLeaf) |
- return cluster->m_deepestBlockContainingAllText = cluster->m_root; |
+ return root; |
size_t lastDepth = 0; |
- const RenderObject* lastTextLeaf = findTextLeaf(cluster->m_root, lastDepth, Last); |
+ const RenderObject* lastTextLeaf = findTextLeaf(root, lastDepth, Last); |
ASSERT(lastTextLeaf); |
// Equalize the depths if necessary. Only one of the while loops below will get executed. |
@@ -368,16 +394,16 @@ const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* clu |
} |
if (firstNode->isRenderBlock()) |
- return cluster->m_deepestBlockContainingAllText = toRenderBlock(firstNode); |
+ return toRenderBlock(firstNode); |
// containingBlock() should never leave the cluster, since it only skips ancestors when finding |
// the container of position:absolute/fixed blocks, and those cannot exist between a cluster and |
// its text node's lowest common ancestor as isAutosizingCluster would have made them into their |
// own independent cluster. |
const RenderBlock* containingBlock = firstNode->containingBlock(); |
- ASSERT(containingBlock->isDescendantOf(cluster->m_root)); |
+ ASSERT(containingBlock->isDescendantOf(root)); |
- return cluster->m_deepestBlockContainingAllText = containingBlock; |
+ return containingBlock; |
} |
const RenderObject* FastTextAutosizer::findTextLeaf(const RenderObject* parent, size_t& depth, TextLeafSearch firstOrLast) |
@@ -467,7 +493,7 @@ bool FastTextAutosizer::isNarrowerDescendant(Cluster* cluster) |
FastTextAutosizer::Cluster* FastTextAutosizer::currentCluster() const |
{ |
ASSERT(!m_clusterStack.isEmpty()); |
- return m_clusterStack.last(); |
+ return m_clusterStack.last().get(); |
} |
void FastTextAutosizer::FingerprintMapper::add(const RenderBlock* block, AtomicString fingerprint) |