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

Unified Diff: Source/core/rendering/FastTextAutosizer.cpp

Issue 200603002: Refactor FastTextAutosizer to remove the TextAutosizer dependencies (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebase 2 Created 6 years, 9 months 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
« no previous file with comments | « Source/core/rendering/FastTextAutosizer.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/FastTextAutosizer.cpp
diff --git a/Source/core/rendering/FastTextAutosizer.cpp b/Source/core/rendering/FastTextAutosizer.cpp
index 85322761c96cc65e153cecf63528e1cceadced6f..2888f16994725ba42ddb4ffb1768cb3b4b7342aa 100644
--- a/Source/core/rendering/FastTextAutosizer.cpp
+++ b/Source/core/rendering/FastTextAutosizer.cpp
@@ -42,7 +42,6 @@
#include "core/rendering/RenderListMarker.h"
#include "core/rendering/RenderTableCell.h"
#include "core/rendering/RenderView.h"
-#include "core/rendering/TextAutosizer.h"
using namespace std;
@@ -64,6 +63,182 @@ static const RenderObject* parentElementRenderer(const RenderObject* renderer)
return 0;
}
+static const Vector<QualifiedName>& formInputTags()
+{
+ // Returns the tags for the form input elements.
+ DEFINE_STATIC_LOCAL(Vector<QualifiedName>, formInputTags, ());
+ if (formInputTags.isEmpty()) {
+ formInputTags.append(HTMLNames::inputTag);
+ formInputTags.append(HTMLNames::buttonTag);
+ formInputTags.append(HTMLNames::selectTag);
+ }
+ return formInputTags;
+}
+
+static bool isAutosizingContainer(const RenderObject* renderer)
+{
+ // "Autosizing containers" are the smallest unit for which we can
+ // enable/disable Text Autosizing.
+ // - Must not be inline, as different multipliers on one line looks terrible.
+ // Exceptions are inline-block and alike elements (inline-table, -webkit-inline-*),
+ // as they often contain entire multi-line columns of text.
+ // - Must not be list items, as items in the same list should look consistent (*).
+ // - Must not be normal list items, as items in the same list should look
+ // consistent, unless they are floating or position:absolute/fixed.
+ Node* node = renderer->generatingNode();
+ if ((node && !node->hasChildren())
+ || !renderer->isRenderBlock()
+ || (renderer->isInline() && !renderer->style()->isDisplayReplacedType()))
+ return false;
+ if (renderer->isListItem())
+ return renderer->isFloating() || renderer->isOutOfFlowPositioned();
+ // Avoid creating containers for text within text controls, buttons, or <select> buttons.
+ Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode() : 0;
+ if (parentNode && parentNode->isElementNode() && formInputTags().contains(toElement(parentNode)->tagQName()))
+ return false;
+
+ return true;
+}
+
+static RenderObject* nextInPreOrderSkippingDescendantsOfContainers(const RenderObject* current, const RenderObject* stayWithin)
+{
+ if (current == stayWithin || !isAutosizingContainer(current))
+ return current->nextInPreOrder(stayWithin);
+ return current->nextInPreOrderAfterChildren(stayWithin);
+}
+
+static bool isIndependentDescendant(const RenderBlock* renderer)
+{
+ ASSERT(isAutosizingContainer(renderer));
+
+ // "Autosizing clusters" are special autosizing containers within which we
+ // want to enforce a uniform text size multiplier, in the hopes of making
+ // the major sections of the page look internally consistent.
+ // All their descendants (including other autosizing containers) must share
+ // the same multiplier, except for subtrees which are themselves clusters,
+ // and some of their descendant containers might not be autosized at all
+ // (for example if their height is constrained).
+ // Additionally, clusterShouldBeAutosized requires each cluster to contain a
+ // minimum amount of text, without which it won't be autosized.
+ //
+ // Clusters are chosen using very similar criteria to CSS flow roots, aka
+ // block formatting contexts (http://w3.org/TR/css3-box/#flow-root), since
+ // flow roots correspond to box containers that behave somewhat
+ // independently from their parent (for example they don't overlap floats).
+ // The definition of a flow root also conveniently includes most of the
+ // ways that a box and its children can have significantly different width
+ // from the box's parent (we want to avoid having significantly different
+ // width blocks within a cluster, since the narrower blocks would end up
+ // larger than would otherwise be necessary).
+ RenderBlock* containingBlock = renderer->containingBlock();
+ return renderer->isRenderView()
+ || renderer->isFloating()
+ || renderer->isOutOfFlowPositioned()
+ || renderer->isTableCell()
+ || renderer->isTableCaption()
+ || renderer->isFlexibleBoxIncludingDeprecated()
+ || renderer->hasColumns()
+ || (containingBlock && containingBlock->isHorizontalWritingMode() != renderer->isHorizontalWritingMode())
+ || renderer->style()->isDisplayReplacedType()
+ || renderer->isTextArea()
+ || renderer->style()->userModify() != READ_ONLY;
+ // FIXME: Tables need special handling to multiply all their columns by
+ // the same amount even if they're different widths; so do hasColumns()
+ // containers, and probably flexboxes...
+}
+
+static bool containerIsRowOfLinks(const RenderObject* container)
+{
+ // A "row of links" is a container for which holds:
+ // 1. it should not contain non-link text elements longer than 3 characters
+ // 2. it should contain min. 3 inline links and all links should
+ // have the same specified font size
+ // 3. it should not contain <br> elements
+ // 4. it should contain only inline elements unless they are containers,
+ // children of link elements or children of sub-containers.
+ int linkCount = 0;
+ RenderObject* renderer = container->nextInPreOrder(container);
+ float matchingFontSize = -1;
+
+ while (renderer) {
+ if (!isAutosizingContainer(renderer)) {
+ if (renderer->isText() && toRenderText(renderer)->text().impl()->stripWhiteSpace()->length() > 3)
+ return false;
+ if (!renderer->isInline())
+ return false;
+ if (renderer->isBR())
+ return false;
+ }
+ if (renderer->style()->isLink()) {
+ if (matchingFontSize < 0) {
+ matchingFontSize = renderer->style()->specifiedFontSize();
+ } else {
+ if (matchingFontSize != renderer->style()->specifiedFontSize())
+ return false;
+ }
+
+ linkCount++;
+ // Skip traversing descendants of the link.
+ renderer = renderer->nextInPreOrderAfterChildren(container);
+ } else {
+ renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, container);
+ }
+ }
+
+ return (linkCount >= 3);
+}
+
+static bool contentHeightIsConstrained(const RenderBlock* container)
+{
+ // FIXME: Propagate constrainedness down the tree, to avoid inefficiently walking back up from each box.
+ // FIXME: This code needs to take into account vertical writing modes.
+ // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in.
+ for (; container; container = container->containingBlock()) {
+ RenderStyle* style = container->style();
+ if (style->overflowY() >= OSCROLL)
+ return false;
+ if (style->height().isSpecified() || style->maxHeight().isSpecified() || container->isOutOfFlowPositioned()) {
+ // Some sites (e.g. wikipedia) set their html and/or body elements to height:100%,
+ // without intending to constrain the height of the content within them.
+ return !container->isRoot() && !container->isBody();
+ }
+ if (container->isFloating())
+ return false;
+ }
+ return false;
+}
+
+static bool containerContainsOneOfTags(const RenderBlock* container, const Vector<QualifiedName>& tags)
+{
+ const RenderObject* renderer = container;
+ while (renderer) {
+ const Node* rendererNode = renderer->node();
+ if (rendererNode && rendererNode->isElementNode()) {
+ if (tags.contains(toElement(rendererNode)->tagQName()))
+ return true;
+ }
+ renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, container);
+ }
+
+ return false;
+}
+
+static bool containerShouldBeAutosized(const RenderBlock* container)
+{
+ if (containerContainsOneOfTags(container, formInputTags()))
+ return false;
+
+ if (containerIsRowOfLinks(container))
+ return false;
+
+ // Don't autosize block-level text that can't wrap (as it's likely to
+ // expand sideways and break the page's layout).
+ if (!container->style()->autoWrap())
+ return false;
+
+ return !contentHeightIsConstrained(container);
+}
+
FastTextAutosizer::FastTextAutosizer(const Document* document)
: m_document(document)
, m_frameWidth(0)
@@ -189,7 +364,7 @@ void FastTextAutosizer::inflateTable(RenderTable* table)
RenderTableCell* renderTableCell = toRenderTableCell(cell);
bool shouldAutosize;
- if (!TextAutosizer::containerShouldBeAutosized(renderTableCell))
+ if (!containerShouldBeAutosized(renderTableCell))
shouldAutosize = false;
else if (Supercluster* supercluster = getSupercluster(renderTableCell))
shouldAutosize = anyClusterHasEnoughTextToAutosize(supercluster->m_roots, table);
@@ -285,8 +460,8 @@ bool FastTextAutosizer::isFingerprintingCandidate(const RenderBlock* block)
{
// FIXME: move the logic out of TextAutosizer.cpp into this class.
return block->isRenderView()
- || (TextAutosizer::isAutosizingContainer(block)
- && (TextAutosizer::isIndependentDescendant(block)
+ || (isAutosizingContainer(block)
+ && (isIndependentDescendant(block)
|| mightBeWiderOrNarrowerDescendant(block)));
}
@@ -311,7 +486,7 @@ bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R
return true;
}
- if (!TextAutosizer::containerShouldBeAutosized(root)) {
+ if (!containerShouldBeAutosized(root)) {
cluster->m_hasEnoughTextToAutosize = NotEnoughText;
return false;
}
@@ -324,12 +499,12 @@ bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R
while (descendant) {
if (descendant->isRenderBlock()) {
RenderBlock* block = toRenderBlock(descendant);
- if (TextAutosizer::isAutosizingContainer(block)) {
+ if (isAutosizingContainer(block)) {
// Note: Ideally we would check isWiderOrNarrowerDescendant here but we only know that
// after the block has entered layout, which may not be the case.
- bool isAutosizingClusterRoot = TextAutosizer::isIndependentDescendant(block) || block->isTable();
+ bool isAutosizingClusterRoot = isIndependentDescendant(block) || block->isTable();
if ((isAutosizingClusterRoot && !block->isTableCell())
- || !TextAutosizer::containerShouldBeAutosized(block)) {
+ || !containerShouldBeAutosized(block)) {
descendant = descendant->nextInPreOrderAfterChildren(root);
continue;
}
@@ -405,18 +580,18 @@ FastTextAutosizer::Fingerprint FastTextAutosizer::computeFingerprint(const Rende
FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBlock* block)
{
- if (!TextAutosizer::isAutosizingContainer(block))
+ if (!isAutosizingContainer(block))
return 0;
Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster();
ASSERT(parentCluster || block->isRenderView());
// Create clusters to suppress / unsuppress autosizing based on containerShouldBeAutosized.
- bool containerCanAutosize = TextAutosizer::containerShouldBeAutosized(block);
+ bool containerCanAutosize = containerShouldBeAutosized(block);
bool parentClusterCanAutosize = parentCluster && parentCluster->m_autosize;
bool createClusterThatMightAutosize = block->isRenderView()
|| mightBeWiderOrNarrowerDescendant(block)
- || TextAutosizer::isIndependentDescendant(block)
+ || isIndependentDescendant(block)
|| block->isTable();
// If the container would not alter the m_autosize bit, it doesn't need to be a cluster.
@@ -467,7 +642,7 @@ float FastTextAutosizer::clusterMultiplier(Cluster* cluster)
ASSERT(m_renderViewInfoPrepared);
if (!cluster->m_multiplier) {
if (cluster->m_root->isTable()
- || TextAutosizer::isIndependentDescendant(cluster->m_root)
+ || isIndependentDescendant(cluster->m_root)
|| isWiderOrNarrowerDescendant(cluster)) {
if (cluster->m_supercluster) {
@@ -621,7 +796,7 @@ const RenderObject* FastTextAutosizer::findTextLeaf(const RenderObject* parent,
while (child) {
// Note: At this point clusters may not have been created for these blocks so we cannot rely
// on m_clusters. Instead, we use a best-guess about whether the block will become a cluster.
- if (!TextAutosizer::isAutosizingContainer(child) || !TextAutosizer::isIndependentDescendant(toRenderBlock(child))) {
+ if (!isAutosizingContainer(child) || !isIndependentDescendant(toRenderBlock(child))) {
const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast);
if (leaf)
return leaf;
« no previous file with comments | « Source/core/rendering/FastTextAutosizer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698