Changeset 143125 in webkit


Ignore:
Timestamp:
Feb 17, 2013 12:17:42 AM (11 years ago)
Author:
akling@apple.com
Message:

Optimize GlyphPage for case where all glyphs are available in the same font.
<http://webkit.org/b/108835>
<rdar://problem/13157042>

Reviewed by Antti Koivisto.

Let GlyphPage begin optimistically assuming that all its glyphs will be represented in
the same SimpleFontData*. In this (very common) case, only keep a single SimpleFontData*.

If glyphs from multiple fonts are mixed in one page, an array of per-glyph SimpleFontData*
is allocated transparently.

This was landed before with some bogus branch prediction hints and didn't fare well on
page cyclers (intl2 specifically.) These have been removed this time around, and will
hopefully be regression-free.

4.98 MB progression on Membuster3.

  • platform/graphics/GlyphPageTreeNode.cpp:

(WebCore::GlyphPageTreeNode::initializePage):

  • platform/graphics/GlyphPage.h:

(WebCore::GlyphPage::createUninitialized):
(WebCore::GlyphPage::createZeroedSystemFallbackPage):
(WebCore::GlyphPage::createCopiedSystemFallbackPage):

There are now three ways of constructing a GlyphPage, two of them are only used for
creating system fallback pages.

(WebCore::GlyphPage::setGlyphDataForIndex):

Hold off creating a SimpleFontData* array until we're sure there are two different
SimpleFontData* backing the glyphs in this page.
We don't store font data for glyph #0, instead we let the getters always return null for it.

(WebCore::GlyphPage::~GlyphPage):

Free the SimpleFontData* array if needed.

(WebCore::GlyphPage::glyphDataForCharacter):
(WebCore::GlyphPage::glyphDataForIndex):
(WebCore::GlyphPage::fontDataForCharacter):

The font data for glyph #0 is always a null pointer now.

(WebCore::GlyphPage::clearForFontData):

Updated for new storage format.

  • rendering/svg/SVGTextRunRenderingContext.cpp:

(WebCore::SVGTextRunRenderingContext::glyphDataForCharacter):

Fix bug where non-zero glyph was temporarily associated with null font data,
which triggered the new assertion in setGlyphDataForIndex().

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r143124 r143125  
     12013-02-17  Andreas Kling  <akling@apple.com>
     2
     3        Optimize GlyphPage for case where all glyphs are available in the same font.
     4        <http://webkit.org/b/108835>
     5        <rdar://problem/13157042>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Let GlyphPage begin optimistically assuming that all its glyphs will be represented in
     10        the same SimpleFontData*. In this (very common) case, only keep a single SimpleFontData*.
     11
     12        If glyphs from multiple fonts are mixed in one page, an array of per-glyph SimpleFontData*
     13        is allocated transparently.
     14
     15        This was landed before with some bogus branch prediction hints and didn't fare well on
     16        page cyclers (intl2 specifically.) These have been removed this time around, and will
     17        hopefully be regression-free.
     18
     19        4.98 MB progression on Membuster3.
     20
     21        * platform/graphics/GlyphPageTreeNode.cpp:
     22        (WebCore::GlyphPageTreeNode::initializePage):
     23        * platform/graphics/GlyphPage.h:
     24        (WebCore::GlyphPage::createUninitialized):
     25        (WebCore::GlyphPage::createZeroedSystemFallbackPage):
     26        (WebCore::GlyphPage::createCopiedSystemFallbackPage):
     27
     28            There are now three ways of constructing a GlyphPage, two of them are only used for
     29            creating system fallback pages.
     30
     31        (WebCore::GlyphPage::setGlyphDataForIndex):
     32
     33            Hold off creating a SimpleFontData* array until we're sure there are two different
     34            SimpleFontData* backing the glyphs in this page.
     35            We don't store font data for glyph #0, instead we let the getters always return null for it.
     36
     37        (WebCore::GlyphPage::~GlyphPage):
     38
     39            Free the SimpleFontData* array if needed.
     40
     41        (WebCore::GlyphPage::glyphDataForCharacter):
     42        (WebCore::GlyphPage::glyphDataForIndex):
     43        (WebCore::GlyphPage::fontDataForCharacter):
     44
     45            The font data for glyph #0 is always a null pointer now.
     46
     47        (WebCore::GlyphPage::clearForFontData):
     48
     49            Updated for new storage format.
     50
     51        * rendering/svg/SVGTextRunRenderingContext.cpp:
     52        (WebCore::SVGTextRunRenderingContext::glyphDataForCharacter):
     53
     54            Fix bug where non-zero glyph was temporarily associated with null font data,
     55            which triggered the new assertion in setGlyphDataForIndex().
     56
    1572013-02-16  Andreas Kling  <akling@apple.com>
    258
  • trunk/Source/WebCore/platform/graphics/GlyphPage.h

    r142897 r143125  
    11/*
    2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
    33 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
    44 *
     
    3434#include <wtf/PassRefPtr.h>
    3535#include <wtf/RefCounted.h>
     36#include <wtf/RefPtr.h>
    3637#include <wtf/unicode/Unicode.h>
    3738
     
    6364class GlyphPage : public RefCounted<GlyphPage> {
    6465public:
    65     static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner)
    66     {
    67         return adoptRef(new GlyphPage(owner));
     66    static PassRefPtr<GlyphPage> createUninitialized(GlyphPageTreeNode* owner)
     67    {
     68        return adoptRef(new GlyphPage(owner, false));
     69    }
     70
     71    static PassRefPtr<GlyphPage> createZeroedSystemFallbackPage(GlyphPageTreeNode* owner)
     72    {
     73        return adoptRef(new GlyphPage(owner, true));
     74    }
     75
     76    PassRefPtr<GlyphPage> createCopiedSystemFallbackPage(GlyphPageTreeNode* owner) const
     77    {
     78        RefPtr<GlyphPage> page = GlyphPage::createUninitialized(owner);
     79        memcpy(page->m_glyphs, m_glyphs, sizeof(m_glyphs));
     80        page->m_fontDataForAllGlyphs = m_fontDataForAllGlyphs;
     81        if (m_perGlyphFontData) {
     82            page->m_perGlyphFontData = static_cast<const SimpleFontData**>(fastMalloc(size * sizeof(SimpleFontData*)));
     83            memcpy(page->m_perGlyphFontData, m_perGlyphFontData, size * sizeof(SimpleFontData*));
     84        }
     85        return page.release();
     86    }
     87
     88    ~GlyphPage()
     89    {
     90        if (m_perGlyphFontData)
     91            fastFree(m_perGlyphFontData);
    6892    }
    6993
     
    7397    GlyphData glyphDataForCharacter(UChar32 c) const
    7498    {
    75         unsigned index = indexForCharacter(c);
    76         return GlyphData(m_glyphs[index], m_glyphFontData[index]);
     99        return glyphDataForIndex(indexForCharacter(c));
    77100    }
    78101
     
    80103    {
    81104        ASSERT_WITH_SECURITY_IMPLICATION(index < size);
    82         return GlyphData(m_glyphs[index], m_glyphFontData[index]);
     105        Glyph glyph = m_glyphs[index];
     106        if (!glyph)
     107            return GlyphData(0, 0);
     108        if (m_perGlyphFontData)
     109            return GlyphData(glyph, m_perGlyphFontData[index]);
     110        return GlyphData(glyph, m_fontDataForAllGlyphs);
    83111    }
    84112
     
    91119    const SimpleFontData* fontDataForCharacter(UChar32 c) const
    92120    {
    93         return m_glyphFontData[indexForCharacter(c)];
     121        return glyphDataForIndex(indexForCharacter(c)).fontData;
    94122    }
    95123
     
    99127    }
    100128
    101     void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f)
     129    void setGlyphDataForIndex(unsigned index, Glyph glyph, const SimpleFontData* fontData)
    102130    {
    103131        ASSERT_WITH_SECURITY_IMPLICATION(index < size);
    104         m_glyphs[index] = g;
    105         m_glyphFontData[index] = f;
     132        m_glyphs[index] = glyph;
     133
     134        // GlyphPage getters will always return a null SimpleFontData* for glyph #0, so don't worry about the pointer for them.
     135        if (!glyph)
     136            return;
     137
     138        // A glyph index without a font data pointer makes no sense.
     139        ASSERT(fontData);
     140
     141        if (m_perGlyphFontData) {
     142            m_perGlyphFontData[index] = fontData;
     143            return;
     144        }
     145
     146        if (!m_fontDataForAllGlyphs)
     147            m_fontDataForAllGlyphs = fontData;
     148
     149        if (m_fontDataForAllGlyphs == fontData)
     150            return;
     151
     152        // This GlyphPage houses glyphs from multiple fonts, transition to an array of SimpleFontData pointers.
     153        const SimpleFontData* oldFontData = m_fontDataForAllGlyphs;
     154        m_perGlyphFontData = static_cast<const SimpleFontData**>(fastMalloc(size * sizeof(SimpleFontData*)));
     155        for (unsigned i = 0; i < size; ++i)
     156            m_perGlyphFontData[i] = oldFontData;
     157        m_perGlyphFontData[index] = fontData;
    106158    }
    107159
     
    110162        setGlyphDataForIndex(index, glyphData.glyph, glyphData.fontData);
    111163    }
    112    
    113     void copyFrom(const GlyphPage& other)
    114     {
    115         memcpy(m_glyphs, other.m_glyphs, sizeof(m_glyphs));
    116         memcpy(m_glyphFontData, other.m_glyphFontData, sizeof(m_glyphFontData));
    117     }
    118 
    119     void clear()
    120     {
    121         memset(m_glyphs, 0, sizeof(m_glyphs));
    122         memset(m_glyphFontData, 0, sizeof(m_glyphFontData));
    123     }
    124164
    125165    void clearForFontData(const SimpleFontData* fontData)
    126166    {
     167        if (!m_perGlyphFontData) {
     168            if (m_fontDataForAllGlyphs == fontData) {
     169                memset(m_glyphs, 0, sizeof(m_glyphs));
     170                m_fontDataForAllGlyphs = 0;
     171            }
     172            return;
     173        }
    127174        for (size_t i = 0; i < size; ++i) {
    128             if (m_glyphFontData[i] == fontData) {
     175            if (m_perGlyphFontData[i] == fontData) {
    129176                m_glyphs[i] = 0;
    130                 m_glyphFontData[i] = 0;
     177                m_perGlyphFontData[i] = 0;
    131178            }
    132179        }
     
    139186
    140187private:
    141     GlyphPage(GlyphPageTreeNode* owner)
    142         : m_owner(owner)
    143     {
    144     }
    145 
    146     // Separate arrays, rather than array of GlyphData, to save space.
     188    GlyphPage(GlyphPageTreeNode* owner, bool clearGlyphs)
     189        : m_fontDataForAllGlyphs(0)
     190        , m_perGlyphFontData(0)
     191        , m_owner(owner)
     192    {
     193        if (clearGlyphs)
     194            memset(m_glyphs, 0, sizeof(m_glyphs));
     195    }
     196
     197    const SimpleFontData* m_fontDataForAllGlyphs;
     198    const SimpleFontData** m_perGlyphFontData;
     199
     200    GlyphPageTreeNode* m_owner;
    147201    Glyph m_glyphs[size];
    148     const SimpleFontData* m_glyphFontData[size];
    149 
    150     GlyphPageTreeNode* m_owner;
    151202};
    152203
    153204} // namespace WebCore
    154205
    155 #endif // GlyphPageTreeNode_h
     206#endif // GlyphPage_h
  • trunk/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp

    r142897 r143125  
    201201                }
    202202            }
    203            
    204             m_page = GlyphPage::create(this);
     203
     204            m_page = GlyphPage::createUninitialized(this);
    205205
    206206            // Now that we have a buffer full of characters, we want to get back an array
     
    226226                    if (from < static_cast<int>(GlyphPage::size) && to > 0) {
    227227                        if (haveGlyphs && !scratchPage) {
    228                             scratchPage = GlyphPage::create(this);
     228                            scratchPage = GlyphPage::createUninitialized(this);
    229229                            pageToFill = scratchPage.get();
    230230                        }
     
    280280            } else {
    281281                // Combine the parent's glyphs and ours to form a new more complete page.
    282                 m_page = GlyphPage::create(this);
     282                m_page = GlyphPage::createUninitialized(this);
    283283
    284284                // Overlay the parent page on the fallback page. Check if the fallback font
     
    301301        }
    302302    } else {
    303         m_page = GlyphPage::create(this);
    304303        // System fallback. Initialized with the parent's page here, as individual
    305304        // entries may use different fonts depending on character. If the Font
     
    307306        // ask the system for the best font to use and fill that glyph in for us.
    308307        if (parentPage)
    309             m_page->copyFrom(*parentPage);
     308            m_page = parentPage->createCopiedSystemFallbackPage(this);
    310309        else
    311             m_page->clear();
     310            m_page = GlyphPage::createZeroedSystemFallbackPage(this);
    312311    }
    313312}
  • trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp

    r142897 r143125  
    231231    // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily
    232232    // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly.
    233     page->setGlyphDataForCharacter(character, glyphData.glyph, 0);
     233    page->setGlyphDataForCharacter(character, 0, 0);
    234234
    235235    // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before.
Note: See TracChangeset for help on using the changeset viewer.