Home | History | Annotate | Download | only in harfbuzz
      1 /*
      2  * Copyright (c) 2012 Google Inc. All rights reserved.
      3  * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "config.h"
     33 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h"
     34 
     35 #include "hb.h"
     36 #include "platform/LayoutUnit.h"
     37 #include "platform/RuntimeEnabledFeatures.h"
     38 #include "platform/fonts/Character.h"
     39 #include "platform/fonts/Font.h"
     40 #include "platform/fonts/GlyphBuffer.h"
     41 #include "platform/fonts/harfbuzz/HarfBuzzFace.h"
     42 #include "platform/text/SurrogatePairAwareTextIterator.h"
     43 #include "platform/text/TextBreakIterator.h"
     44 #include "wtf/Compiler.h"
     45 #include "wtf/MathExtras.h"
     46 #include "wtf/unicode/Unicode.h"
     47 #include <unicode/normlzr.h>
     48 #include <unicode/uchar.h>
     49 #include <unicode/uscript.h>
     50 
     51 #include <list>
     52 #include <map>
     53 #include <string>
     54 
     55 namespace WebCore {
     56 
     57 template<typename T>
     58 class HarfBuzzScopedPtr {
     59 public:
     60     typedef void (*DestroyFunction)(T*);
     61 
     62     HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
     63         : m_ptr(ptr)
     64         , m_destroy(destroy)
     65     {
     66         ASSERT(m_destroy);
     67     }
     68     ~HarfBuzzScopedPtr()
     69     {
     70         if (m_ptr)
     71             (*m_destroy)(m_ptr);
     72     }
     73 
     74     T* get() { return m_ptr; }
     75     void set(T* ptr) { m_ptr = ptr; }
     76 private:
     77     T* m_ptr;
     78     DestroyFunction m_destroy;
     79 };
     80 
     81 
     82 static const unsigned cHarfBuzzCacheMaxSize = 256;
     83 
     84 struct CachedShapingResultsLRUNode;
     85 struct CachedShapingResults;
     86 typedef std::map<std::wstring, CachedShapingResults*> CachedShapingResultsMap;
     87 typedef std::list<CachedShapingResultsLRUNode*> CachedShapingResultsLRU;
     88 
     89 struct CachedShapingResults {
     90     CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_direction_t runDir, const String& newLocale);
     91     ~CachedShapingResults();
     92 
     93     hb_buffer_t* buffer;
     94     Font font;
     95     hb_direction_t dir;
     96     String locale;
     97     CachedShapingResultsLRU::iterator lru;
     98 };
     99 
    100 struct CachedShapingResultsLRUNode {
    101     CachedShapingResultsLRUNode(const CachedShapingResultsMap::iterator& cacheEntry);
    102     ~CachedShapingResultsLRUNode();
    103 
    104     CachedShapingResultsMap::iterator entry;
    105 };
    106 
    107 CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* fontData, hb_direction_t dirData, const String& newLocale)
    108     : buffer(harfBuzzBuffer)
    109     , font(*fontData)
    110     , dir(dirData)
    111     , locale(newLocale)
    112 {
    113 }
    114 
    115 CachedShapingResults::~CachedShapingResults()
    116 {
    117     hb_buffer_destroy(buffer);
    118 }
    119 
    120 CachedShapingResultsLRUNode::CachedShapingResultsLRUNode(const CachedShapingResultsMap::iterator& cacheEntry)
    121     : entry(cacheEntry)
    122 {
    123 }
    124 
    125 CachedShapingResultsLRUNode::~CachedShapingResultsLRUNode()
    126 {
    127 }
    128 
    129 class HarfBuzzRunCache {
    130 public:
    131     HarfBuzzRunCache();
    132     ~HarfBuzzRunCache();
    133 
    134     CachedShapingResults* find(const std::wstring& key) const;
    135     void remove(CachedShapingResults* node);
    136     void moveToBack(CachedShapingResults* node);
    137     bool insert(const std::wstring& key, CachedShapingResults* run);
    138 
    139 private:
    140     CachedShapingResultsMap m_harfBuzzRunMap;
    141     CachedShapingResultsLRU m_harfBuzzRunLRU;
    142 };
    143 
    144 
    145 HarfBuzzRunCache::HarfBuzzRunCache()
    146 {
    147 }
    148 
    149 HarfBuzzRunCache::~HarfBuzzRunCache()
    150 {
    151     for (CachedShapingResultsMap::iterator it = m_harfBuzzRunMap.begin(); it != m_harfBuzzRunMap.end(); ++it)
    152         delete it->second;
    153     for (CachedShapingResultsLRU::iterator it = m_harfBuzzRunLRU.begin(); it != m_harfBuzzRunLRU.end(); ++it)
    154         delete *it;
    155 }
    156 
    157 bool HarfBuzzRunCache::insert(const std::wstring& key, CachedShapingResults* data)
    158 {
    159     std::pair<CachedShapingResultsMap::iterator, bool> results =
    160         m_harfBuzzRunMap.insert(CachedShapingResultsMap::value_type(key, data));
    161 
    162     if (!results.second)
    163         return false;
    164 
    165     CachedShapingResultsLRUNode* node = new CachedShapingResultsLRUNode(results.first);
    166 
    167     m_harfBuzzRunLRU.push_back(node);
    168     data->lru = --m_harfBuzzRunLRU.end();
    169 
    170     if (m_harfBuzzRunMap.size() > cHarfBuzzCacheMaxSize) {
    171         CachedShapingResultsLRUNode* lru = m_harfBuzzRunLRU.front();
    172         CachedShapingResults* foo = lru->entry->second;
    173         m_harfBuzzRunMap.erase(lru->entry);
    174         m_harfBuzzRunLRU.pop_front();
    175         delete foo;
    176         delete lru;
    177     }
    178 
    179     return true;
    180 }
    181 
    182 inline CachedShapingResults* HarfBuzzRunCache::find(const std::wstring& key) const
    183 {
    184     CachedShapingResultsMap::const_iterator it = m_harfBuzzRunMap.find(key);
    185 
    186     return it != m_harfBuzzRunMap.end() ? it->second : 0;
    187 }
    188 
    189 inline void HarfBuzzRunCache::remove(CachedShapingResults* node)
    190 {
    191     CachedShapingResultsLRUNode* lruNode = *node->lru;
    192 
    193     m_harfBuzzRunLRU.erase(node->lru);
    194     m_harfBuzzRunMap.erase(lruNode->entry);
    195     delete lruNode;
    196     delete node;
    197 }
    198 
    199 inline void HarfBuzzRunCache::moveToBack(CachedShapingResults* node)
    200 {
    201     CachedShapingResultsLRUNode* lruNode = *node->lru;
    202     m_harfBuzzRunLRU.erase(node->lru);
    203     m_harfBuzzRunLRU.push_back(lruNode);
    204     node->lru = --m_harfBuzzRunLRU.end();
    205 }
    206 
    207 HarfBuzzRunCache& harfBuzzRunCache()
    208 {
    209     DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ());
    210     return globalHarfBuzzRunCache;
    211 }
    212 
    213 static inline float harfBuzzPositionToFloat(hb_position_t value)
    214 {
    215     return static_cast<float>(value) / (1 << 16);
    216 }
    217 
    218 static inline unsigned countGraphemesInCluster(const UChar* normalizedBuffer, unsigned normalizedBufferLength, uint16_t startIndex, uint16_t endIndex)
    219 {
    220     if (startIndex > endIndex) {
    221         uint16_t tempIndex = startIndex;
    222         startIndex = endIndex;
    223         endIndex = tempIndex;
    224     }
    225     uint16_t length = endIndex - startIndex;
    226     ASSERT(static_cast<unsigned>(startIndex + length) <= normalizedBufferLength);
    227     TextBreakIterator* cursorPosIterator = cursorMovementIterator(&normalizedBuffer[startIndex], length);
    228 
    229     int cursorPos = cursorPosIterator->current();
    230     int numGraphemes = -1;
    231     while (0 <= cursorPos) {
    232         cursorPos = cursorPosIterator->next();
    233         numGraphemes++;
    234     }
    235     return numGraphemes < 0 ? 0 : numGraphemes;
    236 }
    237 
    238 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_t script)
    239     : m_fontData(fontData)
    240     , m_startIndex(startIndex)
    241     , m_numCharacters(numCharacters)
    242     , m_numGlyphs(0)
    243     , m_direction(direction)
    244     , m_script(script)
    245     , m_width(0)
    246 {
    247 }
    248 
    249 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const HarfBuzzRun& rhs)
    250     : m_fontData(rhs.m_fontData)
    251     , m_startIndex(rhs.m_startIndex)
    252     , m_numCharacters(rhs.m_numCharacters)
    253     , m_numGlyphs(rhs.m_numGlyphs)
    254     , m_direction(rhs.m_direction)
    255     , m_script(rhs.m_script)
    256     , m_glyphs(rhs.m_glyphs)
    257     , m_advances(rhs.m_advances)
    258     , m_glyphToCharacterIndexes(rhs.m_glyphToCharacterIndexes)
    259     , m_offsets(rhs.m_offsets)
    260     , m_width(rhs.m_width)
    261 {
    262 }
    263 
    264 HarfBuzzShaper::HarfBuzzRun::~HarfBuzzRun()
    265 {
    266 }
    267 
    268 inline void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfBuzzBuffer)
    269 {
    270     m_numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
    271     m_glyphs.resize(m_numGlyphs);
    272     m_advances.resize(m_numGlyphs);
    273     m_glyphToCharacterIndexes.resize(m_numGlyphs);
    274     m_offsets.resize(m_numGlyphs);
    275 }
    276 
    277 inline void HarfBuzzShaper::HarfBuzzRun::copyShapeResultAndGlyphPositions(const HarfBuzzRun& run)
    278 {
    279     m_numGlyphs = run.m_numGlyphs;
    280     m_glyphs = run.m_glyphs;
    281     m_advances = run.m_advances;
    282     m_glyphToCharacterIndexes = run.m_glyphToCharacterIndexes;
    283     m_offsets = run.m_offsets;
    284     m_width = run.m_width;
    285 }
    286 
    287 inline void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY)
    288 {
    289     m_glyphs[index] = glyphId;
    290     m_advances[index] = advance;
    291     m_offsets[index] = FloatPoint(offsetX, offsetY);
    292 }
    293 
    294 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
    295 {
    296     ASSERT(targetX <= m_width);
    297     float currentX = 0;
    298     float currentAdvance = m_advances[0];
    299     unsigned glyphIndex = 0;
    300 
    301     // Sum up advances that belong to a character.
    302     while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
    303         currentAdvance += m_advances[++glyphIndex];
    304     currentAdvance = currentAdvance / 2.0;
    305     if (targetX <= currentAdvance)
    306         return rtl() ? m_numCharacters : 0;
    307 
    308     ++glyphIndex;
    309     while (glyphIndex < m_numGlyphs) {
    310         unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1];
    311         float prevAdvance = currentAdvance;
    312         currentAdvance = m_advances[glyphIndex];
    313         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
    314             currentAdvance += m_advances[++glyphIndex];
    315         currentAdvance = currentAdvance / 2.0;
    316         float nextX = currentX + prevAdvance + currentAdvance;
    317         if (currentX <= targetX && targetX <= nextX)
    318             return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex];
    319         currentX = nextX;
    320         ++glyphIndex;
    321     }
    322 
    323     return rtl() ? 0 : m_numCharacters;
    324 }
    325 
    326 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
    327 {
    328     ASSERT(offset < m_numCharacters);
    329     unsigned glyphIndex = 0;
    330     float position = 0;
    331     if (rtl()) {
    332         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] > offset) {
    333             position += m_advances[glyphIndex];
    334             ++glyphIndex;
    335         }
    336         // For RTL, we need to return the right side boundary of the character.
    337         // Add advance of glyphs which are part of the character.
    338         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) {
    339             position += m_advances[glyphIndex];
    340             ++glyphIndex;
    341         }
    342         position += m_advances[glyphIndex];
    343     } else {
    344         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) {
    345             position += m_advances[glyphIndex];
    346             ++glyphIndex;
    347         }
    348     }
    349     return position;
    350 }
    351 
    352 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* destination, unsigned* destinationLength)
    353 {
    354     unsigned position = 0;
    355     bool error = false;
    356     const UChar* source;
    357     String stringFor8BitRun;
    358     if (run.is8Bit()) {
    359         stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length());
    360         source = stringFor8BitRun.characters16();
    361     } else
    362         source = run.characters16();
    363 
    364     *destinationLength = 0;
    365     while (position < length) {
    366         UChar32 character;
    367         U16_NEXT(source, position, length, character);
    368         // Don't normalize tabs as they are not treated as spaces for word-end.
    369         if (Character::treatAsSpace(character) && character != '\t')
    370             character = ' ';
    371         else if (Character::treatAsZeroWidthSpaceInComplexScript(character))
    372             character = zeroWidthSpace;
    373         U16_APPEND(destination, *destinationLength, length, character, error);
    374         ASSERT_UNUSED(error, !error);
    375     }
    376 }
    377 
    378 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmphasisOrNot forTextEmphasis)
    379     : m_font(font)
    380     , m_normalizedBufferLength(0)
    381     , m_run(run)
    382     , m_wordSpacingAdjustment(font->fontDescription().wordSpacing())
    383     , m_padding(0)
    384     , m_padPerWordBreak(0)
    385     , m_padError(0)
    386     , m_letterSpacing(font->fontDescription().letterSpacing())
    387     , m_fromIndex(0)
    388     , m_toIndex(m_run.length())
    389     , m_forTextEmphasis(forTextEmphasis)
    390     , m_glyphBoundingBox(std::numeric_limits<float>::max(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::max())
    391 {
    392     m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
    393     normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength);
    394     setPadding(m_run.expansion());
    395     setFontFeatures();
    396 }
    397 
    398 bool HarfBuzzShaper::isWordEnd(unsigned index)
    399 {
    400     // This could refer a high-surrogate, but should work.
    401     return index && isCodepointSpace(m_normalizedBuffer[index]);
    402 }
    403 
    404 int HarfBuzzShaper::determineWordBreakSpacing()
    405 {
    406     int wordBreakSpacing = m_wordSpacingAdjustment;
    407 
    408     if (m_padding > 0) {
    409         int toPad = roundf(m_padPerWordBreak + m_padError);
    410         m_padError += m_padPerWordBreak - toPad;
    411 
    412         if (m_padding < toPad)
    413             toPad = m_padding;
    414         m_padding -= toPad;
    415         wordBreakSpacing += toPad;
    416     }
    417     return wordBreakSpacing;
    418 }
    419 
    420 // setPadding sets a number of pixels to be distributed across the TextRun.
    421 // WebKit uses this to justify text.
    422 void HarfBuzzShaper::setPadding(int padding)
    423 {
    424     m_padding = padding;
    425     m_padError = 0;
    426     if (!m_padding)
    427         return;
    428 
    429     // If we have padding to distribute, then we try to give an equal
    430     // amount to each space. The last space gets the smaller amount, if
    431     // any.
    432     unsigned numWordEnds = 0;
    433 
    434     for (unsigned i = 0; i < m_normalizedBufferLength; i++) {
    435         if (isWordEnd(i))
    436             numWordEnds++;
    437     }
    438 
    439     if (numWordEnds)
    440         m_padPerWordBreak = m_padding / numWordEnds;
    441     else
    442         m_padPerWordBreak = 0;
    443 }
    444 
    445 
    446 void HarfBuzzShaper::setDrawRange(int from, int to)
    447 {
    448     ASSERT_WITH_SECURITY_IMPLICATION(from >= 0);
    449     ASSERT_WITH_SECURITY_IMPLICATION(to <= m_run.length());
    450     m_fromIndex = from;
    451     m_toIndex = to;
    452 }
    453 
    454 void HarfBuzzShaper::setFontFeatures()
    455 {
    456     const FontDescription& description = m_font->fontDescription();
    457     if (description.orientation() == Vertical) {
    458         static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) };
    459         static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) };
    460         m_features.append(vert);
    461         m_features.append(vrt2);
    462     }
    463 
    464     static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast<unsigned>(-1) };
    465     static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast<unsigned>(-1) };
    466     switch (description.kerning()) {
    467     case FontDescription::NormalKerning:
    468         // kern/vkrn are enabled by default
    469         break;
    470     case FontDescription::NoneKerning:
    471         m_features.append(description.orientation() == Vertical ? noVkrn : noKern);
    472         break;
    473     case FontDescription::AutoKerning:
    474         break;
    475     }
    476 
    477     static hb_feature_t noClig = { HB_TAG('c', 'l', 'i', 'g'), 0, 0, static_cast<unsigned>(-1) };
    478     static hb_feature_t noLiga = { HB_TAG('l', 'i', 'g', 'a'), 0, 0, static_cast<unsigned>(-1) };
    479     switch (description.commonLigaturesState()) {
    480     case FontDescription::DisabledLigaturesState:
    481         m_features.append(noLiga);
    482         m_features.append(noClig);
    483         break;
    484     case FontDescription::EnabledLigaturesState:
    485         // liga and clig are on by default
    486         break;
    487     case FontDescription::NormalLigaturesState:
    488         break;
    489     }
    490     static hb_feature_t dlig = { HB_TAG('d', 'l', 'i', 'g'), 1, 0, static_cast<unsigned>(-1) };
    491     switch (description.discretionaryLigaturesState()) {
    492     case FontDescription::DisabledLigaturesState:
    493         // dlig is off by default
    494         break;
    495     case FontDescription::EnabledLigaturesState:
    496         m_features.append(dlig);
    497         break;
    498     case FontDescription::NormalLigaturesState:
    499         break;
    500     }
    501     static hb_feature_t hlig = { HB_TAG('h', 'l', 'i', 'g'), 1, 0, static_cast<unsigned>(-1) };
    502     switch (description.historicalLigaturesState()) {
    503     case FontDescription::DisabledLigaturesState:
    504         // hlig is off by default
    505         break;
    506     case FontDescription::EnabledLigaturesState:
    507         m_features.append(hlig);
    508         break;
    509     case FontDescription::NormalLigaturesState:
    510         break;
    511     }
    512     static hb_feature_t noCalt = { HB_TAG('c', 'a', 'l', 't'), 0, 0, static_cast<unsigned>(-1) };
    513     switch (description.contextualLigaturesState()) {
    514     case FontDescription::DisabledLigaturesState:
    515         m_features.append(noCalt);
    516         break;
    517     case FontDescription::EnabledLigaturesState:
    518         // calt is on by default
    519         break;
    520     case FontDescription::NormalLigaturesState:
    521         break;
    522     }
    523 
    524     FontFeatureSettings* settings = description.featureSettings();
    525     if (!settings)
    526         return;
    527 
    528     unsigned numFeatures = settings->size();
    529     for (unsigned i = 0; i < numFeatures; ++i) {
    530         hb_feature_t feature;
    531         const AtomicString& tag = settings->at(i).tag();
    532         feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
    533         feature.value = settings->at(i).value();
    534         feature.start = 0;
    535         feature.end = static_cast<unsigned>(-1);
    536         m_features.append(feature);
    537     }
    538 }
    539 
    540 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
    541 {
    542     if (!createHarfBuzzRuns())
    543         return false;
    544 
    545     m_totalWidth = 0;
    546     if (!shapeHarfBuzzRuns())
    547         return false;
    548 
    549     if (!RuntimeEnabledFeatures::subpixelFontScalingEnabled())
    550         m_totalWidth = roundf(m_totalWidth);
    551 
    552     if (m_harfBuzzRuns.last()->hasGlyphToCharacterIndexes()
    553         && glyphBuffer && !fillGlyphBuffer(glyphBuffer))
    554         return false;
    555 
    556     return true;
    557 }
    558 
    559 FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
    560 {
    561     return point + m_startOffset;
    562 }
    563 
    564 static inline int handleMultipleUChar(
    565     UChar32 character,
    566     unsigned clusterLength,
    567     const SimpleFontData* currentFontData,
    568     const UChar* currentCharacterPosition,
    569     const UChar* markCharactersEnd,
    570     const UChar* normalizedBufferEnd)
    571 {
    572     if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
    573         int markLength = clusterLength;
    574         while (markCharactersEnd < normalizedBufferEnd) {
    575             UChar32 nextCharacter;
    576             int nextCharacterLength = 0;
    577             U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter);
    578             if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
    579                 break;
    580             markLength += nextCharacterLength;
    581             markCharactersEnd += nextCharacterLength;
    582         }
    583 
    584         if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) {
    585             return markLength;
    586         }
    587     }
    588     return 0;
    589 }
    590 
    591 struct CandidateRun {
    592     UChar32 character;
    593     unsigned start;
    594     unsigned end;
    595     const SimpleFontData* fontData;
    596     UScriptCode script;
    597 };
    598 
    599 static inline bool collectCandidateRuns(const UChar* normalizedBuffer,
    600     size_t bufferLength, const Font* font, Vector<CandidateRun>* runs)
    601 {
    602     const UChar* normalizedBufferEnd = normalizedBuffer + bufferLength;
    603     SurrogatePairAwareTextIterator iterator(normalizedBuffer, 0, bufferLength, bufferLength);
    604     UChar32 character;
    605     unsigned clusterLength = 0;
    606     unsigned startIndexOfCurrentRun = 0;
    607     if (!iterator.consume(character, clusterLength))
    608         return false;
    609 
    610     const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false).fontData;
    611     UErrorCode errorCode = U_ZERO_ERROR;
    612     UScriptCode nextScript = uscript_getScript(character, &errorCode);
    613     if (U_FAILURE(errorCode))
    614         return false;
    615 
    616     do {
    617         const UChar* currentCharacterPosition = iterator.characters();
    618         const SimpleFontData* currentFontData = nextFontData;
    619         UScriptCode currentScript = nextScript;
    620 
    621         UChar32 lastCharacter = character;
    622         for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
    623             if (Character::treatAsZeroWidthSpace(character))
    624                 continue;
    625 
    626             int length = handleMultipleUChar(character, clusterLength, currentFontData, currentCharacterPosition, iterator.characters() + clusterLength, normalizedBufferEnd);
    627             if (length) {
    628                 clusterLength = length;
    629                 continue;
    630             }
    631 
    632             nextFontData = font->glyphDataForCharacter(character, false).fontData;
    633             nextScript = uscript_getScript(character, &errorCode);
    634             if (U_FAILURE(errorCode))
    635                 return false;
    636             if (lastCharacter == zeroWidthJoiner)
    637                 currentFontData = nextFontData;
    638             if ((nextFontData != currentFontData) || ((currentScript != nextScript) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, currentScript))))
    639                 break;
    640             currentCharacterPosition = iterator.characters();
    641             lastCharacter = character;
    642         }
    643 
    644         CandidateRun run = { character, startIndexOfCurrentRun, iterator.currentCharacter(), currentFontData, currentScript };
    645         runs->append(run);
    646 
    647         startIndexOfCurrentRun = iterator.currentCharacter();
    648     } while (iterator.consume(character, clusterLength));
    649 
    650     return true;
    651 }
    652 
    653 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length,
    654     CandidateRun& adjacentRun)
    655 {
    656     for (int i = 0; i < length; i++) {
    657         if (scriptExtensions[i] == adjacentRun.script)
    658             return true;
    659     }
    660     return false;
    661 }
    662 
    663 static inline void resolveRunBasedOnScriptExtensions(Vector<CandidateRun>& runs,
    664     CandidateRun& run, size_t i, size_t length, UScriptCode* scriptExtensions,
    665     int extensionsLength, size_t& nextResolvedRun)
    666 {
    667     // If uscript_getScriptExtensions returns 1 it only contains the script value,
    668     // we only care about ScriptExtensions which is indicated by a value >= 2.
    669     if (extensionsLength <= 1)
    670         return;
    671 
    672     if (i > 0 && matchesAdjacentRun(scriptExtensions, extensionsLength, runs[i - 1])) {
    673         run.script = runs[i - 1].script;
    674         return;
    675     }
    676 
    677     for (size_t j = i + 1; j < length; j++) {
    678         if (runs[j].script != USCRIPT_COMMON
    679             && runs[j].script != USCRIPT_INHERITED
    680             && matchesAdjacentRun(scriptExtensions, extensionsLength, runs[j])) {
    681             nextResolvedRun = j;
    682             break;
    683         }
    684     }
    685 }
    686 
    687 static inline void resolveRunBasedOnScriptValue(Vector<CandidateRun>& runs,
    688     CandidateRun& run, size_t i, size_t length, size_t& nextResolvedRun)
    689 {
    690     if (run.script != USCRIPT_COMMON)
    691         return;
    692 
    693     if (i > 0 && runs[i - 1].script != USCRIPT_COMMON) {
    694         run.script = runs[i - 1].script;
    695         return;
    696     }
    697 
    698     for (size_t j = i + 1; j < length; j++) {
    699         if (runs[j].script != USCRIPT_COMMON
    700             && runs[j].script != USCRIPT_INHERITED) {
    701             nextResolvedRun = j;
    702             break;
    703         }
    704     }
    705 }
    706 
    707 static inline bool resolveCandidateRuns(Vector<CandidateRun>& runs)
    708 {
    709     UScriptCode scriptExtensions[8];
    710     UErrorCode errorCode = U_ZERO_ERROR;
    711     size_t length = runs.size();
    712     size_t nextResolvedRun = 0;
    713     for (size_t i = 0; i < length; i++) {
    714         CandidateRun& run = runs[i];
    715         nextResolvedRun = 0;
    716 
    717         if (run.script == USCRIPT_INHERITED)
    718             run.script = i > 0 ? runs[i - 1].script : USCRIPT_COMMON;
    719 
    720         int extensionsLength = uscript_getScriptExtensions(run.character,
    721             scriptExtensions, sizeof(scriptExtensions), &errorCode);
    722         if (U_FAILURE(errorCode))
    723             return false;
    724 
    725         resolveRunBasedOnScriptExtensions(runs, run, i, length,
    726             scriptExtensions, extensionsLength, nextResolvedRun);
    727         resolveRunBasedOnScriptValue(runs, run, i, length,
    728             nextResolvedRun);
    729         for (size_t j = i; j < nextResolvedRun; j++)
    730             runs[j].script = runs[nextResolvedRun].script;
    731 
    732         i = std::max(i, nextResolvedRun);
    733     }
    734     return true;
    735 }
    736 
    737 bool HarfBuzzShaper::createHarfBuzzRuns()
    738 {
    739     Vector<CandidateRun> candidateRuns;
    740     if (!collectCandidateRuns(m_normalizedBuffer.get(),
    741         m_normalizedBufferLength, m_font, &candidateRuns))
    742         return false;
    743 
    744     if (!resolveCandidateRuns(candidateRuns))
    745         return false;
    746 
    747     size_t length = candidateRuns.size();
    748     for (size_t i = 0; i < length; ) {
    749         CandidateRun& run = candidateRuns[i];
    750         CandidateRun lastMatchingRun = run;
    751         for (i++; i < length; i++) {
    752             if (candidateRuns[i].script != run.script
    753                 || candidateRuns[i].fontData != run.fontData)
    754                 break;
    755             lastMatchingRun = candidateRuns[i];
    756         }
    757         addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script);
    758     }
    759     return !m_harfBuzzRuns.isEmpty();
    760 }
    761 
    762 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
    763 // without hb-icu. See http://crbug.com/356929
    764 static inline hb_script_t ICUScriptToHBScript(UScriptCode script)
    765 {
    766     if (UNLIKELY(script == USCRIPT_INVALID_CODE))
    767         return HB_SCRIPT_INVALID;
    768 
    769     return hb_script_from_string(uscript_getShortName(script), -1);
    770 }
    771 
    772 
    773 void HarfBuzzShaper::addHarfBuzzRun(unsigned startCharacter,
    774     unsigned endCharacter, const SimpleFontData* fontData,
    775     UScriptCode script)
    776 {
    777     ASSERT(endCharacter > startCharacter);
    778     ASSERT(script != USCRIPT_INVALID_CODE);
    779     return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData,
    780         startCharacter, endCharacter - startCharacter,
    781         m_run.direction(), ICUScriptToHBScript(script)));
    782 }
    783 
    784 static const uint16_t* toUint16(const UChar* src)
    785 {
    786     // FIXME: This relies on undefined behavior however it works on the
    787     // current versions of all compilers we care about and avoids making
    788     // a copy of the string.
    789     COMPILE_ASSERT(sizeof(UChar) == sizeof(uint16_t), UChar_is_the_same_size_as_uint16_t);
    790     return reinterpret_cast<const uint16_t*>(src);
    791 }
    792 
    793 bool HarfBuzzShaper::shapeHarfBuzzRuns()
    794 {
    795     HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
    796 
    797     HarfBuzzRunCache& runCache = harfBuzzRunCache();
    798     const FontDescription& fontDescription = m_font->fontDescription();
    799     const String& localeString = fontDescription.locale();
    800     CString locale = localeString.latin1();
    801 
    802     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
    803         unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
    804         HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
    805         const SimpleFontData* currentFontData = currentRun->fontData();
    806         if (currentFontData->isSVGFont())
    807             return false;
    808 
    809         FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentFontData->platformData());
    810         HarfBuzzFace* face = platformData->harfBuzzFace();
    811         if (!face)
    812             return false;
    813 
    814         hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(locale.data(), locale.length()));
    815         hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
    816         hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
    817 
    818         hb_segment_properties_t props;
    819         hb_buffer_get_segment_properties(harfBuzzBuffer.get(), &props);
    820 
    821         const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex();
    822         std::wstring key(src, src + currentRun->numCharacters());
    823 
    824         CachedShapingResults* cachedResults = runCache.find(key);
    825         if (cachedResults) {
    826             if (cachedResults->dir == props.direction && cachedResults->font == *m_font && cachedResults->locale == localeString) {
    827                 currentRun->applyShapeResult(cachedResults->buffer);
    828                 setGlyphPositionsForHarfBuzzRun(currentRun, cachedResults->buffer);
    829 
    830                 hb_buffer_clear_contents(harfBuzzBuffer.get());
    831 
    832                 runCache.moveToBack(cachedResults);
    833 
    834                 continue;
    835             }
    836 
    837             runCache.remove(cachedResults);
    838         }
    839 
    840         // Add a space as pre-context to the buffer. This prevents showing dotted-circle
    841         // for combining marks at the beginning of runs.
    842         static const uint16_t preContext = ' ';
    843         hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
    844 
    845         if (fontDescription.variant() == FontVariantSmallCaps && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
    846             String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()).upper();
    847             ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, therefore upperText is 16 bit, even after we call makeUpper().
    848             hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(upperText.characters16()), currentRun->numCharacters(), 0, currentRun->numCharacters());
    849         } else {
    850             hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(m_normalizedBuffer.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun->numCharacters());
    851         }
    852 
    853         if (fontDescription.orientation() == Vertical)
    854             face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
    855 
    856         HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy);
    857 
    858         hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
    859         currentRun->applyShapeResult(harfBuzzBuffer.get());
    860         setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
    861 
    862         runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_font, props.direction, localeString));
    863 
    864         harfBuzzBuffer.set(hb_buffer_create());
    865     }
    866 
    867     return true;
    868 }
    869 
    870 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer)
    871 {
    872     const SimpleFontData* currentFontData = currentRun->fontData();
    873     hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
    874     hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0);
    875 
    876     if (!currentRun->hasGlyphToCharacterIndexes()) {
    877         // FIXME: https://crbug.com/337886
    878         ASSERT_NOT_REACHED();
    879         return;
    880     }
    881 
    882     unsigned numGlyphs = currentRun->numGlyphs();
    883     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    884     float totalAdvance = 0;
    885     FloatPoint glyphOrigin;
    886 
    887     // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
    888     for (size_t i = 0; i < numGlyphs; ++i) {
    889         bool runEnd = i + 1 == numGlyphs;
    890         uint16_t glyph = glyphInfos[i].codepoint;
    891         float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
    892         float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
    893         float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance);
    894 
    895         unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
    896         bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
    897         float spacing = 0;
    898 
    899         glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
    900 
    901         if (isClusterEnd && !Character::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex]))
    902             spacing += m_letterSpacing;
    903 
    904         if (isClusterEnd && isWordEnd(currentCharacterIndex))
    905             spacing += determineWordBreakSpacing();
    906 
    907         if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
    908             currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
    909             continue;
    910         }
    911 
    912         advance += spacing;
    913         if (m_run.rtl()) {
    914             // In RTL, spacing should be added to left side of glyphs.
    915             offsetX += spacing;
    916             if (!isClusterEnd)
    917                 offsetX += m_letterSpacing;
    918         }
    919 
    920         currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
    921 
    922         FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph);
    923         glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
    924         m_glyphBoundingBox.unite(glyphBounds);
    925         glyphOrigin += FloatSize(advance + offsetX, offsetY);
    926 
    927         totalAdvance += advance;
    928     }
    929     currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
    930     m_totalWidth += currentRun->width();
    931 }
    932 
    933 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
    934 {
    935     FloatPoint* offsets = currentRun->offsets();
    936     uint16_t* glyphs = currentRun->glyphs();
    937     float* advances = currentRun->advances();
    938     unsigned numGlyphs = currentRun->numGlyphs();
    939     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    940     for (unsigned i = 0; i < numGlyphs; ++i) {
    941         uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
    942         FloatPoint& currentOffset = offsets[i];
    943         FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1];
    944         float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
    945         float glyphAdvanceY = nextOffset.y() - currentOffset.y();
    946         if (m_run.rtl()) {
    947             if (currentCharacterIndex >= m_toIndex)
    948                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
    949             else if (currentCharacterIndex >= m_fromIndex)
    950                 glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
    951         } else {
    952             if (currentCharacterIndex < m_fromIndex)
    953                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
    954             else if (currentCharacterIndex < m_toIndex)
    955                 glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
    956         }
    957     }
    958 }
    959 
    960 void HarfBuzzShaper::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun)
    961 {
    962     // FIXME: Instead of generating a synthetic GlyphBuffer here which is then used by the
    963     // drawEmphasisMarks method of FontFastPath, we should roll our own emphasis mark drawing function.
    964 
    965     float* advances = currentRun->advances();
    966     unsigned numGlyphs = currentRun->numGlyphs();
    967     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    968     unsigned graphemesInCluster = 1;
    969     float clusterAdvance = 0;
    970     uint16_t clusterStart;
    971 
    972     // A "cluster" in this context means a cluster as it is used by HarfBuzz:
    973     // The minimal group of characters and corresponding glyphs, that cannot be broken
    974     // down further from a text shaping point of view.
    975     // A cluster can contain multiple glyphs and grapheme clusters, with mutually
    976     // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters,
    977     // then linearly split the sum of corresponding glyph advances by the number of
    978     // grapheme clusters in order to find positions for emphasis mark drawing.
    979 
    980     if (m_run.rtl())
    981         clusterStart = currentRun->startIndex() + currentRun->numCharacters();
    982     else
    983         clusterStart = currentRun->startIndex() + glyphToCharacterIndexes[0];
    984 
    985     for (unsigned i = 0; i < numGlyphs; ++i) {
    986         uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
    987         bool isRunEnd = (i + 1 == numGlyphs);
    988         bool isClusterEnd =  isRunEnd || (currentRun->startIndex() + glyphToCharacterIndexes[i + 1] != currentCharacterIndex);
    989         clusterAdvance += advances[i];
    990 
    991         if (isClusterEnd) {
    992             uint16_t clusterEnd;
    993             if (m_run.rtl())
    994                 clusterEnd = currentCharacterIndex;
    995             else
    996                 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->numCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1];
    997 
    998             graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get(), m_normalizedBufferLength, clusterStart, clusterEnd);
    999             if (!graphemesInCluster || !clusterAdvance)
   1000                 continue;
   1001 
   1002             float glyphAdvanceX = clusterAdvance / graphemesInCluster;
   1003             for (unsigned j = 0; j < graphemesInCluster; ++j) {
   1004                 // Do not put emphasis marks on space, separator, and control characters.
   1005                 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[currentCharacterIndex]) ? 1 : 0;
   1006                 glyphBuffer->add(glyphToAdd, currentRun->fontData(), glyphAdvanceX);
   1007             }
   1008             clusterStart = clusterEnd;
   1009             clusterAdvance = 0;
   1010         }
   1011     }
   1012 }
   1013 
   1014 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
   1015 {
   1016     unsigned numRuns = m_harfBuzzRuns.size();
   1017     if (m_run.rtl()) {
   1018         m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
   1019         for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
   1020             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
   1021             if (!currentRun->hasGlyphToCharacterIndexes()) {
   1022                 // FIXME: bug 337886, 359664
   1023                 continue;
   1024             }
   1025             FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0];
   1026             if (m_forTextEmphasis == ForTextEmphasis)
   1027                 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
   1028             else
   1029                 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
   1030         }
   1031     } else {
   1032         m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
   1033         for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
   1034             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
   1035             if (!currentRun->hasGlyphToCharacterIndexes()) {
   1036                 // FIXME: bug 337886, 359664
   1037                 continue;
   1038             }
   1039             FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
   1040             if (m_forTextEmphasis == ForTextEmphasis)
   1041                 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
   1042             else
   1043                 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
   1044         }
   1045     }
   1046     return glyphBuffer->size();
   1047 }
   1048 
   1049 int HarfBuzzShaper::offsetForPosition(float targetX)
   1050 {
   1051     int charactersSoFar = 0;
   1052     float currentX = 0;
   1053 
   1054     if (m_run.rtl()) {
   1055         charactersSoFar = m_normalizedBufferLength;
   1056         for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
   1057             charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
   1058             float nextX = currentX + m_harfBuzzRuns[i]->width();
   1059             float offsetForRun = targetX - currentX;
   1060             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
   1061                 // The x value in question is within this script run.
   1062                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
   1063                 return charactersSoFar + index;
   1064             }
   1065             currentX = nextX;
   1066         }
   1067     } else {
   1068         for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
   1069             float nextX = currentX + m_harfBuzzRuns[i]->width();
   1070             float offsetForRun = targetX - currentX;
   1071             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
   1072                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
   1073                 return charactersSoFar + index;
   1074             }
   1075             charactersSoFar += m_harfBuzzRuns[i]->numCharacters();
   1076             currentX = nextX;
   1077         }
   1078     }
   1079 
   1080     return charactersSoFar;
   1081 }
   1082 
   1083 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
   1084 {
   1085     float currentX = 0;
   1086     float fromX = 0;
   1087     float toX = 0;
   1088     bool foundFromX = false;
   1089     bool foundToX = false;
   1090 
   1091     if (m_run.rtl())
   1092         currentX = m_totalWidth;
   1093     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
   1094         if (m_run.rtl())
   1095             currentX -= m_harfBuzzRuns[i]->width();
   1096         int numCharacters = m_harfBuzzRuns[i]->numCharacters();
   1097         if (!foundFromX && from >= 0 && from < numCharacters) {
   1098             fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX;
   1099             foundFromX = true;
   1100         } else
   1101             from -= numCharacters;
   1102 
   1103         if (!foundToX && to >= 0 && to < numCharacters) {
   1104             toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX;
   1105             foundToX = true;
   1106         } else
   1107             to -= numCharacters;
   1108 
   1109         if (foundFromX && foundToX)
   1110             break;
   1111         if (!m_run.rtl())
   1112             currentX += m_harfBuzzRuns[i]->width();
   1113     }
   1114 
   1115     // The position in question might be just after the text.
   1116     if (!foundFromX)
   1117         fromX = 0;
   1118     if (!foundToX)
   1119         toX = m_run.rtl() ? 0 : m_totalWidth;
   1120 
   1121     if (fromX < toX) {
   1122         return Font::pixelSnappedSelectionRect(
   1123             point.x() + fromX, point.x() + toX,
   1124             point.y(), height);
   1125     }
   1126 
   1127     return Font::pixelSnappedSelectionRect(
   1128         point.x() + toX, point.x() + fromX,
   1129         point.y(), height);
   1130 }
   1131 
   1132 } // namespace WebCore
   1133