diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/TextAutoSizing.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/rendering/TextAutoSizing.cpp')
-rw-r--r-- | Source/WebCore/rendering/TextAutoSizing.cpp | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/TextAutoSizing.cpp b/Source/WebCore/rendering/TextAutoSizing.cpp new file mode 100644 index 000000000..aaf71cb79 --- /dev/null +++ b/Source/WebCore/rendering/TextAutoSizing.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TextAutoSizing.h" + +#if ENABLE(TEXT_AUTOSIZING) + +#include "CSSFontSelector.h" +#include "Document.h" +#include "Logging.h" +#include "RenderListMarker.h" +#include "RenderText.h" +#include "StyleResolver.h" + +namespace WebCore { + +static RenderStyle cloneRenderStyleWithState(const RenderStyle& currentStyle) +{ + auto newStyle = RenderStyle::clone(currentStyle); + if (currentStyle.lastChildState()) + newStyle.setLastChildState(); + if (currentStyle.firstChildState()) + newStyle.setFirstChildState(); + return newStyle; +} + +TextAutoSizingKey::TextAutoSizingKey(DeletedTag) +{ + HashTraits<std::unique_ptr<RenderStyle>>::constructDeletedValue(m_style); +} + +TextAutoSizingKey::TextAutoSizingKey(const RenderStyle& style, unsigned hash) + : m_style(RenderStyle::clonePtr(style)) // FIXME: This seems very inefficient. + , m_hash(hash) +{ +} + +void TextAutoSizingValue::addTextNode(Text& node, float size) +{ + node.renderer()->setCandidateComputedTextSize(size); + m_autoSizedNodes.add(&node); +} + +static const float maxScaleIncrease = 1.7f; + +auto TextAutoSizingValue::adjustTextNodeSizes() -> StillHasNodes +{ + // Remove stale nodes. Nodes may have had their renderers detached. We'll also need to remove the style from the documents m_textAutoSizedNodes + // collection. Return true indicates we need to do that removal. + Vector<Text*> nodesForRemoval; + for (auto& textNode : m_autoSizedNodes) { + auto* renderer = textNode->renderer(); + if (!renderer || !renderer->style().textSizeAdjust().isAuto() || !renderer->candidateComputedTextSize()) + nodesForRemoval.append(textNode.get()); + } + + for (auto& node : nodesForRemoval) + m_autoSizedNodes.remove(node); + + StillHasNodes stillHasNodes = m_autoSizedNodes.isEmpty() ? StillHasNodes::No : StillHasNodes::Yes; + + // If we only have one piece of text with the style on the page don't adjust it's size. + if (m_autoSizedNodes.size() <= 1) + return stillHasNodes; + + // Compute average size. + float cumulativeSize = 0; + for (auto& node : m_autoSizedNodes) + cumulativeSize += node->renderer()->candidateComputedTextSize(); + + float averageSize = std::round(cumulativeSize / m_autoSizedNodes.size()); + + // Adjust sizes. + bool firstPass = true; + for (auto& node : m_autoSizedNodes) { + auto& renderer = *node->renderer(); + if (renderer.style().fontDescription().computedSize() == averageSize) + continue; + + float specifiedSize = renderer.style().fontDescription().specifiedSize(); + float scaleChange = averageSize / specifiedSize; + if (scaleChange > maxScaleIncrease && firstPass) { + firstPass = false; + averageSize = std::round(specifiedSize * maxScaleIncrease); + scaleChange = averageSize / specifiedSize; + } + + LOG(TextAutosizing, " adjust node size %p firstPass=%d averageSize=%f scaleChange=%f", node.get(), firstPass, averageSize, scaleChange); + + auto* parentRenderer = renderer.parent(); + + auto style = cloneRenderStyleWithState(renderer.style()); + auto fontDescription = style.fontDescription(); + fontDescription.setComputedSize(averageSize); + style.setFontDescription(fontDescription); + style.fontCascade().update(&node->document().fontSelector()); + parentRenderer->setStyle(WTFMove(style)); + + if (parentRenderer->isAnonymousBlock()) + parentRenderer = parentRenderer->parent(); + + // If we have a list we should resize ListMarkers separately. + if (is<RenderListMarker>(*parentRenderer->firstChild())) { + auto& listMarkerRenderer = downcast<RenderListMarker>(*parentRenderer->firstChild()); + auto style = cloneRenderStyleWithState(listMarkerRenderer.style()); + style.setFontDescription(fontDescription); + style.fontCascade().update(&node->document().fontSelector()); + listMarkerRenderer.setStyle(WTFMove(style)); + } + + // Resize the line height of the parent. + auto& parentStyle = parentRenderer->style(); + auto& lineHeightLength = parentStyle.specifiedLineHeight(); + + int specifiedLineHeight; + if (lineHeightLength.isPercent()) + specifiedLineHeight = minimumValueForLength(lineHeightLength, fontDescription.specifiedSize()); + else + specifiedLineHeight = lineHeightLength.value(); + + int lineHeight = specifiedLineHeight * scaleChange; + if (lineHeightLength.isFixed() && lineHeightLength.value() == lineHeight) + continue; + + auto newParentStyle = cloneRenderStyleWithState(parentStyle); + newParentStyle.setLineHeight(Length(lineHeight, Fixed)); + newParentStyle.setSpecifiedLineHeight(Length { lineHeightLength }); + newParentStyle.setFontDescription(fontDescription); + newParentStyle.fontCascade().update(&node->document().fontSelector()); + parentRenderer->setStyle(WTFMove(newParentStyle)); + } + + return stillHasNodes; +} + +TextAutoSizingValue::~TextAutoSizingValue() +{ + reset(); +} + +void TextAutoSizingValue::reset() +{ + for (auto& node : m_autoSizedNodes) { + auto* renderer = node->renderer(); + if (!renderer) + continue; + + auto* parentRenderer = renderer->parent(); + if (!parentRenderer) + continue; + + // Reset the font size back to the original specified size + auto fontDescription = renderer->style().fontDescription(); + float originalSize = fontDescription.specifiedSize(); + if (fontDescription.computedSize() != originalSize) { + fontDescription.setComputedSize(originalSize); + auto style = cloneRenderStyleWithState(renderer->style()); + style.setFontDescription(fontDescription); + style.fontCascade().update(&node->document().fontSelector()); + parentRenderer->setStyle(WTFMove(style)); + } + + // Reset the line height of the parent. + if (parentRenderer->isAnonymousBlock()) + parentRenderer = parentRenderer->parent(); + + auto& parentStyle = parentRenderer->style(); + auto& originalLineHeight = parentStyle.specifiedLineHeight(); + if (originalLineHeight == parentStyle.lineHeight()) + continue; + + auto newParentStyle = cloneRenderStyleWithState(parentStyle); + newParentStyle.setLineHeight(Length { originalLineHeight }); + newParentStyle.setFontDescription(fontDescription); + newParentStyle.fontCascade().update(&node->document().fontSelector()); + parentRenderer->setStyle(WTFMove(newParentStyle)); + } +} + +} // namespace WebCore + +#endif // ENABLE(TEXT_AUTOSIZING) |