Title: [129074] trunk/Source/WebCore
Revision
129074
Author
[email protected]
Date
2012-09-19 17:00:45 -0700 (Wed, 19 Sep 2012)

Log Message

[Chromium] Improve glyph positioning of HarfBuzzShaper
https://bugs.webkit.org/show_bug.cgi?id=97093

Reviewed by Tony Chang.

For proper positioning, HarfBuzzShaper requires the positions(offsets and advance)
of the previous glyph. This mean we need to shape all HarfBuzzRuns before glyph positioning.
Collect and shape HarfBuzzRuns, then set positions of glyphs.

No new tests. Tests that uses spacing for complex text (e.g. fast/text/atsui-negative-spacing-features.html)
should close in the expectations. (not the identical, maybe there are subtle differences between
harfbuzz old and harfbuzz ng)

* platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp:
(WebCore::HarfBuzzShaper::HarfBuzzRun::applyShapeResult): Allocate m_offsets.
(WebCore::HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions): Renamed and set offset too.
(WebCore::HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition):
(WebCore::HarfBuzzShaper::shape): Call fillGlyphBuffer() if we need to fill glyphBuffer.
(WebCore::HarfBuzzShaper::shapeHarfBuzzRuns): Removed glyph positioning code.
(WebCore::HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun): Ditto.
(WebCore::HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun): Added.
(WebCore):
(WebCore::HarfBuzzShaper::fillGlyphBuffer): Added.
* platform/graphics/harfbuzz/ng/HarfBuzzShaper.h:
(HarfBuzzRun):
(WebCore::HarfBuzzShaper::HarfBuzzRun::offsets): Added.
(WebCore::HarfBuzzShaper::HarfBuzzRun::glyphToCharacterIndexes): Added.
(HarfBuzzShaper):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (129073 => 129074)


--- trunk/Source/WebCore/ChangeLog	2012-09-19 23:59:01 UTC (rev 129073)
+++ trunk/Source/WebCore/ChangeLog	2012-09-20 00:00:45 UTC (rev 129074)
@@ -1,3 +1,34 @@
+2012-09-19  Kenichi Ishibashi  <[email protected]>
+
+        [Chromium] Improve glyph positioning of HarfBuzzShaper
+        https://bugs.webkit.org/show_bug.cgi?id=97093
+
+        Reviewed by Tony Chang.
+
+        For proper positioning, HarfBuzzShaper requires the positions(offsets and advance)
+        of the previous glyph. This mean we need to shape all HarfBuzzRuns before glyph positioning.
+        Collect and shape HarfBuzzRuns, then set positions of glyphs.
+
+        No new tests. Tests that uses spacing for complex text (e.g. fast/text/atsui-negative-spacing-features.html)
+        should close in the expectations. (not the identical, maybe there are subtle differences between
+        harfbuzz old and harfbuzz ng)
+
+        * platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp:
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::applyShapeResult): Allocate m_offsets.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions): Renamed and set offset too.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition):
+        (WebCore::HarfBuzzShaper::shape): Call fillGlyphBuffer() if we need to fill glyphBuffer.
+        (WebCore::HarfBuzzShaper::shapeHarfBuzzRuns): Removed glyph positioning code.
+        (WebCore::HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun): Ditto.
+        (WebCore::HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun): Added.
+        (WebCore):
+        (WebCore::HarfBuzzShaper::fillGlyphBuffer): Added.
+        * platform/graphics/harfbuzz/ng/HarfBuzzShaper.h:
+        (HarfBuzzRun):
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::offsets): Added.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::glyphToCharacterIndexes): Added.
+        (HarfBuzzShaper):
+
 2012-09-19  James Simonsen  <[email protected]>
 
         [Chromium] Disable resource load scheduling

Modified: trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp (129073 => 129074)


--- trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp	2012-09-19 23:59:01 UTC (rev 129073)
+++ trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp	2012-09-20 00:00:45 UTC (rev 129074)
@@ -85,12 +85,13 @@
     m_numGlyphs = hb_buffer_get_length(harfbuzzBuffer);
     m_glyphs.resize(m_numGlyphs);
     m_advances.resize(m_numGlyphs);
-    m_glyphToCharacterIndex.resize(m_numGlyphs);
+    m_glyphToCharacterIndexes.resize(m_numGlyphs);
     m_logClusters.resize(m_numCharacters);
+    m_offsets.resize(m_numGlyphs);
 
     hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(harfbuzzBuffer, 0);
     for (unsigned i = 0; i < m_numGlyphs; ++i)
-        m_glyphToCharacterIndex[i] = infos[i].cluster;
+        m_glyphToCharacterIndexes[i] = infos[i].cluster;
 
     // Fill logical clusters
     unsigned index = 0;
@@ -111,10 +112,11 @@
     }
 }
 
-void HarfBuzzShaper::HarfBuzzRun::setGlyphAndAdvance(unsigned index, uint16_t glyphId, float advance)
+void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY)
 {
     m_glyphs[index] = glyphId;
     m_advances[index] = advance;
+    m_offsets[index] = FloatPoint(offsetX, offsetY);
 }
 
 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
@@ -126,7 +128,7 @@
         float currentAdvance = m_advances[i] / 2.0;
         float nextX = currentX + prevAdvance + currentAdvance;
         if (currentX <= targetX && targetX <= nextX)
-            return m_glyphToCharacterIndex[i] + (rtl() ? 1 : 0);
+            return m_glyphToCharacterIndexes[i] + (rtl() ? 1 : 0);
         currentX = nextX;
         prevAdvance = currentAdvance;
     }
@@ -190,11 +192,6 @@
     m_toIndex = to;
 }
 
-bool HarfBuzzShaper::shouldDrawCharacterAt(int index)
-{
-    return m_fromIndex <= index && index < m_toIndex;
-}
-
 void HarfBuzzShaper::setFontFeatures()
 {
     FontFeatureSettings* settings = m_font->fontDescription().featureSettings();
@@ -218,9 +215,13 @@
         return false;
 
     m_totalWidth = 0;
-    if (!shapeHarfBuzzRuns(glyphBuffer))
+    if (!shapeHarfBuzzRuns())
         return false;
     m_totalWidth = roundf(m_totalWidth);
+
+    if (glyphBuffer)
+        fillGlyphBuffer(glyphBuffer);
+
     return true;
 }
 
@@ -304,14 +305,12 @@
     return !m_harfbuzzRuns.isEmpty();
 }
 
-bool HarfBuzzShaper::shapeHarfBuzzRuns(GlyphBuffer* glyphBuffer)
+bool HarfBuzzShaper::shapeHarfBuzzRuns()
 {
     HarfBuzzScopedPtr<hb_buffer_t> harfbuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
-    float pendingGlyphAdvanceX = 0;
-    float pendingGlyphAdvanceY = 0;
 
     hb_buffer_set_unicode_funcs(harfbuzzBuffer.get(), hb_icu_get_unicode_funcs());
-    if (m_run.directionalOverride())
+    if (m_run.rtl() || m_run.directionalOverride())
         hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
 
     for (unsigned i = 0; i < m_harfbuzzRuns.size(); ++i) {
@@ -335,16 +334,17 @@
         hb_shape(harfbuzzFont.get(), harfbuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
 
         currentRun->applyShapeResult(harfbuzzBuffer.get());
-        setGlyphPositionsForHarfBuzzRun(currentRun, i, harfbuzzBuffer.get(), glyphBuffer, pendingGlyphAdvanceX, pendingGlyphAdvanceY);
+        setGlyphPositionsForHarfBuzzRun(currentRun, harfbuzzBuffer.get());
 
         hb_buffer_reset(harfbuzzBuffer.get());
-        if (m_run.directionalOverride())
+        if (m_run.rtl() || m_run.directionalOverride())
             hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
     }
+
     return true;
 }
 
-void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, unsigned runIndexInVisualOrder, hb_buffer_t* harfbuzzBuffer, GlyphBuffer* glyphBuffer, float& pendingGlyphAdvanceX, float& pendingGlyphAdvanceY)
+void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfbuzzBuffer)
 {
     const SimpleFontData* currentFontData = currentRun->fontData();
     hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfbuzzBuffer, 0);
@@ -352,58 +352,93 @@
 
     unsigned numGlyphs = currentRun->numGlyphs();
     float totalAdvance = 0;
-    float nextOffsetX = harfbuzzPositionToFloat(glyphPositions[0].x_offset);
-    float nextOffsetY = -harfbuzzPositionToFloat(glyphPositions[0].y_offset);
-    // HarfBuzz returns the shaping result in visual order. We need not to flip them for RTL.
+
+    // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
     for (size_t i = 0; i < numGlyphs; ++i) {
         bool runEnd = i + 1 == numGlyphs;
         uint16_t glyph = glyphInfos[i].codepoint;
-        float offsetX = nextOffsetX;
-        float offsetY = nextOffsetY;
+        float offsetX = harfbuzzPositionToFloat(glyphPositions[i].x_offset);
+        float offsetY = -harfbuzzPositionToFloat(glyphPositions[i].y_offset);
         float advance = harfbuzzPositionToFloat(glyphPositions[i].x_advance);
-        nextOffsetX = runEnd ? 0 : harfbuzzPositionToFloat(glyphPositions[i + 1].x_offset);
-        nextOffsetY = runEnd ? 0 : -harfbuzzPositionToFloat(glyphPositions[i + 1].y_offset);
 
         unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
         bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
-        float spacing = isClusterEnd ? m_letterSpacing : 0;
+        float spacing = 0;
+        if (isClusterEnd && !Font::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex]))
+            spacing += m_letterSpacing;
 
         if (isClusterEnd && isWordEnd(currentCharacterIndex))
             spacing += determineWordBreakSpacing();
 
         if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
-            currentRun->setGlyphAndAdvance(i, glyph, 0);
-            if (glyphBuffer && shouldDrawCharacterAt(currentCharacterIndex))
-                glyphBuffer->add(glyph, currentFontData, createGlyphBufferAdvance(0, 0));
+            currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
             continue;
         }
 
         advance += spacing;
-
-        currentRun->setGlyphAndAdvance(i, glyph, advance);
-        if (glyphBuffer) {
-            if (!i && !runIndexInVisualOrder)
-                m_startOffset.set(offsetX, offsetY);
-            float glyphAdvanceX = advance + nextOffsetX - offsetX;
-            float glyphAdvanceY = nextOffsetY - offsetY;
-            if (shouldDrawCharacterAt(currentCharacterIndex)) {
-                glyphAdvanceX += pendingGlyphAdvanceX;
-                glyphAdvanceY += pendingGlyphAdvanceY;
-                pendingGlyphAdvanceX = 0;
-                pendingGlyphAdvanceY = 0;
-                glyphBuffer->add(glyph, currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
-            } else {
-                pendingGlyphAdvanceX += glyphAdvanceX;
-                pendingGlyphAdvanceY += glyphAdvanceY;
-            }
+        if (m_run.rtl()) {
+            // In RTL, spacing should be added to left side of glyphs.
+            offsetX += spacing;
+            if (!isClusterEnd)
+                offsetX += m_letterSpacing;
         }
 
+        currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
+
         totalAdvance += advance;
     }
     currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
     m_totalWidth += currentRun->width();
 }
 
+void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
+{
+    FloatPoint* offsets = currentRun->offsets();
+    uint16_t* glyphs = currentRun->glyphs();
+    float* advances = currentRun->advances();
+    unsigned numGlyphs = currentRun->numGlyphs();
+    uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
+
+    for (unsigned i = 0; i < numGlyphs; ++i) {
+        uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
+        FloatPoint& currentOffset = offsets[i];
+        FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1];
+        float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
+        float glyphAdvanceY = nextOffset.y() - currentOffset.y();
+        if (m_run.rtl()) {
+            if (currentCharacterIndex > m_toIndex)
+                m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
+            else if (currentCharacterIndex >= m_fromIndex)
+                glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
+        } else {
+            if (currentCharacterIndex < m_fromIndex)
+                m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
+            else if (currentCharacterIndex < m_toIndex)
+                glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
+        }
+    }
+}
+
+void HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
+{
+    unsigned numRuns = m_harfbuzzRuns.size();
+    if (m_run.rtl()) {
+        m_startOffset = m_harfbuzzRuns.last()->offsets()[0];
+        for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
+            HarfBuzzRun* currentRun = m_harfbuzzRuns[runIndex].get();
+            FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfbuzzRuns[runIndex - 1]->offsets()[0];
+            fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
+        }
+    } else {
+        m_startOffset = m_harfbuzzRuns.first()->offsets()[0];
+        for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
+            HarfBuzzRun* currentRun = m_harfbuzzRuns[runIndex].get();
+            FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfbuzzRuns[runIndex + 1]->offsets()[0];
+            fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
+        }
+    }
+}
+
 int HarfBuzzShaper::offsetForPosition(float targetX)
 {
     int charactersSoFar = 0;

Modified: trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h (129073 => 129074)


--- trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h	2012-09-19 23:59:01 UTC (rev 129073)
+++ trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h	2012-09-20 00:00:45 UTC (rev 129074)
@@ -67,7 +67,7 @@
         }
 
         void applyShapeResult(hb_buffer_t*);
-        void setGlyphAndAdvance(unsigned index, uint16_t glyphId, float advance);
+        void setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY);
         void setWidth(float width) { m_width = width; }
 
         int characterIndexForXPosition(float targetX);
@@ -79,6 +79,8 @@
         unsigned numGlyphs() const { return m_numGlyphs; }
         uint16_t* glyphs() { return &m_glyphs[0]; }
         float* advances() { return &m_advances[0]; }
+        FloatPoint* offsets() { return &m_offsets[0]; }
+        uint16_t* glyphToCharacterIndexes() { return &m_glyphToCharacterIndexes[0]; }
         float width() { return m_width; }
 
     private:
@@ -93,16 +95,18 @@
         Vector<uint16_t, 256> m_glyphs;
         Vector<float, 256> m_advances;
         Vector<uint16_t, 256> m_logClusters;
-        Vector<uint16_t, 256> m_glyphToCharacterIndex;
+        Vector<uint16_t, 256> m_glyphToCharacterIndexes;
+        Vector<FloatPoint, 256> m_offsets;
         float m_width;
     };
 
-    bool shouldDrawCharacterAt(int index);
     void setFontFeatures();
 
     bool collectHarfBuzzRuns();
-    bool shapeHarfBuzzRuns(GlyphBuffer*);
-    void setGlyphPositionsForHarfBuzzRun(HarfBuzzRun*, unsigned runIndexInVisualOrder, hb_buffer_t*, GlyphBuffer*, float& pendingGlyphAdvanceX, float& pendingGlyphAdvanceY);
+    bool shapeHarfBuzzRuns();
+    void fillGlyphBuffer(GlyphBuffer*);
+    void fillGlyphBufferFromHarfBuzzRun(GlyphBuffer*, HarfBuzzRun*, FloatPoint& firstOffsetOfNextRun);
+    void setGlyphPositionsForHarfBuzzRun(HarfBuzzRun*, hb_buffer_t*);
 
     GlyphBufferAdvance createGlyphBufferAdvance(float, float);
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to