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 blink {
     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, hb_direction_t 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::setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY)
    278 {
    279     m_glyphs[index] = glyphId;
    280     m_advances[index] = advance;
    281     m_offsets[index] = FloatPoint(offsetX, offsetY);
    282 }
    283 
    284 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
    285 {
    286     ASSERT(targetX <= m_width);
    287     float currentX = 0;
    288     float currentAdvance = m_advances[0];
    289     unsigned glyphIndex = 0;
    290 
    291     // Sum up advances that belong to a character.
    292     while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
    293         currentAdvance += m_advances[++glyphIndex];
    294     currentAdvance = currentAdvance / 2.0;
    295     if (targetX <= currentAdvance)
    296         return rtl() ? m_numCharacters : 0;
    297 
    298     currentX = currentAdvance;
    299     ++glyphIndex;
    300     while (glyphIndex < m_numGlyphs) {
    301         unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1];
    302         float prevAdvance = currentAdvance;
    303         currentAdvance = m_advances[glyphIndex];
    304         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
    305             currentAdvance += m_advances[++glyphIndex];
    306         currentAdvance = currentAdvance / 2.0;
    307         float nextX = currentX + prevAdvance + currentAdvance;
    308         if (currentX <= targetX && targetX <= nextX)
    309             return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex];
    310         currentX = nextX;
    311         ++glyphIndex;
    312     }
    313 
    314     return rtl() ? 0 : m_numCharacters;
    315 }
    316 
    317 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
    318 {
    319     ASSERT(offset < m_numCharacters);
    320     unsigned glyphIndex = 0;
    321     float position = 0;
    322     if (rtl()) {
    323         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] > offset) {
    324             position += m_advances[glyphIndex];
    325             ++glyphIndex;
    326         }
    327         // For RTL, we need to return the right side boundary of the character.
    328         // Add advance of glyphs which are part of the character.
    329         while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) {
    330             position += m_advances[glyphIndex];
    331             ++glyphIndex;
    332         }
    333         position += m_advances[glyphIndex];
    334     } else {
    335         while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) {
    336             position += m_advances[glyphIndex];
    337             ++glyphIndex;
    338         }
    339     }
    340     return position;
    341 }
    342 
    343 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* destination, unsigned* destinationLength)
    344 {
    345     unsigned position = 0;
    346     bool error = false;
    347     const UChar* source;
    348     String stringFor8BitRun;
    349     if (run.is8Bit()) {
    350         stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length());
    351         source = stringFor8BitRun.characters16();
    352     } else
    353         source = run.characters16();
    354 
    355     *destinationLength = 0;
    356     while (position < length) {
    357         UChar32 character;
    358         U16_NEXT(source, position, length, character);
    359         // Don't normalize tabs as they are not treated as spaces for word-end.
    360         if (run.normalizeSpace() && Character::isNormalizedCanvasSpaceCharacter(character))
    361             character = space;
    362         else if (Character::treatAsSpace(character) && character != characterTabulation)
    363             character = space;
    364         else if (Character::treatAsZeroWidthSpaceInComplexScript(character))
    365             character = zeroWidthSpace;
    366 
    367         U16_APPEND(destination, *destinationLength, length, character, error);
    368         ASSERT_UNUSED(error, !error);
    369     }
    370 }
    371 
    372 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmphasisOrNot forTextEmphasis, HashSet<const SimpleFontData*>* fallbackFonts)
    373     : m_font(font)
    374     , m_normalizedBufferLength(0)
    375     , m_run(run)
    376     , m_wordSpacingAdjustment(font->fontDescription().wordSpacing())
    377     , m_padding(0)
    378     , m_padPerWordBreak(0)
    379     , m_padError(0)
    380     , m_letterSpacing(font->fontDescription().letterSpacing())
    381     , m_fromIndex(0)
    382     , m_toIndex(m_run.length())
    383     , m_forTextEmphasis(forTextEmphasis)
    384     , m_glyphBoundingBox(std::numeric_limits<float>::max(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::max())
    385     , m_fallbackFonts(fallbackFonts)
    386 {
    387     m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
    388     normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength);
    389     setPadding(m_run.expansion());
    390     setFontFeatures();
    391 }
    392 
    393 // In complex text word-spacing affects each line-break, space (U+0020) and non-breaking space (U+00A0).
    394 static inline bool isCodepointSpace(UChar c)
    395 {
    396     return c == space || c == noBreakSpace || c == newlineCharacter;
    397 }
    398 
    399 static inline bool isWordEnd(const UChar* normalizedBuffer, unsigned index)
    400 {
    401     // This could refer a high-surrogate, but should work.
    402     return index && isCodepointSpace(normalizedBuffer[index]);
    403 }
    404 
    405 int HarfBuzzShaper::determineWordBreakSpacing()
    406 {
    407     int wordBreakSpacing = m_wordSpacingAdjustment;
    408 
    409     if (m_padding > 0) {
    410         int toPad = roundf(m_padPerWordBreak + m_padError);
    411         m_padError += m_padPerWordBreak - toPad;
    412 
    413         if (m_padding < toPad)
    414             toPad = m_padding;
    415         m_padding -= toPad;
    416         wordBreakSpacing += toPad;
    417     }
    418     return wordBreakSpacing;
    419 }
    420 
    421 // setPadding sets a number of pixels to be distributed across the TextRun.
    422 // WebKit uses this to justify text.
    423 void HarfBuzzShaper::setPadding(int padding)
    424 {
    425     m_padding = padding;
    426     m_padError = 0;
    427     if (!m_padding)
    428         return;
    429 
    430     // If we have padding to distribute, then we try to give an equal
    431     // amount to each space. The last space gets the smaller amount, if
    432     // any.
    433     unsigned numWordEnds = 0;
    434 
    435     for (unsigned i = 0; i < m_normalizedBufferLength; i++) {
    436         if (isWordEnd(m_normalizedBuffer.get(), i))
    437             numWordEnds++;
    438     }
    439 
    440     if (numWordEnds)
    441         m_padPerWordBreak = m_padding / numWordEnds;
    442     else
    443         m_padPerWordBreak = 0;
    444 }
    445 
    446 
    447 void HarfBuzzShaper::setDrawRange(int from, int to)
    448 {
    449     ASSERT_WITH_SECURITY_IMPLICATION(from >= 0);
    450     ASSERT_WITH_SECURITY_IMPLICATION(to <= m_run.length());
    451     m_fromIndex = from;
    452     m_toIndex = to;
    453 }
    454 
    455 void HarfBuzzShaper::setFontFeatures()
    456 {
    457     const FontDescription& description = m_font->fontDescription();
    458     if (description.orientation() == Vertical) {
    459         static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) };
    460         static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) };
    461         m_features.append(vert);
    462         m_features.append(vrt2);
    463     }
    464 
    465     static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast<unsigned>(-1) };
    466     static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast<unsigned>(-1) };
    467     switch (description.kerning()) {
    468     case FontDescription::NormalKerning:
    469         // kern/vkrn are enabled by default
    470         break;
    471     case FontDescription::NoneKerning:
    472         m_features.append(description.orientation() == Vertical ? noVkrn : noKern);
    473         break;
    474     case FontDescription::AutoKerning:
    475         break;
    476     }
    477 
    478     static hb_feature_t noClig = { HB_TAG('c', 'l', 'i', 'g'), 0, 0, static_cast<unsigned>(-1) };
    479     static hb_feature_t noLiga = { HB_TAG('l', 'i', 'g', 'a'), 0, 0, static_cast<unsigned>(-1) };
    480     switch (description.commonLigaturesState()) {
    481     case FontDescription::DisabledLigaturesState:
    482         m_features.append(noLiga);
    483         m_features.append(noClig);
    484         break;
    485     case FontDescription::EnabledLigaturesState:
    486         // liga and clig are on by default
    487         break;
    488     case FontDescription::NormalLigaturesState:
    489         break;
    490     }
    491     static hb_feature_t dlig = { HB_TAG('d', 'l', 'i', 'g'), 1, 0, static_cast<unsigned>(-1) };
    492     switch (description.discretionaryLigaturesState()) {
    493     case FontDescription::DisabledLigaturesState:
    494         // dlig is off by default
    495         break;
    496     case FontDescription::EnabledLigaturesState:
    497         m_features.append(dlig);
    498         break;
    499     case FontDescription::NormalLigaturesState:
    500         break;
    501     }
    502     static hb_feature_t hlig = { HB_TAG('h', 'l', 'i', 'g'), 1, 0, static_cast<unsigned>(-1) };
    503     switch (description.historicalLigaturesState()) {
    504     case FontDescription::DisabledLigaturesState:
    505         // hlig is off by default
    506         break;
    507     case FontDescription::EnabledLigaturesState:
    508         m_features.append(hlig);
    509         break;
    510     case FontDescription::NormalLigaturesState:
    511         break;
    512     }
    513     static hb_feature_t noCalt = { HB_TAG('c', 'a', 'l', 't'), 0, 0, static_cast<unsigned>(-1) };
    514     switch (description.contextualLigaturesState()) {
    515     case FontDescription::DisabledLigaturesState:
    516         m_features.append(noCalt);
    517         break;
    518     case FontDescription::EnabledLigaturesState:
    519         // calt is on by default
    520         break;
    521     case FontDescription::NormalLigaturesState:
    522         break;
    523     }
    524 
    525     static hb_feature_t hwid = { HB_TAG('h', 'w', 'i', 'd'), 1, 0, static_cast<unsigned>(-1) };
    526     static hb_feature_t twid = { HB_TAG('t', 'w', 'i', 'd'), 1, 0, static_cast<unsigned>(-1) };
    527     static hb_feature_t qwid = { HB_TAG('d', 'w', 'i', 'd'), 1, 0, static_cast<unsigned>(-1) };
    528     switch (description.widthVariant()) {
    529     case HalfWidth:
    530         m_features.append(hwid);
    531         break;
    532     case ThirdWidth:
    533         m_features.append(twid);
    534         break;
    535     case QuarterWidth:
    536         m_features.append(qwid);
    537         break;
    538     case RegularWidth:
    539         break;
    540     }
    541 
    542     FontFeatureSettings* settings = description.featureSettings();
    543     if (!settings)
    544         return;
    545 
    546     unsigned numFeatures = settings->size();
    547     for (unsigned i = 0; i < numFeatures; ++i) {
    548         hb_feature_t feature;
    549         const AtomicString& tag = settings->at(i).tag();
    550         feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
    551         feature.value = settings->at(i).value();
    552         feature.start = 0;
    553         feature.end = static_cast<unsigned>(-1);
    554         m_features.append(feature);
    555     }
    556 }
    557 
    558 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
    559 {
    560     if (!createHarfBuzzRuns())
    561         return false;
    562 
    563     m_totalWidth = 0;
    564     if (!shapeHarfBuzzRuns())
    565         return false;
    566 
    567     if (!RuntimeEnabledFeatures::subpixelFontScalingEnabled())
    568         m_totalWidth = roundf(m_totalWidth);
    569 
    570     if (m_harfBuzzRuns.last()->hasGlyphToCharacterIndexes()
    571         && glyphBuffer && !fillGlyphBuffer(glyphBuffer))
    572         return false;
    573 
    574     return true;
    575 }
    576 
    577 FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
    578 {
    579     return point + m_startOffset;
    580 }
    581 
    582 static inline int handleMultipleUChar(
    583     UChar32 character,
    584     unsigned clusterLength,
    585     const SimpleFontData* currentFontData,
    586     const UChar* currentCharacterPosition,
    587     const UChar* markCharactersEnd,
    588     const UChar* normalizedBufferEnd)
    589 {
    590     if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
    591         int markLength = clusterLength;
    592         while (markCharactersEnd < normalizedBufferEnd) {
    593             UChar32 nextCharacter;
    594             int nextCharacterLength = 0;
    595             U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter);
    596             if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
    597                 break;
    598             markLength += nextCharacterLength;
    599             markCharactersEnd += nextCharacterLength;
    600         }
    601 
    602         if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) {
    603             return markLength;
    604         }
    605     }
    606     return 0;
    607 }
    608 
    609 struct CandidateRun {
    610     UChar32 character;
    611     unsigned start;
    612     unsigned end;
    613     const SimpleFontData* fontData;
    614     UScriptCode script;
    615 };
    616 
    617 static inline bool collectCandidateRuns(const UChar* normalizedBuffer,
    618     size_t bufferLength, const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize)
    619 {
    620     const UChar* normalizedBufferEnd = normalizedBuffer + bufferLength;
    621     SurrogatePairAwareTextIterator iterator(normalizedBuffer, 0, bufferLength, bufferLength);
    622     UChar32 character;
    623     unsigned clusterLength = 0;
    624     unsigned startIndexOfCurrentRun = 0;
    625 
    626     if (!iterator.consume(character, clusterLength))
    627         return false;
    628 
    629     const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData;
    630     UErrorCode errorCode = U_ZERO_ERROR;
    631     UScriptCode nextScript = uscript_getScript(character, &errorCode);
    632     if (U_FAILURE(errorCode))
    633         return false;
    634 
    635     do {
    636         const UChar* currentCharacterPosition = iterator.characters();
    637         const SimpleFontData* currentFontData = nextFontData;
    638         UScriptCode currentScript = nextScript;
    639 
    640         UChar32 lastCharacter = character;
    641         for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) {
    642             if (Character::treatAsZeroWidthSpace(character))
    643                 continue;
    644 
    645             int length = handleMultipleUChar(character, clusterLength, currentFontData, currentCharacterPosition, iterator.characters() + clusterLength, normalizedBufferEnd);
    646             if (length) {
    647                 clusterLength = length;
    648                 continue;
    649             }
    650 
    651             nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData;
    652             nextScript = uscript_getScript(character, &errorCode);
    653             if (U_FAILURE(errorCode))
    654                 return false;
    655             if (lastCharacter == zeroWidthJoiner)
    656                 currentFontData = nextFontData;
    657             if ((nextFontData != currentFontData) || ((currentScript != nextScript) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, currentScript))))
    658                 break;
    659             currentCharacterPosition = iterator.characters();
    660             lastCharacter = character;
    661         }
    662 
    663         CandidateRun run = { character, startIndexOfCurrentRun, iterator.currentCharacter(), currentFontData, currentScript };
    664         runs->append(run);
    665 
    666         startIndexOfCurrentRun = iterator.currentCharacter();
    667     } while (iterator.consume(character, clusterLength));
    668 
    669     return true;
    670 }
    671 
    672 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length,
    673     CandidateRun& adjacentRun)
    674 {
    675     for (int i = 0; i < length; i++) {
    676         if (scriptExtensions[i] == adjacentRun.script)
    677             return true;
    678     }
    679     return false;
    680 }
    681 
    682 static inline void resolveRunBasedOnScriptExtensions(Vector<CandidateRun>& runs,
    683     CandidateRun& run, size_t i, size_t length, UScriptCode* scriptExtensions,
    684     int extensionsLength, size_t& nextResolvedRun)
    685 {
    686     // If uscript_getScriptExtensions returns 1 it only contains the script value,
    687     // we only care about ScriptExtensions which is indicated by a value >= 2.
    688     if (extensionsLength <= 1)
    689         return;
    690 
    691     if (i > 0 && matchesAdjacentRun(scriptExtensions, extensionsLength, runs[i - 1])) {
    692         run.script = runs[i - 1].script;
    693         return;
    694     }
    695 
    696     for (size_t j = i + 1; j < length; j++) {
    697         if (runs[j].script != USCRIPT_COMMON
    698             && runs[j].script != USCRIPT_INHERITED
    699             && matchesAdjacentRun(scriptExtensions, extensionsLength, runs[j])) {
    700             nextResolvedRun = j;
    701             break;
    702         }
    703     }
    704 }
    705 
    706 static inline void resolveRunBasedOnScriptValue(Vector<CandidateRun>& runs,
    707     CandidateRun& run, size_t i, size_t length, size_t& nextResolvedRun)
    708 {
    709     if (run.script != USCRIPT_COMMON)
    710         return;
    711 
    712     if (i > 0 && runs[i - 1].script != USCRIPT_COMMON) {
    713         run.script = runs[i - 1].script;
    714         return;
    715     }
    716 
    717     for (size_t j = i + 1; j < length; j++) {
    718         if (runs[j].script != USCRIPT_COMMON
    719             && runs[j].script != USCRIPT_INHERITED) {
    720             nextResolvedRun = j;
    721             break;
    722         }
    723     }
    724 }
    725 
    726 static inline bool resolveCandidateRuns(Vector<CandidateRun>& runs)
    727 {
    728     UScriptCode scriptExtensions[8];
    729     UErrorCode errorCode = U_ZERO_ERROR;
    730     size_t length = runs.size();
    731     size_t nextResolvedRun = 0;
    732     for (size_t i = 0; i < length; i++) {
    733         CandidateRun& run = runs[i];
    734         nextResolvedRun = 0;
    735 
    736         if (run.script == USCRIPT_INHERITED)
    737             run.script = i > 0 ? runs[i - 1].script : USCRIPT_COMMON;
    738 
    739         int extensionsLength = uscript_getScriptExtensions(run.character,
    740             scriptExtensions, sizeof(scriptExtensions), &errorCode);
    741         if (U_FAILURE(errorCode))
    742             return false;
    743 
    744         resolveRunBasedOnScriptExtensions(runs, run, i, length,
    745             scriptExtensions, extensionsLength, nextResolvedRun);
    746         resolveRunBasedOnScriptValue(runs, run, i, length,
    747             nextResolvedRun);
    748         for (size_t j = i; j < nextResolvedRun; j++)
    749             runs[j].script = runs[nextResolvedRun].script;
    750 
    751         i = std::max(i, nextResolvedRun);
    752     }
    753     return true;
    754 }
    755 
    756 bool HarfBuzzShaper::createHarfBuzzRuns()
    757 {
    758     Vector<CandidateRun> candidateRuns;
    759     if (!collectCandidateRuns(m_normalizedBuffer.get(),
    760         m_normalizedBufferLength, m_font, &candidateRuns, m_run.normalizeSpace()))
    761         return false;
    762 
    763     if (!resolveCandidateRuns(candidateRuns))
    764         return false;
    765 
    766     size_t length = candidateRuns.size();
    767     for (size_t i = 0; i < length; ) {
    768         CandidateRun& run = candidateRuns[i];
    769         CandidateRun lastMatchingRun = run;
    770         for (i++; i < length; i++) {
    771             if (candidateRuns[i].script != run.script
    772                 || candidateRuns[i].fontData != run.fontData)
    773                 break;
    774             lastMatchingRun = candidateRuns[i];
    775         }
    776         addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script);
    777     }
    778     return !m_harfBuzzRuns.isEmpty();
    779 }
    780 
    781 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
    782 // without hb-icu. See http://crbug.com/356929
    783 static inline hb_script_t ICUScriptToHBScript(UScriptCode script)
    784 {
    785     if (UNLIKELY(script == USCRIPT_INVALID_CODE))
    786         return HB_SCRIPT_INVALID;
    787 
    788     return hb_script_from_string(uscript_getShortName(script), -1);
    789 }
    790 
    791 static inline hb_direction_t TextDirectionToHBDirection(TextDirection dir)
    792 {
    793     return dir == RTL ? HB_DIRECTION_RTL : HB_DIRECTION_LTR;
    794 }
    795 
    796 
    797 void HarfBuzzShaper::addHarfBuzzRun(unsigned startCharacter,
    798     unsigned endCharacter, const SimpleFontData* fontData,
    799     UScriptCode script)
    800 {
    801     ASSERT(endCharacter > startCharacter);
    802     ASSERT(script != USCRIPT_INVALID_CODE);
    803     if (m_fallbackFonts)
    804         m_fallbackFonts->add(fontData);
    805     return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData,
    806         startCharacter, endCharacter - startCharacter,
    807         TextDirectionToHBDirection(m_run.direction()),
    808         ICUScriptToHBScript(script)));
    809 }
    810 
    811 static const uint16_t* toUint16(const UChar* src)
    812 {
    813     // FIXME: This relies on undefined behavior however it works on the
    814     // current versions of all compilers we care about and avoids making
    815     // a copy of the string.
    816     COMPILE_ASSERT(sizeof(UChar) == sizeof(uint16_t), UChar_is_the_same_size_as_uint16_t);
    817     return reinterpret_cast<const uint16_t*>(src);
    818 }
    819 
    820 bool HarfBuzzShaper::shapeHarfBuzzRuns()
    821 {
    822     HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy);
    823 
    824     HarfBuzzRunCache& runCache = harfBuzzRunCache();
    825     const FontDescription& fontDescription = m_font->fontDescription();
    826     const String& localeString = fontDescription.locale();
    827     CString locale = localeString.latin1();
    828 
    829     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
    830         unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
    831         HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
    832         const SimpleFontData* currentFontData = currentRun->fontData();
    833         if (currentFontData->isSVGFont())
    834             return false;
    835 
    836         FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentFontData->platformData());
    837         HarfBuzzFace* face = platformData->harfBuzzFace();
    838         if (!face)
    839             return false;
    840 
    841         hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(locale.data(), locale.length()));
    842         hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
    843         hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction());
    844 
    845         const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex();
    846         std::wstring key(src, src + currentRun->numCharacters());
    847 
    848         CachedShapingResults* cachedResults = runCache.find(key);
    849         if (cachedResults) {
    850             if (cachedResults->dir == currentRun->direction() && cachedResults->font == *m_font && cachedResults->locale == localeString) {
    851                 currentRun->applyShapeResult(cachedResults->buffer);
    852                 setGlyphPositionsForHarfBuzzRun(currentRun, cachedResults->buffer);
    853 
    854                 hb_buffer_clear_contents(harfBuzzBuffer.get());
    855 
    856                 runCache.moveToBack(cachedResults);
    857 
    858                 continue;
    859             }
    860 
    861             runCache.remove(cachedResults);
    862         }
    863 
    864         // Add a space as pre-context to the buffer. This prevents showing dotted-circle
    865         // for combining marks at the beginning of runs.
    866         static const uint16_t preContext = space;
    867         hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
    868 
    869         if (fontDescription.variant() == FontVariantSmallCaps && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
    870             String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()).upper();
    871             ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, therefore upperText is 16 bit, even after we call makeUpper().
    872             hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(upperText.characters16()), currentRun->numCharacters(), 0, currentRun->numCharacters());
    873         } else {
    874             hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(m_normalizedBuffer.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun->numCharacters());
    875         }
    876 
    877         if (fontDescription.orientation() == Vertical)
    878             face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
    879 
    880         HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy);
    881 
    882         hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
    883         currentRun->applyShapeResult(harfBuzzBuffer.get());
    884         setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
    885 
    886         runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_font, currentRun->direction(), localeString));
    887 
    888         harfBuzzBuffer.set(hb_buffer_create());
    889     }
    890 
    891     return true;
    892 }
    893 
    894 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer)
    895 {
    896     const SimpleFontData* currentFontData = currentRun->fontData();
    897     hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
    898     hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0);
    899 
    900     if (!currentRun->hasGlyphToCharacterIndexes()) {
    901         // FIXME: https://crbug.com/337886
    902         ASSERT_NOT_REACHED();
    903         return;
    904     }
    905 
    906     unsigned numGlyphs = currentRun->numGlyphs();
    907     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    908     float totalAdvance = 0;
    909     FloatPoint glyphOrigin;
    910 
    911     // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
    912     for (size_t i = 0; i < numGlyphs; ++i) {
    913         bool runEnd = i + 1 == numGlyphs;
    914         uint16_t glyph = glyphInfos[i].codepoint;
    915         float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
    916         float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
    917         float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance);
    918 
    919         unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster;
    920         bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster;
    921         float spacing = 0;
    922 
    923         glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
    924 
    925         if (isClusterEnd && !Character::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex]))
    926             spacing += m_letterSpacing;
    927 
    928         if (isClusterEnd && isWordEnd(m_normalizedBuffer.get(), currentCharacterIndex))
    929             spacing += determineWordBreakSpacing();
    930 
    931         if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
    932             currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
    933             continue;
    934         }
    935 
    936         advance += spacing;
    937         if (m_run.rtl()) {
    938             // In RTL, spacing should be added to left side of glyphs.
    939             offsetX += spacing;
    940             if (!isClusterEnd)
    941                 offsetX += m_letterSpacing;
    942         }
    943 
    944         currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
    945 
    946         FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph);
    947         glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
    948         m_glyphBoundingBox.unite(glyphBounds);
    949         glyphOrigin += FloatSize(advance + offsetX, offsetY);
    950 
    951         totalAdvance += advance;
    952     }
    953     currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
    954     m_totalWidth += currentRun->width();
    955 }
    956 
    957 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
    958 {
    959     FloatPoint* offsets = currentRun->offsets();
    960     uint16_t* glyphs = currentRun->glyphs();
    961     float* advances = currentRun->advances();
    962     unsigned numGlyphs = currentRun->numGlyphs();
    963     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    964     for (unsigned i = 0; i < numGlyphs; ++i) {
    965         uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
    966         FloatPoint& currentOffset = offsets[i];
    967         FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1];
    968         float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
    969         float glyphAdvanceY = nextOffset.y() - currentOffset.y();
    970         if (m_run.rtl()) {
    971             if (currentCharacterIndex >= m_toIndex)
    972                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
    973             else if (currentCharacterIndex >= m_fromIndex)
    974                 glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
    975         } else {
    976             if (currentCharacterIndex < m_fromIndex)
    977                 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
    978             else if (currentCharacterIndex < m_toIndex)
    979                 glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
    980         }
    981     }
    982 }
    983 
    984 void HarfBuzzShaper::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun)
    985 {
    986     // FIXME: Instead of generating a synthetic GlyphBuffer here which is then used by the
    987     // drawEmphasisMarks method of FontFastPath, we should roll our own emphasis mark drawing function.
    988 
    989     float* advances = currentRun->advances();
    990     unsigned numGlyphs = currentRun->numGlyphs();
    991     uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
    992     unsigned graphemesInCluster = 1;
    993     float clusterAdvance = 0;
    994     uint16_t clusterStart;
    995 
    996     // A "cluster" in this context means a cluster as it is used by HarfBuzz:
    997     // The minimal group of characters and corresponding glyphs, that cannot be broken
    998     // down further from a text shaping point of view.
    999     // A cluster can contain multiple glyphs and grapheme clusters, with mutually
   1000     // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters,
   1001     // then linearly split the sum of corresponding glyph advances by the number of
   1002     // grapheme clusters in order to find positions for emphasis mark drawing.
   1003 
   1004     if (m_run.rtl())
   1005         clusterStart = currentRun->startIndex() + currentRun->numCharacters();
   1006     else
   1007         clusterStart = currentRun->startIndex() + glyphToCharacterIndexes[0];
   1008 
   1009     for (unsigned i = 0; i < numGlyphs; ++i) {
   1010         uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
   1011         bool isRunEnd = (i + 1 == numGlyphs);
   1012         bool isClusterEnd =  isRunEnd || (currentRun->startIndex() + glyphToCharacterIndexes[i + 1] != currentCharacterIndex);
   1013         clusterAdvance += advances[i];
   1014 
   1015         if (isClusterEnd) {
   1016             uint16_t clusterEnd;
   1017             if (m_run.rtl())
   1018                 clusterEnd = currentCharacterIndex;
   1019             else
   1020                 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->numCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1];
   1021 
   1022             graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get(), m_normalizedBufferLength, clusterStart, clusterEnd);
   1023             if (!graphemesInCluster || !clusterAdvance)
   1024                 continue;
   1025 
   1026             float glyphAdvanceX = clusterAdvance / graphemesInCluster;
   1027             for (unsigned j = 0; j < graphemesInCluster; ++j) {
   1028                 // Do not put emphasis marks on space, separator, and control characters.
   1029                 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[currentCharacterIndex]) ? 1 : 0;
   1030                 glyphBuffer->add(glyphToAdd, currentRun->fontData(), glyphAdvanceX);
   1031             }
   1032             clusterStart = clusterEnd;
   1033             clusterAdvance = 0;
   1034         }
   1035     }
   1036 }
   1037 
   1038 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
   1039 {
   1040     unsigned numRuns = m_harfBuzzRuns.size();
   1041     if (m_run.rtl()) {
   1042         m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
   1043         for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
   1044             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
   1045             if (!currentRun->hasGlyphToCharacterIndexes()) {
   1046                 // FIXME: bug 337886, 359664
   1047                 continue;
   1048             }
   1049             FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0];
   1050             if (m_forTextEmphasis == ForTextEmphasis)
   1051                 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
   1052             else
   1053                 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
   1054         }
   1055     } else {
   1056         m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
   1057         for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
   1058             HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
   1059             if (!currentRun->hasGlyphToCharacterIndexes()) {
   1060                 // FIXME: bug 337886, 359664
   1061                 continue;
   1062             }
   1063             FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
   1064             if (m_forTextEmphasis == ForTextEmphasis)
   1065                 fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
   1066             else
   1067                 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
   1068         }
   1069     }
   1070     return glyphBuffer->size();
   1071 }
   1072 
   1073 int HarfBuzzShaper::offsetForPosition(float targetX)
   1074 {
   1075     int charactersSoFar = 0;
   1076     float currentX = 0;
   1077 
   1078     if (m_run.rtl()) {
   1079         charactersSoFar = m_normalizedBufferLength;
   1080         for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
   1081             charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
   1082             float nextX = currentX + m_harfBuzzRuns[i]->width();
   1083             float offsetForRun = targetX - currentX;
   1084             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
   1085                 // The x value in question is within this script run.
   1086                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
   1087                 return charactersSoFar + index;
   1088             }
   1089             currentX = nextX;
   1090         }
   1091     } else {
   1092         for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
   1093             float nextX = currentX + m_harfBuzzRuns[i]->width();
   1094             float offsetForRun = targetX - currentX;
   1095             if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
   1096                 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun);
   1097                 return charactersSoFar + index;
   1098             }
   1099             charactersSoFar += m_harfBuzzRuns[i]->numCharacters();
   1100             currentX = nextX;
   1101         }
   1102     }
   1103 
   1104     return charactersSoFar;
   1105 }
   1106 
   1107 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
   1108 {
   1109     float currentX = 0;
   1110     float fromX = 0;
   1111     float toX = 0;
   1112     bool foundFromX = false;
   1113     bool foundToX = false;
   1114 
   1115     if (m_run.rtl())
   1116         currentX = m_totalWidth;
   1117     for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
   1118         if (m_run.rtl())
   1119             currentX -= m_harfBuzzRuns[i]->width();
   1120         int numCharacters = m_harfBuzzRuns[i]->numCharacters();
   1121         if (!foundFromX && from >= 0 && from < numCharacters) {
   1122             fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX;
   1123             foundFromX = true;
   1124         } else
   1125             from -= numCharacters;
   1126 
   1127         if (!foundToX && to >= 0 && to < numCharacters) {
   1128             toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX;
   1129             foundToX = true;
   1130         } else
   1131             to -= numCharacters;
   1132 
   1133         if (foundFromX && foundToX)
   1134             break;
   1135         if (!m_run.rtl())
   1136             currentX += m_harfBuzzRuns[i]->width();
   1137     }
   1138 
   1139     // The position in question might be just after the text.
   1140     if (!foundFromX)
   1141         fromX = 0;
   1142     if (!foundToX)
   1143         toX = m_run.rtl() ? 0 : m_totalWidth;
   1144 
   1145     if (fromX < toX) {
   1146         return Font::pixelSnappedSelectionRect(
   1147             point.x() + fromX, point.x() + toX,
   1148             point.y(), height);
   1149     }
   1150 
   1151     return Font::pixelSnappedSelectionRect(
   1152         point.x() + toX, point.x() + fromX,
   1153         point.y(), height);
   1154 }
   1155 
   1156 } // namespace blink
   1157