Title: [211738] trunk/Source/WebCore
Revision
211738
Author
za...@apple.com
Date
2017-02-06 11:06:39 -0800 (Mon, 06 Feb 2017)

Log Message

Simple line layout: Use simplified text measuring when possible.
https://bugs.webkit.org/show_bug.cgi?id=167843
<rdar://problem/30364907>

Reviewed by Antti Koivisto.

This patch adds a simplified version of text width measuring.
Certain type of text runs (no spacing etc) only require a subset of what we
currently do in FontCascade::width().

* platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::widthForSimpleText):
* platform/graphics/FontCascade.h:
* platform/graphics/WidthCache.h:
(WebCore::WidthCache::add):
(WebCore::WidthCache::addSlowCase):
* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::advanceInternal):
* rendering/RenderText.cpp:
(WebCore::RenderText::styleDidChange):
(WebCore::RenderText::setRenderedText):
(WebCore::RenderText::computeCanUseSimplifiedTextMeasuring):
* rendering/RenderText.h:
(WebCore::RenderText::canUseSimplifiedTextMeasuring):
* rendering/SimpleLineLayoutFlowContents.cpp:
(WebCore::SimpleLineLayout::initializeSegments):
* rendering/SimpleLineLayoutFlowContents.h:
* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragmentIterator):
(WebCore::SimpleLineLayout::TextFragmentIterator::textWidth):
* rendering/SimpleLineLayoutTextFragmentIterator.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (211737 => 211738)


--- trunk/Source/WebCore/ChangeLog	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/ChangeLog	2017-02-06 19:06:39 UTC (rev 211738)
@@ -1,3 +1,38 @@
+2017-02-06  Zalan Bujtas  <za...@apple.com>
+
+        Simple line layout: Use simplified text measuring when possible.
+        https://bugs.webkit.org/show_bug.cgi?id=167843
+        <rdar://problem/30364907>
+
+        Reviewed by Antti Koivisto.
+
+        This patch adds a simplified version of text width measuring.
+        Certain type of text runs (no spacing etc) only require a subset of what we
+        currently do in FontCascade::width().
+
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::FontCascade::widthForSimpleText):
+        * platform/graphics/FontCascade.h:
+        * platform/graphics/WidthCache.h:
+        (WebCore::WidthCache::add):
+        (WebCore::WidthCache::addSlowCase):
+        * platform/graphics/WidthIterator.cpp:
+        (WebCore::WidthIterator::advanceInternal):
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::styleDidChange):
+        (WebCore::RenderText::setRenderedText):
+        (WebCore::RenderText::computeCanUseSimplifiedTextMeasuring):
+        * rendering/RenderText.h:
+        (WebCore::RenderText::canUseSimplifiedTextMeasuring):
+        * rendering/SimpleLineLayoutFlowContents.cpp:
+        (WebCore::SimpleLineLayout::initializeSegments):
+        * rendering/SimpleLineLayoutFlowContents.h:
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragmentIterator):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::textWidth):
+        * rendering/SimpleLineLayoutTextFragmentIterator.h:
+
 2017-02-06  Carlos Garcia Campos  <cgar...@igalia.com>
 
         Resource usage overlay should ignore mouse events outside bounds by default

Modified: trunk/Source/WebCore/platform/graphics/FontCascade.cpp (211737 => 211738)


--- trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2017-02-06 19:06:39 UTC (rev 211738)
@@ -33,6 +33,9 @@
 #include "SurrogatePairAwareTextIterator.h"
 #include "TextRun.h"
 #include "WidthIterator.h"
+#if USE(CAIRO)
+#include <cairo.h>
+#endif
 #include <wtf/MainThread.h>
 #include <wtf/MathExtras.h>
 #include <wtf/NeverDestroyed.h>
@@ -377,6 +380,37 @@
     return result;
 }
 
+float FontCascade::widthForSimpleText(StringView text) const
+{
+    ASSERT(codePath(TextRun(text)) != FontCascade::Complex);
+    float* cacheEntry = m_fonts->widthCache().add(text, std::numeric_limits<float>::quiet_NaN());
+    if (cacheEntry && !std::isnan(*cacheEntry))
+        return *cacheEntry;
+
+    Vector<GlyphBufferGlyph, 16> glyphs;
+    Vector<GlyphBufferAdvance, 16> advances;
+    auto& font = primaryFont();
+    for (unsigned i = 0; i < text.length(); ++i) {
+        auto glyph = glyphDataForCharacter(text[i], false).glyph;
+#if USE(CAIRO)
+        cairo_glyph_t cairoGlyph;
+        cairoGlyph.index = glyph;
+        glyphs.append(cairoGlyph);
+#else
+        glyphs.append(glyph);
+#endif
+        advances.append(FloatSize(font.widthForGlyph(glyph), 0));
+    }
+    font.applyTransforms(&glyphs[0], &advances[0], glyphs.size(), enableKerning(), requiresShaping());
+    float runWidth = 0;
+    for (auto& advance : advances)
+        runWidth += advance.width();
+
+    if (cacheEntry)
+        *cacheEntry = runWidth;
+    return runWidth;
+}
+
 GlyphData FontCascade::glyphDataForCharacter(UChar32 c, bool mirror, FontVariant variant) const
 {
     if (variant == AutoVariant) {

Modified: trunk/Source/WebCore/platform/graphics/FontCascade.h (211737 => 211738)


--- trunk/Source/WebCore/platform/graphics/FontCascade.h	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.h	2017-02-06 19:06:39 UTC (rev 211738)
@@ -139,6 +139,7 @@
     DashArray dashesForIntersectionsWithRect(const TextRun&, const FloatPoint& textOrigin, const FloatRect& lineExtents) const;
 
     WEBCORE_EXPORT float width(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
+    float widthForSimpleText(StringView text) const;
 
     std::unique_ptr<TextLayout, TextLayoutDeleter> createLayout(RenderText&, float xPos, bool collapseWhiteSpace) const;
     static float width(TextLayout&, unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts = 0);

Modified: trunk/Source/WebCore/platform/graphics/WidthCache.h (211737 => 211738)


--- trunk/Source/WebCore/platform/graphics/WidthCache.h	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/platform/graphics/WidthCache.h	2017-02-06 19:06:39 UTC (rev 211738)
@@ -119,6 +119,21 @@
     {
     }
 
+    float* add(StringView text, float entry)
+    {
+        if (MemoryPressureHandler::singleton().isUnderMemoryPressure())
+            return nullptr;
+
+        if (static_cast<unsigned>(text.length()) > SmallStringKey::capacity())
+            return nullptr;
+
+        if (m_countdown > 0) {
+            --m_countdown;
+            return nullptr;
+        }
+        return addSlowCase(text, entry);
+    }
+
     float* add(const TextRun& run, float entry, bool hasKerningOrLigatures, bool hasWordSpacingOrLetterSpacing, GlyphOverflow* glyphOverflow)
     {
         if (MemoryPressureHandler::singleton().isUnderMemoryPressure())
@@ -143,7 +158,7 @@
             return 0;
         }
 
-        return addSlowCase(run, entry);
+        return addSlowCase(run.text(), entry);
     }
 
     void clear()
@@ -153,23 +168,24 @@
     }
 
 private:
-    float* addSlowCase(const TextRun& run, float entry)
+
+    float* addSlowCase(StringView text, float entry)
     {
-        int length = run.length();
+        int length = text.length();
         bool isNewEntry;
-        float *value;
+        float* value;
         if (length == 1) {
-            SingleCharMap::AddResult addResult = m_singleCharMap.add(run[0], entry);
+            SingleCharMap::AddResult addResult = m_singleCharMap.fastAdd(text[0], entry);
             isNewEntry = addResult.isNewEntry;
             value = &addResult.iterator->value;
         } else {
             SmallStringKey smallStringKey;
-            if (run.is8Bit())
-                smallStringKey = SmallStringKey(run.characters8(), length);
+            if (text.is8Bit())
+                smallStringKey = SmallStringKey(text.characters8(), length);
             else
-                smallStringKey = SmallStringKey(run.characters16(), length);
+                smallStringKey = SmallStringKey(text.characters16(), length);
 
-            Map::AddResult addResult = m_map.add(smallStringKey, entry);
+            Map::AddResult addResult = m_map.fastAdd(smallStringKey, entry);
             isNewEntry = addResult.isNewEntry;
             value = &addResult.iterator->value;
         }

Modified: trunk/Source/WebCore/platform/graphics/WidthIterator.cpp (211737 => 211738)


--- trunk/Source/WebCore/platform/graphics/WidthIterator.cpp	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/platform/graphics/WidthIterator.cpp	2017-02-06 19:06:39 UTC (rev 211738)
@@ -172,6 +172,7 @@
 template <typename TextIterator>
 inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, GlyphBuffer* glyphBuffer)
 {
+    // The core logic here needs to match SimpleLineLayout::widthForSimpleText()
     bool rtl = m_run.rtl();
     bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_expansion) && !m_run.spacingDisabled();
 

Modified: trunk/Source/WebCore/rendering/RenderText.cpp (211737 => 211738)


--- trunk/Source/WebCore/rendering/RenderText.cpp	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/rendering/RenderText.cpp	2017-02-06 19:06:39 UTC (rev 211738)
@@ -257,6 +257,8 @@
     if (!oldStyle) {
         m_useBackslashAsYenSymbol = computeUseBackslashAsYenSymbol();
         needsResetText = m_useBackslashAsYenSymbol;
+        // It should really be computed in the c'tor, but during construction we don't have parent yet -and RenderText style == parent()->style()
+        m_canUseSimplifiedTextMeasuring = computeCanUseSimplifiedTextMeasuring();
     } else if (oldStyle->fontCascade().useBackslashAsYenSymbol() != newStyle.fontCascade().useBackslashAsYenSymbol()) {
         m_useBackslashAsYenSymbol = computeUseBackslashAsYenSymbol();
         needsResetText = true;
@@ -1179,7 +1181,8 @@
 
     m_isAllASCII = m_text.containsOnlyASCII();
     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
-
+    m_canUseSimplifiedTextMeasuring = computeCanUseSimplifiedTextMeasuring();
+    
     if (m_text != originalText) {
         originalTextMap().set(this, originalText);
         m_originalTextDiffersFromRendered = true;
@@ -1221,6 +1224,29 @@
         characters[revealedCharactersOffset] = characterToReveal;
 }
 
+bool RenderText::computeCanUseSimplifiedTextMeasuring() const
+{
+    if (!m_canUseSimpleFontCodePath)
+        return false;
+    
+    auto& font = style().fontCascade();
+    if (font.wordSpacing() || font.letterSpacing())
+        return false;
+
+    // Additional check on the font codepath.
+    TextRun run(m_text);
+    run.setCharacterScanForCodePath(false);
+    if (font.codePath(run) != FontCascade::Simple)
+        return false;
+
+    auto whitespaceIsCollapsed = style().collapseWhiteSpace();
+    for (unsigned i = 0; i < m_text.length(); ++i) {
+        if ((!whitespaceIsCollapsed && m_text[i] == '\t') || m_text[i] == noBreakSpace || m_text[i] >= HiraganaLetterSmallA)
+            return false;
+    }
+    return true;
+}
+
 void RenderText::setText(const String& text, bool force)
 {
     ASSERT(!text.isNull());

Modified: trunk/Source/WebCore/rendering/RenderText.h (211737 => 211738)


--- trunk/Source/WebCore/rendering/RenderText.h	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/rendering/RenderText.h	2017-02-06 19:06:39 UTC (rev 211738)
@@ -171,6 +171,8 @@
     LayoutUnit topOfFirstText() const;
     
     bool containsOnlyWhitespace(unsigned from, unsigned len) const;
+    
+    bool canUseSimplifiedTextMeasuring() const { return m_canUseSimplifiedTextMeasuring; }
 
 protected:
     virtual void computePreferredLogicalWidths(float leadWidth);
@@ -202,6 +204,7 @@
     void secureText(UChar mask);
 
     LayoutRect collectSelectionRectsForLineBoxes(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent, Vector<LayoutRect>*);
+    bool computeCanUseSimplifiedTextMeasuring() const;
 
     void node() const = delete;
     void container() const = delete; // Use parent() instead.
@@ -223,6 +226,7 @@
     mutable unsigned m_knownToHaveNoOverflowAndNoFallbackFonts : 1;
     unsigned m_useBackslashAsYenSymbol : 1;
     unsigned m_originalTextDiffersFromRendered : 1;
+    unsigned m_canUseSimplifiedTextMeasuring : 1;
 
 #if ENABLE(TEXT_AUTOSIZING)
     // FIXME: This should probably be part of the text sizing structures in Document instead. That would save some memory.

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp (211737 => 211738)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp	2017-02-06 19:06:39 UTC (rev 211738)
@@ -47,12 +47,13 @@
         if (is<RenderText>(child)) {
             auto& textChild = downcast<RenderText>(child);
             unsigned textLength = textChild.text()->length();
-            segments.append(FlowContents::Segment { startPosition, startPosition + textLength, textChild.text(), textChild });
+            segments.append(FlowContents::Segment { startPosition, startPosition + textLength, textChild.text(),
+                textChild, textChild.canUseSimplifiedTextMeasuring() });
             startPosition += textLength;
             continue;
         }
         if (is<RenderLineBreak>(child)) {
-            segments.append(FlowContents::Segment { startPosition, startPosition, String(), child });
+            segments.append(FlowContents::Segment { startPosition, startPosition, String(), child, true });
             continue;
         }
         ASSERT_NOT_REACHED();

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h (211737 => 211738)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h	2017-02-06 19:06:39 UTC (rev 211738)
@@ -47,6 +47,7 @@
         unsigned end;
         StringView text;
         const RenderObject& renderer;
+        bool canUseSimplifiedTextMeasuring;
     };
     const Segment& segmentForRun(unsigned start, unsigned end) const;
 

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp (211737 => 211738)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp	2017-02-06 19:06:39 UTC (rev 211738)
@@ -34,7 +34,7 @@
 namespace WebCore {
 namespace SimpleLineLayout {
 
-TextFragmentIterator::Style::Style(const RenderStyle& style)
+TextFragmentIterator::Style::Style(const RenderStyle& style, bool useSimplifiedTextMeasuring)
     : font(style.fontCascade())
     , textAlign(style.textAlign())
     , collapseWhitespace(style.collapseWhiteSpace())
@@ -44,11 +44,11 @@
     , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || preserveNewline)))
     , breakNBSP(wrapLines && style.nbspMode() == SPACE)
     , keepAllWordsForCJK(style.wordBreak() == KeepAllWordBreak)
-    , spaceWidth(font.width(TextRun(StringView(&space, 1))))
+    , spaceWidth(useSimplifiedTextMeasuring ? font.widthForSimpleText(StringView(&space, 1)) : font.width(TextRun(StringView(&space, 1))))
     , wordSpacing(font.wordSpacing())
     , tabWidth(collapseWhitespace ? 0 : style.tabSize())
     , shouldHyphenate(style.hyphens() == HyphensAuto && canHyphenate(style.locale()))
-    , hyphenStringWidth(shouldHyphenate ? font.width(TextRun(style.hyphenString())) : 0)
+    , hyphenStringWidth(shouldHyphenate ? (useSimplifiedTextMeasuring ? font.widthForSimpleText(style.hyphenString()) : font.width(TextRun(style.hyphenString()))) : 0)
     , hyphenLimitBefore(style.hyphenationLimitBefore() < 0 ? 2 : style.hyphenationLimitBefore())
     , hyphenLimitAfter(style.hyphenationLimitAfter() < 0 ? 2 : style.hyphenationLimitAfter())
     , locale(style.locale())
@@ -61,7 +61,7 @@
     : m_flowContents(flow)
     , m_currentSegment(m_flowContents.begin())
     , m_lineBreakIterator(m_currentSegment->text, flow.style().locale())
-    , m_style(flow.style())
+    , m_style(flow.style(), m_currentSegment->canUseSimplifiedTextMeasuring)
 {
 }
 
@@ -247,10 +247,15 @@
     bool measureWithEndSpace = m_style.collapseWhitespace && segmentTo < segment.text.length() && segment.text[segmentTo] == ' ';
     if (measureWithEndSpace)
         ++segmentTo;
-    TextRun run(StringView(segment.text).substring(segmentFrom, segmentTo - segmentFrom), xPosition);
-    if (m_style.tabWidth)
-        run.setTabSize(true, m_style.tabWidth);
-    float width = m_style.font.width(run);
+    float width = 0;
+    if (segment.canUseSimplifiedTextMeasuring)
+        width = m_style.font.widthForSimpleText(StringView(segment.text).substring(segmentFrom, segmentTo - segmentFrom));
+    else {
+        TextRun run(StringView(segment.text).substring(segmentFrom, segmentTo - segmentFrom), xPosition);
+        if (m_style.tabWidth)
+            run.setTabSize(true, m_style.tabWidth);
+        width = m_style.font.width(run);
+    }
     if (measureWithEndSpace)
         width -= (m_style.spaceWidth + m_style.wordSpacing);
     return std::max<float>(0, width);

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h (211737 => 211738)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h	2017-02-06 18:59:19 UTC (rev 211737)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h	2017-02-06 19:06:39 UTC (rev 211738)
@@ -105,7 +105,7 @@
     std::optional<unsigned> lastHyphenPosition(const TextFragmentIterator::TextFragment& run, unsigned beforeIndex) const;
 
     struct Style {
-        explicit Style(const RenderStyle&);
+        explicit Style(const RenderStyle&, bool useSimplifiedTextMeasuring);
 
         const FontCascade& font;
         ETextAlign textAlign;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to