[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

xji at chromium.org xji at chromium.org
Wed Dec 22 14:43:26 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 05bcd8cba0035f9a72860a79cc6e295f1147c64a
Author: xji at chromium.org <xji at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Oct 18 17:41:19 2010 +0000

    2010-10-18  Xiaomei Ji  <xji at chromium.org>
    
            Reviewed by David Levin.
    
            Code cleanup: Move most function members in TextRunWorker from inlined.
            https://bugs.webkit.org/show_bug.cgi?id=47732
    
            No functionality change, so no tests added.
    
            * platform/graphics/chromium/FontLinux.cpp:
            (WebCore::TextRunWalker::setWordSpacingAdjustment):
            (WebCore::TextRunWalker::setLetterSpacingAdjustment):
            (WebCore::TextRunWalker::setXOffsetToZero):
            (WebCore::TextRunWalker::rtl):
            (WebCore::TextRunWalker::glyphs):
            (WebCore::TextRunWalker::length):
            (WebCore::TextRunWalker::xPositions):
            (WebCore::TextRunWalker::advances):
            (WebCore::TextRunWalker::width):
            (WebCore::TextRunWalker::logClusters):
            (WebCore::TextRunWalker::numCodePoints):
            (WebCore::TextRunWalker::fontPlatformDataForScriptRun):
            (WebCore::TextRunWalker::isCodepointSpace):
            (WebCore::TextRunWalker::TextRunWalker):
            (WebCore::TextRunWalker::~TextRunWalker):
            (WebCore::TextRunWalker::isWordBreak):
            (WebCore::TextRunWalker::setPadding):
            (WebCore::TextRunWalker::reset):
            (WebCore::TextRunWalker::setBackwardsIteration):
            (WebCore::TextRunWalker::nextScriptRun):
            (WebCore::TextRunWalker::widthOfFullRun):
            (WebCore::TextRunWalker::getTextRun):
            (WebCore::TextRunWalker::getNormalizedTextRun):
            (WebCore::TextRunWalker::setupFontForScriptRun):
            (WebCore::TextRunWalker::allocHarfbuzzFont):
            (WebCore::TextRunWalker::deleteGlyphArrays):
            (WebCore::TextRunWalker::createGlyphArrays):
            (WebCore::TextRunWalker::resetGlyphArrays):
            (WebCore::TextRunWalker::shapeGlyphs):
            (WebCore::TextRunWalker::setGlyphXPositions):
            (WebCore::TextRunWalker::mirrorCharacters):
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@69972 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 0be8479..04a974e 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,45 @@
+2010-10-18  Xiaomei Ji  <xji at chromium.org>
+
+        Reviewed by David Levin.
+
+        Code cleanup: Move most function members in TextRunWorker from inlined.
+        https://bugs.webkit.org/show_bug.cgi?id=47732
+
+        No functionality change, so no tests added.
+
+        * platform/graphics/chromium/FontLinux.cpp:
+        (WebCore::TextRunWalker::setWordSpacingAdjustment):
+        (WebCore::TextRunWalker::setLetterSpacingAdjustment):
+        (WebCore::TextRunWalker::setXOffsetToZero):
+        (WebCore::TextRunWalker::rtl):
+        (WebCore::TextRunWalker::glyphs):
+        (WebCore::TextRunWalker::length):
+        (WebCore::TextRunWalker::xPositions):
+        (WebCore::TextRunWalker::advances):
+        (WebCore::TextRunWalker::width):
+        (WebCore::TextRunWalker::logClusters):
+        (WebCore::TextRunWalker::numCodePoints):
+        (WebCore::TextRunWalker::fontPlatformDataForScriptRun):
+        (WebCore::TextRunWalker::isCodepointSpace):
+        (WebCore::TextRunWalker::TextRunWalker):
+        (WebCore::TextRunWalker::~TextRunWalker):
+        (WebCore::TextRunWalker::isWordBreak):
+        (WebCore::TextRunWalker::setPadding):
+        (WebCore::TextRunWalker::reset):
+        (WebCore::TextRunWalker::setBackwardsIteration):
+        (WebCore::TextRunWalker::nextScriptRun):
+        (WebCore::TextRunWalker::widthOfFullRun):
+        (WebCore::TextRunWalker::getTextRun):
+        (WebCore::TextRunWalker::getNormalizedTextRun):
+        (WebCore::TextRunWalker::setupFontForScriptRun):
+        (WebCore::TextRunWalker::allocHarfbuzzFont):
+        (WebCore::TextRunWalker::deleteGlyphArrays):
+        (WebCore::TextRunWalker::createGlyphArrays):
+        (WebCore::TextRunWalker::resetGlyphArrays):
+        (WebCore::TextRunWalker::shapeGlyphs):
+        (WebCore::TextRunWalker::setGlyphXPositions):
+        (WebCore::TextRunWalker::mirrorCharacters):
+
 2010-10-18  No'am Rosenthal  <noam.rosenthal at nokia.com>
 
         Reviewed by Andreas Kling.
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index 4d984c4..f38273c 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -161,62 +161,23 @@ static int truncateFixedPointToInteger(HB_Fixed value)
 // can call |reset| to start over again.
 class TextRunWalker {
 public:
-    TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
-        : m_font(font)
-        , m_startingX(startingX)
-        , m_offsetX(m_startingX)
-        , m_run(getTextRun(run))
-        , m_iterateBackwards(m_run.rtl())
-        , m_wordSpacingAdjustment(0)
-        , m_padding(0)
-        , m_padError(0)
-    {
-        // Do not use |run| inside this constructor. Use |m_run| instead.
-
-        memset(&m_item, 0, sizeof(m_item));
-        // We cannot know, ahead of time, how many glyphs a given script run
-        // will produce. We take a guess that script runs will not produce more
-        // than twice as many glyphs as there are code points plus a bit of
-        // padding and fallback if we find that we are wrong.
-        createGlyphArrays((m_run.length() + 2) * 2);
-
-        m_item.log_clusters = new unsigned short[m_run.length()];
-
-        m_item.face = 0;
-        m_item.font = allocHarfbuzzFont();
-
-        m_item.item.bidiLevel = m_run.rtl();
-
-        int length = m_run.length();
-        m_item.stringLength = length;
-
-        if (!m_item.item.bidiLevel)
-            m_item.string = m_run.characters();
-        else {
-            // Assume mirrored character is in the same Unicode multilingual plane as the original one.
-            UChar* string = new UChar[length];
-            mirrorCharacters(string, m_run.characters(), length);
-            m_item.string = string;
-        }
-
-        reset();
-    }
+    TextRunWalker(const TextRun&, unsigned, const Font*);
+    ~TextRunWalker();
 
-    ~TextRunWalker()
-    {
-        fastFree(m_item.font);
-        deleteGlyphArrays();
-        delete[] m_item.log_clusters;
-        if (m_item.item.bidiLevel)
-            delete[] m_item.string;
-    }
+    bool isWordBreak(unsigned, bool);
+    // setPadding sets a number of pixels to be distributed across the TextRun.
+    // WebKit uses this to justify text.
+    void setPadding(int);
+    void reset();
+    void setBackwardsIteration(bool);
+    // Advance to the next script run, returning false when the end of the
+    // TextRun has been reached.
+    bool nextScriptRun();
+    float widthOfFullRun();
 
     // setWordSpacingAdjustment sets a delta (in pixels) which is applied at
     // each word break in the TextRun.
-    void setWordSpacingAdjustment(int wordSpacingAdjustment)
-    {
-        m_wordSpacingAdjustment = wordSpacingAdjustment;
-    }
+    void setWordSpacingAdjustment(int wordSpacingAdjustment) { m_wordSpacingAdjustment = wordSpacingAdjustment; }
 
     // setLetterSpacingAdjustment sets an additional number of pixels that is
     // added to the advance after each output cluster. This matches the behaviour
@@ -224,408 +185,431 @@ public:
     //
     // (NOTE: currently does nothing because I don't know how to get the
     // cluster information from Harfbuzz.)
-    void setLetterSpacingAdjustment(int letterSpacingAdjustment)
-    {
-        m_letterSpacing = letterSpacingAdjustment;
-    }
-
-    bool isWordBreak(unsigned i, bool isRTL)
-    {
-        if (!isRTL)
-            return i && isCodepointSpace(m_item.string[i]) && !isCodepointSpace(m_item.string[i - 1]);
-        return i != m_item.stringLength - 1 && isCodepointSpace(m_item.string[i]) && !isCodepointSpace(m_item.string[i + 1]);
-    }
-
-    // setPadding sets a number of pixels to be distributed across the TextRun.
-    // WebKit uses this to justify text.
-    void setPadding(int padding)
-    {
-        m_padding = padding;
-        if (!m_padding)
-            return;
-
-        // If we have padding to distribute, then we try to give an equal
-        // amount to each space. The last space gets the smaller amount, if
-        // any.
-        unsigned numWordBreaks = 0;
-        bool isRTL = m_iterateBackwards;
-
-        for (unsigned i = 0; i < m_item.stringLength; i++) {
-            if (isWordBreak(i, isRTL))
-                numWordBreaks++;
-        }
-
-        if (numWordBreaks)
-            m_padPerWordBreak = m_padding / numWordBreaks;
-        else
-            m_padPerWordBreak = 0;
-    }
-
-    void reset()
-    {
-        if (m_iterateBackwards)
-            m_indexOfNextScriptRun = m_run.length() - 1;
-        else
-            m_indexOfNextScriptRun = 0;
-        m_offsetX = m_startingX;
-    }
+    void setLetterSpacingAdjustment(int letterSpacingAdjustment) { m_letterSpacing = letterSpacingAdjustment; }
 
     // Set the x offset for the next script run. This affects the values in
     // |xPositions|
-    void setXOffsetToZero()
-    {
-        m_offsetX = 0;
-    }
-
-    bool rtl() const
-    {
-        return m_run.rtl();
-    }
-
-    void setBackwardsIteration(bool isBackwards)
-    {
-        m_iterateBackwards = isBackwards;
-        reset();
-    }
-
-    // Advance to the next script run, returning false when the end of the
-    // TextRun has been reached.
-    bool nextScriptRun()
-    {
-        if (m_iterateBackwards) {
-            // In right-to-left mode we need to render the shaped glyph backwards and
-            // also render the script runs themselves backwards. So given a TextRun:
-            //    AAAAAAACTTTTTTT   (A = Arabic, C = Common, T = Thai)
-            // we render:
-            //    TTTTTTCAAAAAAA
-            // (and the glyphs in each A, C and T section are backwards too)
-            if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
-                return false;
-        } else {
-            if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
-                return false;
-
-            // It is actually wrong to consider script runs at all in this code.
-            // Other WebKit code (e.g. Mac) segments complex text just by finding
-            // the longest span of text covered by a single font.
-            // But we currently need to call hb_utf16_script_run_next anyway to fill
-            // in the harfbuzz data structures to e.g. pick the correct script's shaper.
-            // So we allow that to run first, then do a second pass over the range it
-            // found and take the largest subregion that stays within a single font.
-            const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
-            unsigned endOfRun;
-            for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
-                const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData;
-                if (nextGlyphData != glyphData)
-                    break;
-            }
-            m_item.item.length = endOfRun;
-            m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
-        }
-
-        setupFontForScriptRun();
-        shapeGlyphs();
-        setGlyphXPositions(rtl());
-
-        return true;
-    }
-
-    const uint16_t* glyphs() const
-    {
-        return m_glyphs16;
-    }
+    void setXOffsetToZero() { m_offsetX = 0; }
+    bool rtl() const { return m_run.rtl(); }
+    const uint16_t* glyphs() const { return m_glyphs16; }
 
     // Return the length of the array returned by |glyphs|
-    const unsigned length() const
-    {
-        return m_item.num_glyphs;
-    }
+    const unsigned length() const { return m_item.num_glyphs; }
 
     // Return the x offset for each of the glyphs. Note that this is translated
     // by the current x offset and that the x offset is updated for each script
     // run.
-    const SkScalar* xPositions() const
-    {
-        return m_xPositions;
-    }
+    const SkScalar* xPositions() const { return m_xPositions; }
 
     // Get the advances (widths) for each glyph.
-    const HB_Fixed* advances() const
-    {
-        return m_item.advances;
-    }
+    const HB_Fixed* advances() const { return m_item.advances; }
 
     // Return the width (in px) of the current script run.
-    const unsigned width() const
-    {
-        return m_pixelWidth;
-    }
+    const unsigned width() const { return m_pixelWidth; }
 
     // Return the cluster log for the current script run. For example:
     //   script run: f i a n c é  (fi gets ligatured)
     //   log clutrs: 0 0 1 2 3 4
     // So, for each input code point, the log tells you which output glyph was
     // generated for it.
-    const unsigned short* logClusters() const
-    {
-        return m_item.log_clusters;
-    }
+    const unsigned short* logClusters() const { return m_item.log_clusters; }
 
     // return the number of code points in the current script run
-    const unsigned numCodePoints() const
-    {
-        return m_numCodePoints;
-    }
+    const unsigned numCodePoints() const { return m_numCodePoints; }
 
-    const FontPlatformData* fontPlatformDataForScriptRun()
-    {
-        return reinterpret_cast<FontPlatformData*>(m_item.font->userData);
-    }
+    const FontPlatformData* fontPlatformDataForScriptRun() { return reinterpret_cast<FontPlatformData*>(m_item.font->userData); }
 
-    float widthOfFullRun()
-    {
-        float widthSum = 0;
-        while (nextScriptRun())
-            widthSum += width();
+private:
+    const TextRun& getTextRun(const TextRun&);
+    const TextRun& getNormalizedTextRun(const TextRun&);
+    void setupFontForScriptRun();
+    HB_FontRec* allocHarfbuzzFont();
+    void deleteGlyphArrays();
+    void createGlyphArrays(int);
+    void resetGlyphArrays();
+    void shapeGlyphs();
+    void setGlyphXPositions(bool);
+    void mirrorCharacters(UChar*, const UChar*, int) const;
+
+    // This matches the logic in RenderBlock::findNextLineBreak
+    static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; }
 
-        return widthSum;
-    }
+    const Font* const m_font;
+    HB_ShaperItem m_item;
+    uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
+    SkScalar* m_xPositions; // A vector of x positions for each glyph.
+    ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
+    const unsigned m_startingX; // Offset in pixels of the first script run.
+    unsigned m_offsetX; // Offset in pixels to the start of the next script run.
+    unsigned m_pixelWidth; // Width (in px) of the current script run.
+    unsigned m_numCodePoints; // Code points in current script run.
+    unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays.
 
-private:
-    const TextRun& getTextRun(const TextRun& originalRun)
-    {
-        // Normalize the text run in two ways:
-        // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
-        // (U+0300..) are used in the run. This conversion is necessary since most OpenType
-        // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
-        // their GSUB tables.
-        //
-        // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
-        // the API returns FALSE (= not normalized) for complex runs that don't require NFC
-        // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
-        // Harfbuzz will do the same thing for us using the GSUB table.
-        // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
-        // for characters like '\n' otherwise.
-        for (int i = 0; i < originalRun.length(); ++i) {
-            UChar ch = originalRun[i];
-            UBlockCode block = ::ublock_getCode(ch);
-            if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' ')) {
-                return getNormalizedTextRun(originalRun);
-            }
-        }
-        return originalRun;
-    }
+    OwnPtr<TextRun> m_normalizedRun;
+    OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run.
+    const TextRun& m_run;
+    bool m_iterateBackwards;
+    int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
+    float m_padding; // pixels to be distributed over the line at word breaks.
+    float m_padPerWordBreak; // pixels to be added to each word break.
+    float m_padError; // |m_padPerWordBreak| might have a fractional component.
+                      // Since we only add a whole number of padding pixels at
+                      // each word break we accumulate error. This is the
+                      // number of pixels that we are behind so far.
+    unsigned m_letterSpacing; // pixels to be added after each glyph.
+};
 
-    const TextRun& getNormalizedTextRun(const TextRun& originalRun)
-    {
-        icu::UnicodeString normalizedString;
-        UErrorCode error = U_ZERO_ERROR;
-        icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error);
-        if (U_FAILURE(error))
-            return originalRun;
-
-        m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]);
-        normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error);
-        ASSERT(U_SUCCESS(error));
-
-        for (int i = 0; i < normalizedString.length(); ++i) {
-            if (Font::treatAsSpace(m_normalizedBuffer[i]))
-                m_normalizedBuffer[i] = ' ';
-        }
 
-        m_normalizedRun.set(new TextRun(originalRun));
-        m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length());
-        return *m_normalizedRun;
-    }
+TextRunWalker::TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
+    : m_font(font)
+    , m_startingX(startingX)
+    , m_offsetX(m_startingX)
+    , m_run(getTextRun(run))
+    , m_iterateBackwards(m_run.rtl())
+    , m_wordSpacingAdjustment(0)
+    , m_padding(0)
+    , m_padError(0)
+{
+    // Do not use |run| inside this constructor. Use |m_run| instead.
 
-    void setupFontForScriptRun()
-    {
-        const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
-        const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData();
-        m_item.face = platformData.harfbuzzFace();
-        void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
-        m_item.font->userData = opaquePlatformData;
-    }
+    memset(&m_item, 0, sizeof(m_item));
+    // We cannot know, ahead of time, how many glyphs a given script run
+    // will produce. We take a guess that script runs will not produce more
+    // than twice as many glyphs as there are code points plus a bit of
+    // padding and fallback if we find that we are wrong.
+    createGlyphArrays((m_run.length() + 2) * 2);
 
-    HB_FontRec* allocHarfbuzzFont()
-    {
-        HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
-        memset(font, 0, sizeof(HB_FontRec));
-        font->klass = &harfbuzzSkiaClass;
-        font->userData = 0;
-        // The values which harfbuzzSkiaClass returns are already scaled to
-        // pixel units, so we just set all these to one to disable further
-        // scaling.
-        font->x_ppem = 1;
-        font->y_ppem = 1;
-        font->x_scale = 1;
-        font->y_scale = 1;
-
-        return font;
-    }
+    m_item.log_clusters = new unsigned short[m_run.length()];
 
-    void deleteGlyphArrays()
-    {
-        delete[] m_item.glyphs;
-        delete[] m_item.attributes;
-        delete[] m_item.advances;
-        delete[] m_item.offsets;
-        delete[] m_glyphs16;
-        delete[] m_xPositions;
-    }
+    m_item.face = 0;
+    m_item.font = allocHarfbuzzFont();
 
-    void createGlyphArrays(int size)
-    {
-        m_item.glyphs = new HB_Glyph[size];
-        m_item.attributes = new HB_GlyphAttributes[size];
-        m_item.advances = new HB_Fixed[size];
-        m_item.offsets = new HB_FixedPoint[size];
+    m_item.item.bidiLevel = m_run.rtl();
 
-        m_glyphs16 = new uint16_t[size];
-        m_xPositions = new SkScalar[size];
+    int length = m_run.length();
+    m_item.stringLength = length;
 
-        m_item.num_glyphs = size;
-        m_glyphsArrayCapacity = size; // Save the GlyphArrays size.
-        resetGlyphArrays();
+    if (!m_item.item.bidiLevel)
+        m_item.string = m_run.characters();
+    else {
+        // Assume mirrored character is in the same Unicode multilingual plane as the original one.
+        UChar* string = new UChar[length];
+        mirrorCharacters(string, m_run.characters(), length);
+        m_item.string = string;
     }
 
-    void resetGlyphArrays()
-    {
-        int size = m_item.num_glyphs;
-        // All the types here don't have pointers. It is safe to reset to
-        // zero unless Harfbuzz breaks the compatibility in the future.
-        memset(m_item.glyphs, 0, size * sizeof(HB_Glyph));
-        memset(m_item.attributes, 0, size * sizeof(HB_GlyphAttributes));
-        memset(m_item.advances, 0, size * sizeof(HB_Fixed));
-        memset(m_item.offsets, 0, size * sizeof(HB_FixedPoint));
-        memset(m_glyphs16, 0, size * sizeof(uint16_t));
-        memset(m_xPositions, 0, size * sizeof(SkScalar));
+    reset();
+}
+
+TextRunWalker::~TextRunWalker()
+{
+    fastFree(m_item.font);
+    deleteGlyphArrays();
+    delete[] m_item.log_clusters;
+    if (m_item.item.bidiLevel)
+        delete[] m_item.string;
+}
+
+bool TextRunWalker::isWordBreak(unsigned index, bool isRTL)
+{
+    if (!isRTL)
+        return index && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index - 1]);
+    return index != m_item.stringLength - 1 && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index + 1]);
+}
+
+// setPadding sets a number of pixels to be distributed across the TextRun.
+// WebKit uses this to justify text.
+void TextRunWalker::setPadding(int padding)
+{
+    m_padding = padding;
+    if (!m_padding)
+        return;
+
+    // If we have padding to distribute, then we try to give an equal
+    // amount to each space. The last space gets the smaller amount, if
+    // any.
+    unsigned numWordBreaks = 0;
+    bool isRTL = m_iterateBackwards;
+
+    for (unsigned i = 0; i < m_item.stringLength; i++) {
+        if (isWordBreak(i, isRTL))
+            numWordBreaks++;
     }
 
-    void shapeGlyphs()
-    {
-        // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to
-        // HB_ShapeItem() used less space than was available, the capacity of
-        // the array may be larger than the current value of m_item.num_glyphs. 
-        // So, we need to reset the num_glyphs to the capacity of the array.
-        m_item.num_glyphs = m_glyphsArrayCapacity;
-        resetGlyphArrays();
-        while (!HB_ShapeItem(&m_item)) {
-            // We overflowed our arrays. Resize and retry.
-            // HB_ShapeItem fills in m_item.num_glyphs with the needed size.
-            deleteGlyphArrays();
-            // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer
-            // shaper (at least) can fail because of insufficient glyph buffers
-            // and request 0 additional glyphs: throwing us into an infinite
-            // loop.
-            createGlyphArrays(m_item.num_glyphs + 1);
+    if (numWordBreaks)
+        m_padPerWordBreak = m_padding / numWordBreaks;
+    else
+        m_padPerWordBreak = 0;
+}
+
+void TextRunWalker::reset()
+{
+    if (m_iterateBackwards)
+        m_indexOfNextScriptRun = m_run.length() - 1;
+    else
+        m_indexOfNextScriptRun = 0;
+    m_offsetX = m_startingX;
+}
+
+void TextRunWalker::setBackwardsIteration(bool isBackwards)
+{
+    m_iterateBackwards = isBackwards;
+    reset();
+}
+
+// Advance to the next script run, returning false when the end of the
+// TextRun has been reached.
+bool TextRunWalker::nextScriptRun()
+{
+    if (m_iterateBackwards) {
+        // In right-to-left mode we need to render the shaped glyph backwards and
+        // also render the script runs themselves backwards. So given a TextRun:
+        //    AAAAAAACTTTTTTT   (A = Arabic, C = Common, T = Thai)
+        // we render:
+        //    TTTTTTCAAAAAAA
+        // (and the glyphs in each A, C and T section are backwards too)
+        if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+            return false;
+    } else {
+        if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+            return false;
+
+        // It is actually wrong to consider script runs at all in this code.
+        // Other WebKit code (e.g. Mac) segments complex text just by finding
+        // the longest span of text covered by a single font.
+        // But we currently need to call hb_utf16_script_run_next anyway to fill
+        // in the harfbuzz data structures to e.g. pick the correct script's shaper.
+        // So we allow that to run first, then do a second pass over the range it
+        // found and take the largest subregion that stays within a single font.
+        const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
+        unsigned endOfRun;
+        for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
+            const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData;
+            if (nextGlyphData != glyphData)
+                break;
         }
+        m_item.item.length = endOfRun;
+        m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
     }
 
-    void setGlyphXPositions(bool isRTL)
-    {
-        double position = 0;
-        // logClustersIndex indexes logClusters for the first (or last when
-        // RTL) codepoint of the current glyph.  Each time we advance a glyph,
-        // we skip over all the codepoints that contributed to the current
-        // glyph.
-        unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0;
-
-        for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) {
-            // Glyphs are stored in logical order, but for layout purposes we
-            // always go left to right.
-            int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
-
-            m_glyphs16[i] = m_item.glyphs[i];
-            double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
-            m_xPositions[i] = m_offsetX + position + offsetX;
-
-            double advance = truncateFixedPointToInteger(m_item.advances[i]);
-            // The first half of the conjuction works around the case where
-            // output glyphs aren't associated with any codepoints by the
-            // clusters log.
-            if (logClustersIndex < m_item.item.length
-                && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) {
-                advance += m_wordSpacingAdjustment;
-
-                if (m_padding > 0) {
-                    unsigned toPad = roundf(m_padPerWordBreak + m_padError);
-                    m_padError += m_padPerWordBreak - toPad;
-
-                    if (m_padding < toPad)
-                        toPad = m_padding;
-                    m_padding -= toPad;
-                    advance += toPad;
-                }
-            }
+    setupFontForScriptRun();
+    shapeGlyphs();
+    setGlyphXPositions(rtl());
 
-            // We would like to add m_letterSpacing after each cluster, but I
-            // don't know where the cluster information is. This is typically
-            // fine for Roman languages, but breaks more complex languages
-            // terribly.
-            // advance += m_letterSpacing;
-
-            if (isRTL) {
-                while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
-                    logClustersIndex--;
-            } else {
-                while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i)
-                    logClustersIndex++;
-            }
+    return true;
+}
 
-            position += advance;
-        }
+float TextRunWalker::widthOfFullRun()
+{
+    float widthSum = 0;
+    while (nextScriptRun())
+        widthSum += width();
+
+    return widthSum;
+}
+
+const TextRun& TextRunWalker::getTextRun(const TextRun& originalRun)
+{
+    // Normalize the text run in two ways:
+    // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
+    // (U+0300..) are used in the run. This conversion is necessary since most OpenType
+    // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
+    // their GSUB tables.
+    //
+    // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
+    // the API returns FALSE (= not normalized) for complex runs that don't require NFC
+    // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
+    // Harfbuzz will do the same thing for us using the GSUB table.
+    // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
+    // for characters like '\n' otherwise.
+    for (int i = 0; i < originalRun.length(); ++i) {
+        UChar ch = originalRun[i];
+        UBlockCode block = ::ublock_getCode(ch);
+        if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' '))
+            return getNormalizedTextRun(originalRun);
+    }
+    return originalRun;
+}
 
-        m_pixelWidth = position;
-        m_offsetX += m_pixelWidth;
+const TextRun& TextRunWalker::getNormalizedTextRun(const TextRun& originalRun)
+{
+    icu::UnicodeString normalizedString;
+    UErrorCode error = U_ZERO_ERROR;
+    icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error);
+    if (U_FAILURE(error))
+        return originalRun;
+
+    m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]);
+    normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error);
+    ASSERT(U_SUCCESS(error));
+
+    for (int i = 0; i < normalizedString.length(); ++i) {
+        if (Font::treatAsSpace(m_normalizedBuffer[i]))
+            m_normalizedBuffer[i] = ' ';
     }
 
-    static bool isCodepointSpace(HB_UChar16 c)
-    {
-        // This matches the logic in RenderBlock::findNextLineBreak
-        return c == ' ' || c == '\t';
+    m_normalizedRun.set(new TextRun(originalRun));
+    m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length());
+    return *m_normalizedRun;
+}
+
+void TextRunWalker::setupFontForScriptRun()
+{
+    const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData;
+    const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData();
+    m_item.face = platformData.harfbuzzFace();
+    void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
+    m_item.font->userData = opaquePlatformData;
+}
+
+HB_FontRec* TextRunWalker::allocHarfbuzzFont()
+{
+    HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
+    memset(font, 0, sizeof(HB_FontRec));
+    font->klass = &harfbuzzSkiaClass;
+    font->userData = 0;
+    // The values which harfbuzzSkiaClass returns are already scaled to
+    // pixel units, so we just set all these to one to disable further
+    // scaling.
+    font->x_ppem = 1;
+    font->y_ppem = 1;
+    font->x_scale = 1;
+    font->y_scale = 1;
+
+    return font;
+}
+
+void TextRunWalker::deleteGlyphArrays()
+{
+    delete[] m_item.glyphs;
+    delete[] m_item.attributes;
+    delete[] m_item.advances;
+    delete[] m_item.offsets;
+    delete[] m_glyphs16;
+    delete[] m_xPositions;
+}
+
+void TextRunWalker::createGlyphArrays(int size)
+{
+    m_item.glyphs = new HB_Glyph[size];
+    m_item.attributes = new HB_GlyphAttributes[size];
+    m_item.advances = new HB_Fixed[size];
+    m_item.offsets = new HB_FixedPoint[size];
+
+    m_glyphs16 = new uint16_t[size];
+    m_xPositions = new SkScalar[size];
+
+    m_item.num_glyphs = size;
+    m_glyphsArrayCapacity = size; // Save the GlyphArrays size.
+    resetGlyphArrays();
+}
+
+void TextRunWalker::resetGlyphArrays()
+{
+    int size = m_item.num_glyphs;
+    // All the types here don't have pointers. It is safe to reset to
+    // zero unless Harfbuzz breaks the compatibility in the future.
+    memset(m_item.glyphs, 0, size * sizeof(HB_Glyph));
+    memset(m_item.attributes, 0, size * sizeof(HB_GlyphAttributes));
+    memset(m_item.advances, 0, size * sizeof(HB_Fixed));
+    memset(m_item.offsets, 0, size * sizeof(HB_FixedPoint));
+    memset(m_glyphs16, 0, size * sizeof(uint16_t));
+    memset(m_xPositions, 0, size * sizeof(SkScalar));
+}
+
+void TextRunWalker::shapeGlyphs()
+{
+    // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to
+    // HB_ShapeItem() used less space than was available, the capacity of
+    // the array may be larger than the current value of m_item.num_glyphs. 
+    // So, we need to reset the num_glyphs to the capacity of the array.
+    m_item.num_glyphs = m_glyphsArrayCapacity;
+    resetGlyphArrays();
+    while (!HB_ShapeItem(&m_item)) {
+        // We overflowed our arrays. Resize and retry.
+        // HB_ShapeItem fills in m_item.num_glyphs with the needed size.
+        deleteGlyphArrays();
+        // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer
+        // shaper (at least) can fail because of insufficient glyph buffers
+        // and request 0 additional glyphs: throwing us into an infinite
+        // loop.
+        createGlyphArrays(m_item.num_glyphs + 1);
     }
+}
+
+void TextRunWalker::setGlyphXPositions(bool isRTL)
+{
+    double position = 0;
+    // logClustersIndex indexes logClusters for the first (or last when
+    // RTL) codepoint of the current glyph.  Each time we advance a glyph,
+    // we skip over all the codepoints that contributed to the current
+    // glyph.
+    unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0;
+
+    for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) {
+        // Glyphs are stored in logical order, but for layout purposes we
+        // always go left to right.
+        int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
+
+        m_glyphs16[i] = m_item.glyphs[i];
+        double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
+        m_xPositions[i] = m_offsetX + position + offsetX;
+
+        double advance = truncateFixedPointToInteger(m_item.advances[i]);
+        // The first half of the conjuction works around the case where
+        // output glyphs aren't associated with any codepoints by the
+        // clusters log.
+        if (logClustersIndex < m_item.item.length
+            && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) {
+            advance += m_wordSpacingAdjustment;
+
+            if (m_padding > 0) {
+                unsigned toPad = roundf(m_padPerWordBreak + m_padError);
+                m_padError += m_padPerWordBreak - toPad;
+
+                if (m_padding < toPad)
+                    toPad = m_padding;
+                m_padding -= toPad;
+                advance += toPad;
+            }
+        }
+
+        // We would like to add m_letterSpacing after each cluster, but I
+        // don't know where the cluster information is. This is typically
+        // fine for Roman languages, but breaks more complex languages
+        // terribly.
+        // advance += m_letterSpacing;
 
-    void mirrorCharacters(UChar* destination, const UChar* source, int length) const
-    {
-        int position = 0;
-        bool error = false;
-        // Iterate characters in source and mirror character if needed.
-        while (position < length) {
-            UChar32 character;
-            int nextPosition = position;
-            U16_NEXT(source, nextPosition, length, character);
-            character = u_charMirror(character);
-            U16_APPEND(destination, position, length, character, error);
-            ASSERT(!error);
-            position = nextPosition;
+        if (isRTL) {
+            while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
+                logClustersIndex--;
+        } else {
+            while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i)
+                logClustersIndex++;
         }
+
+        position += advance;
     }
 
-    const Font* const m_font;
-    HB_ShaperItem m_item;
-    uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
-    SkScalar* m_xPositions; // A vector of x positions for each glyph.
-    ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
-    const unsigned m_startingX; // Offset in pixels of the first script run.
-    unsigned m_offsetX; // Offset in pixels to the start of the next script run.
-    unsigned m_pixelWidth; // Width (in px) of the current script run.
-    unsigned m_numCodePoints; // Code points in current script run.
-    unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays.
+    m_pixelWidth = position;
+    m_offsetX += m_pixelWidth;
+}
 
-    OwnPtr<TextRun> m_normalizedRun;
-    OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run.
-    const TextRun& m_run;
-    bool m_iterateBackwards;
-    int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
-    float m_padding; // pixels to be distributed over the line at word breaks.
-    float m_padPerWordBreak; // pixels to be added to each word break.
-    float m_padError; // |m_padPerWordBreak| might have a fractional component.
-                      // Since we only add a whole number of padding pixels at
-                      // each word break we accumulate error. This is the
-                      // number of pixels that we are behind so far.
-    unsigned m_letterSpacing; // pixels to be added after each glyph.
-};
+void TextRunWalker::mirrorCharacters(UChar* destination, const UChar* source, int length) const
+{
+    int position = 0;
+    bool error = false;
+    // Iterate characters in source and mirror character if needed.
+    while (position < length) {
+        UChar32 character;
+        int nextPosition = position;
+        U16_NEXT(source, nextPosition, length, character);
+        character = u_charMirror(character);
+        U16_APPEND(destination, position, length, character, error);
+        ASSERT(!error);
+        position = nextPosition;
+    }
+}
 
 static void setupForTextPainting(SkPaint* paint, SkColor color)
 {

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list