Index: third_party/WebKit/Source/core/layout/TextAutosizer.cpp |
diff --git a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp |
index 3de5d5f1182ddf959451ac212379af1856ec20dc..f598a3fdb57e9c6d6c0dd4c0c1f2760502777148 100644 |
--- a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp |
+++ b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp |
@@ -124,7 +124,7 @@ void TextAutosizer::writeClusterDebugInfo(Cluster* cluster) { |
} |
#endif |
-static const LayoutObject* parentElementLayoutObject( |
+static LayoutObject* parentElementLayoutObject( |
const LayoutObject* layoutObject) { |
// At style recalc, the layoutObject's parent may not be attached, |
// so we need to obtain this from the DOM tree. |
@@ -290,13 +290,20 @@ static bool hasExplicitWidth(const LayoutBlock* block) { |
return block->style() && block->style()->width().isSpecified(); |
} |
+static LayoutObject* getParent(const LayoutObject* object) { |
+ LayoutObject* parent = nullptr; |
+ // LayoutObject haven't added to layout tree yet |
+ if (object->node() && object->node()->parentNode()) |
+ parent = object->node()->parentNode()->layoutObject(); |
+ return parent; |
+} |
+ |
TextAutosizer::TextAutosizer(const Document* document) |
: m_document(document), |
m_firstBlockToBeginLayout(nullptr), |
#if ENABLE(ASSERT) |
m_blocksThatHaveBegunLayout(), |
#endif |
- m_superclusters(), |
m_clusterStack(), |
m_fingerprintMapper(), |
m_pageInfo(), |
@@ -305,20 +312,37 @@ TextAutosizer::TextAutosizer(const Document* document) |
TextAutosizer::~TextAutosizer() {} |
-void TextAutosizer::record(const LayoutBlock* block) { |
+void TextAutosizer::record(LayoutBlock* block) { |
if (!m_pageInfo.m_settingEnabled) |
return; |
ASSERT(!m_blocksThatHaveBegunLayout.contains(block)); |
- |
- if (!classifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH)) |
+ if (!classifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH)) { |
+ // !everHadLayout() means the object hasn't layout yet |
+ // which means this object is new added. |
+ // We only deal with new added block here. |
+ // If parent is new added, no need to check its children. |
+ LayoutObject* parent = getParent(block); |
+ if (!block->everHadLayout() && parent && parent->everHadLayout()) |
+ markSuperclusterForConsistencyCheck(parent); |
return; |
+ } |
if (Fingerprint fingerprint = computeFingerprint(block)) |
m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint); |
+ |
+ markSuperclusterForConsistencyCheck(block); |
+} |
+ |
+void TextAutosizer::record(LayoutText* text) { |
+ if (!text || !shouldHandleLayout()) |
+ return; |
+ LayoutObject* parent = getParent(text); |
+ if (parent && parent->everHadLayout()) |
+ markSuperclusterForConsistencyCheck(parent); |
} |
-void TextAutosizer::destroy(const LayoutBlock* block) { |
+void TextAutosizer::destroy(LayoutBlock* block) { |
if (!m_pageInfo.m_settingEnabled && !m_fingerprintMapper.hasFingerprints()) |
return; |
@@ -330,12 +354,11 @@ void TextAutosizer::destroy(const LayoutBlock* block) { |
// Speculative fix for http://crbug.com/369485. |
m_firstBlockToBeginLayout = nullptr; |
m_clusterStack.clear(); |
- m_superclusters.clear(); |
} |
} |
TextAutosizer::BeginLayoutBehavior TextAutosizer::prepareForLayout( |
- const LayoutBlock* block) { |
+ LayoutBlock* block) { |
#if ENABLE(ASSERT) |
m_blocksThatHaveBegunLayout.add(block); |
#endif |
@@ -343,6 +366,8 @@ TextAutosizer::BeginLayoutBehavior TextAutosizer::prepareForLayout( |
if (!m_firstBlockToBeginLayout) { |
m_firstBlockToBeginLayout = block; |
prepareClusterStack(block->parent()); |
+ if (block->isLayoutView()) |
+ checkSuperclusterConsistency(); |
} else if (block == currentCluster()->m_root) { |
// Ignore beginLayout on the same block twice. |
// This can happen with paginated overflow. |
@@ -352,13 +377,13 @@ TextAutosizer::BeginLayoutBehavior TextAutosizer::prepareForLayout( |
return ContinueLayout; |
} |
-void TextAutosizer::prepareClusterStack(const LayoutObject* layoutObject) { |
+void TextAutosizer::prepareClusterStack(LayoutObject* layoutObject) { |
if (!layoutObject) |
return; |
prepareClusterStack(layoutObject->parent()); |
if (layoutObject->isLayoutBlock()) { |
- const LayoutBlock* block = toLayoutBlock(layoutObject); |
+ LayoutBlock* block = toLayoutBlock(layoutObject); |
#if ENABLE(ASSERT) |
m_blocksThatHaveBegunLayout.add(block); |
#endif |
@@ -425,7 +450,6 @@ void TextAutosizer::endLayout(LayoutBlock* block) { |
if (block == m_firstBlockToBeginLayout) { |
m_firstBlockToBeginLayout = nullptr; |
m_clusterStack.clear(); |
- m_superclusters.clear(); |
m_stylesRetainedDuringLayout.clear(); |
#if ENABLE(ASSERT) |
m_blocksThatHaveBegunLayout.clear(); |
@@ -513,6 +537,43 @@ bool TextAutosizer::pageNeedsAutosizing() const { |
return m_pageInfo.m_pageNeedsAutosizing; |
} |
+void TextAutosizer::markSuperclusterForConsistencyCheck(LayoutObject* object) { |
+ if (!object || !shouldHandleLayout()) |
+ return; |
+ |
+ Supercluster* lastSupercluster = nullptr; |
+ LayoutBlock* block = nullptr; |
+ while (object) { |
+ if (object->isLayoutBlock()) { |
+ block = toLayoutBlock(object); |
+ if (block->isTableCell() || |
+ classifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH)) { |
+ // If supercluster hasn't been created yet, create one. |
+ Supercluster* supercluster = |
+ m_fingerprintMapper.createSuperclusterIfNeeded(block); |
+ if (supercluster && |
+ supercluster->m_inheritParentMultiplier == DontInheritMultiplier) { |
+ if (supercluster->m_hasEnoughTextToAutosize != HasEnoughText) { |
+ m_fingerprintMapper.getPotentiallyInconsistentSuperclusters().add( |
+ supercluster); |
+ } |
+ return; |
+ } |
+ if (supercluster) |
+ lastSupercluster = supercluster; |
+ } |
+ } |
+ object = getParent(object); |
+ } |
+ |
+ // If we didn't add any supercluster, we should add one. |
+ if (lastSupercluster && |
+ lastSupercluster->m_hasEnoughTextToAutosize != HasEnoughText) { |
+ m_fingerprintMapper.getPotentiallyInconsistentSuperclusters().add( |
+ lastSupercluster); |
+ } |
+} |
+ |
void TextAutosizer::updatePageInfoInAllFrames() { |
ASSERT(!m_document->frame() || m_document->frame()->isMainFrame()); |
@@ -626,13 +687,21 @@ void TextAutosizer::resetMultipliers() { |
} |
} |
-void TextAutosizer::setAllTextNeedsLayout() { |
- LayoutItem layoutItem = m_document->layoutViewItem(); |
- while (!layoutItem.isNull()) { |
- if (layoutItem.isText()) |
- layoutItem.setNeedsLayoutAndFullPaintInvalidation( |
- LayoutInvalidationReason::TextAutosizing); |
- layoutItem = layoutItem.nextInPreOrder(); |
+void TextAutosizer::setAllTextNeedsLayout(LayoutBlock* container) { |
+ if (!container) |
+ container = m_document->layoutView(); |
+ LayoutObject* object = container; |
+ while (object) { |
+ if (!object->everHadLayout()) { |
+ // Object is new added node, so no need to deal with its children |
+ object = object->nextInPreOrderAfterChildren(container); |
+ } else { |
+ if (object->isText()) { |
+ object->setNeedsLayoutAndFullPaintInvalidation( |
+ LayoutInvalidationReason::TextAutosizing); |
+ } |
+ object = object->nextInPreOrder(container); |
+ } |
} |
} |
@@ -724,7 +793,7 @@ bool TextAutosizer::clusterHasEnoughTextToAutosize( |
} |
TextAutosizer::Fingerprint TextAutosizer::getFingerprint( |
- const LayoutObject* layoutObject) { |
+ LayoutObject* layoutObject) { |
Fingerprint result = m_fingerprintMapper.get(layoutObject); |
if (!result) { |
result = computeFingerprint(layoutObject); |
@@ -740,7 +809,7 @@ TextAutosizer::Fingerprint TextAutosizer::computeFingerprint( |
return 0; |
FingerprintSourceData data; |
- if (const LayoutObject* parent = parentElementLayoutObject(layoutObject)) |
+ if (LayoutObject* parent = parentElementLayoutObject(layoutObject)) |
data.m_parentHash = getFingerprint(parent); |
data.m_qualifiedNameHash = |
@@ -772,8 +841,7 @@ TextAutosizer::Fingerprint TextAutosizer::computeFingerprint( |
sizeof data / sizeof(UChar)); |
} |
-TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster( |
- const LayoutBlock* block) { |
+TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster(LayoutBlock* block) { |
BlockFlags flags = classifyBlock(block); |
if (!(flags & POTENTIAL_ROOT)) |
return nullptr; |
@@ -791,7 +859,8 @@ TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster( |
return nullptr; |
Cluster* cluster = |
- new Cluster(block, flags, parentCluster, getSupercluster(block)); |
+ new Cluster(block, flags, parentCluster, |
+ m_fingerprintMapper.createSuperclusterIfNeeded(block)); |
#ifdef AUTOSIZING_DOM_DEBUG_INFO |
// Non-SUPPRESSING clusters are annotated in clusterMultiplier. |
if (flags & SUPPRESSING) |
@@ -800,13 +869,14 @@ TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster( |
return cluster; |
} |
-TextAutosizer::Supercluster* TextAutosizer::getSupercluster( |
- const LayoutBlock* block) { |
- Fingerprint fingerprint = m_fingerprintMapper.get(block); |
+TextAutosizer::Supercluster* |
+TextAutosizer::FingerprintMapper::createSuperclusterIfNeeded( |
+ LayoutBlock* block) { |
+ Fingerprint fingerprint = get(block); |
if (!fingerprint) |
return nullptr; |
- BlockSet* roots = m_fingerprintMapper.getTentativeClusterRoots(fingerprint); |
+ BlockSet* roots = getTentativeClusterRoots(fingerprint); |
if (!roots || roots->size() < 2 || !roots->contains(block)) |
return nullptr; |
@@ -829,9 +899,11 @@ float TextAutosizer::clusterMultiplier(Cluster* cluster) { |
cluster->m_flags |= WIDER_OR_NARROWER; |
if (cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER)) { |
- if (cluster->m_supercluster) |
+ if (cluster->m_supercluster) { |
cluster->m_multiplier = superclusterMultiplier(cluster); |
- else if (clusterHasEnoughTextToAutosize(cluster)) |
+ cluster->m_supercluster->m_inheritParentMultiplier = |
+ DontInheritMultiplier; |
+ } else if (clusterHasEnoughTextToAutosize(cluster)) |
cluster->m_multiplier = |
multiplierFromBlock(clusterWidthProvider(cluster->m_root)); |
else |
@@ -839,6 +911,8 @@ float TextAutosizer::clusterMultiplier(Cluster* cluster) { |
} else { |
cluster->m_multiplier = |
cluster->m_parent ? clusterMultiplier(cluster->m_parent) : 1.0f; |
+ if (cluster->m_supercluster) |
+ cluster->m_supercluster->m_inheritParentMultiplier = InheritMultiplier; |
} |
#ifdef AUTOSIZING_DOM_DEBUG_INFO |
@@ -851,11 +925,14 @@ float TextAutosizer::clusterMultiplier(Cluster* cluster) { |
bool TextAutosizer::superclusterHasEnoughTextToAutosize( |
Supercluster* supercluster, |
- const LayoutBlock* widthProvider) { |
+ const LayoutBlock* widthProvider, |
+ const bool skipLayoutedNodes) { |
if (supercluster->m_hasEnoughTextToAutosize != UnknownAmountOfText) |
return supercluster->m_hasEnoughTextToAutosize == HasEnoughText; |
for (auto* root : *supercluster->m_roots) { |
+ if (skipLayoutedNodes && !root->normalChildNeedsLayout()) |
+ continue; |
if (clusterWouldHaveEnoughTextToAutosize(root, widthProvider)) { |
supercluster->m_hasEnoughTextToAutosize = HasEnoughText; |
return true; |
@@ -870,8 +947,9 @@ float TextAutosizer::superclusterMultiplier(Cluster* cluster) { |
if (!supercluster->m_multiplier) { |
const LayoutBlock* widthProvider = |
maxClusterWidthProvider(cluster->m_supercluster, cluster->m_root); |
+ RELEASE_ASSERT(widthProvider); |
supercluster->m_multiplier = |
- superclusterHasEnoughTextToAutosize(supercluster, widthProvider) |
+ superclusterHasEnoughTextToAutosize(supercluster, widthProvider, false) |
? multiplierFromBlock(widthProvider) |
: 1.0f; |
} |
@@ -888,10 +966,15 @@ const LayoutBlock* TextAutosizer::clusterWidthProvider( |
} |
const LayoutBlock* TextAutosizer::maxClusterWidthProvider( |
- const Supercluster* supercluster, |
+ Supercluster* supercluster, |
const LayoutBlock* currentRoot) const { |
- const LayoutBlock* result = clusterWidthProvider(currentRoot); |
- float maxWidth = widthFromBlock(result); |
+ const LayoutBlock* result = nullptr; |
+ if (currentRoot) |
+ result = clusterWidthProvider(currentRoot); |
+ |
+ float maxWidth = 0; |
+ if (result) |
+ maxWidth = widthFromBlock(result); |
const BlockSet* roots = supercluster->m_roots; |
for (const auto* root : *roots) { |
@@ -904,7 +987,6 @@ const LayoutBlock* TextAutosizer::maxClusterWidthProvider( |
result = widthProvider; |
} |
} |
- RELEASE_ASSERT(result); |
return result; |
} |
@@ -1171,7 +1253,7 @@ void TextAutosizer::FingerprintMapper::assertMapsAreConsistent() { |
} |
#endif |
-void TextAutosizer::FingerprintMapper::add(const LayoutObject* layoutObject, |
+void TextAutosizer::FingerprintMapper::add(LayoutObject* layoutObject, |
Fingerprint fingerprint) { |
remove(layoutObject); |
@@ -1182,7 +1264,7 @@ void TextAutosizer::FingerprintMapper::add(const LayoutObject* layoutObject, |
} |
void TextAutosizer::FingerprintMapper::addTentativeClusterRoot( |
- const LayoutBlock* block, |
+ LayoutBlock* block, |
Fingerprint fingerprint) { |
add(block, fingerprint); |
@@ -1196,8 +1278,7 @@ void TextAutosizer::FingerprintMapper::addTentativeClusterRoot( |
#endif |
} |
-bool TextAutosizer::FingerprintMapper::remove( |
- const LayoutObject* layoutObject) { |
+bool TextAutosizer::FingerprintMapper::remove(LayoutObject* layoutObject) { |
Fingerprint fingerprint = m_fingerprints.take(layoutObject); |
if (!fingerprint || !layoutObject->isLayoutBlock()) |
return false; |
@@ -1209,8 +1290,18 @@ bool TextAutosizer::FingerprintMapper::remove( |
BlockSet& blocks = *blocksIter->value; |
blocks.remove(toLayoutBlock(layoutObject)); |
- if (blocks.isEmpty()) |
+ if (blocks.isEmpty()) { |
m_blocksForFingerprint.remove(blocksIter); |
+ |
+ SuperclusterMap::iterator superclusterIter = |
+ m_superclusters.find(fingerprint); |
+ |
+ if (superclusterIter != m_superclusters.end()) { |
+ Supercluster* supercluster = superclusterIter->value.get(); |
+ m_potentiallyInconsistentSuperclusters.remove(supercluster); |
+ m_superclusters.remove(superclusterIter); |
+ } |
+ } |
#if ENABLE(ASSERT) |
assertMapsAreConsistent(); |
#endif |
@@ -1302,6 +1393,40 @@ float TextAutosizer::computeAutosizedFontSize(float specifiedSize, |
return computedSize; |
} |
+void TextAutosizer::checkSuperclusterConsistency() { |
+ HashSet<Supercluster*> potentiallyInconsistentSuperclusters = |
+ m_fingerprintMapper.getPotentiallyInconsistentSuperclusters(); |
+ if (potentiallyInconsistentSuperclusters.isEmpty()) |
+ return; |
+ |
+ for (Supercluster* supercluster : potentiallyInconsistentSuperclusters) { |
+ if (HasEnoughText == supercluster->m_hasEnoughTextToAutosize) |
+ continue; |
+ |
+ float oldMultipiler = supercluster->m_multiplier; |
+ supercluster->m_multiplier = 0; |
+ supercluster->m_hasEnoughTextToAutosize = UnknownAmountOfText; |
+ const LayoutBlock* widthProvider = |
+ maxClusterWidthProvider(supercluster, nullptr); |
+ if (!widthProvider) |
+ continue; |
+ |
+ if (superclusterHasEnoughTextToAutosize(supercluster, widthProvider, |
+ true) == HasEnoughText) { |
+ for (auto* root : *supercluster->m_roots) { |
+ if (!root->everHadLayout()) |
+ continue; |
+ |
+ DCHECK(root); |
+ setAllTextNeedsLayout(root); |
+ } |
+ } else { |
+ supercluster->m_multiplier = oldMultipiler; |
+ } |
+ } |
+ potentiallyInconsistentSuperclusters.clear(); |
+} |
+ |
DEFINE_TRACE(TextAutosizer) { |
visitor->trace(m_document); |
} |