Home | History | Annotate | Download | only in harfbuzz
      1 /*
      2  * Copyright (c) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h"
     33 
     34 #include <unicode/normlzr.h>
     35 #include <unicode/uchar.h>
     36 #include "core/platform/graphics/Font.h"
     37 #include "core/platform/graphics/SurrogatePairAwareTextIterator.h"
     38 #include "core/platform/graphics/TextRun.h"
     39 #include "core/platform/graphics/harfbuzz/HarfBuzzFace.h"
     40 #include "hb-icu.h"
     41 #include "wtf/MathExtras.h"
     42 #include "wtf/unicode/Unicode.h"
     43 #include "wtf/Vector.h"
     44 
     45 namespace WebCore {
     46 
     47 template<typename T>
     48 class HarfBuzzScopedPtr {
     49 public:
     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; }
     65 private:
     66     T* m_ptr;
     67     DestroyFunction m_destroy;
     68 };
     69 
     70 static inline float harfBuzzPositionToFloat(hb_position_t value)
     71 {
     72     return static_cast<float>(value) / (1 << 16);
     73 }
     74 
     75 HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_t script)
     76     : m_fontData(fontData)
     77     , m_startIndex(startIndex)
     78     , m_numCharacters(numCharacters)
     79     , m_direction(direction)
     80     , m_script(script)
     81 {
     82 }
     83 
     84 void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfBuzzBuffer)
     85 {
     86     m_numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
     87     m_glyphs.resize(m_numGlyphs);
     88     m_advances.resize(m_numGlyphs);
     89     m_glyphToCharacterIndexes.resize(m_numGlyphs);
     90     m_offsets.resize(m_numGlyphs);
     91 }
     92 
     93 void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY)
     94 {
     95     m_glyphs[index] = glyphId;
     96     m_advances[index] = advance;
     97     m_offsets[index] = FloatPoint(offsetX, offsetY);
     98 }
     99 
    100 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
    101 {
    102     ASSERT(targetX <= m_width);
    103     float currentX = 0;
    104     float currentAdvance = m_advances[0];
    105     unsigned glyphIndex = 0;
    106 
    107     // Sum up advances that belong to a character.
    108     while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
    109         currentAdvance += m_advances[++glyphIndex];
    110     currentAdvance = currentAdvance / 2.0;
    111     if (targetX <= currentAdvance)
    112         return rtl() ? m_numCharacters : 0;
    113 
    114     ++glyphIndex;
    115     while (glyphIndex < m_numGlyphs) {
    116         unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1];
    117         float prevAdvance = currentAdvance;
    118         currentAdvance = m_advances[glyphIndex];
    119         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
    120             currentAdvance += m_advances[++glyphIndex];
    121         currentAdvance = currentAdvance / 2.0;
    122         float nextX = currentX + prevAdvance + currentAdvance;
    123         if (currentX <= targetX && targetX <= nextX)
    124             return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex];
    125         currentX = nextX;
    126         prevAdvance = currentAdvance;
    127         ++glyphIndex;
    128     }
    129 
    130     return rtl() ? 0 : m_numCharacters;
    131 }
    132 
    133 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
    134 {
    135     ASSERT(offset < m_numCharacters);
    136     unsigned glyphIndex = 0;
    137     float position = 0;
    138     if (rtl()) {
    139         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] > offset) {
    140             position += m_advances[glyphIndex];
    141             ++glyphIndex;
    142         }
    143         // For RTL, we need to return the right side boundary of the character.
    144         // Add advance of glyphs which are part of the character.
    145         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) {
    146             position += m_advances[glyphIndex];
    147             ++glyphIndex;
    148         }
    149         position += m_advances[glyphIndex];
    150     } else {
    151         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) {
    152             position += m_advances[glyphIndex];
    153             ++glyphIndex;
    154         }
    155     }
    156     return position;
    157 }
    158 
    159 static void normalizeCharacters(const TextRun& run, UChar* destination, int length)
    160 {
    161     int position = 0;
    162     bool error = false;
    163     const UChar* source;
    164     String stringFor8BitRun;
    165     if (run.is8Bit()) {
    166         stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length());
    167         source = stringFor8BitRun.characters16();
    168     } else
    169         source = run.characters16();
    170 
    171     while (position < length) {
    172         UChar32 character;
    173         int nextPosition = position;
    174         U16_NEXT(source, nextPosition, length, character);
    175         // Don't normalize tabs as they are not treated as spaces for word-end.
    176         if (Font::treatAsSpace(character) && character != '\t')
    177             character = ' ';
    178         else if (Font::treatAsZeroWidthSpaceInComplexScript(character))
    179             character = zeroWidthSpace;
    180         U16_APPEND(destination, position, length, character, error);
    181         ASSERT_UNUSED(error, !error);
    182         position = nextPosition;
    183     }
    184 }
    185 
    186 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run)
    187     : m_font(font)
    188     , m_normalizedBufferLength(0)
    189     , m_run(run)
    190     , m_wordSpacingAdjustment(font->wordSpacing())
    191     , m_padding(0)
    192     , m_padPerWordBreak(0)
    193     , m_padError(0)
    194     , m_letterSpacing(font->letterSpacing())
    195     , m_fromIndex(0)
    196     , m_toIndex(m_run.length())
    197 {
    198     m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
    199     m_normalizedBufferLength = m_run.length();
    200     normalizeCharacters(m_run, m_normalizedBuffer.get(), m_normalizedBufferLength);
    201     setPadding(m_run.expansion());
    202     setFontFeatures();
    203 }
    204 
    205 HarfBuzzShaper::~HarfBuzzShaper()
    206 {
    207 }
    208 
    209 static void normalizeSpacesAndMirrorChars(const UChar* source, UChar* destination, int length, HarfBuzzShaper::NormalizeMode normalizeMode)
    210 {
    211     int position = 0;
    212     bool error = false;
    213     // Iterate characters in source and mirror character if needed.
    214     while (position < length) {
    215         UChar32 character;
    216         int nextPosition = position;
    217         U16_NEXT(source, nextPosition, length, character);
    218         // Don't normalize tabs as they are not treated as spaces for word-end
    219         if (Font::treatAsSpace(character) && character != '\t')
    220             character = ' ';
    221         else if (Font::treatAsZeroWidthSpace(character))
    222             character = zeroWidthSpace;
    223         else if (normalizeMode == HarfBuzzShaper::NormalizeMirrorChars)
    224             character = u_charMirror(character);
    225         U16_APPEND(destination, position, length, character, error);
    226         ASSERT_UNUSED(error, !error);
    227         position = nextPosition;
    228     }
    229 }
    230 
    231 void HarfBuzzShaper::setNormalizedBuffer(NormalizeMode normalizeMode)
    232 {
    233     // Normalize the text run in three ways:
    234     // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
    235     // (U+0300..) are used in the run. This conversion is necessary since most OpenType
    236     // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
    237     // their GSUB tables.
    238     //
    239     // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
    240     // the API returns FALSE (= not normalized) for complex runs that don't require NFC
    241     // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
    242     // HarfBuzz will do the same thing for us using the GSUB table.
    243     // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
    244     // for characters like '\n' otherwise.
    245     // 3) Convert mirrored characters such as parenthesis for rtl text.
    246 
    247     // Convert to NFC form if the text has diacritical marks.
    248     icu::UnicodeString normalizedString;
    249     UErrorCode error = U_ZERO_ERROR;
    250 
    251     const UChar* runCharacters;
    252     String stringFor8BitRun;
    253     if (m_run.is8Bit()) {
    254         stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
    255         runCharacters = stringFor8BitRun.characters16();
    256     } else
    257         runCharacters = m_run.characters16();
    258 
    259     for (int i = 0; i < m_run.length(); ++i) {
    260         UChar ch = runCharacters[i];
    261         if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
    262             icu::Normalizer::normalize(icu::UnicodeString(runCharacters,
    263                 m_run.length()), UNORM_NFC, 0 /* no options */,
    264                 normalizedString, error);
    265             if (U_FAILURE(error))
    266                 normalizedString.remove();
    267             break;
    268         }
    269     }
    270 
    271     const UChar* sourceText;
    272     if (normalizedString.isEmpty()) {
    273         m_normalizedBufferLength = m_run.length();
    274         sourceText = runCharacters;
    275     } else {
    276         m_normalizedBufferLength = normalizedString.length();
    277         sourceText = normalizedString.getBuffer();
    278     }
    279 
    280     m_normalizedBuffer = adoptArrayPtr(new UChar[m_normalizedBufferLength + 1]);
    281     normalizeSpacesAndMirrorChars(sourceText, m_normalizedBuffer.get(), m_normalizedBufferLength, normalizeMode);
    282 }
    283 
    284 bool HarfBuzzShaper::isWordEnd(unsigned index)
    285 {
    286     // This could refer a high-surrogate, but should work.
    287     return index && isCodepointSpace(m_normalizedBuffer[index]);
    288 }
    289 
    290 int HarfBuzzShaper::determineWordBreakSpacing()
    291 {
    292     int wordBreakSpacing = m_wordSpacingAdjustment;
    293 
    294     if (m_padding > 0) {
    295         int toPad = roundf(m_padPerWordBreak + m_padError);
    296         m_padError += m_padPerWordBreak - toPad;
    297 
    298         if (m_padding < toPad)
    299             toPad = m_padding;
    300         m_padding -= toPad;
    301         wordBreakSpacing += toPad;
    302     }
    303     return wordBreakSpacing;
    304 }
    305 
    306 // setPadding sets a number of pixels to be distributed across the TextRun.
    307 // WebKit uses this to justify text.
    308 void HarfBuzzShaper::setPadding(int padding)
    309 {
    310     m_padding = padding;
    311     m_padError = 0;
    312     if (!m_padding)
    313         return;
    314 
    315     // If we have padding to distribute, then we try to give an equal
    316     // amount to each space. The last space gets the smaller amount, if
    317     // any.
    318     unsigned numWordEnds = 0;
    319 
    320     for (unsigned i = 0; i < m_normalizedBufferLength; i++) {
    321         if (isWordEnd(i))
    322             numWordEnds++;
    323     }
    324 
    325     if (numWordEnds)
    326         m_padPerWordBreak = m_padding / numWordEnds;
    327     else
    328         m_padPerWordBreak = 0;
    329 }
    330 
    331 
    332 void HarfBuzzShaper::setDrawRange(int from, int to)
    333 {
    334     ASSERT_WITH_SECURITY_IMPLICATION(from >= 0);
    335     ASSERT_WITH_SECURITY_IMPLICATION(to <= m_run.length());
    336     m_fromIndex = from;
    337     m_toIndex = to;
    338 }
    339 
    340 void HarfBuzzShaper::setFontFeatures()
    341 {
    342     const FontDescription& description = m_font->fontDescription();
    343     if (description.orientation() == Vertical) {
    344         static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) };
    345         static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) };
    346         m_features.append(vert);
    347         m_features.append(vrt2);
    348     }
    349 
    350     FontFeatureSettings* settings = description.featureSettings();
    351     if (!settings)
    352         return;
    353 
    354     unsigned numFeatures = settings->size();
    355     for (unsigned i = 0; i < numFeatures; ++i) {
    356         hb_feature_t feature;
    357         String tag = settings->at(i).tag();
    358         feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
    359         feature.value = settings->at(i).value();
    360         feature.start = 0;
    361         feature.end = static_cast<unsigned>(-1);
    362         m_features.append(feature);
    363     }
    364 }
    365 
    366 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
    367 {
    368     if (!collectHarfBuzzRuns())
    369         return false;
    370 
    371     m_totalWidth = 0;
    372     // WebKit doesn't set direction when calulating widths. Leave the direction setting to
    373     // HarfBuzz when we are calculating widths (except when directionalOverride() is set).
    374     if (!shapeHarfBuzzRuns(glyphBuffer || m_run.directionalOverride()))
    375         return false;
    376     m_totalWidth = roundf(m_totalWidth);
    377 
    378     if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
    379         return false;
    380 
    381     return true;
    382 }
    383 
    384 FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
    385 {
    386     return point + m_startOffset;
    387 }
    388 
    389 bool HarfBuzzShaper::collectHarfBuzzRuns()
    390 {
    391     const UChar* normalizedBufferEnd = m_normalizedBuffer.get() + m_normalizedBufferLength;
    392     SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_normalizedBufferLength, m_normalizedBufferLength);
    393     UChar32 character;
    394     unsigned clusterLength = 0;
    395     unsigned startIndexOfCurrentRun = 0;
    396     if (!iterator.consume(character, clusterLength))
    397         return false;
    398 
    399     const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
    400     UErrorCode errorCode = U_ZERO_ERROR;
    401     UScriptCode nextScript = uscript_getScript(character, &errorCode);
    402     if (U_FAILURE(errorCode))
    403         return false;
    404 
    405     do {
    406         const UChar* currentCharacterPosition = iterator.characters();
    407         const SimpleFontData* currentFontData = nextFontData;
    408         UScriptCode currentScript = nextScript;
    409 
    410         for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
    411             if (Font::treatAsZeroWidthSpace(character))
    412                 continue;
    413 
    414             if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
    415                 int markLength = clusterLength;
    416                 const UChar* markCharactersEnd = iterator.characters() + clusterLength;
    417                 while (markCharactersEnd < normalizedBufferEnd) {
    418                     UChar32 nextCharacter;
    419                     int nextCharacterLength = 0;
    420                     U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter);
    421                     if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
    422                         break;
    423                     markLength += nextCharacterLength;
    424                     markCharactersEnd += nextCharacterLength;
    425                 }
    426 
    427                 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) {
    428                     clusterLength = markLength;
    429                     continue;
    430                 }
    431                 nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
    432             } else
    433                 nextFontData = m_font->glyphDataForCharacter(character, false).fontData;
    434 
    435             nextScript = uscript_getScript(character, &errorCode);
    436             if (U_FAILURE(errorCode))
    437                 return false;
    438             if ((nextFontData != currentFontData) || ((currentScript != nextScript) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, currentScript))))
    439                 break;
    440             if (nextScript == USCRIPT_INHERITED)
    441                 nextScript = currentScript;
    442             currentCharacterPosition = iterator.characters();
    443         }
    444         unsigned numCharactersOfCurrentRun = iterator.currentCharacter() - startIndexOfCurrentRun;
    445         hb_script_t script = hb_icu_script_to_script(currentScript);
    446         m_harfBuzzRuns.append(HarfBuzzRun::create(currentFontData, startIndexOfCurrentRun, numCharactersOfCurrentRun, m_run.direction(), script));
    447         currentFontData = nextFontData;
    448         startIndexOfCurrentRun = iterator.currentCharacter();
    449     } while (iterator.consume(character, clusterLength));
    450 
    451     return !m_harfBuzzRuns.isEmpty();
    452 }
    453 
    454 bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection)
    455 {
    456     HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
    457 
    458     hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs());
    459 
    460     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
    461         unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
    462         HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
    463         const SimpleFontData* currentFontData = currentRun->fontData();
    464         if (currentFontData->isSVGFont())
    465             return false;
    466 
    467         hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
    468         if (shouldSetDirection)
    469             hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
    470         else
    471             // Leaving direction to HarfBuzz to guess is *really* bad, but will do for now.
    472             hb_buffer_guess_segment_properties(harfBuzzBuffer.get());
    473 
    474         // Add a space as pre-context to the buffer. This prevents showing dotted-circle
    475         // for combining marks at the beginning of runs.
    476         static const uint16_t preContext = ' ';
    477         hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
    478 
    479         if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
    480             String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters());
    481             upperText.makeUpper();
    482             currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
    483             ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, therefore upperText is 16 bit, even after we call makeUpper().
    484             hb_buffer_add_utf16(harfBuzzBuffer.get(), upperText.characters16(), currentRun->numCharacters(), 0, currentRun->numCharacters());
    485         } else
    486             hb_buffer_add_utf16(harfBuzzBuffer.get(), m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters(), 0, currentRun->numCharacters());
    487 
    488         FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentFontData->platformData());
    489         HarfBuzzFace* face = platformData->harfBuzzFace();
    490         if (!face)
    491             return false;
    492 
    493         if (m_font->fontDescription().orientation() == Vertical)
    494             face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
    495 
    496         HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy);
    497 
    498         hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
    499 
    500         currentRun->applyShapeResult(harfBuzzBuffer.get());
    501         setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
    502 
    503         hb_buffer_reset(harfBuzzBuffer.get());
    504     }
    505 
    506     return true;
    507 }
    508 
    509 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer)
    510 {
    511     const SimpleFontData* currentFontData = currentRun->fontData();
    512     hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
    513     hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0);
    514 
    515     unsigned numGlyphs = currentRun->numGlyphs();
    516     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    517     float totalAdvance = 0;
    518 
    519     // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
    520     for (size_t i = 0; i < numGlyphs; ++i) {
    521         bool runEnd = i + 1 == numGlyphs;
    522         uint16_t glyph = glyphInfos[i].codepoint;
    523         float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
    524         float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
    525         float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance);
    526 
    527         unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
    528         bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
    529         float spacing = 0;
    530 
    531         glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
    532 
    533         if (isClusterEnd && !Font::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex]))
    534             spacing += m_letterSpacing;
    535 
    536         if (isClusterEnd && isWordEnd(currentCharacterIndex))
    537             spacing += determineWordBreakSpacing();
    538 
    539         if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
    540             currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
    541             continue;
    542         }
    543 
    544         advance += spacing;
    545         if (m_run.rtl()) {
    546             // In RTL, spacing should be added to left side of glyphs.
    547             offsetX += spacing;
    548             if (!isClusterEnd)
    549                 offsetX += m_letterSpacing;
    550         }
    551 
    552         currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
    553 
    554         totalAdvance += advance;
    555     }
    556     currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
    557     m_totalWidth += currentRun->width();
    558 }
    559 
    560 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
    561 {
    562     FloatPoint* offsets = currentRun->offsets();
    563     uint16_t* glyphs = currentRun->glyphs();
    564     float* advances = currentRun->advances();
    565     unsigned numGlyphs = currentRun->numGlyphs();
    566     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    567 
    568     for (unsigned i = 0; i < numGlyphs; ++i) {
    569         uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
    570         FloatPoint& currentOffset = offsets[i];
    571         FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1];
    572         float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
    573         float glyphAdvanceY = nextOffset.y() - currentOffset.y();
    574         if (m_run.rtl()) {
    575             if (currentCharacterIndex > m_toIndex)
    576                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
    577             else if (currentCharacterIndex >= m_fromIndex)
    578                 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
    579         } else {
    580             if (currentCharacterIndex < m_fromIndex)
    581                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
    582             else if (currentCharacterIndex < m_toIndex)
    583                 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY));
    584         }
    585     }
    586 }
    587 
    588 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
    589 {
    590     unsigned numRuns = m_harfBuzzRuns.size();
    591     if (m_run.rtl()) {
    592         m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
    593         for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
    594             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
    595             FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0];
    596             fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
    597         }
    598     } else {
    599         m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
    600         for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
    601             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
    602             FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
    603             fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
    604         }
    605     }
    606     return glyphBuffer->size();
    607 }
    608 
    609 int HarfBuzzShaper::offsetForPosition(float targetX)
    610 {
    611     int charactersSoFar = 0;
    612     float currentX = 0;
    613 
    614     if (m_run.rtl()) {
    615         charactersSoFar = m_normalizedBufferLength;
    616         for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
    617             charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
    618             float nextX = currentX + m_harfBuzzRuns[i]->width();
    619             float offsetForRun = targetX - currentX;
    620             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
    621                 // The x value in question is within this script run.
    622                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
    623                 return charactersSoFar + index;
    624             }
    625             currentX = nextX;
    626         }
    627     } else {
    628         for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
    629             float nextX = currentX + m_harfBuzzRuns[i]->width();
    630             float offsetForRun = targetX - currentX;
    631             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
    632                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
    633                 return charactersSoFar + index;
    634             }
    635             charactersSoFar += m_harfBuzzRuns[i]->numCharacters();
    636             currentX = nextX;
    637         }
    638     }
    639 
    640     return charactersSoFar;
    641 }
    642 
    643 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
    644 {
    645     float currentX = 0;
    646     float fromX = 0;
    647     float toX = 0;
    648     bool foundFromX = false;
    649     bool foundToX = false;
    650 
    651     if (m_run.rtl())
    652         currentX = m_totalWidth;
    653     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
    654         if (m_run.rtl())
    655             currentX -= m_harfBuzzRuns[i]->width();
    656         int numCharacters = m_harfBuzzRuns[i]->numCharacters();
    657         if (!foundFromX && from >= 0 && from < numCharacters) {
    658             fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX;
    659             foundFromX = true;
    660         } else
    661             from -= numCharacters;
    662 
    663         if (!foundToX && to >= 0 && to < numCharacters) {
    664             toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX;
    665             foundToX = true;
    666         } else
    667             to -= numCharacters;
    668 
    669         if (foundFromX && foundToX)
    670             break;
    671         if (!m_run.rtl())
    672             currentX += m_harfBuzzRuns[i]->width();
    673     }
    674 
    675     // The position in question might be just after the text.
    676     if (!foundFromX)
    677         fromX = 0;
    678     if (!foundToX)
    679         toX = m_run.rtl() ? 0 : m_totalWidth;
    680 
    681     // Using floorf() and roundf() as the same as mac port.
    682     if (fromX < toX)
    683         return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height);
    684     return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height);
    685 }
    686 
    687 } // namespace WebCore
    688