Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1117)

Unified Diff: third_party/WebKit/Source/core/layout/TextAutosizer.cpp

Issue 2299213003: Fix the inconsistent problem while the content of textNodes is changed (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: using everHadLayout to determine if nodes are new Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 44838fff84911253c0d28db3d383ab59970e5af8..47325aedfbcccb62cf6529cea86789d6beb46080 100644
--- a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
+++ b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
@@ -88,7 +88,8 @@ void TextAutosizer::writeClusterDebugInfo(Cluster* cluster) {
String explanation = "";
if (cluster->m_flags & SUPPRESSING) {
explanation = "[suppressed]";
- } else if (!(cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER))) {
+ } else if ((!(cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER))) &&
+ isParentClusterReliable(cluster->m_parent)) {
explanation = "[inherited]";
} else if (cluster->m_supercluster) {
explanation = "[supercluster]";
@@ -123,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.
@@ -295,29 +296,32 @@ TextAutosizer::TextAutosizer(const Document* document)
#if ENABLE(ASSERT)
m_blocksThatHaveBegunLayout(),
#endif
- m_superclusters(),
m_clusterStack(),
m_fingerprintMapper(),
+ m_fingerprintsNeedCheckConsistent(),
m_pageInfo(),
m_updatePageInfoDeferred(false) {
}
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)) {
+ newNodeAdded(block);
pdr. 2016/11/20 06:38:13 Are these calls (newNodeAdded and needCheckConsist
cathiechentx 2016/11/22 08:14:47 Yes, it's necessary. Here is to find the nearest-c
return;
+ }
if (Fingerprint fingerprint = computeFingerprint(block))
m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint);
+
+ needCheckConsistent(block);
cathiechentx 2016/11/22 08:14:48 Add block to hashset. So block's children don't ha
}
-void TextAutosizer::destroy(const LayoutBlock* block) {
+void TextAutosizer::destroy(LayoutBlock* block) {
if (!m_pageInfo.m_settingEnabled && !m_fingerprintMapper.hasFingerprints())
return;
@@ -329,12 +333,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
@@ -342,6 +345,8 @@ TextAutosizer::BeginLayoutBehavior TextAutosizer::prepareForLayout(
if (!m_firstBlockToBeginLayout) {
m_firstBlockToBeginLayout = block;
prepareClusterStack(block->parent());
+ if (block->isLayoutView())
pdr. 2016/11/20 06:38:13 Is this isLayoutView check needed?
cathiechentx 2016/11/22 08:14:48 Yes, it is necessary. CheckConsistent might change
+ checkConsistent();
} else if (block == currentCluster()->m_root) {
// Ignore beginLayout on the same block twice.
// This can happen with paginated overflow.
@@ -351,13 +356,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
@@ -424,11 +429,11 @@ 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();
#endif
+ m_fingerprintsNeedCheckConsistent.clear();
// Tables can create two layout scopes for the same block so the isEmpty
// check below is needed to guard against endLayout being called twice.
} else if (!m_clusterStack.isEmpty() && currentCluster()->m_root == block) {
@@ -512,6 +517,65 @@ bool TextAutosizer::pageNeedsAutosizing() const {
return m_pageInfo.m_pageNeedsAutosizing;
}
+void TextAutosizer::newNodeAdded(LayoutObject* object) {
+ if (!object || !shouldHandleLayout())
+ return;
+
+ LayoutObject* parent = object->parent();
+ // Sometimes layoutObject haven't added to layout tree yet
+ if (!parent && object->node() && object->node()->parentNode())
+ parent = object->node()->parentNode()->layoutObject();
+ // !everHadLayout() means the object hasn't layout yet
+ // which means this object is new added. If parent is new added,
+ // no need to checkConsistent its children
+ if (!parent || !parent->everHadLayout())
cathiechentx 2016/11/22 08:14:47 The descendants of a new node will return from her
+ return;
+
+ // Find the nearest LayoutBlock.
+ LayoutBlock* block = nullptr;
+ if (object->isLayoutBlock()) {
+ // Only deal with the !everHadLayout LayoutBlock
+ if (object->everHadLayout())
+ return;
+ block = toLayoutBlock(object);
+ } else {
+ if (parent->isLayoutBlock())
+ block = toLayoutBlock(parent);
+ else
+ block = parent->containingBlock();
+ }
+ if (!block)
+ return;
+
+ // Find the nearest block which choud be a cluster root
+ while (block && !block->isTableCell() &&
+ !classifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH)) {
+ if (!block->parent())
+ return;
+ if (block->parent()->isLayoutBlock())
+ block = toLayoutBlock(block->parent());
+ else
+ block = block->containingBlock();
+ }
+ if (!block)
+ return;
+
+ needCheckConsistent(block);
+}
+
+void TextAutosizer::needCheckConsistent(LayoutBlock* block) {
+ if (!block || !shouldHandleLayout())
+ return;
+
+ if (Fingerprint fingerprint = computeFingerprint(block)) {
+ // If the supercluster hasn't be created yet, create the supercluster.
+ Supercluster* supercluster = m_fingerprintMapper.getSupercluster(block);
+ if (supercluster &&
+ supercluster->m_hasEnoughTextToAutosize != HasEnoughText)
+ m_fingerprintsNeedCheckConsistent.add(fingerprint);
pdr. 2016/11/20 06:38:13 Instead of storing a set of fingerprints, could we
cathiechentx 2016/11/22 08:14:48 Done.
+ }
+}
+
void TextAutosizer::updatePageInfoInAllFrames() {
ASSERT(!m_document->frame() || m_document->frame()->isMainFrame());
@@ -723,7 +787,7 @@ bool TextAutosizer::clusterHasEnoughTextToAutosize(
}
TextAutosizer::Fingerprint TextAutosizer::getFingerprint(
- const LayoutObject* layoutObject) {
+ LayoutObject* layoutObject) {
Fingerprint result = m_fingerprintMapper.get(layoutObject);
if (!result) {
result = computeFingerprint(layoutObject);
@@ -739,7 +803,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 =
@@ -771,8 +835,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;
@@ -789,8 +852,8 @@ TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster(
!!(flags & SUPPRESSING) == parentSuppresses)
return nullptr;
- Cluster* cluster =
- new Cluster(block, flags, parentCluster, getSupercluster(block));
+ Cluster* cluster = new Cluster(block, flags, parentCluster,
+ m_fingerprintMapper.getSupercluster(block));
#ifdef AUTOSIZING_DOM_DEBUG_INFO
// Non-SUPPRESSING clusters are annotated in clusterMultiplier.
if (flags & SUPPRESSING)
@@ -799,13 +862,13 @@ TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster(
return cluster;
}
-TextAutosizer::Supercluster* TextAutosizer::getSupercluster(
- const LayoutBlock* block) {
- Fingerprint fingerprint = m_fingerprintMapper.get(block);
+TextAutosizer::Supercluster* TextAutosizer::FingerprintMapper::getSupercluster(
+ 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;
@@ -819,6 +882,27 @@ TextAutosizer::Supercluster* TextAutosizer::getSupercluster(
return supercluster;
}
+TextAutosizer::Supercluster*
+TextAutosizer::FingerprintMapper::getSuperclusterByFingerprint(
+ const Fingerprint fingerprint) {
+ Supercluster* supercluster = nullptr;
+ SuperclusterMap::iterator superclusterIter =
+ m_superclusters.find(fingerprint);
+ if (superclusterIter != m_superclusters.end()) {
+ supercluster = superclusterIter->value.get();
+ }
+ return supercluster;
+}
+
+bool TextAutosizer::isParentClusterReliable(Cluster* cluster) {
+ if (!cluster)
+ return true;
+ // Cause cluster is changed, m_supercluster's "NotEnoughText" is not reliable
+ // now.
+ return !(cluster->m_supercluster &&
+ cluster->m_supercluster->m_hasEnoughTextToAutosize == NotEnoughText);
+}
+
float TextAutosizer::clusterMultiplier(Cluster* cluster) {
if (cluster->m_multiplier)
return cluster->m_multiplier;
@@ -827,7 +911,8 @@ float TextAutosizer::clusterMultiplier(Cluster* cluster) {
if (!(cluster->m_flags & INDEPENDENT) && isWiderOrNarrowerDescendant(cluster))
cluster->m_flags |= WIDER_OR_NARROWER;
- if (cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER)) {
+ if ((cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER)) ||
+ !isParentClusterReliable(cluster->m_parent)) {
if (cluster->m_supercluster)
cluster->m_multiplier = superclusterMultiplier(cluster);
else if (clusterHasEnoughTextToAutosize(cluster))
@@ -850,11 +935,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;
@@ -869,8 +957,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;
}
@@ -887,10 +976,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) {
@@ -903,7 +997,6 @@ const LayoutBlock* TextAutosizer::maxClusterWidthProvider(
result = widthProvider;
}
}
- RELEASE_ASSERT(result);
return result;
}
@@ -1166,7 +1259,7 @@ void TextAutosizer::FingerprintMapper::assertMapsAreConsistent() {
}
#endif
-void TextAutosizer::FingerprintMapper::add(const LayoutObject* layoutObject,
+void TextAutosizer::FingerprintMapper::add(LayoutObject* layoutObject,
Fingerprint fingerprint) {
remove(layoutObject);
@@ -1177,7 +1270,7 @@ void TextAutosizer::FingerprintMapper::add(const LayoutObject* layoutObject,
}
void TextAutosizer::FingerprintMapper::addTentativeClusterRoot(
- const LayoutBlock* block,
+ LayoutBlock* block,
Fingerprint fingerprint) {
add(block, fingerprint);
@@ -1191,8 +1284,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;
@@ -1204,8 +1296,14 @@ 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())
+ m_superclusters.remove(superclusterIter);
+ }
#if ENABLE(ASSERT)
assertMapsAreConsistent();
#endif
@@ -1297,6 +1395,58 @@ float TextAutosizer::computeAutosizedFontSize(float specifiedSize,
return computedSize;
}
+void setAllTextInsideContainerNeedsLayout(LayoutBlock* container) {
+ DCHECK(container);
+ LayoutObject* layoutObject = container;
+ while (layoutObject) {
+ if (layoutObject->isText()) {
+ layoutObject->setNeedsLayoutAndFullPaintInvalidation(
+ LayoutInvalidationReason::TextAutosizing);
+ }
+ layoutObject = layoutObject->nextInPreOrder(container);
+ }
+}
+
+void TextAutosizer::checkConsistent() {
+ if (m_fingerprintsNeedCheckConsistent.isEmpty())
+ return;
+
+ FingerprintSet::iterator end = m_fingerprintsNeedCheckConsistent.end();
+ for (FingerprintSet::iterator it = m_fingerprintsNeedCheckConsistent.begin();
+ it != end; ++it) {
+ const Fingerprint fingerprint = *it;
+ Supercluster* supercluster =
+ m_fingerprintMapper.getSuperclusterByFingerprint(fingerprint);
+ if (!supercluster)
+ continue;
+
+ 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;
+
+ superclusterHasEnoughTextToAutosize(supercluster, widthProvider, true);
+
+ if (HasEnoughText == supercluster->m_hasEnoughTextToAutosize) {
+ for (auto* root : *supercluster->m_roots) {
+ if (root->normalChildNeedsLayout())
+ continue;
+
+ DCHECK(root);
+ setAllTextInsideContainerNeedsLayout(root);
+ }
+ } else {
+ supercluster->m_multiplier = oldMultipiler;
+ }
+ }
+}
+
DEFINE_TRACE(TextAutosizer) {
visitor->trace(m_document);
}

Powered by Google App Engine
This is Rietveld 408576698