summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/TextAutosizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/TextAutosizer.cpp')
-rw-r--r--Source/WebCore/rendering/TextAutosizer.cpp617
1 files changed, 0 insertions, 617 deletions
diff --git a/Source/WebCore/rendering/TextAutosizer.cpp b/Source/WebCore/rendering/TextAutosizer.cpp
deleted file mode 100644
index f036f54df..000000000
--- a/Source/WebCore/rendering/TextAutosizer.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-
-#if ENABLE(TEXT_AUTOSIZING)
-
-#include "TextAutosizer.h"
-
-#include "Document.h"
-#include "HTMLElement.h"
-#include "InspectorInstrumentation.h"
-#include "IntSize.h"
-#include "RenderObject.h"
-#include "RenderStyle.h"
-#include "RenderText.h"
-#include "RenderView.h"
-#include "Settings.h"
-#include "StyleInheritedData.h"
-
-#include <algorithm>
-#include <wtf/StdLibExtras.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-struct TextAutosizingWindowInfo {
- IntSize windowSize;
- IntSize minLayoutSize;
-};
-
-// Represents cluster related data. Instances should not persist between calls to processSubtree.
-struct TextAutosizingClusterInfo {
- explicit TextAutosizingClusterInfo(RenderBlock* root)
- : root(root)
- , blockContainingAllText(0)
- , maxAllowedDifferenceFromTextWidth(150)
- {
- }
-
- RenderBlock* root;
- const RenderBlock* blockContainingAllText;
-
- // Upper limit on the difference between the width of the cluster's block containing all
- // text and that of a narrow child before the child becomes a separate cluster.
- float maxAllowedDifferenceFromTextWidth;
-
- // Descendants of the cluster that are narrower than the block containing all text and must be
- // processed together.
- Vector<TextAutosizingClusterInfo> narrowDescendants;
-};
-
-
-static const Vector<QualifiedName>& formInputTags()
-{
- // Returns the tags for the form input elements.
- DEFINE_STATIC_LOCAL(Vector<QualifiedName>, formInputTags, ());
- if (formInputTags.isEmpty()) {
- formInputTags.append(inputTag);
- formInputTags.append(buttonTag);
- formInputTags.append(selectTag);
- }
- return formInputTags;
-}
-
-TextAutosizer::TextAutosizer(Document* document)
- : m_document(document)
-{
-}
-
-TextAutosizer::~TextAutosizer()
-{
-}
-
-void TextAutosizer::recalculateMultipliers()
-{
- RenderObject* renderer = m_document->renderer();
- while (renderer) {
- if (renderer->style() && renderer->style()->textAutosizingMultiplier() != 1)
- setMultiplier(renderer, 1);
- renderer = renderer->nextInPreOrder();
- }
-}
-
-bool TextAutosizer::processSubtree(RenderObject* layoutRoot)
-{
- // FIXME: Text Autosizing should only be enabled when m_document->page()->mainFrame().view()->useFixedLayout()
- // is true, but for now it's useful to ignore this so that it can be tested on desktop.
- if (!m_document->settings() || !m_document->settings()->textAutosizingEnabled() || layoutRoot->view()->printing() || !m_document->page())
- return false;
-
- Frame& mainFrame = m_document->page()->mainFrame();
-
- TextAutosizingWindowInfo windowInfo;
-
- // Window area, in logical (density-independent) pixels.
- windowInfo.windowSize = m_document->settings()->textAutosizingWindowSizeOverride();
- if (windowInfo.windowSize.isEmpty())
- windowInfo.windowSize = mainFrame.view()->unscaledVisibleContentSize(ScrollableArea::IncludeScrollbars);
-
- // Largest area of block that can be visible at once (assuming the main
- // frame doesn't get scaled to less than overview scale), in CSS pixels.
- windowInfo.minLayoutSize = mainFrame.view()->layoutSize();
- for (Frame* frame = m_document->frame(); frame; frame = frame->tree().parent()) {
- if (!frame->view()->isInChildFrameWithFrameFlattening())
- windowInfo.minLayoutSize = windowInfo.minLayoutSize.shrunkTo(frame->view()->layoutSize());
- }
-
- // The layoutRoot could be neither a container nor a cluster, so walk up the tree till we find each of these.
- RenderBlock* container = layoutRoot->isRenderBlock() ? toRenderBlock(layoutRoot) : layoutRoot->containingBlock();
- while (container && !isAutosizingContainer(container))
- container = container->containingBlock();
-
- RenderBlock* cluster = container;
- while (cluster && (!isAutosizingContainer(cluster) || !isIndependentDescendant(cluster)))
- cluster = cluster->containingBlock();
-
- TextAutosizingClusterInfo clusterInfo(cluster);
- processCluster(clusterInfo, container, layoutRoot, windowInfo);
- return true;
-}
-
-float TextAutosizer::clusterMultiplier(WritingMode writingMode, const TextAutosizingWindowInfo& windowInfo, float textWidth) const
-{
- int logicalWindowWidth = isHorizontalWritingMode(writingMode) ? windowInfo.windowSize.width() : windowInfo.windowSize.height();
- int logicalLayoutWidth = isHorizontalWritingMode(writingMode) ? windowInfo.minLayoutSize.width() : windowInfo.minLayoutSize.height();
- // Ignore box width in excess of the layout width, to avoid extreme multipliers.
- float logicalClusterWidth = std::min<float>(textWidth, logicalLayoutWidth);
-
- float multiplier = logicalClusterWidth / logicalWindowWidth;
- multiplier *= m_document->settings()->textAutosizingFontScaleFactor();
- return std::max(1.0f, multiplier);
-}
-
-void TextAutosizer::processClusterInternal(TextAutosizingClusterInfo& clusterInfo, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo, float multiplier)
-{
- processContainer(multiplier, container, clusterInfo, subtreeRoot, windowInfo);
-
- Vector<Vector<TextAutosizingClusterInfo> > narrowDescendantsGroups;
- getNarrowDescendantsGroupedByWidth(clusterInfo, narrowDescendantsGroups);
- for (size_t i = 0; i < narrowDescendantsGroups.size(); ++i)
- processCompositeCluster(narrowDescendantsGroups[i], windowInfo);
-}
-
-void TextAutosizer::processCluster(TextAutosizingClusterInfo& clusterInfo, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo)
-{
- // Many pages set a max-width on their content. So especially for the RenderView, instead of
- // just taking the width of |cluster| we find the lowest common ancestor of the first and last
- // descendant text node of the cluster (i.e. the deepest wrapper block that contains all the
- // text), and use its width instead.
- clusterInfo.blockContainingAllText = findDeepestBlockContainingAllText(clusterInfo.root);
- float textWidth = clusterInfo.blockContainingAllText->contentLogicalWidth();
- float multiplier = 1.0;
- if (clusterShouldBeAutosized(clusterInfo, textWidth))
- multiplier = clusterMultiplier(clusterInfo.root->style()->writingMode(), windowInfo, textWidth);
- processClusterInternal(clusterInfo, container, subtreeRoot, windowInfo, multiplier);
-}
-
-void TextAutosizer::processCompositeCluster(Vector<TextAutosizingClusterInfo>& clusterInfos, const TextAutosizingWindowInfo& windowInfo)
-{
- if (clusterInfos.isEmpty())
- return;
-
- float maxTextWidth = 0;
- for (size_t i = 0; i < clusterInfos.size(); ++i) {
- TextAutosizingClusterInfo& clusterInfo = clusterInfos[i];
- clusterInfo.blockContainingAllText = findDeepestBlockContainingAllText(clusterInfo.root);
- maxTextWidth = max<float>(maxTextWidth, clusterInfo.blockContainingAllText->contentLogicalWidth());
- }
-
- float multiplier = 1.0;
- if (compositeClusterShouldBeAutosized(clusterInfos, maxTextWidth))
- multiplier = clusterMultiplier(clusterInfos[0].root->style()->writingMode(), windowInfo, maxTextWidth);
- for (size_t i = 0; i < clusterInfos.size(); ++i) {
- ASSERT(clusterInfos[i].root->style()->writingMode() == clusterInfos[0].root->style()->writingMode());
- processClusterInternal(clusterInfos[i], clusterInfos[i].root, clusterInfos[i].root, windowInfo, multiplier);
- }
-}
-
-void TextAutosizer::processContainer(float multiplier, RenderBlock* container, TextAutosizingClusterInfo& clusterInfo, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo)
-{
- ASSERT(isAutosizingContainer(container));
-
- float localMultiplier = containerShouldBeAutosized(container) ? multiplier: 1;
-
- RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(subtreeRoot, subtreeRoot);
- while (descendant) {
- if (descendant->isText()) {
- if (localMultiplier != 1 && descendant->style()->textAutosizingMultiplier() == 1) {
- setMultiplier(descendant, localMultiplier);
- setMultiplier(descendant->parent(), localMultiplier); // Parent does line spacing.
- }
- // FIXME: Increase list marker size proportionately.
- } else if (isAutosizingContainer(descendant)) {
- RenderBlock* descendantBlock = toRenderBlock(descendant);
- TextAutosizingClusterInfo descendantClusterInfo(descendantBlock);
- if (isWiderDescendant(descendantBlock, clusterInfo) || isIndependentDescendant(descendantBlock))
- processCluster(descendantClusterInfo, descendantBlock, descendantBlock, windowInfo);
- else if (isNarrowDescendant(descendantBlock, clusterInfo)) {
- // Narrow descendants are processed together later to be able to apply the same multiplier
- // to each of them if necessary.
- clusterInfo.narrowDescendants.append(descendantClusterInfo);
- } else
- processContainer(multiplier, descendantBlock, clusterInfo, descendantBlock, windowInfo);
- }
- descendant = nextInPreOrderSkippingDescendantsOfContainers(descendant, subtreeRoot);
- }
-}
-
-void TextAutosizer::setMultiplier(RenderObject* renderer, float multiplier)
-{
- RefPtr<RenderStyle> newStyle = RenderStyle::clone(renderer->style());
- newStyle->setTextAutosizingMultiplier(multiplier);
- renderer->setStyle(newStyle.release());
-}
-
-float TextAutosizer::computeAutosizedFontSize(float specifiedSize, float multiplier)
-{
- // Somewhat arbitrary "pleasant" font size.
- const float pleasantSize = 16;
-
- // Multiply fonts that the page author has specified to be larger than
- // pleasantSize by less and less, until huge fonts are not increased at all.
- // For specifiedSize between 0 and pleasantSize we directly apply the
- // multiplier; hence for specifiedSize == pleasantSize, computedSize will be
- // multiplier * pleasantSize. For greater specifiedSizes we want to
- // gradually fade out the multiplier, so for every 1px increase in
- // specifiedSize beyond pleasantSize we will only increase computedSize
- // by gradientAfterPleasantSize px until we meet the
- // computedSize = specifiedSize line, after which we stay on that line (so
- // then every 1px increase in specifiedSize increases computedSize by 1px).
- const float gradientAfterPleasantSize = 0.5;
-
- float computedSize;
- if (specifiedSize <= pleasantSize)
- computedSize = multiplier * specifiedSize;
- else {
- computedSize = multiplier * pleasantSize + gradientAfterPleasantSize * (specifiedSize - pleasantSize);
- if (computedSize < specifiedSize)
- computedSize = specifiedSize;
- }
- return computedSize;
-}
-
-bool TextAutosizer::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.
- if (!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;
-}
-
-bool TextAutosizer::isNarrowDescendant(const RenderBlock* renderer, TextAutosizingClusterInfo& parentClusterInfo)
-{
- ASSERT(isAutosizingContainer(renderer));
-
- // Autosizing containers that are significantly narrower than the |blockContainingAllText| of
- // their enclosing cluster may be acting as separate columns, hence must be autosized
- // separately. For example the 2nd div in:
- // <body>
- // <div style="float: right; width: 50%"></div>
- // <div style="width: 50%"></div>
- // <body>
- // is the left column, and should be autosized differently from the body.
- // If however the container is only narrower by 150px or less, it's considered part of
- // the enclosing cluster. This 150px limit is adjusted whenever a descendant container is
- // less than 50px narrower than the current limit.
- const float differenceFromMaxWidthDifference = 50;
- float contentWidth = renderer->contentLogicalWidth();
- float clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth();
- float widthDifference = clusterTextWidth - contentWidth;
-
- if (widthDifference - parentClusterInfo.maxAllowedDifferenceFromTextWidth > differenceFromMaxWidthDifference)
- return true;
-
- parentClusterInfo.maxAllowedDifferenceFromTextWidth = std::max(widthDifference, parentClusterInfo.maxAllowedDifferenceFromTextWidth);
- return false;
-}
-
-bool TextAutosizer::isWiderDescendant(const RenderBlock* renderer, const TextAutosizingClusterInfo& parentClusterInfo)
-{
- ASSERT(isAutosizingContainer(renderer));
-
- // Autosizing containers that are wider than the |blockContainingAllText| of their enclosing
- // cluster are treated the same way as autosizing clusters to be autosized separately.
- float contentWidth = renderer->contentLogicalWidth();
- float clusterTextWidth = parentClusterInfo.blockContainingAllText->contentLogicalWidth();
- return contentWidth > clusterTextWidth;
-}
-
-bool TextAutosizer::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).
- return renderer->isRenderView()
- || renderer->isFloating()
- || renderer->isOutOfFlowPositioned()
- || renderer->isTableCell()
- || renderer->isTableCaption()
- || renderer->isFlexibleBoxIncludingDeprecated()
- || renderer->hasColumns()
- || renderer->containingBlock()->isHorizontalWritingMode() != renderer->isHorizontalWritingMode()
- || renderer->style()->isDisplayReplacedType();
- // 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...
-}
-
-bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer, TextAutosizingClusterInfo& parentClusterInfo)
-{
- ASSERT(isAutosizingContainer(renderer));
-
- return isNarrowDescendant(renderer, parentClusterInfo)
- || isWiderDescendant(renderer, parentClusterInfo)
- || isIndependentDescendant(renderer);
-}
-
-bool TextAutosizer::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);
-}
-
-bool TextAutosizer::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;
-}
-
-bool TextAutosizer::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()->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);
-}
-
-bool TextAutosizer::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()) {
- // 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->isFloatingOrOutOfFlowPositioned())
- return false;
- }
- return false;
-}
-
-bool TextAutosizer::clusterShouldBeAutosized(TextAutosizingClusterInfo& clusterInfo, float blockWidth)
-{
- Vector<TextAutosizingClusterInfo> clusterInfos(1, clusterInfo);
- return compositeClusterShouldBeAutosized(clusterInfos, blockWidth);
-}
-
-bool TextAutosizer::compositeClusterShouldBeAutosized(Vector<TextAutosizingClusterInfo>& clusterInfos, float blockWidth)
-{
- // Don't autosize clusters that contain less than 4 lines of text (in
- // practice less lines are required, since measureDescendantTextWidth
- // assumes that characters are 1em wide, but most characters are narrower
- // than that, so we're overestimating their contribution to the linecount).
- //
- // This is to reduce the likelihood of autosizing things like headers and
- // footers, which can be quite visually distracting. The rationale is that
- // if a cluster contains very few lines of text then it's ok to have to zoom
- // in and pan from side to side to read each line, since if there are very
- // few lines of text you'll only need to pan across once or twice.
- float totalTextWidth = 0;
- const float minLinesOfText = 4;
- float minTextWidth = blockWidth * minLinesOfText;
- for (size_t i = 0; i < clusterInfos.size(); ++i) {
- measureDescendantTextWidth(clusterInfos[i].blockContainingAllText, clusterInfos[i], minTextWidth, totalTextWidth);
- if (totalTextWidth >= minTextWidth)
- return true;
- }
- return false;
-}
-
-void TextAutosizer::measureDescendantTextWidth(const RenderBlock* container, TextAutosizingClusterInfo& clusterInfo, float minTextWidth, float& textWidth)
-{
- bool skipLocalText = !containerShouldBeAutosized(container);
-
- RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(container, container);
- while (descendant) {
- if (!skipLocalText && descendant->isText()) {
- textWidth += toRenderText(descendant)->renderedTextLength() * descendant->style()->specifiedFontSize();
- } else if (isAutosizingContainer(descendant)) {
- RenderBlock* descendantBlock = toRenderBlock(descendant);
- if (!isAutosizingCluster(descendantBlock, clusterInfo))
- measureDescendantTextWidth(descendantBlock, clusterInfo, minTextWidth, textWidth);
- }
- if (textWidth >= minTextWidth)
- return;
- descendant = nextInPreOrderSkippingDescendantsOfContainers(descendant, container);
- }
-}
-
-RenderObject* TextAutosizer::nextInPreOrderSkippingDescendantsOfContainers(const RenderObject* current, const RenderObject* stayWithin)
-{
- if (current == stayWithin || !isAutosizingContainer(current))
- return current->nextInPreOrder(stayWithin);
- return current->nextInPreOrderAfterChildren(stayWithin);
-}
-
-const RenderBlock* TextAutosizer::findDeepestBlockContainingAllText(const RenderBlock* cluster)
-{
- size_t firstDepth = 0;
- const RenderObject* firstTextLeaf = findFirstTextLeafNotInCluster(cluster, firstDepth, FirstToLast);
- if (!firstTextLeaf)
- return cluster;
-
- size_t lastDepth = 0;
- const RenderObject* lastTextLeaf = findFirstTextLeafNotInCluster(cluster, lastDepth, LastToFirst);
- ASSERT(lastTextLeaf);
-
- // Equalize the depths if necessary. Only one of the while loops below will get executed.
- const RenderObject* firstNode = firstTextLeaf;
- const RenderObject* lastNode = lastTextLeaf;
- while (firstDepth > lastDepth) {
- firstNode = firstNode->parent();
- --firstDepth;
- }
- while (lastDepth > firstDepth) {
- lastNode = lastNode->parent();
- --lastDepth;
- }
-
- // Go up from both nodes until the parent is the same. Both pointers will point to the LCA then.
- while (firstNode != lastNode) {
- firstNode = firstNode->parent();
- lastNode = lastNode->parent();
- }
-
- if (firstNode->isRenderBlock())
- 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
- // nodes lowest common ancestor as isAutosizingCluster would have made them into their own independent
- // cluster.
- RenderBlock* containingBlock = firstNode->containingBlock();
- ASSERT(containingBlock->isDescendantOf(cluster));
-
- return containingBlock;
-}
-
-const RenderObject* TextAutosizer::findFirstTextLeafNotInCluster(const RenderObject* parent, size_t& depth, TraversalDirection direction)
-{
- if (parent->isEmpty())
- return parent->isText() ? parent : 0;
-
- ++depth;
- const RenderObject* child = (direction == FirstToLast) ? parent->firstChild() : parent->lastChild();
- while (child) {
- if (!isAutosizingContainer(child) || !isIndependentDescendant(toRenderBlock(child))) {
- const RenderObject* leaf = findFirstTextLeafNotInCluster(child, depth, direction);
- if (leaf)
- return leaf;
- }
- child = (direction == FirstToLast) ? child->nextSibling() : child->previousSibling();
- }
- --depth;
-
- return 0;
-}
-
-namespace {
-
-// Compares the width of the specified cluster's roots in descending order.
-bool clusterWiderThanComparisonFn(const TextAutosizingClusterInfo& first, const TextAutosizingClusterInfo& second)
-{
- return first.root->contentLogicalWidth() > second.root->contentLogicalWidth();
-}
-
-} // namespace
-
-void TextAutosizer::getNarrowDescendantsGroupedByWidth(const TextAutosizingClusterInfo& parentClusterInfo, Vector<Vector<TextAutosizingClusterInfo> >& groups)
-{
- ASSERT(parentClusterInfo.blockContainingAllText);
- ASSERT(groups.isEmpty());
-
- Vector<TextAutosizingClusterInfo> clusterInfos(parentClusterInfo.narrowDescendants);
- if (clusterInfos.isEmpty())
- return;
-
- std::sort(clusterInfos.begin(), clusterInfos.end(), &clusterWiderThanComparisonFn);
- groups.grow(1);
-
- // If the width difference between two consecutive elements of |clusterInfos| is greater than
- // this empirically determined value, the next element should start a new group.
- const float maxWidthDifferenceWithinGroup = 100;
- for (size_t i = 0; i < clusterInfos.size(); ++i) {
- groups.last().append(clusterInfos[i]);
-
- if (i + 1 < clusterInfos.size()) {
- float currentWidth = clusterInfos[i].root->contentLogicalWidth();
- float nextWidth = clusterInfos[i + 1].root->contentLogicalWidth();
- if (currentWidth - nextWidth > maxWidthDifferenceWithinGroup)
- groups.grow(groups.size() + 1);
- }
- }
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(TEXT_AUTOSIZING)