Title: [122562] trunk
Revision
122562
Author
[email protected]
Date
2012-07-13 04:16:50 -0700 (Fri, 13 Jul 2012)

Log Message

[Chromium] Fix bugs in HarfBuzzShaper
https://bugs.webkit.org/show_bug.cgi?id=90951

Reviewed by Tony Chang.

Source/WebCore:

The current implementation has following problems:
- Cannot render RTL text if the TextRun is divided into more than two
  HarfBuzzRun.
- Script handling in TextRun partitioning is incorrect.
- Inaccurate calculation of selection rect.
- Wrong rendering position when the first glyph of the TextRun have
  non-zero offsets in terms of HarfBuzz.

To fix these problems I rewrote HarfBuzzShaper class. Here is the summary:
- Divide the whole range of TextRun first, then shape them in visual
  order.
- Divide TextRun in the same way of old-harfbuzz's
  hb_utf16_script_run_next().
- Prefer float than int when calculating selection.
- Adjust the drawing point after shaping.

Added tests covers the fix except for the last problem. The last problem will be covered
by fast/text/international/complex-joining-using-gpos.html after chromium linux port switches
to use HarfBuzzShaper.

Tests: fast/text/shaping/shaping-script-order.html
       fast/text/shaping/shaping-selection-rect.html

* platform/graphics/harfbuzz/FontHarfBuzz.cpp:
(WebCore::Font::drawComplexText): Adjusts point after shaping.
* platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp:
(WebCore::HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun):
(WebCore):
(WebCore::HarfBuzzShaper::HarfBuzzRun::applyShapeResult): Added.
(WebCore::HarfBuzzShaper::HarfBuzzRun::setGlyphAndAdvance): Offsets are no longer needed.
(WebCore::HarfBuzzShaper::HarfBuzzRun::xPositionForOffset): Calculates character offset based on advance.
(WebCore::normalizeCharacters): Added.
(WebCore::HarfBuzzShaper::HarfBuzzShaper):
(WebCore::HarfBuzzShaper::~HarfBuzzShaper):
(WebCore::HarfBuzzShaper::shape): Divides TextRun first, then shapes them.
(WebCore::HarfBuzzShaper::adjustStartPoint): Added.
(WebCore::HarfBuzzShaper::collectHarfBuzzRuns): Added.
(WebCore::HarfBuzzShaper::shapeHarfBuzzRuns): Added.
(WebCore::HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun): Followed other changes.
(WebCore::HarfBuzzShaper::selectionRect): Use float for calculating selection.
* platform/graphics/harfbuzz/ng/HarfBuzzShaper.h:
(HarfBuzzShaper): Holds the start index of character. Removed unnecessary variables.
(WebCore::HarfBuzzShaper::HarfBuzzRun::create): Ditto.
(HarfBuzzRun):
(WebCore::HarfBuzzShaper::HarfBuzzRun::fontData): Added.
(WebCore::HarfBuzzShaper::HarfBuzzRun::startIndex): Ditto.
(WebCore::HarfBuzzShaper::HarfBuzzRun::glyphs): Ditto.
(WebCore::HarfBuzzShaper::HarfBuzzRun::advances): Ditto.

LayoutTests:

Add tests for harfbuzz-ng shaper. I tried to use -expected.html style expectations,
but it didn't work because there are very slight difference between CoreText and HarfBuzz in
rendering result.

* fast/text/shaping/shaping-script-order.html: Added.
* fast/text/shaping/shaping-selection-rect.html: Added.
* platform/chromium/TestExpectations: Need rebaseline.
* platform/efl/TestExpectations: Skip added tests because the port doesn't use harfbuzz.
* platform/gtk/TestExpectations: Ditto.
* platform/mac/TestExpectations: Ditto.
* platform/qt/TestExpectations: Ditto.
* platform/win/Skipped: Ditto.
* platform/wincairo/Skipped: Ditto.
* platform/wk2/Skipped: Ditto.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (122561 => 122562)


--- trunk/LayoutTests/ChangeLog	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/ChangeLog	2012-07-13 11:16:50 UTC (rev 122562)
@@ -1,3 +1,25 @@
+2012-07-13  Kenichi Ishibashi  <[email protected]>
+
+        [Chromium] Fix bugs in HarfBuzzShaper
+        https://bugs.webkit.org/show_bug.cgi?id=90951
+
+        Reviewed by Tony Chang.
+
+        Add tests for harfbuzz-ng shaper. I tried to use -expected.html style expectations,
+        but it didn't work because there are very slight difference between CoreText and HarfBuzz in
+        rendering result.
+
+        * fast/text/shaping/shaping-script-order.html: Added.
+        * fast/text/shaping/shaping-selection-rect.html: Added.
+        * platform/chromium/TestExpectations: Need rebaseline.
+        * platform/efl/TestExpectations: Skip added tests because the port doesn't use harfbuzz.
+        * platform/gtk/TestExpectations: Ditto.
+        * platform/mac/TestExpectations: Ditto.
+        * platform/qt/TestExpectations: Ditto.
+        * platform/win/Skipped: Ditto.
+        * platform/wincairo/Skipped: Ditto.
+        * platform/wk2/Skipped: Ditto.
+
 2012-07-13  Kent Tamura  <[email protected]>
 
         Make calendar pickers testable

Added: trunk/LayoutTests/fast/text/shaping/shaping-script-order.html (0 => 122562)


--- trunk/LayoutTests/fast/text/shaping/shaping-script-order.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/shaping/shaping-script-order.html	2012-07-13 11:16:50 UTC (rev 122562)
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style>
+    .lro {
+        font-family: "times new roman"; /* non AAT font on mac */
+        direction:ltr;
+        unicode-bidi:bidi-override;
+    };
+</style>
+</head>
+<body>
+The following two lines should be the same:
+<p class="lro">abc&#x05d2;&#x05d1;&#x05d0;&#x0661;&#x0662;&#x0663;</p>
+<p class="lro" style="-webkit-font-feature-settings: 'kern';">abc&#x05d2;&#x05d1;&#x05d0;&#x0661;&#x0662;&#x0663;</p>
+</body>
+</html>

Added: trunk/LayoutTests/fast/text/shaping/shaping-selection-rect.html (0 => 122562)


--- trunk/LayoutTests/fast/text/shaping/shaping-selection-rect.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/shaping/shaping-selection-rect.html	2012-07-13 11:16:50 UTC (rev 122562)
@@ -0,0 +1,23 @@
+<html>
+<head>
+<style>
+    #target {
+        font-family: "times new roman"; /* non AAT font on mac */
+        -webkit-font-feature-settings: 'kern';
+    };
+</style>
+<script>
+function test()
+{
+    var targetText = document.getElementById("target").firstChild;
+    window.getSelection().setBaseAndExtent(target, 0, target, 9);
+}
+</script>
+</head>
+<body _onload_="test()">
+<p>The selection should cover the all of the below text. There should be no blank between C and F.
+<div id="target">
+ABC<span style="direction: rtl; unicode-bidi: bidi-override;">DEF</span>GHI
+</div>
+</body>
+</html>

Modified: trunk/LayoutTests/platform/chromium/TestExpectations (122561 => 122562)


--- trunk/LayoutTests/platform/chromium/TestExpectations	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/chromium/TestExpectations	2012-07-13 11:16:50 UTC (rev 122562)
@@ -3748,3 +3748,7 @@
 
 // Started crashing after 122286
 BUGWK91133 WIN : storage/indexeddb/constants.html = PASS CRASH
+
+// Need rebaseline
+BUGWK90951 : fast/text/shaping/shaping-selection-rect.html = MISSING
+BUGWK90951 : fast/text/shaping/shaping-script-order.html = MISSING

Modified: trunk/LayoutTests/platform/efl/TestExpectations (122561 => 122562)


--- trunk/LayoutTests/platform/efl/TestExpectations	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/efl/TestExpectations	2012-07-13 11:16:50 UTC (rev 122562)
@@ -738,3 +738,6 @@
 
 // Looks like missing multipart/x-mixed-replace support in libsoup. Failing on both GTK and EFL.
 BUGWK68979 : http/tests/multipart/multipart-replace-non-html-content.php = TEXT
+
+// Skip tests in fast/text/shaping
+BUGWK90951 SKIP : fast/text/shaping = PASS

Modified: trunk/LayoutTests/platform/gtk/TestExpectations (122561 => 122562)


--- trunk/LayoutTests/platform/gtk/TestExpectations	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/gtk/TestExpectations	2012-07-13 11:16:50 UTC (rev 122562)
@@ -1254,6 +1254,9 @@
 
 BUGWK91009 DEBUG : fast/xsl/xslt-missing-namespace-in-xslt.xml = TEXT
 
+// Skip tests in fast/text/shaping
+BUGWK90951 SKIP : fast/text/shaping = PASS
+
 //////////////////////////////////////////////////////////////////////////////////////////
 // End of Tests failing
 //////////////////////////////////////////////////////////////////////////////////////////

Modified: trunk/LayoutTests/platform/mac/TestExpectations (122561 => 122562)


--- trunk/LayoutTests/platform/mac/TestExpectations	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2012-07-13 11:16:50 UTC (rev 122562)
@@ -295,3 +295,6 @@
 
 // INPUT_TYPE_DATE is not enabled on the Mac
 BUGWK90987 : fast/forms/input-in-table-cell-no-value.html = IMAGE
+
+// Skip tests in fast/text/shaping
+BUGWK90951 SKIP : fast/text/shaping = PASS

Modified: trunk/LayoutTests/platform/qt/TestExpectations (122561 => 122562)


--- trunk/LayoutTests/platform/qt/TestExpectations	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/qt/TestExpectations	2012-07-13 11:16:50 UTC (rev 122562)
@@ -113,3 +113,6 @@
 
 // Dialog element is not yet enabled.
 BUGWK84635 SKIP : fast/dom/HTMLDialogElement = TEXT
+
+// Skip tests in fast/text/shaping
+BUGWK90951 SKIP : fast/text/shaping = PASS

Modified: trunk/LayoutTests/platform/win/Skipped (122561 => 122562)


--- trunk/LayoutTests/platform/win/Skipped	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/win/Skipped	2012-07-13 11:16:50 UTC (rev 122562)
@@ -1944,3 +1944,6 @@
 # Content Security Policy 1.1 (ENABLE_CSP_NEXT) is not enabled
 # https://bugs.webkit.org/show_bug.cgi?id=85558
 http/tests/security/contentSecurityPolicy/1.1
+
+# Skip tests in fast/text/shaping
+fast/text/shaping

Modified: trunk/LayoutTests/platform/wincairo/Skipped (122561 => 122562)


--- trunk/LayoutTests/platform/wincairo/Skipped	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/wincairo/Skipped	2012-07-13 11:16:50 UTC (rev 122562)
@@ -2126,3 +2126,6 @@
 # Content Security Policy 1.1 (ENABLE_CSP_NEXT) is not enabled
 # https://bugs.webkit.org/show_bug.cgi?id=85558
 http/tests/security/contentSecurityPolicy/1.1
+
+# Skip tests in fast/text/shaping
+fast/text/shaping

Modified: trunk/LayoutTests/platform/wk2/Skipped (122561 => 122562)


--- trunk/LayoutTests/platform/wk2/Skipped	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/LayoutTests/platform/wk2/Skipped	2012-07-13 11:16:50 UTC (rev 122562)
@@ -1419,6 +1419,9 @@
 # https://bugs.webkit.org/show_bug.cgi?id=90177
 fast/events/drag-display-none-element.html
 
+# Skip tests in fast/text/shaping
+fast/text/shaping
+
 ### END OF (4) Features that are not supported in WebKit2 and likely never will be
 ########################################
 

Modified: trunk/Source/WebCore/ChangeLog (122561 => 122562)


--- trunk/Source/WebCore/ChangeLog	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/Source/WebCore/ChangeLog	2012-07-13 11:16:50 UTC (rev 122562)
@@ -1,3 +1,59 @@
+2012-07-13  Kenichi Ishibashi  <[email protected]>
+
+        [Chromium] Fix bugs in HarfBuzzShaper
+        https://bugs.webkit.org/show_bug.cgi?id=90951
+
+        Reviewed by Tony Chang.
+
+        The current implementation has following problems:
+        - Cannot render RTL text if the TextRun is divided into more than two
+          HarfBuzzRun.
+        - Script handling in TextRun partitioning is incorrect.
+        - Inaccurate calculation of selection rect.
+        - Wrong rendering position when the first glyph of the TextRun have
+          non-zero offsets in terms of HarfBuzz.
+
+        To fix these problems I rewrote HarfBuzzShaper class. Here is the summary:
+        - Divide the whole range of TextRun first, then shape them in visual
+          order.
+        - Divide TextRun in the same way of old-harfbuzz's
+          hb_utf16_script_run_next().
+        - Prefer float than int when calculating selection.
+        - Adjust the drawing point after shaping.
+
+        Added tests covers the fix except for the last problem. The last problem will be covered
+        by fast/text/international/complex-joining-using-gpos.html after chromium linux port switches
+        to use HarfBuzzShaper.
+
+        Tests: fast/text/shaping/shaping-script-order.html
+               fast/text/shaping/shaping-selection-rect.html
+
+        * platform/graphics/harfbuzz/FontHarfBuzz.cpp:
+        (WebCore::Font::drawComplexText): Adjusts point after shaping.
+        * platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp:
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun):
+        (WebCore):
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::applyShapeResult): Added.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::setGlyphAndAdvance): Offsets are no longer needed.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::xPositionForOffset): Calculates character offset based on advance.
+        (WebCore::normalizeCharacters): Added.
+        (WebCore::HarfBuzzShaper::HarfBuzzShaper):
+        (WebCore::HarfBuzzShaper::~HarfBuzzShaper):
+        (WebCore::HarfBuzzShaper::shape): Divides TextRun first, then shapes them.
+        (WebCore::HarfBuzzShaper::adjustStartPoint): Added.
+        (WebCore::HarfBuzzShaper::collectHarfBuzzRuns): Added.
+        (WebCore::HarfBuzzShaper::shapeHarfBuzzRuns): Added.
+        (WebCore::HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun): Followed other changes.
+        (WebCore::HarfBuzzShaper::selectionRect): Use float for calculating selection.
+        * platform/graphics/harfbuzz/ng/HarfBuzzShaper.h:
+        (HarfBuzzShaper): Holds the start index of character. Removed unnecessary variables.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::create): Ditto.
+        (HarfBuzzRun):
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::fontData): Added.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::startIndex): Ditto.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::glyphs): Ditto.
+        (WebCore::HarfBuzzShaper::HarfBuzzRun::advances): Ditto.
+
 2012-07-13  Kentaro Hara  <[email protected]>
 
         Unreviewed, rolling out r122545.

Modified: trunk/Source/WebCore/platform/graphics/harfbuzz/FontHarfBuzz.cpp (122561 => 122562)


--- trunk/Source/WebCore/platform/graphics/harfbuzz/FontHarfBuzz.cpp	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/Source/WebCore/platform/graphics/harfbuzz/FontHarfBuzz.cpp	2012-07-13 11:16:50 UTC (rev 122562)
@@ -187,7 +187,8 @@
     HarfBuzzShaper shaper(this, run);
     if (!shaper.shape(&glyphBuffer))
         return;
-    drawGlyphBuffer(gc, run, glyphBuffer, point);
+    FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
+    drawGlyphBuffer(gc, run, glyphBuffer, adjustedPoint);
 #else
     SkCanvas* canvas = gc->platformContext()->canvas();
     ComplexTextController controller(this, run, point.x(), point.y());

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


--- trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp	2012-07-13 11:16:50 UTC (rev 122562)
@@ -32,6 +32,7 @@
 #include "HarfBuzzShaper.h"
 
 #include "Font.h"
+#include "HarfBuzzFace.h"
 #include "SurrogatePairAwareTextIterator.h"
 #include "TextRun.h"
 #include "hb-icu.h"
@@ -43,19 +44,47 @@
 
 namespace WebCore {
 
+template<typename T>
+class HarfBuzzScopedPtr {
+public:
+    typedef void (*DestroyFunction)(T*);
+
+    HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
+        : m_ptr(ptr)
+        , m_destroy(destroy)
+    {
+        ASSERT(m_destroy);
+    }
+    ~HarfBuzzScopedPtr()
+    {
+        if (m_ptr)
+            (*m_destroy)(m_ptr);
+    }
+
+    T* get() { return m_ptr; }
+private:
+    T* m_ptr;
+    DestroyFunction m_destroy;
+};
+
 static inline float harfbuzzPositionToFloat(hb_position_t value)
 {
     return static_cast<float>(value) / (1 << 16);
 }
 
-HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(unsigned numCharacters, TextDirection direction, hb_buffer_t* harfbuzzBuffer)
-    : m_numCharacters(numCharacters)
+HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction)
+    : m_fontData(fontData)
+    , m_startIndex(startIndex)
+    , m_numCharacters(numCharacters)
     , m_direction(direction)
 {
+}
+
+void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfbuzzBuffer)
+{
     m_numGlyphs = hb_buffer_get_length(harfbuzzBuffer);
     m_glyphs.resize(m_numGlyphs);
     m_advances.resize(m_numGlyphs);
-    m_offsets.resize(m_numGlyphs);
     m_glyphToCharacterIndex.resize(m_numGlyphs);
     m_logClusters.resize(m_numCharacters);
 
@@ -82,10 +111,9 @@
     }
 }
 
-void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float x, float y, float advance)
+void HarfBuzzShaper::HarfBuzzRun::setGlyphAndAdvance(unsigned index, uint16_t glyphId, float advance)
 {
     m_glyphs[index] = glyphId;
-    m_offsets[index].set(x, y);
     m_advances[index] = advance;
 }
 
@@ -106,31 +134,49 @@
     return rtl() ? 0 : m_numCharacters;
 }
 
-int HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
+float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
 {
     ASSERT(offset < m_numCharacters);
     unsigned glyphIndex = m_logClusters[offset];
-    ASSERT(glyphIndex < m_numGlyphs);
-    float position = m_offsets[glyphIndex].x();
+    ASSERT(glyphIndex <= m_numGlyphs);
+    float position = 0;
+    for (unsigned i = 0; i < glyphIndex; ++i)
+        position += m_advances[i];
     if (rtl())
         position += m_advances[glyphIndex];
-    return roundf(position);
+    return position;
 }
 
+static void normalizeCharacters(const UChar* source, UChar* destination, int length)
+{
+    int position = 0;
+    bool error = false;
+    while (position < length) {
+        UChar32 character;
+        int nextPosition = position;
+        U16_NEXT(source, nextPosition, length, character);
+        if (Font::treatAsSpace(character))
+            character = ' ';
+        else if (Font::treatAsZeroWidthSpaceInComplexScript(character))
+            character = zeroWidthSpace;
+        U16_APPEND(destination, position, length, character, error);
+        ASSERT_UNUSED(error, !error);
+        position = nextPosition;
+    }
+}
+
 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run)
     : HarfBuzzShaperBase(font, run)
-    , m_startIndexOfCurrentRun(0)
-    , m_numCharactersOfCurrentRun(0)
-    , m_harfbuzzBuffer(0)
 {
-    setNormalizedBuffer();
+    m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
+    m_normalizedBufferLength = m_run.length();
+    normalizeCharacters(m_run.characters(), m_normalizedBuffer.get(), m_normalizedBufferLength);
+    setPadding(m_run.expansion());
     setFontFeatures();
 }
 
 HarfBuzzShaper::~HarfBuzzShaper()
 {
-    if (m_harfbuzzBuffer)
-        hb_buffer_destroy(m_harfbuzzBuffer);
 }
 
 void HarfBuzzShaper::setFontFeatures()
@@ -152,101 +198,101 @@
 
 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
 {
+    if (!collectHarfBuzzRuns())
+        return false;
+
     m_totalWidth = 0;
-    while (setupHarfBuzzRun()) {
-        if (!shapeHarfBuzzRun())
-            return false;
-        setGlyphPositionsForHarfBuzzRun(glyphBuffer);
-    }
-
-    if (!m_harfbuzzRuns.size())
+    if (!shapeHarfBuzzRuns(glyphBuffer))
         return false;
-
+    m_totalWidth = roundf(m_totalWidth);
     return true;
 }
 
-bool HarfBuzzShaper::setupHarfBuzzRun()
+FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
 {
-    m_startIndexOfCurrentRun += m_numCharactersOfCurrentRun;
+    return point + m_startOffset;
+}
 
-    // Iterate through the text to take the largest range that stays within
-    // a single font.
-    int endOfRunIndex = m_normalizedBufferLength - m_startIndexOfCurrentRun;
-    SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get() + m_startIndexOfCurrentRun, 0, endOfRunIndex, endOfRunIndex);
+bool HarfBuzzShaper::collectHarfBuzzRuns()
+{
+    SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_normalizedBufferLength, m_normalizedBufferLength);
     UChar32 character;
     unsigned clusterLength = 0;
+    unsigned startIndexOfCurrentRun = 0;
     if (!iterator.consume(character, clusterLength))
         return false;
 
-    m_currentFontData = m_font->glyphDataForCharacter(character, false).fontData;
+    const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
     UErrorCode errorCode = U_ZERO_ERROR;
-    UScriptCode currentScript = uscript_getScript(character, &errorCode);
+    UScriptCode nextScript = uscript_getScript(character, &errorCode);
     if (U_FAILURE(errorCode))
         return false;
-    if (currentScript == USCRIPT_INHERITED)
-        currentScript = USCRIPT_COMMON;
-    for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
-        const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
-        if (nextFontData != m_currentFontData)
-            break;
-        UScriptCode nextScript = uscript_getScript(character, &errorCode);
-        if (U_FAILURE(errorCode))
-            return false;
-        if (currentScript == nextScript || nextScript == USCRIPT_INHERITED || nextScript == USCRIPT_COMMON)
-            continue;
-        if (currentScript == USCRIPT_COMMON)
-            currentScript = nextScript;
-        else
-            break;
-    }
-    m_numCharactersOfCurrentRun = iterator.currentCharacter();
 
-    if (!m_harfbuzzBuffer) {
-        m_harfbuzzBuffer = hb_buffer_create();
-        hb_buffer_set_unicode_funcs(m_harfbuzzBuffer, hb_icu_get_unicode_funcs());
-    } else
-        hb_buffer_reset(m_harfbuzzBuffer);
-    hb_buffer_set_script(m_harfbuzzBuffer, hb_icu_script_to_script(currentScript));
+    do {
+        const SimpleFontData* currentFontData = nextFontData;
+        UScriptCode currentScript = nextScript;
 
-    // WebKit always sets direction to LTR during width calculation.
-    // We only set direction when direction is explicitly set to RTL so that
-    // preventng wrong width calculation.
-    if (m_run.rtl())
-        hb_buffer_set_direction(m_harfbuzzBuffer, HB_DIRECTION_RTL);
+        for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
+            nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
+            if (nextFontData != currentFontData)
+                break;
+            nextScript = uscript_getScript(character, &errorCode);
+            if (U_FAILURE(errorCode))
+                return false;
+            if ((currentScript != nextScript) && (currentScript != USCRIPT_INHERITED))
+                break;
+        }
+        unsigned numCharactersOfCurrentRun = iterator.currentCharacter() - startIndexOfCurrentRun;
+        m_harfbuzzRuns.append(HarfBuzzRun::create(currentFontData, startIndexOfCurrentRun, numCharactersOfCurrentRun, m_run.direction()));
+        currentFontData = nextFontData;
+        startIndexOfCurrentRun = iterator.currentCharacter();
+    } while (iterator.consume(character, clusterLength));
 
-    // Determine whether this run needs to be converted to small caps.
-    // nextScriptRun() will always send us a run of the same case, because a
-    // case change while in small-caps mode always results in different
-    // FontData, so we only need to check the first character's case.
-    if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[m_startIndexOfCurrentRun])) {
-        String upperText = String(m_normalizedBuffer.get() + m_startIndexOfCurrentRun, m_numCharactersOfCurrentRun);
-        upperText.makeUpper();
-        m_currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
-        hb_buffer_add_utf16(m_harfbuzzBuffer, upperText.characters(), m_numCharactersOfCurrentRun, 0, m_numCharactersOfCurrentRun);
-    } else
-        hb_buffer_add_utf16(m_harfbuzzBuffer, m_normalizedBuffer.get() + m_startIndexOfCurrentRun, m_numCharactersOfCurrentRun, 0, m_numCharactersOfCurrentRun);
-
-    return true;
+    return !m_harfbuzzRuns.isEmpty();
 }
 
-bool HarfBuzzShaper::shapeHarfBuzzRun()
+bool HarfBuzzShaper::shapeHarfBuzzRuns(GlyphBuffer* glyphBuffer)
 {
-    FontPlatformData* platformData = const_cast<FontPlatformData*>(&m_currentFontData->platformData());
-    HarfBuzzFace* face = platformData->harfbuzzFace();
-    if (!face)
-        return false;
-    hb_font_t* harfbuzzFont = face->createFont();
-    hb_shape(harfbuzzFont, m_harfbuzzBuffer, m_features.size() > 0 ? m_features.data() : 0, m_features.size());
-    hb_font_destroy(harfbuzzFont);
-    m_harfbuzzRuns.append(HarfBuzzRun::create(m_numCharactersOfCurrentRun, m_run.direction(), m_harfbuzzBuffer));
+    HarfBuzzScopedPtr<hb_buffer_t> harfbuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
+    hb_buffer_set_unicode_funcs(harfbuzzBuffer.get(), hb_icu_get_unicode_funcs());
+    if (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) {
+        unsigned runIndex = m_run.rtl() ? m_harfbuzzRuns.size() - i - 1 : i;
+        HarfBuzzRun* currentRun = m_harfbuzzRuns[runIndex].get();
+        const SimpleFontData* currentFontData = currentRun->fontData();
+
+        if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
+            String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters());
+            upperText.makeUpper();
+            currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
+            hb_buffer_add_utf16(harfbuzzBuffer.get(), upperText.characters(), currentRun->numCharacters(), 0, currentRun->numCharacters());
+        } else
+            hb_buffer_add_utf16(harfbuzzBuffer.get(), m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters(), 0, currentRun->numCharacters());
+
+        FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentFontData->platformData());
+        HarfBuzzFace* face = platformData->harfbuzzFace();
+        if (!face)
+            return false;
+        HarfBuzzScopedPtr<hb_font_t> harfbuzzFont(face->createFont(), hb_font_destroy);
+        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);
+
+        hb_buffer_reset(harfbuzzBuffer.get());
+        if (m_run.directionalOverride())
+            hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+    }
     return true;
 }
 
-void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(GlyphBuffer* glyphBuffer)
+void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, unsigned runIndexInVisualOrder, hb_buffer_t* harfbuzzBuffer, GlyphBuffer* glyphBuffer)
 {
-    hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(m_harfbuzzBuffer, 0);
-    hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(m_harfbuzzBuffer, 0);
-    HarfBuzzRun* currentRun = m_harfbuzzRuns.last().get();
+    const SimpleFontData* currentFontData = currentRun->fontData();
+    hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfbuzzBuffer, 0);
+    hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfbuzzBuffer, 0);
 
     unsigned numGlyphs = currentRun->numGlyphs();
     float totalAdvance = 0;
@@ -262,26 +308,29 @@
         nextOffsetX = runEnd ? 0 : harfbuzzPositionToFloat(glyphPositions[i + 1].x_offset);
         nextOffsetY = runEnd ? 0 : -harfbuzzPositionToFloat(glyphPositions[i + 1].y_offset);
 
-        unsigned currentCharacterIndex = m_startIndexOfCurrentRun + glyphInfos[i].cluster;
+        unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
         bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
         float spacing = isClusterEnd ? m_letterSpacing : 0;
 
         if (isClusterEnd && isWordEnd(currentCharacterIndex))
             spacing += determineWordBreakSpacing();
 
-        if (m_currentFontData->isZeroWidthSpaceGlyph(glyph)) {
-            currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
+        if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
+            currentRun->setGlyphAndAdvance(i, glyph, 0);
             if (glyphBuffer)
-                glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(0, 0));
+                glyphBuffer->add(glyph, currentFontData, createGlyphBufferAdvance(0, 0));
             continue;
         }
 
         advance += spacing;
-        currentRun->setGlyphAndPositions(i, glyph, totalAdvance + offsetX, offsetY, advance);
+
+        currentRun->setGlyphAndAdvance(i, glyph, advance);
         if (glyphBuffer) {
+            if (!i && !runIndexInVisualOrder)
+                m_startOffset.set(offsetX, offsetY);
             float glyphAdvanceX = advance + nextOffsetX - offsetX;
             float glyphAdvanceY = nextOffsetY - offsetY;
-            glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
+            glyphBuffer->add(glyph, currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
         }
 
         totalAdvance += advance;
@@ -324,37 +373,46 @@
 
 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
 {
-    int fromX = -1, toX = -1;
-    int currentX = 0;
-    // Iterate through the script runs in logical order, searching for the run covering the positions of interest.
+    float currentX = 0;
+    float fromX;
+    float toX;
+    bool foundFromX = false;
+    bool foundToX = false;
+
+    if (m_run.rtl())
+        currentX = m_totalWidth;
     for (unsigned i = 0; i < m_harfbuzzRuns.size(); ++i) {
+        if (m_run.rtl())
+            currentX -= m_harfbuzzRuns[i]->width();
         int numCharacters = m_harfbuzzRuns[i]->numCharacters();
-        if (fromX == -1 && from >= 0 && from < numCharacters)
+        if (!foundFromX && from >= 0 && from < numCharacters) {
             fromX = m_harfbuzzRuns[i]->xPositionForOffset(from) + currentX;
-        else
+            foundFromX = true;
+        } else
             from -= numCharacters;
 
-        if (toX == -1 && to >= 0 && to < numCharacters)
+        if (!foundToX && to >= 0 && to < numCharacters) {
             toX = m_harfbuzzRuns[i]->xPositionForOffset(to) + currentX;
-        else
+            foundToX = true;
+        } else
             to -= numCharacters;
 
-        if (fromX != -1 && toX != -1)
+        if (foundFromX && foundToX)
             break;
-        currentX += m_harfbuzzRuns[i]->width();
+        if (!m_run.rtl())
+            currentX += m_harfbuzzRuns[i]->width();
     }
 
     // The position in question might be just after the text.
-    if (fromX == -1)
+    if (!foundFromX)
         fromX = 0;
-    if (toX == -1)
+    if (!foundToX)
         toX = m_run.rtl() ? 0 : m_totalWidth;
 
-    ASSERT(fromX != -1 && toX != -1);
-
+    // Using floorf() and roundf() as the same as mac port.
     if (fromX < toX)
-        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
-    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
+        return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height);
+    return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height);
 }
 
 } // namespace WebCore

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


--- trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h	2012-07-13 11:03:08 UTC (rev 122561)
+++ trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h	2012-07-13 11:16:50 UTC (rev 122562)
@@ -52,6 +52,7 @@
     virtual ~HarfBuzzShaper();
 
     bool shape(GlyphBuffer* = 0);
+    FloatPoint adjustStartPoint(const FloatPoint&);
     float totalWidth() { return m_totalWidth; }
     int offsetForPosition(float targetX);
     FloatRect selectionRect(const FloatPoint&, int height, int from, int to);
@@ -59,31 +60,37 @@
 private:
     class HarfBuzzRun {
     public:
-        static PassOwnPtr<HarfBuzzRun> create(unsigned numCharacters, TextDirection direction, hb_buffer_t* buffer)
+        static PassOwnPtr<HarfBuzzRun> create(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction)
         {
-            return adoptPtr(new HarfBuzzRun(numCharacters, direction, buffer));
+            return adoptPtr(new HarfBuzzRun(fontData, startIndex, numCharacters, direction));
         }
 
-        void setGlyphAndPositions(unsigned index, uint16_t glyphId, float x, float y, float);
+        void applyShapeResult(hb_buffer_t*);
+        void setGlyphAndAdvance(unsigned index, uint16_t glyphId, float advance);
         void setWidth(float width) { m_width = width; }
 
         int characterIndexForXPosition(int targetX);
-        int xPositionForOffset(unsigned offset);
+        float xPositionForOffset(unsigned offset);
 
+        const SimpleFontData* fontData() { return m_fontData; }
+        unsigned startIndex() const { return m_startIndex; }
         unsigned numCharacters() const { return m_numCharacters; }
         unsigned numGlyphs() const { return m_numGlyphs; }
+        uint16_t* glyphs() { return &m_glyphs[0]; }
+        float* advances() { return &m_advances[0]; }
         float width() { return m_width; }
 
     private:
-        HarfBuzzRun(unsigned numCharacters, TextDirection, hb_buffer_t*);
+        HarfBuzzRun(const SimpleFontData*, unsigned startIndex, unsigned numCharacters, TextDirection);
         bool rtl() { return m_direction == RTL; }
 
+        const SimpleFontData* m_fontData;
+        unsigned m_startIndex;
         size_t m_numCharacters;
         unsigned m_numGlyphs;
         TextDirection m_direction;
         Vector<uint16_t, 256> m_glyphs;
         Vector<float, 256> m_advances;
-        Vector<FloatPoint, 256> m_offsets;
         Vector<uint16_t, 256> m_logClusters;
         Vector<uint16_t, 256> m_glyphToCharacterIndex;
         float m_width;
@@ -91,19 +98,17 @@
 
     void setFontFeatures();
 
-    bool setupHarfBuzzRun();
-    bool shapeHarfBuzzRun();
-    void setGlyphPositionsForHarfBuzzRun(GlyphBuffer*);
+    bool collectHarfBuzzRuns();
+    bool shapeHarfBuzzRuns(GlyphBuffer*);
+    void setGlyphPositionsForHarfBuzzRun(HarfBuzzRun*, unsigned runIndexInVisualOrder, hb_buffer_t*, GlyphBuffer*);
 
     GlyphBufferAdvance createGlyphBufferAdvance(float, float);
 
     Vector<hb_feature_t, 4> m_features;
-    unsigned m_startIndexOfCurrentRun;
-    unsigned m_numCharactersOfCurrentRun;
-    const SimpleFontData* m_currentFontData;
-    hb_buffer_t* m_harfbuzzBuffer;
     Vector<OwnPtr<HarfBuzzRun>, 16> m_harfbuzzRuns;
 
+    FloatPoint m_startOffset;
+
     float m_totalWidth;
 };
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to