Cache glyph widths to GlyphPages
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Mar 2015 01:10:53 +0000 (01:10 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Mar 2015 01:10:53 +0000 (01:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142028

Reviewed by Andreas Kling.

Currently we have a separate cache in Font for glyph widths. In practice we always need
the widths so we can just cache them in GlyphPages. This simplifies the code and removes
a per-character hash lookup from WidthIterator.

* platform/graphics/Font.cpp:
(WebCore::Font::Font):
(WebCore::Font::initCharWidths):
(WebCore::Font::platformGlyphInit):
(WebCore::createAndFillGlyphPage):
(WebCore::Font::computeWidthForGlyph):

    Rename to make it clear this doesn't cache.

(WebCore::GlyphPage::setGlyphDataForIndex):

    Initialize the width.
    This could go to GlyphPage.cpp if we had one.

* platform/graphics/Font.h:
(WebCore::Font::glyphZeroWidth):
(WebCore::Font::isZeroWidthSpaceGlyph):
(WebCore::Font::zeroGlyph): Deleted.
(WebCore::Font::setZeroGlyph): Deleted.
(WebCore::Font::widthForGlyph): Deleted.
* platform/graphics/FontCascade.cpp:
(WebCore::offsetToMiddleOfGlyph):
* platform/graphics/FontCascadeFonts.cpp:
(WebCore::FontCascadeFonts::glyphDataForCharacter):
* platform/graphics/GlyphPage.h:
(WebCore::GlyphData::GlyphData):

    Return width too as part of GlyphData.

(WebCore::GlyphPage::glyphDataForIndex):
(WebCore::GlyphPage::setGlyphDataForCharacter):
(WebCore::GlyphPage::setGlyphDataForIndex):
(WebCore::GlyphPage::GlyphPage):
* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::advanceInternal):

    No need to lookup width separately now.

* platform/graphics/mac/ComplexTextController.cpp:
(WebCore::ComplexTextController::adjustGlyphsAndAdvances):
* platform/graphics/mac/ComplexTextControllerCoreText.mm:
(WebCore::ComplexTextController::ComplexTextRun::ComplexTextRun):
* rendering/mathml/RenderMathMLOperator.cpp:
(WebCore::RenderMathMLOperator::advanceForGlyph):
* rendering/svg/SVGTextRunRenderingContext.cpp:
(WebCore::missingGlyphForFont):
* svg/SVGFontData.cpp:
(WebCore::SVGFontData::initializeFont):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181492 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/Font.cpp
Source/WebCore/platform/graphics/Font.h
Source/WebCore/platform/graphics/FontCascade.cpp
Source/WebCore/platform/graphics/FontCascadeFonts.cpp
Source/WebCore/platform/graphics/GlyphPage.h
Source/WebCore/platform/graphics/WidthIterator.cpp
Source/WebCore/platform/graphics/mac/ComplexTextController.cpp
Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.mm
Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp
Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp
Source/WebCore/svg/SVGFontData.cpp

index 4d6cf9c..493e453 100644 (file)
@@ -1,3 +1,63 @@
+2015-03-13  Antti Koivisto  <antti@apple.com>
+
+        Cache glyph widths to GlyphPages
+        https://bugs.webkit.org/show_bug.cgi?id=142028
+
+        Reviewed by Andreas Kling.
+
+        Currently we have a separate cache in Font for glyph widths. In practice we always need
+        the widths so we can just cache them in GlyphPages. This simplifies the code and removes
+        a per-character hash lookup from WidthIterator.
+
+        * platform/graphics/Font.cpp:
+        (WebCore::Font::Font):
+        (WebCore::Font::initCharWidths):
+        (WebCore::Font::platformGlyphInit):
+        (WebCore::createAndFillGlyphPage):
+        (WebCore::Font::computeWidthForGlyph):
+
+            Rename to make it clear this doesn't cache.
+
+        (WebCore::GlyphPage::setGlyphDataForIndex):
+
+            Initialize the width.
+            This could go to GlyphPage.cpp if we had one.
+
+        * platform/graphics/Font.h:
+        (WebCore::Font::glyphZeroWidth):
+        (WebCore::Font::isZeroWidthSpaceGlyph):
+        (WebCore::Font::zeroGlyph): Deleted.
+        (WebCore::Font::setZeroGlyph): Deleted.
+        (WebCore::Font::widthForGlyph): Deleted.
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::offsetToMiddleOfGlyph):
+        * platform/graphics/FontCascadeFonts.cpp:
+        (WebCore::FontCascadeFonts::glyphDataForCharacter):
+        * platform/graphics/GlyphPage.h:
+        (WebCore::GlyphData::GlyphData):
+
+            Return width too as part of GlyphData.
+
+        (WebCore::GlyphPage::glyphDataForIndex):
+        (WebCore::GlyphPage::setGlyphDataForCharacter):
+        (WebCore::GlyphPage::setGlyphDataForIndex):
+        (WebCore::GlyphPage::GlyphPage):
+        * platform/graphics/WidthIterator.cpp:
+        (WebCore::WidthIterator::advanceInternal):
+
+            No need to lookup width separately now.
+
+        * platform/graphics/mac/ComplexTextController.cpp:
+        (WebCore::ComplexTextController::adjustGlyphsAndAdvances):
+        * platform/graphics/mac/ComplexTextControllerCoreText.mm:
+        (WebCore::ComplexTextController::ComplexTextRun::ComplexTextRun):
+        * rendering/mathml/RenderMathMLOperator.cpp:
+        (WebCore::RenderMathMLOperator::advanceForGlyph):
+        * rendering/svg/SVGTextRunRenderingContext.cpp:
+        (WebCore::missingGlyphForFont):
+        * svg/SVGFontData.cpp:
+        (WebCore::SVGFontData::initializeFont):
+
 2015-03-13  Eric Carlson  <eric.carlson@apple.com>
 
         [Mac] Enable WIRELESS_PLAYBACK_TARGET
index b62d41d..a25c7a8 100644 (file)
@@ -54,16 +54,9 @@ Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoadi
     : m_maxCharWidth(-1)
     , m_avgCharWidth(-1)
     , m_platformData(platformData)
-    , m_treatAsFixedPitch(false)
     , m_isCustomFont(isCustomFont)
     , m_isLoading(isLoading)
     , m_isTextOrientationFallback(isTextOrientationFallback)
-    , m_isBrokenIdeographFallback(false)
-    , m_mathData(nullptr)
-#if ENABLE(OPENTYPE_VERTICAL)
-    , m_verticalData(0)
-#endif
-    , m_hasVerticalGlyphs(false)
 {
     platformInit();
     platformGlyphInit();
@@ -79,21 +72,11 @@ Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoadi
 Font::Font(std::unique_ptr<SVGData> svgData, float fontSize, bool syntheticBold, bool syntheticItalic)
     : m_platformData(FontPlatformData(fontSize, syntheticBold, syntheticItalic))
     , m_svgData(WTF::move(svgData))
-    , m_treatAsFixedPitch(false)
     , m_isCustomFont(true)
-    , m_isLoading(false)
-    , m_isTextOrientationFallback(false)
-    , m_isBrokenIdeographFallback(false)
-    , m_mathData(nullptr)
-#if ENABLE(OPENTYPE_VERTICAL)
-    , m_verticalData(0)
-#endif
-    , m_hasVerticalGlyphs(false)
-#if PLATFORM(IOS)
-    , m_shouldNotBeUsedForArabic(false)
-#endif
 {
     m_svgData->initializeFont(this, fontSize);
+    if (m_glyphPageZero)
+        m_glyphPageZero->setImmutable();
 }
 
 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
@@ -106,7 +89,7 @@ void Font::initCharWidths()
         static const UChar32 digitZeroChar = '0';
         Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph;
         if (digitZeroGlyph)
-            m_avgCharWidth = widthForGlyph(digitZeroGlyph);
+            m_avgCharWidth = computeWidthForGlyph(digitZeroGlyph);
     }
 
     // If we can't retrieve the width of a '0', fall back to the x height.
@@ -121,35 +104,37 @@ void Font::platformGlyphInit()
 {
     auto* glyphPageZero = glyphPage(0);
     if (!glyphPageZero) {
-        m_spaceGlyph = 0;
-        m_spaceWidth = 0;
-        m_zeroGlyph = 0;
-        m_adjustedSpaceWidth = 0;
         determinePitch();
-        m_zeroWidthSpaceGlyph = 0;
         return;
     }
-
     // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
     // are mapped to the ZERO WIDTH SPACE glyph.
     m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
-
     // Nasty hack to determine if we should round or ceil space widths.
     // If the font is monospace or fake monospace we ceil to ensure that 
     // every character and the space are the same width. Otherwise we round.
-    m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
-    float width = widthForGlyph(m_spaceGlyph);
-    m_spaceWidth = width;
-    m_zeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
-    m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
+    auto spaceGlyphData = glyphPageZero->glyphDataForCharacter(' ');
+    m_spaceGlyph = spaceGlyphData.glyph;
+    m_spaceWidth = spaceGlyphData.width;
+    m_fontMetrics.setZeroWidth(glyphPageZero->glyphDataForCharacter('0').width);
     determinePitch();
-    m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
+    m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(m_spaceWidth) : roundf(m_spaceWidth);
+    m_glyphZeroWidth = computeWidthForGlyph(0);
 
     // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
     // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
     // See <http://bugs.webkit.org/show_bug.cgi?id=13178> and Font::isZeroWidthSpaceGlyph()
     if (m_zeroWidthSpaceGlyph == m_spaceGlyph)
         m_zeroWidthSpaceGlyph = 0;
+    else {
+        // Fixup the page zero now that we know the zero width glyph.
+        for (unsigned i = 0; i < GlyphPage::size; ++i) {
+            auto glyphData = m_glyphPageZero->glyphDataForIndex(i);
+            if (glyphData.glyph == m_zeroWidthSpaceGlyph)
+                m_glyphPageZero->setGlyphDataForIndex(i, { glyphData.glyph, 0, glyphData.font });
+        }
+    }
+    m_glyphPageZero->setImmutable();
 }
 
 Font::~Font()
@@ -171,7 +156,7 @@ static bool fillGlyphPage(GlyphPage& pageToFill, unsigned offset, unsigned lengt
     return hasGlyphs;
 }
 
-static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font* font)
+RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font* font)
 {
 #if PLATFORM(IOS)
     // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
@@ -244,22 +229,45 @@ static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font*
     if (!haveGlyphs)
         return nullptr;
 
-    glyphPage->setImmutable();
     return glyphPage;
 }
 
+float Font::computeWidthForGlyph(Glyph glyph) const
+{
+    if (isZeroWidthSpaceGlyph(glyph))
+        return 0;
+    float width;
+    if (isSVGFont())
+        width = m_svgData->widthForSVGGlyph(glyph, m_platformData.size());
+#if ENABLE(OPENTYPE_VERTICAL)
+    else if (m_verticalData)
+#if USE(CG) || USE(CAIRO)
+        width = m_verticalData->advanceHeight(this, glyph) + m_syntheticBoldOffset;
+#else
+        width = m_verticalData->advanceHeight(this, glyph);
+#endif
+#endif
+    else
+        width = platformWidthForGlyph(glyph);
+    return width;
+}
+
 const GlyphPage* Font::glyphPage(unsigned pageNumber) const
 {
     if (!pageNumber) {
         if (!m_glyphPageZero)
             m_glyphPageZero = createAndFillGlyphPage(0, this);
+        // Zero page is marked immutable in platformGlyphInit.
         return m_glyphPageZero.get();
     }
     auto addResult = m_glyphPages.add(pageNumber, nullptr);
-    if (addResult.isNewEntry)
-        addResult.iterator->value = createAndFillGlyphPage(pageNumber, this);
-
-    return addResult.iterator->value.get();
+    auto& page = addResult.iterator->value;
+    if (addResult.isNewEntry) {
+        page = createAndFillGlyphPage(pageNumber, this);
+        if (page)
+            page->setImmutable();
+    }
+    return page.get();
 }
 
 Glyph Font::glyphForCharacter(UChar32 character) const
@@ -458,4 +466,10 @@ void Font::removeFromSystemFallbackCache()
     }
 }
 
+void GlyphPage::setGlyphDataForIndex(unsigned index, Glyph glyph, const Font* font)
+{
+    setGlyphDataForIndex(index, { glyph, font ? font->computeWidthForGlyph(glyph) : 0, font });
+}
+
+
 } // namespace WebCore
index dca5b51..400701c 100644 (file)
@@ -140,9 +140,8 @@ public:
     void setAvgCharWidth(float avgCharWidth) { m_avgCharWidth = avgCharWidth; }
 
     FloatRect boundsForGlyph(Glyph) const;
-    float widthForGlyph(Glyph) const;
-    FloatRect platformBoundsForGlyph(Glyph) const;
-    float platformWidthForGlyph(Glyph) const;
+
+    float computeWidthForGlyph(Glyph) const;
 
     float spaceWidth() const { return m_spaceWidth; }
     float adjustedSpaceWidth() const { return m_adjustedSpaceWidth; }
@@ -151,6 +150,7 @@ public:
         m_spaceWidth = spaceWidth;
         m_adjustedSpaceWidth = spaceWidth;
     }
+    float glyphZeroWidth() const { return m_glyphZeroWidth; }
 
 #if USE(CG) || USE(CAIRO)
     float syntheticBoldOffset() const { return m_syntheticBoldOffset; }
@@ -161,8 +161,6 @@ public:
     Glyph zeroWidthSpaceGlyph() const { return m_zeroWidthSpaceGlyph; }
     void setZeroWidthSpaceGlyph(Glyph spaceGlyph) { m_zeroWidthSpaceGlyph = spaceGlyph; }
     bool isZeroWidthSpaceGlyph(Glyph glyph) const { return glyph == m_zeroWidthSpaceGlyph && glyph; }
-    Glyph zeroGlyph() const { return m_zeroGlyph; }
-    void setZeroGlyph(Glyph zeroGlyph) { m_zeroGlyph = zeroGlyph; }
 
     GlyphData glyphDataForCharacter(UChar32) const;
     Glyph glyphForCharacter(UChar32) const;
@@ -227,8 +225,13 @@ private:
     PassRefPtr<Font> createScaledFont(const FontDescription&, float scaleFactor) const;
     PassRefPtr<Font> platformCreateScaledFont(const FontDescription&, float scaleFactor) const;
 
+    float platformWidthForGlyph(Glyph) const;
+    FloatRect platformBoundsForGlyph(Glyph) const;
+
     void removeFromSystemFallbackCache();
 
+    friend RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font*);
+
 #if PLATFORM(WIN)
     void initGDIFont();
     void platformCommonDestroy();
@@ -246,14 +249,13 @@ private:
     mutable RefPtr<GlyphPage> m_glyphPageZero;
     mutable HashMap<unsigned, RefPtr<GlyphPage>> m_glyphPages;
     mutable std::unique_ptr<GlyphMetricsMap<FloatRect>> m_glyphToBoundsMap;
-    mutable GlyphMetricsMap<float> m_glyphToWidthMap;
 
-    bool m_treatAsFixedPitch;
-    bool m_isCustomFont; // Whether or not we are custom font loaded via @font-face
-    bool m_isLoading; // Whether or not this custom font is still in the act of loading.
+    bool m_treatAsFixedPitch { false };
+    bool m_isCustomFont { false }; // Whether or not we are custom font loaded via @font-face
+    bool m_isLoading { false }; // Whether or not this custom font is still in the act of loading.
 
-    bool m_isTextOrientationFallback;
-    bool m_isBrokenIdeographFallback;
+    bool m_isTextOrientationFallback { false };
+    bool m_isBrokenIdeographFallback { false };
 
     bool m_isUsedInSystemFallbackCache { false };
 
@@ -261,14 +263,15 @@ private:
 #if ENABLE(OPENTYPE_VERTICAL)
     RefPtr<OpenTypeVerticalData> m_verticalData;
 #endif
-    bool m_hasVerticalGlyphs;
+    bool m_hasVerticalGlyphs { false };
+
+    Glyph m_spaceGlyph { 0 };
+    float m_spaceWidth { 0 };
+    float m_adjustedSpaceWidth { 0 };
 
-    Glyph m_spaceGlyph;
-    float m_spaceWidth;
-    Glyph m_zeroGlyph;
-    float m_adjustedSpaceWidth;
+    Glyph m_zeroWidthSpaceGlyph { 0 };
 
-    Glyph m_zeroWidthSpaceGlyph;
+    float m_glyphZeroWidth { 0 };
 
     struct DerivedFontData {
         explicit DerivedFontData(bool custom)
@@ -309,7 +312,7 @@ private:
     mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
 #endif
 #if PLATFORM(IOS)
-    bool m_shouldNotBeUsedForArabic;
+    bool m_shouldNotBeUsedForArabic { false };
 #endif
 };
 
@@ -332,32 +335,6 @@ ALWAYS_INLINE FloatRect Font::boundsForGlyph(Glyph glyph) const
     return bounds;
 }
 
-ALWAYS_INLINE float Font::widthForGlyph(Glyph glyph) const
-{
-    if (isZeroWidthSpaceGlyph(glyph))
-        return 0;
-
-    float width = m_glyphToWidthMap.metricsForGlyph(glyph);
-    if (width != cGlyphSizeUnknown)
-        return width;
-
-    if (isSVGFont())
-        width = m_svgData->widthForSVGGlyph(glyph, m_platformData.size());
-#if ENABLE(OPENTYPE_VERTICAL)
-    else if (m_verticalData)
-#if USE(CG) || USE(CAIRO)
-        width = m_verticalData->advanceHeight(this, glyph) + m_syntheticBoldOffset;
-#else
-        width = m_verticalData->advanceHeight(this, glyph);
-#endif
-#endif
-    else
-        width = platformWidthForGlyph(glyph);
-
-    m_glyphToWidthMap.setMetricsForGlyph(glyph, width);
-    return width;
-}
-
 } // namespace WebCore
 
 #endif // Font_h
index 275f5f0..5ce2564 100644 (file)
@@ -1339,7 +1339,7 @@ inline static float offsetToMiddleOfGlyph(const Font* fontData, Glyph glyph)
         return bounds.x() + bounds.width() / 2;
     }
     // FIXME: Use glyph bounds once they make sense for vertical fonts.
-    return fontData->widthForGlyph(glyph) / 2;
+    return fontData->computeWidthForGlyph(glyph) / 2;
 }
 
 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
index dd3be1a..899b096 100644 (file)
@@ -387,7 +387,7 @@ GlyphData FontCascadeFonts::glyphDataForCharacter(UChar32 c, const FontDescripti
             cachedPage = GlyphPage::createCopyForMixedFonts(*cachedPage);
 
         glyphData = glyphDataForNormalVariant(c, description);
-        cachedPage->setGlyphDataForCharacter(c, glyphData.glyph, glyphData.font);
+        cachedPage->setGlyphDataForCharacter(c, glyphData);
     }
     return glyphData;
 }
index 36d8fe0..75fd6b8 100644 (file)
@@ -44,13 +44,16 @@ class Font;
 // Holds the glyph index and the corresponding Font information for a given
 // character.
 struct GlyphData {
-    GlyphData(Glyph g = 0, const Font* f = 0)
-        : glyph(g)
-        , font(f)
-    {
-    }
-    Glyph glyph;
-    const Font* font;
+    GlyphData() { }
+    GlyphData(Glyph glyph, float width, const Font* font)
+        : glyph(glyph)
+        , width(width)
+        , font(font)
+    { }
+
+    Glyph glyph { 0 };
+    float width { 0 };
+    const Font* font { nullptr };
 };
 
 #if COMPILER(MSVC)
@@ -109,9 +112,10 @@ public:
     {
         ASSERT_WITH_SECURITY_IMPLICATION(index < size);
         Glyph glyph = m_glyphs[index];
+        float width = m_widths[index];
         if (hasPerGlyphFontData())
-            return GlyphData(glyph, m_perGlyphFontData[index]);
-        return GlyphData(glyph, glyph ? m_fontForAllGlyphs : 0);
+            return { glyph, width, m_perGlyphFontData[index] };
+        return { glyph, width, glyph ? m_fontForAllGlyphs : nullptr };
     }
 
     ALWAYS_INLINE Glyph glyphAt(unsigned index) const
@@ -128,31 +132,29 @@ public:
         return m_glyphs[index] ? m_fontForAllGlyphs : 0;
     }
 
-    void setGlyphDataForCharacter(UChar32 c, Glyph g, const Font* f)
+    void setGlyphDataForCharacter(UChar32 c, const GlyphData& glyphData)
     {
-        setGlyphDataForIndex(indexForCharacter(c), g, f);
+        setGlyphDataForIndex(indexForCharacter(c), glyphData);
     }
 
-    void setGlyphDataForIndex(unsigned index, Glyph glyph, const Font* font)
+    void setGlyphDataForIndex(unsigned index, Glyph, const Font*);
+
+    void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData)
     {
         ASSERT_WITH_SECURITY_IMPLICATION(index < size);
         ASSERT(!m_isImmutable);
-        
-        m_glyphs[index] = glyph;
+
+        m_glyphs[index] = glyphData.glyph;
+        m_widths[index] = glyphData.width;
 
         // GlyphPage getters will always return a null Font* for glyph #0 if there's no per-glyph font array.
         if (hasPerGlyphFontData()) {
-            m_perGlyphFontData[index] = glyph ? font : 0;
+            m_perGlyphFontData[index] =  glyphData.glyph ?  glyphData.font : 0;
             return;
         }
 
         // A single-font GlyphPage already assigned m_fontForAllGlyphs in the constructor.
-        ASSERT(!glyph || font == m_fontForAllGlyphs);
-    }
-
-    void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData)
-    {
-        setGlyphDataForIndex(index, glyphData.glyph, glyphData.font);
+        ASSERT(!glyphData.glyph || glyphData.font == m_fontForAllGlyphs);
     }
 
     // Implemented by the platform.
@@ -168,6 +170,7 @@ private:
         : m_fontForAllGlyphs(fontForAllGlyphs)
     {
         memset(m_glyphs, 0, sizeof(m_glyphs));
+        memset(m_widths, 0, sizeof(m_widths));
         if (hasPerGlyphFontData())
             memset(m_perGlyphFontData, 0, sizeof(Font*) * GlyphPage::size);
         ++s_count;
@@ -175,8 +178,9 @@ private:
 
     bool hasPerGlyphFontData() const { return !m_fontForAllGlyphs; }
 
-    const Font* m_fontForAllGlyphs;
+    const Font* m_fontForAllGlyphs { nullptr };
     Glyph m_glyphs[size];
+    float m_widths[size];
 
     bool m_isImmutable { false };
     // NOTE: This array has (GlyphPage::size) elements if m_fontForAllGlyphs is null.
index fcf634d..1a0731b 100644 (file)
@@ -191,7 +191,7 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph
         if (character == '\t' && m_run.allowTabs())
             width = m_font->tabWidth(*font, m_run.tabSize(), m_run.xPos() + m_runWidthSoFar + widthSinceLastRounding);
         else {
-            width = font->widthForGlyph(glyph);
+            width = glyphData.width;
 
             // SVG uses horizontalGlyphStretch(), when textLength is used to stretch/squeeze text.
             width *= m_run.horizontalGlyphStretch();
index d3a8113..7ed4cea 100644 (file)
@@ -638,7 +638,7 @@ void ComplexTextController::adjustGlyphsAndAdvances()
             CGSize advance = treatAsSpace ? CGSizeMake(spaceWidth, advances[i].height) : advances[i];
 #if PLATFORM(IOS)
             if (isEmoji && advance.width)
-                advance.width = font.widthForGlyph(glyph);
+                advance.width = font.computeWidthForGlyph(glyph);
 #endif
 
             if (ch == '\t' && m_run.allowTabs())
index 3f97131..37484d9 100644 (file)
@@ -168,7 +168,7 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(const Font& font, const UC
     // Synthesize a run of missing glyphs.
     m_glyphsVector.fill(0, m_glyphCount);
     m_glyphs = m_glyphsVector.data();
-    m_advancesVector.fill(CGSizeMake(m_font.widthForGlyph(0), 0), m_glyphCount);
+    m_advancesVector.fill(CGSizeMake(m_font.glyphZeroWidth(), 0), m_glyphCount);
     m_advances = m_advancesVector.data();
 }
 
index 938f6bc..7d99541 100644 (file)
@@ -1343,7 +1343,10 @@ float RenderMathMLOperator::heightForGlyph(const GlyphData& data) const
 
 float RenderMathMLOperator::advanceForGlyph(const GlyphData& data) const
 {
-    return data.font && data.glyph ? data.font->widthForGlyph(data.glyph) : 0;
+    // FIXME: MathML code synthesizes bad GlyphDatas.
+    if (!data.font)
+        return 0;
+    return data.width ? data.width : data.font->computeWidthForGlyph(data.glyph);
 }
 
 void RenderMathMLOperator::computePreferredLogicalWidths()
index dd3f285..4c5dfa6 100644 (file)
@@ -298,7 +298,8 @@ static GlyphData missingGlyphForFont(const FontCascade& font)
     SVGFontElement* fontElement;
     SVGFontFaceElement* fontFaceElement;
     svgFontAndFontFaceElementForFontData(&primaryFont, fontFaceElement, fontElement);
-    return GlyphData(fontElement->missingGlyph(), &primaryFont);
+    auto missingGlyph = fontElement->missingGlyph();
+    return { missingGlyph, primaryFont.computeWidthForGlyph(missingGlyph), &primaryFont };
 }
 
 GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const FontCascade& font, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength, String& normalizedSpacesStringCache)
index 5289403..921b0ee 100644 (file)
@@ -79,7 +79,7 @@ void SVGFontData::initializeFont(Font* font, float fontSize)
     if (!xHeight && glyphPageZero) {
         // Fallback if x_heightAttr is not specified for the font element.
         Glyph letterXGlyph = glyphPageZero->glyphDataForCharacter('x').glyph;
-        xHeight = letterXGlyph ? font->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
+        xHeight = letterXGlyph ? font->computeWidthForGlyph(letterXGlyph) : 2 * ascent / 3;
     }
 
     FontMetrics& fontMetrics = font->fontMetrics();
@@ -99,17 +99,17 @@ void SVGFontData::initializeFont(Font* font, float fontSize)
     }
 
     // Calculate space width.
-    Glyph spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
-    font->setSpaceGlyph(spaceGlyph);
-    font->setSpaceWidths(font->widthForGlyph(spaceGlyph));
+    auto spaceGlyphData = glyphPageZero->glyphDataForCharacter(' ');
+    font->setSpaceGlyph(spaceGlyphData.glyph);
+    font->setSpaceWidths(spaceGlyphData.width);
 
     // Estimate average character width.
-    Glyph numeralZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
-    font->setAvgCharWidth(numeralZeroGlyph ? font->widthForGlyph(numeralZeroGlyph) : font->spaceWidth());
+    auto numeralZeroGlyphData = glyphPageZero->glyphDataForCharacter('0');
+    font->setAvgCharWidth(numeralZeroGlyphData.glyph ? numeralZeroGlyphData.width : font->spaceWidth());
 
     // Estimate maximum character width.
-    Glyph letterWGlyph = glyphPageZero->glyphDataForCharacter('W').glyph;
-    font->setMaxCharWidth(letterWGlyph ? font->widthForGlyph(letterWGlyph) : ascent);
+    auto letterWGlyphData = glyphPageZero->glyphDataForCharacter('W');
+    font->setMaxCharWidth(letterWGlyphData.glyph ? letterWGlyphData.width : ascent);
 }
 
 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
@@ -177,6 +177,7 @@ bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& gly
             SVGGlyph& svgGlyph = glyphs[0];
             iterator.setLastGlyphName(svgGlyph.glyphName);
             glyphData.glyph = svgGlyph.tableEntry;
+            glyphData.width = glyphData.font->computeWidthForGlyph(glyphData.glyph);
             advanceLength = svgGlyph.unicodeStringLength;
             return true;
         }
@@ -200,6 +201,7 @@ bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& gly
             continue;
         iterator.setLastGlyphName(svgGlyph.glyphName);
         glyphData.glyph = svgGlyph.tableEntry;
+        glyphData.width = glyphData.font->computeWidthForGlyph(glyphData.glyph);
         advanceLength = svgGlyph.unicodeStringLength;
         return true;
     }