diff options
Diffstat (limited to 'Source/WebCore/rendering/TextAutosizer.cpp')
-rw-r--r-- | Source/WebCore/rendering/TextAutosizer.cpp | 617 |
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) |