Changeset 122562 in webkit


Ignore:
Timestamp:
Jul 13, 2012 4:16:50 AM (12 years ago)
Author:
bashi@chromium.org
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.
Location:
trunk
Files:
3 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r122558 r122562  
     12012-07-13  Kenichi Ishibashi  <bashi@chromium.org>
     2
     3        [Chromium] Fix bugs in HarfBuzzShaper
     4        https://bugs.webkit.org/show_bug.cgi?id=90951
     5
     6        Reviewed by Tony Chang.
     7
     8        Add tests for harfbuzz-ng shaper. I tried to use -expected.html style expectations,
     9        but it didn't work because there are very slight difference between CoreText and HarfBuzz in
     10        rendering result.
     11
     12        * fast/text/shaping/shaping-script-order.html: Added.
     13        * fast/text/shaping/shaping-selection-rect.html: Added.
     14        * platform/chromium/TestExpectations: Need rebaseline.
     15        * platform/efl/TestExpectations: Skip added tests because the port doesn't use harfbuzz.
     16        * platform/gtk/TestExpectations: Ditto.
     17        * platform/mac/TestExpectations: Ditto.
     18        * platform/qt/TestExpectations: Ditto.
     19        * platform/win/Skipped: Ditto.
     20        * platform/wincairo/Skipped: Ditto.
     21        * platform/wk2/Skipped: Ditto.
     22
    1232012-07-13  Kent Tamura  <tkent@chromium.org>
    224
  • trunk/LayoutTests/platform/chromium/TestExpectations

    r122558 r122562  
    37493749// Started crashing after 122286
    37503750BUGWK91133 WIN : storage/indexeddb/constants.html = PASS CRASH
     3751
     3752// Need rebaseline
     3753BUGWK90951 : fast/text/shaping/shaping-selection-rect.html = MISSING
     3754BUGWK90951 : fast/text/shaping/shaping-script-order.html = MISSING
  • trunk/LayoutTests/platform/efl/TestExpectations

    r122420 r122562  
    739739// Looks like missing multipart/x-mixed-replace support in libsoup. Failing on both GTK and EFL.
    740740BUGWK68979 : http/tests/multipart/multipart-replace-non-html-content.php = TEXT
     741
     742// Skip tests in fast/text/shaping
     743BUGWK90951 SKIP : fast/text/shaping = PASS
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r122467 r122562  
    12551255BUGWK91009 DEBUG : fast/xsl/xslt-missing-namespace-in-xslt.xml = TEXT
    12561256
     1257// Skip tests in fast/text/shaping
     1258BUGWK90951 SKIP : fast/text/shaping = PASS
     1259
    12571260//////////////////////////////////////////////////////////////////////////////////////////
    12581261// End of Tests failing
  • trunk/LayoutTests/platform/mac/TestExpectations

    r122495 r122562  
    296296// INPUT_TYPE_DATE is not enabled on the Mac
    297297BUGWK90987 : fast/forms/input-in-table-cell-no-value.html = IMAGE
     298
     299// Skip tests in fast/text/shaping
     300BUGWK90951 SKIP : fast/text/shaping = PASS
  • trunk/LayoutTests/platform/qt/TestExpectations

    r122420 r122562  
    114114// Dialog element is not yet enabled.
    115115BUGWK84635 SKIP : fast/dom/HTMLDialogElement = TEXT
     116
     117// Skip tests in fast/text/shaping
     118BUGWK90951 SKIP : fast/text/shaping = PASS
  • trunk/LayoutTests/platform/win/Skipped

    r122528 r122562  
    19451945# https://bugs.webkit.org/show_bug.cgi?id=85558
    19461946http/tests/security/contentSecurityPolicy/1.1
     1947
     1948# Skip tests in fast/text/shaping
     1949fast/text/shaping
  • trunk/LayoutTests/platform/wincairo/Skipped

    r122528 r122562  
    21272127# https://bugs.webkit.org/show_bug.cgi?id=85558
    21282128http/tests/security/contentSecurityPolicy/1.1
     2129
     2130# Skip tests in fast/text/shaping
     2131fast/text/shaping
  • trunk/LayoutTests/platform/wk2/Skipped

    r122473 r122562  
    14201420fast/events/drag-display-none-element.html
    14211421
     1422# Skip tests in fast/text/shaping
     1423fast/text/shaping
     1424
    14221425### END OF (4) Features that are not supported in WebKit2 and likely never will be
    14231426########################################
  • trunk/Source/WebCore/ChangeLog

    r122561 r122562  
     12012-07-13  Kenichi Ishibashi  <bashi@chromium.org>
     2
     3        [Chromium] Fix bugs in HarfBuzzShaper
     4        https://bugs.webkit.org/show_bug.cgi?id=90951
     5
     6        Reviewed by Tony Chang.
     7
     8        The current implementation has following problems:
     9        - Cannot render RTL text if the TextRun is divided into more than two
     10          HarfBuzzRun.
     11        - Script handling in TextRun partitioning is incorrect.
     12        - Inaccurate calculation of selection rect.
     13        - Wrong rendering position when the first glyph of the TextRun have
     14          non-zero offsets in terms of HarfBuzz.
     15
     16        To fix these problems I rewrote HarfBuzzShaper class. Here is the summary:
     17        - Divide the whole range of TextRun first, then shape them in visual
     18          order.
     19        - Divide TextRun in the same way of old-harfbuzz's
     20          hb_utf16_script_run_next().
     21        - Prefer float than int when calculating selection.
     22        - Adjust the drawing point after shaping.
     23
     24        Added tests covers the fix except for the last problem. The last problem will be covered
     25        by fast/text/international/complex-joining-using-gpos.html after chromium linux port switches
     26        to use HarfBuzzShaper.
     27
     28        Tests: fast/text/shaping/shaping-script-order.html
     29               fast/text/shaping/shaping-selection-rect.html
     30
     31        * platform/graphics/harfbuzz/FontHarfBuzz.cpp:
     32        (WebCore::Font::drawComplexText): Adjusts point after shaping.
     33        * platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp:
     34        (WebCore::HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun):
     35        (WebCore):
     36        (WebCore::HarfBuzzShaper::HarfBuzzRun::applyShapeResult): Added.
     37        (WebCore::HarfBuzzShaper::HarfBuzzRun::setGlyphAndAdvance): Offsets are no longer needed.
     38        (WebCore::HarfBuzzShaper::HarfBuzzRun::xPositionForOffset): Calculates character offset based on advance.
     39        (WebCore::normalizeCharacters): Added.
     40        (WebCore::HarfBuzzShaper::HarfBuzzShaper):
     41        (WebCore::HarfBuzzShaper::~HarfBuzzShaper):
     42        (WebCore::HarfBuzzShaper::shape): Divides TextRun first, then shapes them.
     43        (WebCore::HarfBuzzShaper::adjustStartPoint): Added.
     44        (WebCore::HarfBuzzShaper::collectHarfBuzzRuns): Added.
     45        (WebCore::HarfBuzzShaper::shapeHarfBuzzRuns): Added.
     46        (WebCore::HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun): Followed other changes.
     47        (WebCore::HarfBuzzShaper::selectionRect): Use float for calculating selection.
     48        * platform/graphics/harfbuzz/ng/HarfBuzzShaper.h:
     49        (HarfBuzzShaper): Holds the start index of character. Removed unnecessary variables.
     50        (WebCore::HarfBuzzShaper::HarfBuzzRun::create): Ditto.
     51        (HarfBuzzRun):
     52        (WebCore::HarfBuzzShaper::HarfBuzzRun::fontData): Added.
     53        (WebCore::HarfBuzzShaper::HarfBuzzRun::startIndex): Ditto.
     54        (WebCore::HarfBuzzShaper::HarfBuzzRun::glyphs): Ditto.
     55        (WebCore::HarfBuzzShaper::HarfBuzzRun::advances): Ditto.
     56
    1572012-07-13  Kentaro Hara  <haraken@chromium.org>
    258
  • trunk/Source/WebCore/platform/graphics/harfbuzz/FontHarfBuzz.cpp

    r122310 r122562  
    188188    if (!shaper.shape(&glyphBuffer))
    189189        return;
    190     drawGlyphBuffer(gc, run, glyphBuffer, point);
     190    FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
     191    drawGlyphBuffer(gc, run, glyphBuffer, adjustedPoint);
    191192#else
    192193    SkCanvas* canvas = gc->platformContext()->canvas();
  • trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.cpp

    r120156 r122562  
    3333
    3434#include "Font.h"
     35#include "HarfBuzzFace.h"
    3536#include "SurrogatePairAwareTextIterator.h"
    3637#include "TextRun.h"
     
    4445namespace WebCore {
    4546
     47template<typename T>
     48class HarfBuzzScopedPtr {
     49public:
     50    typedef void (*DestroyFunction)(T*);
     51
     52    HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
     53        : m_ptr(ptr)
     54        , m_destroy(destroy)
     55    {
     56        ASSERT(m_destroy);
     57    }
     58    ~HarfBuzzScopedPtr()
     59    {
     60        if (m_ptr)
     61            (*m_destroy)(m_ptr);
     62    }
     63
     64    T* get() { return m_ptr; }
     65private:
     66    T* m_ptr;
     67    DestroyFunction m_destroy;
     68};
     69
    4670static inline float harfbuzzPositionToFloat(hb_position_t value)
    4771{
     
    4973}
    5074
    51 HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(unsigned numCharacters, TextDirection direction, hb_buffer_t* harfbuzzBuffer)
    52     : m_numCharacters(numCharacters)
     75HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction)
     76    : m_fontData(fontData)
     77    , m_startIndex(startIndex)
     78    , m_numCharacters(numCharacters)
    5379    , m_direction(direction)
     80{
     81}
     82
     83void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfbuzzBuffer)
    5484{
    5585    m_numGlyphs = hb_buffer_get_length(harfbuzzBuffer);
    5686    m_glyphs.resize(m_numGlyphs);
    5787    m_advances.resize(m_numGlyphs);
    58     m_offsets.resize(m_numGlyphs);
    5988    m_glyphToCharacterIndex.resize(m_numGlyphs);
    6089    m_logClusters.resize(m_numCharacters);
     
    83112}
    84113
    85 void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float x, float y, float advance)
     114void HarfBuzzShaper::HarfBuzzRun::setGlyphAndAdvance(unsigned index, uint16_t glyphId, float advance)
    86115{
    87116    m_glyphs[index] = glyphId;
    88     m_offsets[index].set(x, y);
    89117    m_advances[index] = advance;
    90118}
     
    107135}
    108136
    109 int HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
     137float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
    110138{
    111139    ASSERT(offset < m_numCharacters);
    112140    unsigned glyphIndex = m_logClusters[offset];
    113     ASSERT(glyphIndex < m_numGlyphs);
    114     float position = m_offsets[glyphIndex].x();
     141    ASSERT(glyphIndex <= m_numGlyphs);
     142    float position = 0;
     143    for (unsigned i = 0; i < glyphIndex; ++i)
     144        position += m_advances[i];
    115145    if (rtl())
    116146        position += m_advances[glyphIndex];
    117     return roundf(position);
     147    return position;
     148}
     149
     150static void normalizeCharacters(const UChar* source, UChar* destination, int length)
     151{
     152    int position = 0;
     153    bool error = false;
     154    while (position < length) {
     155        UChar32 character;
     156        int nextPosition = position;
     157        U16_NEXT(source, nextPosition, length, character);
     158        if (Font::treatAsSpace(character))
     159            character = ' ';
     160        else if (Font::treatAsZeroWidthSpaceInComplexScript(character))
     161            character = zeroWidthSpace;
     162        U16_APPEND(destination, position, length, character, error);
     163        ASSERT_UNUSED(error, !error);
     164        position = nextPosition;
     165    }
    118166}
    119167
    120168HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run)
    121169    : HarfBuzzShaperBase(font, run)
    122     , m_startIndexOfCurrentRun(0)
    123     , m_numCharactersOfCurrentRun(0)
    124     , m_harfbuzzBuffer(0)
    125 {
    126     setNormalizedBuffer();
     170{
     171    m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
     172    m_normalizedBufferLength = m_run.length();
     173    normalizeCharacters(m_run.characters(), m_normalizedBuffer.get(), m_normalizedBufferLength);
     174    setPadding(m_run.expansion());
    127175    setFontFeatures();
    128176}
     
    130178HarfBuzzShaper::~HarfBuzzShaper()
    131179{
    132     if (m_harfbuzzBuffer)
    133         hb_buffer_destroy(m_harfbuzzBuffer);
    134180}
    135181
     
    153199bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
    154200{
     201    if (!collectHarfBuzzRuns())
     202        return false;
     203
    155204    m_totalWidth = 0;
    156     while (setupHarfBuzzRun()) {
    157         if (!shapeHarfBuzzRun())
    158             return false;
    159         setGlyphPositionsForHarfBuzzRun(glyphBuffer);
    160     }
    161 
    162     if (!m_harfbuzzRuns.size())
     205    if (!shapeHarfBuzzRuns(glyphBuffer))
    163206        return false;
    164 
     207    m_totalWidth = roundf(m_totalWidth);
    165208    return true;
    166209}
    167210
    168 bool HarfBuzzShaper::setupHarfBuzzRun()
    169 {
    170     m_startIndexOfCurrentRun += m_numCharactersOfCurrentRun;
    171 
    172     // Iterate through the text to take the largest range that stays within
    173     // a single font.
    174     int endOfRunIndex = m_normalizedBufferLength - m_startIndexOfCurrentRun;
    175     SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get() + m_startIndexOfCurrentRun, 0, endOfRunIndex, endOfRunIndex);
     211FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
     212{
     213    return point + m_startOffset;
     214}
     215
     216bool HarfBuzzShaper::collectHarfBuzzRuns()
     217{
     218    SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_normalizedBufferLength, m_normalizedBufferLength);
    176219    UChar32 character;
    177220    unsigned clusterLength = 0;
     221    unsigned startIndexOfCurrentRun = 0;
    178222    if (!iterator.consume(character, clusterLength))
    179223        return false;
    180224
    181     m_currentFontData = m_font->glyphDataForCharacter(character, false).fontData;
     225    const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
    182226    UErrorCode errorCode = U_ZERO_ERROR;
    183     UScriptCode currentScript = uscript_getScript(character, &errorCode);
     227    UScriptCode nextScript = uscript_getScript(character, &errorCode);
    184228    if (U_FAILURE(errorCode))
    185229        return false;
    186     if (currentScript == USCRIPT_INHERITED)
    187         currentScript = USCRIPT_COMMON;
    188     for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
    189         const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
    190         if (nextFontData != m_currentFontData)
    191             break;
    192         UScriptCode nextScript = uscript_getScript(character, &errorCode);
    193         if (U_FAILURE(errorCode))
     230
     231    do {
     232        const SimpleFontData* currentFontData = nextFontData;
     233        UScriptCode currentScript = nextScript;
     234
     235        for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
     236            nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
     237            if (nextFontData != currentFontData)
     238                break;
     239            nextScript = uscript_getScript(character, &errorCode);
     240            if (U_FAILURE(errorCode))
     241                return false;
     242            if ((currentScript != nextScript) && (currentScript != USCRIPT_INHERITED))
     243                break;
     244        }
     245        unsigned numCharactersOfCurrentRun = iterator.currentCharacter() - startIndexOfCurrentRun;
     246        m_harfbuzzRuns.append(HarfBuzzRun::create(currentFontData, startIndexOfCurrentRun, numCharactersOfCurrentRun, m_run.direction()));
     247        currentFontData = nextFontData;
     248        startIndexOfCurrentRun = iterator.currentCharacter();
     249    } while (iterator.consume(character, clusterLength));
     250
     251    return !m_harfbuzzRuns.isEmpty();
     252}
     253
     254bool HarfBuzzShaper::shapeHarfBuzzRuns(GlyphBuffer* glyphBuffer)
     255{
     256    HarfBuzzScopedPtr<hb_buffer_t> harfbuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
     257    hb_buffer_set_unicode_funcs(harfbuzzBuffer.get(), hb_icu_get_unicode_funcs());
     258    if (m_run.directionalOverride())
     259        hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
     260
     261    for (unsigned i = 0; i < m_harfbuzzRuns.size(); ++i) {
     262        unsigned runIndex = m_run.rtl() ? m_harfbuzzRuns.size() - i - 1 : i;
     263        HarfBuzzRun* currentRun = m_harfbuzzRuns[runIndex].get();
     264        const SimpleFontData* currentFontData = currentRun->fontData();
     265
     266        if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
     267            String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters());
     268            upperText.makeUpper();
     269            currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
     270            hb_buffer_add_utf16(harfbuzzBuffer.get(), upperText.characters(), currentRun->numCharacters(), 0, currentRun->numCharacters());
     271        } else
     272            hb_buffer_add_utf16(harfbuzzBuffer.get(), m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters(), 0, currentRun->numCharacters());
     273
     274        FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentFontData->platformData());
     275        HarfBuzzFace* face = platformData->harfbuzzFace();
     276        if (!face)
    194277            return false;
    195         if (currentScript == nextScript || nextScript == USCRIPT_INHERITED || nextScript == USCRIPT_COMMON)
    196             continue;
    197         if (currentScript == USCRIPT_COMMON)
    198             currentScript = nextScript;
    199         else
    200             break;
    201     }
    202     m_numCharactersOfCurrentRun = iterator.currentCharacter();
    203 
    204     if (!m_harfbuzzBuffer) {
    205         m_harfbuzzBuffer = hb_buffer_create();
    206         hb_buffer_set_unicode_funcs(m_harfbuzzBuffer, hb_icu_get_unicode_funcs());
    207     } else
    208         hb_buffer_reset(m_harfbuzzBuffer);
    209     hb_buffer_set_script(m_harfbuzzBuffer, hb_icu_script_to_script(currentScript));
    210 
    211     // WebKit always sets direction to LTR during width calculation.
    212     // We only set direction when direction is explicitly set to RTL so that
    213     // preventng wrong width calculation.
    214     if (m_run.rtl())
    215         hb_buffer_set_direction(m_harfbuzzBuffer, HB_DIRECTION_RTL);
    216 
    217     // Determine whether this run needs to be converted to small caps.
    218     // nextScriptRun() will always send us a run of the same case, because a
    219     // case change while in small-caps mode always results in different
    220     // FontData, so we only need to check the first character's case.
    221     if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[m_startIndexOfCurrentRun])) {
    222         String upperText = String(m_normalizedBuffer.get() + m_startIndexOfCurrentRun, m_numCharactersOfCurrentRun);
    223         upperText.makeUpper();
    224         m_currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
    225         hb_buffer_add_utf16(m_harfbuzzBuffer, upperText.characters(), m_numCharactersOfCurrentRun, 0, m_numCharactersOfCurrentRun);
    226     } else
    227         hb_buffer_add_utf16(m_harfbuzzBuffer, m_normalizedBuffer.get() + m_startIndexOfCurrentRun, m_numCharactersOfCurrentRun, 0, m_numCharactersOfCurrentRun);
    228 
     278        HarfBuzzScopedPtr<hb_font_t> harfbuzzFont(face->createFont(), hb_font_destroy);
     279        hb_shape(harfbuzzFont.get(), harfbuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
     280
     281        currentRun->applyShapeResult(harfbuzzBuffer.get());
     282        setGlyphPositionsForHarfBuzzRun(currentRun, i, harfbuzzBuffer.get(), glyphBuffer);
     283
     284        hb_buffer_reset(harfbuzzBuffer.get());
     285        if (m_run.directionalOverride())
     286            hb_buffer_set_direction(harfbuzzBuffer.get(), m_run.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
     287    }
    229288    return true;
    230289}
    231290
    232 bool HarfBuzzShaper::shapeHarfBuzzRun()
    233 {
    234     FontPlatformData* platformData = const_cast<FontPlatformData*>(&m_currentFontData->platformData());
    235     HarfBuzzFace* face = platformData->harfbuzzFace();
    236     if (!face)
    237         return false;
    238     hb_font_t* harfbuzzFont = face->createFont();
    239     hb_shape(harfbuzzFont, m_harfbuzzBuffer, m_features.size() > 0 ? m_features.data() : 0, m_features.size());
    240     hb_font_destroy(harfbuzzFont);
    241     m_harfbuzzRuns.append(HarfBuzzRun::create(m_numCharactersOfCurrentRun, m_run.direction(), m_harfbuzzBuffer));
    242     return true;
    243 }
    244 
    245 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(GlyphBuffer* glyphBuffer)
    246 {
    247     hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(m_harfbuzzBuffer, 0);
    248     hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(m_harfbuzzBuffer, 0);
    249     HarfBuzzRun* currentRun = m_harfbuzzRuns.last().get();
     291void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, unsigned runIndexInVisualOrder, hb_buffer_t* harfbuzzBuffer, GlyphBuffer* glyphBuffer)
     292{
     293    const SimpleFontData* currentFontData = currentRun->fontData();
     294    hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfbuzzBuffer, 0);
     295    hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfbuzzBuffer, 0);
    250296
    251297    unsigned numGlyphs = currentRun->numGlyphs();
     
    263309        nextOffsetY = runEnd ? 0 : -harfbuzzPositionToFloat(glyphPositions[i + 1].y_offset);
    264310
    265         unsigned currentCharacterIndex = m_startIndexOfCurrentRun + glyphInfos[i].cluster;
     311        unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
    266312        bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
    267313        float spacing = isClusterEnd ? m_letterSpacing : 0;
     
    270316            spacing += determineWordBreakSpacing();
    271317
    272         if (m_currentFontData->isZeroWidthSpaceGlyph(glyph)) {
    273             currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
     318        if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
     319            currentRun->setGlyphAndAdvance(i, glyph, 0);
    274320            if (glyphBuffer)
    275                 glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(0, 0));
     321                glyphBuffer->add(glyph, currentFontData, createGlyphBufferAdvance(0, 0));
    276322            continue;
    277323        }
    278324
    279325        advance += spacing;
    280         currentRun->setGlyphAndPositions(i, glyph, totalAdvance + offsetX, offsetY, advance);
     326
     327        currentRun->setGlyphAndAdvance(i, glyph, advance);
    281328        if (glyphBuffer) {
     329            if (!i && !runIndexInVisualOrder)
     330                m_startOffset.set(offsetX, offsetY);
    282331            float glyphAdvanceX = advance + nextOffsetX - offsetX;
    283332            float glyphAdvanceY = nextOffsetY - offsetY;
    284             glyphBuffer->add(glyph, m_currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
     333            glyphBuffer->add(glyph, currentFontData, createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
    285334        }
    286335
     
    325374FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
    326375{
    327     int fromX = -1, toX = -1;
    328     int currentX = 0;
    329     // Iterate through the script runs in logical order, searching for the run covering the positions of interest.
     376    float currentX = 0;
     377    float fromX;
     378    float toX;
     379    bool foundFromX = false;
     380    bool foundToX = false;
     381
     382    if (m_run.rtl())
     383        currentX = m_totalWidth;
    330384    for (unsigned i = 0; i < m_harfbuzzRuns.size(); ++i) {
     385        if (m_run.rtl())
     386            currentX -= m_harfbuzzRuns[i]->width();
    331387        int numCharacters = m_harfbuzzRuns[i]->numCharacters();
    332         if (fromX == -1 && from >= 0 && from < numCharacters)
     388        if (!foundFromX && from >= 0 && from < numCharacters) {
    333389            fromX = m_harfbuzzRuns[i]->xPositionForOffset(from) + currentX;
    334         else
     390            foundFromX = true;
     391        } else
    335392            from -= numCharacters;
    336393
    337         if (toX == -1 && to >= 0 && to < numCharacters)
     394        if (!foundToX && to >= 0 && to < numCharacters) {
    338395            toX = m_harfbuzzRuns[i]->xPositionForOffset(to) + currentX;
    339         else
     396            foundToX = true;
     397        } else
    340398            to -= numCharacters;
    341399
    342         if (fromX != -1 && toX != -1)
     400        if (foundFromX && foundToX)
    343401            break;
    344         currentX += m_harfbuzzRuns[i]->width();
     402        if (!m_run.rtl())
     403            currentX += m_harfbuzzRuns[i]->width();
    345404    }
    346405
    347406    // The position in question might be just after the text.
    348     if (fromX == -1)
     407    if (!foundFromX)
    349408        fromX = 0;
    350     if (toX == -1)
     409    if (!foundToX)
    351410        toX = m_run.rtl() ? 0 : m_totalWidth;
    352411
    353     ASSERT(fromX != -1 && toX != -1);
    354 
     412    // Using floorf() and roundf() as the same as mac port.
    355413    if (fromX < toX)
    356         return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
    357     return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
     414        return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height);
     415    return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height);
    358416}
    359417
  • trunk/Source/WebCore/platform/graphics/harfbuzz/ng/HarfBuzzShaper.h

    r120156 r122562  
    5353
    5454    bool shape(GlyphBuffer* = 0);
     55    FloatPoint adjustStartPoint(const FloatPoint&);
    5556    float totalWidth() { return m_totalWidth; }
    5657    int offsetForPosition(float targetX);
     
    6061    class HarfBuzzRun {
    6162    public:
    62         static PassOwnPtr<HarfBuzzRun> create(unsigned numCharacters, TextDirection direction, hb_buffer_t* buffer)
     63        static PassOwnPtr<HarfBuzzRun> create(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction)
    6364        {
    64             return adoptPtr(new HarfBuzzRun(numCharacters, direction, buffer));
     65            return adoptPtr(new HarfBuzzRun(fontData, startIndex, numCharacters, direction));
    6566        }
    6667
    67         void setGlyphAndPositions(unsigned index, uint16_t glyphId, float x, float y, float);
     68        void applyShapeResult(hb_buffer_t*);
     69        void setGlyphAndAdvance(unsigned index, uint16_t glyphId, float advance);
    6870        void setWidth(float width) { m_width = width; }
    6971
    7072        int characterIndexForXPosition(int targetX);
    71         int xPositionForOffset(unsigned offset);
     73        float xPositionForOffset(unsigned offset);
    7274
     75        const SimpleFontData* fontData() { return m_fontData; }
     76        unsigned startIndex() const { return m_startIndex; }
    7377        unsigned numCharacters() const { return m_numCharacters; }
    7478        unsigned numGlyphs() const { return m_numGlyphs; }
     79        uint16_t* glyphs() { return &m_glyphs[0]; }
     80        float* advances() { return &m_advances[0]; }
    7581        float width() { return m_width; }
    7682
    7783    private:
    78         HarfBuzzRun(unsigned numCharacters, TextDirection, hb_buffer_t*);
     84        HarfBuzzRun(const SimpleFontData*, unsigned startIndex, unsigned numCharacters, TextDirection);
    7985        bool rtl() { return m_direction == RTL; }
    8086
     87        const SimpleFontData* m_fontData;
     88        unsigned m_startIndex;
    8189        size_t m_numCharacters;
    8290        unsigned m_numGlyphs;
     
    8492        Vector<uint16_t, 256> m_glyphs;
    8593        Vector<float, 256> m_advances;
    86         Vector<FloatPoint, 256> m_offsets;
    8794        Vector<uint16_t, 256> m_logClusters;
    8895        Vector<uint16_t, 256> m_glyphToCharacterIndex;
     
    9299    void setFontFeatures();
    93100
    94     bool setupHarfBuzzRun();
    95     bool shapeHarfBuzzRun();
    96     void setGlyphPositionsForHarfBuzzRun(GlyphBuffer*);
     101    bool collectHarfBuzzRuns();
     102    bool shapeHarfBuzzRuns(GlyphBuffer*);
     103    void setGlyphPositionsForHarfBuzzRun(HarfBuzzRun*, unsigned runIndexInVisualOrder, hb_buffer_t*, GlyphBuffer*);
    97104
    98105    GlyphBufferAdvance createGlyphBufferAdvance(float, float);
    99106
    100107    Vector<hb_feature_t, 4> m_features;
    101     unsigned m_startIndexOfCurrentRun;
    102     unsigned m_numCharactersOfCurrentRun;
    103     const SimpleFontData* m_currentFontData;
    104     hb_buffer_t* m_harfbuzzBuffer;
    105108    Vector<OwnPtr<HarfBuzzRun>, 16> m_harfbuzzRuns;
     109
     110    FloatPoint m_startOffset;
    106111
    107112    float m_totalWidth;
Note: See TracChangeset for help on using the changeset viewer.