Title: [143125] trunk/Source/WebCore
Revision
143125
Author
[email protected]
Date
2013-02-17 00:17:42 -0800 (Sun, 17 Feb 2013)

Log 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().

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (143124 => 143125)


--- trunk/Source/WebCore/ChangeLog	2013-02-17 06:01:39 UTC (rev 143124)
+++ trunk/Source/WebCore/ChangeLog	2013-02-17 08:17:42 UTC (rev 143125)
@@ -1,3 +1,59 @@
+2013-02-17  Andreas Kling  <[email protected]>
+
+        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().
+
 2013-02-16  Andreas Kling  <[email protected]>
 
         Remove multi-threading gunk from WebKit2's PluginInfoStore.

Modified: trunk/Source/WebCore/platform/graphics/GlyphPage.h (143124 => 143125)


--- trunk/Source/WebCore/platform/graphics/GlyphPage.h	2013-02-17 06:01:39 UTC (rev 143124)
+++ trunk/Source/WebCore/platform/graphics/GlyphPage.h	2013-02-17 08:17:42 UTC (rev 143125)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 #include "Glyph.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
 #include <wtf/unicode/Unicode.h>
 
 namespace WebCore {
@@ -62,24 +63,51 @@
 // to be overriding the parent's node, but provide no additional information.
 class GlyphPage : public RefCounted<GlyphPage> {
 public:
-    static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner)
+    static PassRefPtr<GlyphPage> createUninitialized(GlyphPageTreeNode* owner)
     {
-        return adoptRef(new GlyphPage(owner));
+        return adoptRef(new GlyphPage(owner, false));
     }
 
+    static PassRefPtr<GlyphPage> createZeroedSystemFallbackPage(GlyphPageTreeNode* owner)
+    {
+        return adoptRef(new GlyphPage(owner, true));
+    }
+
+    PassRefPtr<GlyphPage> createCopiedSystemFallbackPage(GlyphPageTreeNode* owner) const
+    {
+        RefPtr<GlyphPage> page = GlyphPage::createUninitialized(owner);
+        memcpy(page->m_glyphs, m_glyphs, sizeof(m_glyphs));
+        page->m_fontDataForAllGlyphs = m_fontDataForAllGlyphs;
+        if (m_perGlyphFontData) {
+            page->m_perGlyphFontData = static_cast<const SimpleFontData**>(fastMalloc(size * sizeof(SimpleFontData*)));
+            memcpy(page->m_perGlyphFontData, m_perGlyphFontData, size * sizeof(SimpleFontData*));
+        }
+        return page.release();
+    }
+
+    ~GlyphPage()
+    {
+        if (m_perGlyphFontData)
+            fastFree(m_perGlyphFontData);
+    }
+
     static const size_t size = 256; // Covers Latin-1 in a single page.
 
     unsigned indexForCharacter(UChar32 c) const { return c % size; }
     GlyphData glyphDataForCharacter(UChar32 c) const
     {
-        unsigned index = indexForCharacter(c);
-        return GlyphData(m_glyphs[index], m_glyphFontData[index]);
+        return glyphDataForIndex(indexForCharacter(c));
     }
 
     GlyphData glyphDataForIndex(unsigned index) const
     {
         ASSERT_WITH_SECURITY_IMPLICATION(index < size);
-        return GlyphData(m_glyphs[index], m_glyphFontData[index]);
+        Glyph glyph = m_glyphs[index];
+        if (!glyph)
+            return GlyphData(0, 0);
+        if (m_perGlyphFontData)
+            return GlyphData(glyph, m_perGlyphFontData[index]);
+        return GlyphData(glyph, m_fontDataForAllGlyphs);
     }
 
     Glyph glyphAt(unsigned index) const
@@ -90,7 +118,7 @@
 
     const SimpleFontData* fontDataForCharacter(UChar32 c) const
     {
-        return m_glyphFontData[indexForCharacter(c)];
+        return glyphDataForIndex(indexForCharacter(c)).fontData;
     }
 
     void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f)
@@ -98,36 +126,55 @@
         setGlyphDataForIndex(indexForCharacter(c), g, f);
     }
 
-    void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f)
+    void setGlyphDataForIndex(unsigned index, Glyph glyph, const SimpleFontData* fontData)
     {
         ASSERT_WITH_SECURITY_IMPLICATION(index < size);
-        m_glyphs[index] = g;
-        m_glyphFontData[index] = f;
+        m_glyphs[index] = glyph;
+
+        // GlyphPage getters will always return a null SimpleFontData* for glyph #0, so don't worry about the pointer for them.
+        if (!glyph)
+            return;
+
+        // A glyph index without a font data pointer makes no sense.
+        ASSERT(fontData);
+
+        if (m_perGlyphFontData) {
+            m_perGlyphFontData[index] = fontData;
+            return;
+        }
+
+        if (!m_fontDataForAllGlyphs)
+            m_fontDataForAllGlyphs = fontData;
+
+        if (m_fontDataForAllGlyphs == fontData)
+            return;
+
+        // This GlyphPage houses glyphs from multiple fonts, transition to an array of SimpleFontData pointers.
+        const SimpleFontData* oldFontData = m_fontDataForAllGlyphs;
+        m_perGlyphFontData = static_cast<const SimpleFontData**>(fastMalloc(size * sizeof(SimpleFontData*)));
+        for (unsigned i = 0; i < size; ++i)
+            m_perGlyphFontData[i] = oldFontData;
+        m_perGlyphFontData[index] = fontData;
     }
 
     void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData)
     {
         setGlyphDataForIndex(index, glyphData.glyph, glyphData.fontData);
     }
-    
-    void copyFrom(const GlyphPage& other)
-    {
-        memcpy(m_glyphs, other.m_glyphs, sizeof(m_glyphs));
-        memcpy(m_glyphFontData, other.m_glyphFontData, sizeof(m_glyphFontData));
-    }
 
-    void clear()
-    {
-        memset(m_glyphs, 0, sizeof(m_glyphs));
-        memset(m_glyphFontData, 0, sizeof(m_glyphFontData));
-    }
-
     void clearForFontData(const SimpleFontData* fontData)
     {
+        if (!m_perGlyphFontData) {
+            if (m_fontDataForAllGlyphs == fontData) {
+                memset(m_glyphs, 0, sizeof(m_glyphs));
+                m_fontDataForAllGlyphs = 0;
+            }
+            return;
+        }
         for (size_t i = 0; i < size; ++i) {
-            if (m_glyphFontData[i] == fontData) {
+            if (m_perGlyphFontData[i] == fontData) {
                 m_glyphs[i] = 0;
-                m_glyphFontData[i] = 0;
+                m_perGlyphFontData[i] = 0;
             }
         }
     }
@@ -138,18 +185,22 @@
     bool fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData*);
 
 private:
-    GlyphPage(GlyphPageTreeNode* owner)
-        : m_owner(owner)
+    GlyphPage(GlyphPageTreeNode* owner, bool clearGlyphs)
+        : m_fontDataForAllGlyphs(0)
+        , m_perGlyphFontData(0)
+        , m_owner(owner)
     {
+        if (clearGlyphs)
+            memset(m_glyphs, 0, sizeof(m_glyphs));
     }
 
-    // Separate arrays, rather than array of GlyphData, to save space.
-    Glyph m_glyphs[size];
-    const SimpleFontData* m_glyphFontData[size];
+    const SimpleFontData* m_fontDataForAllGlyphs;
+    const SimpleFontData** m_perGlyphFontData;
 
     GlyphPageTreeNode* m_owner;
+    Glyph m_glyphs[size];
 };
 
 } // namespace WebCore
 
-#endif // GlyphPageTreeNode_h
+#endif // GlyphPage_h

Modified: trunk/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp (143124 => 143125)


--- trunk/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp	2013-02-17 06:01:39 UTC (rev 143124)
+++ trunk/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp	2013-02-17 08:17:42 UTC (rev 143125)
@@ -200,9 +200,9 @@
                     buffer[i * 2 + 1] = U16_TRAIL(c);
                 }
             }
-            
-            m_page = GlyphPage::create(this);
 
+            m_page = GlyphPage::createUninitialized(this);
+
             // Now that we have a buffer full of characters, we want to get back an array
             // of glyph indices.  This part involves calling into the platform-specific 
             // routine of our glyph map for actually filling in the page with the glyphs.
@@ -225,7 +225,7 @@
                     int to = 1 + min(static_cast<int>(range.to()) - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1);
                     if (from < static_cast<int>(GlyphPage::size) && to > 0) {
                         if (haveGlyphs && !scratchPage) {
-                            scratchPage = GlyphPage::create(this);
+                            scratchPage = GlyphPage::createUninitialized(this);
                             pageToFill = scratchPage.get();
                         }
 
@@ -279,7 +279,7 @@
                 m_page = parentPage;
             } else {
                 // Combine the parent's glyphs and ours to form a new more complete page.
-                m_page = GlyphPage::create(this);
+                m_page = GlyphPage::createUninitialized(this);
 
                 // Overlay the parent page on the fallback page. Check if the fallback font
                 // has added anything.
@@ -300,15 +300,14 @@
             }
         }
     } else {
-        m_page = GlyphPage::create(this);
         // System fallback. Initialized with the parent's page here, as individual
         // entries may use different fonts depending on character. If the Font
         // ever finds it needs a glyph out of the system fallback page, it will
         // ask the system for the best font to use and fill that glyph in for us.
         if (parentPage)
-            m_page->copyFrom(*parentPage);
+            m_page = parentPage->createCopiedSystemFallbackPage(this);
         else
-            m_page->clear();
+            m_page = GlyphPage::createZeroedSystemFallbackPage(this);
     }
 }
 

Modified: trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp (143124 => 143125)


--- trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp	2013-02-17 06:01:39 UTC (rev 143124)
+++ trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp	2013-02-17 08:17:42 UTC (rev 143125)
@@ -230,7 +230,7 @@
     // No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.)
     // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily
     // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly.
-    page->setGlyphDataForCharacter(character, glyphData.glyph, 0);
+    page->setGlyphDataForCharacter(character, 0, 0);
 
     // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before.
     GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to