Home | History | Annotate | Download | only in fonts
      1 /*
      2  * Copyright 2009, The Android Open Source Project
      3  * Copyright (C) 2006 Apple Computer, Inc.  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
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 
     29 #define LOG_TAG "FontAndroid"
     30 
     31 #include "AndroidLog.h"
     32 #include "EmojiFont.h"
     33 #include "GraphicsOperation.h"
     34 #include "Font.h"
     35 #include "FontData.h"
     36 #include "FontFallbackList.h"
     37 #include "GraphicsContext.h"
     38 #include "GlyphBuffer.h"
     39 #include "IntRect.h"
     40 #include "NotImplemented.h"
     41 #include "PlatformGraphicsContext.h"
     42 #include "SkCanvas.h"
     43 #include "SkColorFilter.h"
     44 #include "SkLayerDrawLooper.h"
     45 #include "SkPaint.h"
     46 #include "SkTemplates.h"
     47 #include "SkTypeface.h"
     48 #include "SkUtils.h"
     49 #include "TextRun.h"
     50 #include "SkTypeface_android.h"
     51 
     52 #ifdef SUPPORT_COMPLEX_SCRIPTS
     53 #include "HarfbuzzSkia.h"
     54 #include <unicode/normlzr.h>
     55 #include <unicode/uchar.h>
     56 #include <wtf/OwnArrayPtr.h>
     57 #include <wtf/OwnPtr.h>
     58 #include <wtf/PassOwnArrayPtr.h>
     59 #include <wtf/PassOwnPtr.h>
     60 #include <wtf/unicode/CharacterNames.h>
     61 #include <wtf/unicode/Unicode.h>
     62 #endif
     63 
     64 using namespace android;
     65 
     66 namespace WebCore {
     67 
     68 typedef std::pair<int, float> FallbackFontKey;
     69 
     70 typedef HashMap<FallbackFontKey, FontPlatformData*> FallbackHash;
     71 
     72 static void updateForFont(SkPaint* paint, const SimpleFontData* font) {
     73     font->platformData().setupPaint(paint);
     74     paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     75 }
     76 
     77 static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc,
     78                           const SimpleFontData* font) {
     79     gc->setupFillPaint(paint);
     80     updateForFont(paint, font);
     81     return paint;
     82 }
     83 
     84 static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc,
     85                             const SimpleFontData* font) {
     86     gc->setupStrokePaint(paint);
     87     updateForFont(paint, font);
     88     return paint;
     89 }
     90 
     91 static bool setupForText(SkPaint* paint, GraphicsContext* gc,
     92                          const SimpleFontData* font) {
     93     int mode = gc->textDrawingMode() & (TextModeFill | TextModeStroke);
     94     if (!mode)
     95         return false;
     96 
     97     paint->setVerticalText(font->platformData().orientation() == Vertical);
     98 
     99     FloatSize shadowOffset;
    100     float shadowBlur;
    101     Color shadowColor;
    102     ColorSpace shadowColorSpace;
    103 
    104     if (RenderSkinAndroid::DrawableResolution() >= RenderSkinAndroid::HighRes)
    105         paint->setAutohinted(false);
    106 
    107     bool hasShadow = gc->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
    108     bool hasBothStrokeAndFill =
    109         (mode & (TextModeStroke | TextModeFill)) == (TextModeStroke | TextModeFill);
    110     if (hasShadow || hasBothStrokeAndFill) {
    111         SkLayerDrawLooper* looper = new SkLayerDrawLooper;
    112         paint->setLooper(looper)->unref();
    113 
    114         // The layerDrawLooper uses at the root paint to determine the text
    115         // encoding so we need to make sure it is properly configured.
    116         updateForFont(paint, font);
    117 
    118         // Specify the behavior of the looper
    119         SkLayerDrawLooper::LayerInfo info;
    120         info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits;
    121         info.fColorMode = SkXfermode::kSrc_Mode;
    122         info.fFlagsMask = SkPaint::kAllFlags;
    123 
    124         // The paint is only valid until the looper receives another call to
    125         // addLayer(). Therefore, we must cache certain state for later use.
    126         bool hasFillPaint = false;
    127         bool hasStrokePaint = false;
    128         SkScalar strokeWidth;
    129 
    130         if ((mode & TextModeStroke) && gc->willStroke()) {
    131             strokeWidth = setupStroke(looper->addLayer(info), gc, font)->getStrokeWidth();
    132             hasStrokePaint = true;
    133         }
    134         if ((mode & TextModeFill) && gc->willFill()) {
    135             setupFill(looper->addLayer(info), gc, font);
    136             hasFillPaint = true;
    137         }
    138 
    139         if (hasShadow) {
    140             SkPaint shadowPaint;
    141             SkPoint offset;
    142             if (gc->setupShadowPaint(&shadowPaint, &offset)) {
    143 
    144                 // add an offset to the looper when creating a shadow layer
    145                 info.fOffset.set(offset.fX, offset.fY);
    146 
    147                 SkPaint* p = looper->addLayer(info);
    148                 *p = shadowPaint;
    149 
    150                 // Currently, only GraphicsContexts associated with the
    151                 // HTMLCanvasElement have shadows ignore transforms set.  This
    152                 // allows us to distinguish between CSS and Canvas shadows which
    153                 // have different rendering specifications.
    154                 if (gc->shadowsIgnoreTransforms()) {
    155                     SkColorFilter* cf = SkColorFilter::CreateModeFilter(p->getColor(),
    156                             SkXfermode::kSrcIn_Mode);
    157                     p->setColorFilter(cf)->unref();
    158                 } else { // in CSS
    159                     p->setShader(NULL);
    160                 }
    161 
    162                 if (hasStrokePaint && !hasFillPaint) {
    163                     // stroke the shadow if we have stroke but no fill
    164                     p->setStyle(SkPaint::kStroke_Style);
    165                     p->setStrokeWidth(strokeWidth);
    166                 }
    167                 updateForFont(p, font);
    168             }
    169         }
    170     } else if (mode & TextModeFill) {
    171         (void)setupFill(paint, gc, font);
    172     } else if (mode & TextModeStroke) {
    173         (void)setupStroke(paint, gc, font);
    174     } else {
    175         return false;
    176     }
    177     return true;
    178 }
    179 
    180 bool Font::canReturnFallbackFontsForComplexText()
    181 {
    182     return false;
    183 }
    184 
    185 bool Font::canExpandAroundIdeographsInComplexText()
    186 {
    187     return false;
    188 }
    189 
    190 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
    191                       const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
    192                       const FloatPoint& point) const
    193 {
    194     // compile-time assert
    195     SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t));
    196 
    197     if (numGlyphs == 1 && glyphBuffer.glyphAt(from) == 0x3) {
    198         // Webkit likes to draw end text control command for some reason
    199         // Just ignore it
    200         return;
    201     }
    202 
    203     SkPaint paint;
    204     if (!setupForText(&paint, gc, font)) {
    205         return;
    206     }
    207 
    208     SkScalar                    x = SkFloatToScalar(point.x());
    209     SkScalar                    y = SkFloatToScalar(point.y());
    210     const GlyphBufferGlyph*     glyphs = glyphBuffer.glyphs(from);
    211     const GlyphBufferAdvance*   adv = glyphBuffer.advances(from);
    212     SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
    213     SkPoint*                    pos = storage.get();
    214 
    215     SkCanvas* canvas = gc->platformContext()->recordingCanvas();
    216 
    217     /*  We need an array of [x,y,x,y,x,y,...], but webkit is giving us
    218         point.xy + [width, height, width, height, ...], so we have to convert
    219      */
    220 
    221     if (font->platformData().orientation() == Vertical) {
    222         float yOffset = SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent());
    223         gc->platformContext()->setTextOffset(FloatSize(0.0f, -yOffset)); // compensate for offset in bounds calculation
    224         y += yOffset;
    225     }
    226 
    227     if (EmojiFont::IsAvailable()) {
    228         // set filtering, to make scaled images look nice(r)
    229         paint.setFilterBitmap(true);
    230 
    231         SkMatrix rotator;
    232         rotator.reset();
    233         if (font->platformData().orientation() == Vertical) {
    234             canvas->save();
    235             canvas->rotate(-90);
    236             rotator.setRotate(90);
    237         }
    238 
    239         int localIndex = 0;
    240         int localCount = 0;
    241         for (int i = 0; i < numGlyphs; i++) {
    242             if (EmojiFont::IsEmojiGlyph(glyphs[i])) {
    243                 if (localCount) {
    244                     rotator.mapPoints(&pos[localIndex], localCount);
    245                     canvas->drawPosText(&glyphs[localIndex],
    246                                      localCount * sizeof(uint16_t),
    247                                      &pos[localIndex], paint);
    248                 }
    249                 EmojiFont::Draw(canvas, glyphs[i], x, y, paint);
    250                 // reset local index/count track for "real" glyphs
    251                 localCount = 0;
    252                 localIndex = i + 1;
    253             } else {
    254                 pos[i].set(x, y);
    255                 localCount += 1;
    256             }
    257             x += SkFloatToScalar(adv[i].width());
    258             y += SkFloatToScalar(adv[i].height());
    259         }
    260 
    261         // draw the last run of glyphs (if any)
    262         if (localCount) {
    263             rotator.mapPoints(&pos[localIndex], localCount);
    264             canvas->drawPosText(&glyphs[localIndex],
    265                              localCount * sizeof(uint16_t),
    266                              &pos[localIndex], paint);
    267 
    268         }
    269 
    270         if (font->platformData().orientation() == Vertical)
    271             canvas->restore();
    272     } else {
    273         for (int i = 0; i < numGlyphs; i++) {
    274             pos[i].set(x, y);
    275             y += SkFloatToScalar(adv[i].height());
    276             x += SkFloatToScalar(adv[i].width());
    277         }
    278 
    279         if (font->platformData().orientation() == Vertical) {
    280             canvas->save();
    281             canvas->rotate(-90);
    282             SkMatrix rotator;
    283             rotator.reset();
    284             rotator.setRotate(90);
    285             rotator.mapPoints(pos, numGlyphs);
    286         }
    287         canvas->drawPosText(glyphs,
    288             numGlyphs * sizeof(uint16_t), pos, paint);
    289 
    290         if (font->platformData().orientation() == Vertical)
    291             canvas->restore();
    292     }
    293 
    294     if (font->platformData().orientation() == Vertical)
    295         gc->platformContext()->setTextOffset(FloatSize()); // reset to undo above
    296 }
    297 
    298 void Font::drawEmphasisMarksForComplexText(WebCore::GraphicsContext*, WebCore::TextRun const&, WTF::AtomicString const&, WebCore::FloatPoint const&, int, int) const
    299 {
    300     notImplemented();
    301 }
    302 
    303 #ifndef SUPPORT_COMPLEX_SCRIPTS
    304 
    305 FloatRect Font::selectionRectForComplexText(const TextRun& run,
    306                                 const FloatPoint& point, int h, int, int) const
    307 {
    308     SkPaint              paint;
    309     SkScalar             width, left;
    310     SkPaint::FontMetrics metrics;
    311 
    312     primaryFont()->platformData().setupPaint(&paint);
    313 
    314     width = paint.measureText(run.characters(), run.length() << 1);
    315     SkScalar spacing = paint.getFontMetrics(&metrics);
    316 
    317     return FloatRect(point.x(),
    318                      point.y(),
    319                      roundf(SkScalarToFloat(width)),
    320                      roundf(SkScalarToFloat(spacing)));
    321 }
    322 
    323 void Font::drawComplexText(GraphicsContext* gc, TextRun const& run,
    324                            FloatPoint const& point, int, int) const
    325 {
    326     SkCanvas*   canvas = gc->platformContext()->mCanvas;
    327     SkPaint     paint;
    328 
    329     if (!setupForText(&paint, gc, primaryFont())) {
    330         return;
    331     }
    332 
    333     // go to chars, instead of glyphs, which was set by setupForText()
    334     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    335 
    336     canvas->drawText(run.characters(), run.length() << 1,
    337                      SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
    338                      paint);
    339 }
    340 
    341 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
    342 {
    343     SkPaint paint;
    344 
    345     primaryFont()->platformData().setupPaint(&paint);
    346 
    347 //printf("--------- complext measure %d chars\n", run.to() - run.from());
    348 
    349     SkScalar width = paint.measureText(run.characters(), run.length() << 1);
    350     return SkScalarToFloat(width);
    351 }
    352 
    353 int Font::offsetForPositionForComplexText(const TextRun& run, float x,
    354                                           bool includePartialGlyphs) const
    355 {
    356     SkPaint                         paint;
    357     int                             count = run.length();
    358     SkAutoSTMalloc<64, SkScalar>    storage(count);
    359     SkScalar*                       widths = storage.get();
    360 
    361     primaryFont()->platformData().setupPaint(&paint);
    362 
    363     count = paint.getTextWidths(run.characters(), count << 1, widths);
    364 
    365     if (count > 0)
    366     {
    367         SkScalar pos = 0;
    368         for (int i = 0; i < count; i++)
    369         {
    370             if (x < SkScalarRound(pos + SkScalarHalf(widths[i])))
    371                 return i;
    372             pos += widths[i];
    373         }
    374     }
    375     return count;
    376 }
    377 
    378 #else
    379 
    380 // TODO Should we remove the multilayer support?
    381 // If yes. remove isCanvasMultiLayered() and adjustTextRenderMode().
    382 static bool isCanvasMultiLayered(SkCanvas* canvas)
    383 {
    384     SkCanvas::LayerIter layerIterator(canvas, false);
    385     layerIterator.next();
    386     return !layerIterator.done();
    387 }
    388 
    389 static void adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered)
    390 {
    391     // Our layers only have a single alpha channel. This means that subpixel
    392     // rendered text cannot be compositied correctly when the layer is
    393     // collapsed. Therefore, subpixel text is disabled when we are drawing
    394     // onto a layer.
    395     if (isCanvasMultiLayered)
    396         paint->setLCDRenderText(false);
    397 }
    398 
    399 // Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
    400 // handle subpixel positioning so this function is used to truncate Harfbuzz
    401 // values to a number of pixels.
    402 static int truncateFixedPointToInteger(HB_Fixed value)
    403 {
    404     return value >> 6;
    405 }
    406 
    407 // TextRunWalker walks a TextRun and presents each script run in sequence. A
    408 // TextRun is a sequence of code-points with the same embedding level (i.e. they
    409 // are all left-to-right or right-to-left). A script run is a subsequence where
    410 // all the characters have the same script (e.g. Arabic, Thai etc). Shaping is
    411 // only ever done with script runs since the shapers only know how to deal with
    412 // a single script.
    413 //
    414 // After creating it, the script runs are either iterated backwards or forwards.
    415 // It defaults to backwards for RTL and forwards otherwise (which matches the
    416 // presentation order), however you can set it with |setBackwardsIteration|.
    417 //
    418 // Once you have setup the object, call |nextScriptRun| to get the first script
    419 // run. This will return false when the iteration is complete. At any time you
    420 // can call |reset| to start over again.
    421 class TextRunWalker {
    422 public:
    423     TextRunWalker(const TextRun&, int, int, const Font*);
    424     ~TextRunWalker();
    425 
    426     bool isWordBreak(unsigned, bool);
    427     // setPadding sets a number of pixels to be distributed across the TextRun.
    428     // WebKit uses this to justify text.
    429     void setPadding(int);
    430     void reset();
    431     void setBackwardsIteration(bool);
    432     // Advance to the next script run, returning false when the end of the
    433     // TextRun has been reached.
    434     bool nextScriptRun();
    435     float widthOfFullRun();
    436 
    437     // setWordSpacingAdjustment sets a delta (in pixels) which is applied at
    438     // each word break in the TextRun.
    439     void setWordSpacingAdjustment(int wordSpacingAdjustment)
    440     {
    441         m_wordSpacingAdjustment = wordSpacingAdjustment;
    442     }
    443 
    444     // setLetterSpacingAdjustment sets an additional number of pixels that is
    445     // added to the advance after each output cluster. This matches the behaviour
    446     // of WidthIterator::advance.
    447     //
    448     // (NOTE: currently does nothing because I don't know how to get the
    449     // cluster information from Harfbuzz.)
    450     void setLetterSpacingAdjustment(int letterSpacingAdjustment)
    451     {
    452         m_letterSpacing = letterSpacingAdjustment;
    453     }
    454 
    455     // setWordAndLetterSpacing calls setWordSpacingAdjustment() and
    456     // setLetterSpacingAdjustment() to override m_wordSpacingAdjustment
    457     // and m_letterSpacing.
    458     void setWordAndLetterSpacing(int wordSpacingAdjustment, int letterSpacingAdjustment);
    459 
    460     // Set the x offset for the next script run. This affects the values in
    461     // |xPositions|
    462     void setXOffsetToZero() { m_offsetX = 0; }
    463     bool rtl() const { return m_run.rtl(); }
    464     const uint16_t* glyphs() const { return m_glyphs16; }
    465 
    466     // Return the length of the array returned by |glyphs|
    467     unsigned length() const { return m_item.num_glyphs; }
    468 
    469     // Return the offset for each of the glyphs. Note that this is translated
    470     // by the current x offset and that the x offset is updated for each script
    471     // run.
    472     const SkPoint* positions() const { return m_positions; }
    473 
    474     // Get the advances (widths) for each glyph.
    475     const HB_Fixed* advances() const { return m_item.advances; }
    476 
    477     // Return the width (in px) of the current script run.
    478     unsigned width() const { return m_pixelWidth; }
    479 
    480     // Return the cluster log for the current script run. For example:
    481     //   script run: f i a n c   (fi gets ligatured)
    482     //   log clutrs: 0 0 1 2 3 4
    483     // So, for each input code point, the log tells you which output glyph was
    484     // generated for it.
    485     const unsigned short* logClusters() const { return m_item.log_clusters; }
    486 
    487     // return the number of code points in the current script run
    488     unsigned numCodePoints() const { return m_numCodePoints; }
    489 
    490     const FontPlatformData* fontPlatformDataForScriptRun() {
    491         return reinterpret_cast<FontPlatformData*>(m_item.font->userData);
    492     }
    493 
    494 private:
    495     void setupFontForScriptRun();
    496     const FontPlatformData* setupComplexFont(HB_Script script, const FontPlatformData& platformData);
    497     HB_FontRec* allocHarfbuzzFont();
    498     void deleteGlyphArrays();
    499     void createGlyphArrays(int);
    500     void resetGlyphArrays();
    501     void shapeGlyphs();
    502     void setGlyphPositions(bool);
    503 
    504     static void normalizeSpacesAndMirrorChars(const UChar* source, bool rtl,
    505         UChar* destination, int length);
    506     static const TextRun& getNormalizedTextRun(const TextRun& originalRun,
    507         OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer);
    508 
    509     // This matches the logic in RenderBlock::findNextLineBreak
    510     static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; }
    511 
    512     const Font* const m_font;
    513     HB_ShaperItem m_item;
    514     uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
    515     SkPoint* m_positions; // A vector of positions for each glyph.
    516     ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
    517     const int m_startingX; // Offset in pixels of the first script run.
    518     const int m_startingY; // Offset in pixels of the first script run.
    519     int m_offsetX; // Offset in pixels to the start of the next script run.
    520     unsigned m_pixelWidth; // Width (in px) of the current script run.
    521     unsigned m_numCodePoints; // Code points in current script run.
    522     unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays.
    523 
    524     OwnPtr<TextRun> m_normalizedRun;
    525     OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run.
    526     const TextRun& m_run;
    527     bool m_iterateBackwards;
    528     int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
    529     float m_padding; // pixels to be distributed over the line at word breaks.
    530     float m_padPerWordBreak; // pixels to be added to each word break.
    531     float m_padError; // |m_padPerWordBreak| might have a fractional component.
    532                       // Since we only add a whole number of padding pixels at
    533                       // each word break we accumulate error. This is the
    534                       // number of pixels that we are behind so far.
    535     unsigned m_letterSpacing; // pixels to be added after each glyph.
    536 };
    537 
    538 TextRunWalker::TextRunWalker(const TextRun& run, int startingX, int startingY, const Font* font)
    539     : m_font(font)
    540     , m_startingX(startingX)
    541     , m_startingY(startingY)
    542     , m_offsetX(m_startingX)
    543     , m_run(getNormalizedTextRun(run, m_normalizedRun, m_normalizedBuffer))
    544     , m_iterateBackwards(m_run.rtl())
    545     , m_wordSpacingAdjustment(0)
    546     , m_padding(0)
    547     , m_padPerWordBreak(0)
    548     , m_padError(0)
    549     , m_letterSpacing(0)
    550 {
    551     // Do not use |run| inside this constructor. Use |m_run| instead.
    552 
    553     memset(&m_item, 0, sizeof(m_item));
    554     // We cannot know, ahead of time, how many glyphs a given script run
    555     // will produce. We take a guess that script runs will not produce more
    556     // than twice as many glyphs as there are code points plus a bit of
    557     // padding and fallback if we find that we are wrong.
    558     createGlyphArrays((m_run.length() + 2) * 2);
    559 
    560     m_item.log_clusters = new unsigned short[m_run.length()];
    561 
    562     m_item.face = 0;
    563     m_item.font = allocHarfbuzzFont();
    564 
    565     m_item.item.bidiLevel = m_run.rtl();
    566 
    567     m_item.string = m_run.characters();
    568     m_item.stringLength = m_run.length();
    569 
    570     reset();
    571 }
    572 
    573 TextRunWalker::~TextRunWalker()
    574 {
    575     fastFree(m_item.font);
    576     deleteGlyphArrays();
    577     delete[] m_item.log_clusters;
    578 }
    579 
    580 bool TextRunWalker::isWordBreak(unsigned index, bool isRTL)
    581 {
    582     if (!isRTL)
    583         return index && isCodepointSpace(m_item.string[index])
    584             && !isCodepointSpace(m_item.string[index - 1]);
    585     return index != m_item.stringLength - 1 && isCodepointSpace(m_item.string[index])
    586         && !isCodepointSpace(m_item.string[index + 1]);
    587 }
    588 
    589 // setPadding sets a number of pixels to be distributed across the TextRun.
    590 // WebKit uses this to justify text.
    591 void TextRunWalker::setPadding(int padding)
    592 {
    593     m_padding = padding;
    594     if (!m_padding)
    595         return;
    596 
    597     // If we have padding to distribute, then we try to give an equal
    598     // amount to each space. The last space gets the smaller amount, if
    599     // any.
    600     unsigned numWordBreaks = 0;
    601     bool isRTL = m_iterateBackwards;
    602 
    603     for (unsigned i = 0; i < m_item.stringLength; i++) {
    604         if (isWordBreak(i, isRTL))
    605             numWordBreaks++;
    606     }
    607 
    608     if (numWordBreaks)
    609         m_padPerWordBreak = m_padding / numWordBreaks;
    610     else
    611         m_padPerWordBreak = 0;
    612 }
    613 
    614 void TextRunWalker::reset()
    615 {
    616     if (m_iterateBackwards)
    617         m_indexOfNextScriptRun = m_run.length() - 1;
    618     else
    619         m_indexOfNextScriptRun = 0;
    620     m_offsetX = m_startingX;
    621 }
    622 
    623 void TextRunWalker::setBackwardsIteration(bool isBackwards)
    624 {
    625     m_iterateBackwards = isBackwards;
    626     reset();
    627 }
    628 
    629 // Advance to the next script run, returning false when the end of the
    630 // TextRun has been reached.
    631 bool TextRunWalker::nextScriptRun()
    632 {
    633     if (m_iterateBackwards) {
    634         // In right-to-left mode we need to render the shaped glyph backwards and
    635         // also render the script runs themselves backwards. So given a TextRun:
    636         //    AAAAAAACTTTTTTT   (A = Arabic, C = Common, T = Thai)
    637         // we render:
    638         //    TTTTTTCAAAAAAA
    639         // (and the glyphs in each A, C and T section are backwards too)
    640         if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(),
    641             m_run.length(), &m_indexOfNextScriptRun))
    642             return false;
    643     } else {
    644         if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(),
    645             m_run.length(), &m_indexOfNextScriptRun))
    646             return false;
    647 
    648         // It is actually wrong to consider script runs at all in this code.
    649         // Other WebKit code (e.g. Mac) segments complex text just by finding
    650         // the longest span of text covered by a single font.
    651         // But we currently need to call hb_utf16_script_run_next anyway to fill
    652         // in the harfbuzz data structures to e.g. pick the correct script's shaper.
    653         // So we allow that to run first, then do a second pass over the range it
    654         // found and take the largest subregion that stays within a single font.
    655         const FontData* glyphData = m_font->glyphDataForCharacter(
    656            m_item.string[m_item.item.pos], false).fontData;
    657         unsigned endOfRun;
    658         for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
    659             const FontData* nextGlyphData = m_font->glyphDataForCharacter(
    660                 m_item.string[m_item.item.pos + endOfRun], false).fontData;
    661             if (nextGlyphData != glyphData)
    662                 break;
    663         }
    664         m_item.item.length = endOfRun;
    665         m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
    666     }
    667 
    668     setupFontForScriptRun();
    669     shapeGlyphs();
    670     setGlyphPositions(rtl());
    671 
    672     return true;
    673 }
    674 
    675 float TextRunWalker::widthOfFullRun()
    676 {
    677     float widthSum = 0;
    678     while (nextScriptRun())
    679         widthSum += width();
    680 
    681     return widthSum;
    682 }
    683 
    684 void TextRunWalker::setWordAndLetterSpacing(int wordSpacingAdjustment,
    685                                             int letterSpacingAdjustment)
    686 {
    687     setWordSpacingAdjustment(wordSpacingAdjustment);
    688     setLetterSpacingAdjustment(letterSpacingAdjustment);
    689 }
    690 
    691 const FontPlatformData* TextRunWalker::setupComplexFont(
    692     HB_Script script, const FontPlatformData& platformData)
    693 {
    694     static FallbackHash fallbackPlatformData;
    695 
    696     // generate scriptStyleIndex - we need unique hash IDs for each style
    697     // of each script - normal, bold, italic, bolditalic. the first set of
    698     // NUM_SCRIPTS are the normal style version, followed by bold, then
    699     // italic, then bold italic. additional fake style bits can be added.
    700     int scriptStyleIndex = script;
    701     if (platformData.isFakeBold())
    702         scriptStyleIndex += HB_ScriptCount;
    703     if (platformData.isFakeItalic())
    704         scriptStyleIndex += HB_ScriptCount << 1;
    705 
    706     FallbackFontKey key(scriptStyleIndex, platformData.size());
    707     FontPlatformData* newPlatformData = 0;
    708 
    709     if (!fallbackPlatformData.contains(key)) {
    710         SkTypeface::Style currentStyle = SkTypeface::kNormal;
    711         if (platformData.typeface())
    712             currentStyle = platformData.typeface()->style();
    713         SkTypeface* typeface = SkCreateTypefaceForScript(script, currentStyle,
    714             SkPaint::kElegant_Variant);
    715         newPlatformData = new FontPlatformData(platformData, typeface);
    716         SkSafeUnref(typeface);
    717         fallbackPlatformData.set(key, newPlatformData);
    718     }
    719 
    720     if (!newPlatformData)
    721         newPlatformData = fallbackPlatformData.get(key);
    722 
    723     // If we couldn't allocate a new FontPlatformData, revert to the one passed
    724     return newPlatformData ? newPlatformData : &platformData;
    725 }
    726 
    727 void TextRunWalker::setupFontForScriptRun()
    728 {
    729     const FontData* fontData = m_font->glyphDataForCharacter(m_run[0], false).fontData;
    730     const FontPlatformData& platformData =
    731         fontData->fontDataForCharacter(' ')->platformData();
    732     const FontPlatformData* complexPlatformData = setupComplexFont(m_item.item.script, platformData);
    733 
    734     m_item.face = complexPlatformData->harfbuzzFace();
    735     m_item.font->userData = const_cast<FontPlatformData*>(complexPlatformData);
    736 
    737     int size = complexPlatformData->size();
    738     m_item.font->x_ppem = size;
    739     m_item.font->y_ppem = size;
    740     // x_ and y_scale are the conversion factors from font design space (fEmSize) to 1/64th of device pixels in 16.16 format.
    741     const int devicePixelFraction = 64;
    742     const int multiplyFor16Dot16 = 1 << 16;
    743     int scale = devicePixelFraction * size * multiplyFor16Dot16 / complexPlatformData->emSizeInFontUnits();
    744     m_item.font->x_scale = scale;
    745     m_item.font->y_scale = scale;
    746 }
    747 
    748 HB_FontRec* TextRunWalker::allocHarfbuzzFont()
    749 {
    750     HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
    751     memset(font, 0, sizeof(HB_FontRec));
    752     font->klass = &harfbuzzSkiaClass;
    753     font->userData = 0;
    754 
    755     return font;
    756 }
    757 
    758 void TextRunWalker::deleteGlyphArrays()
    759 {
    760     delete[] m_item.glyphs;
    761     delete[] m_item.attributes;
    762     delete[] m_item.advances;
    763     delete[] m_item.offsets;
    764     delete[] m_glyphs16;
    765     delete[] m_positions;
    766 }
    767 
    768 void TextRunWalker::createGlyphArrays(int size)
    769 {
    770     m_item.glyphs = new HB_Glyph[size];
    771     m_item.attributes = new HB_GlyphAttributes[size];
    772     m_item.advances = new HB_Fixed[size];
    773     m_item.offsets = new HB_FixedPoint[size];
    774 
    775     m_glyphs16 = new uint16_t[size];
    776     m_positions = new SkPoint[size];
    777 
    778     m_item.num_glyphs = size;
    779     m_glyphsArrayCapacity = size; // Save the GlyphArrays size.
    780 }
    781 
    782 void TextRunWalker::resetGlyphArrays()
    783 {
    784     int size = m_item.num_glyphs;
    785     // All the types here don't have pointers. It is safe to reset to
    786     // zero unless Harfbuzz breaks the compatibility in the future.
    787     memset(m_item.glyphs, 0, size * sizeof(m_item.glyphs[0]));
    788     memset(m_item.attributes, 0, size * sizeof(m_item.attributes[0]));
    789     memset(m_item.advances, 0, size * sizeof(m_item.advances[0]));
    790     memset(m_item.offsets, 0, size * sizeof(m_item.offsets[0]));
    791     memset(m_glyphs16, 0, size * sizeof(m_glyphs16[0]));
    792     memset(m_positions, 0, size * sizeof(m_positions[0]));
    793 }
    794 
    795 void TextRunWalker::shapeGlyphs()
    796 {
    797     // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to
    798     // HB_ShapeItem() used less space than was available, the capacity of
    799     // the array may be larger than the current value of m_item.num_glyphs.
    800     // So, we need to reset the num_glyphs to the capacity of the array.
    801     m_item.num_glyphs = m_glyphsArrayCapacity;
    802     resetGlyphArrays();
    803     while (!HB_ShapeItem(&m_item)) {
    804         // We overflowed our arrays. Resize and retry.
    805         // HB_ShapeItem fills in m_item.num_glyphs with the needed size.
    806         deleteGlyphArrays();
    807         createGlyphArrays(m_item.num_glyphs << 1);
    808         resetGlyphArrays();
    809     }
    810 }
    811 
    812 void TextRunWalker::setGlyphPositions(bool isRTL)
    813 {
    814     int position = 0;
    815     // logClustersIndex indexes logClusters for the first (or last when
    816     // RTL) codepoint of the current glyph.  Each time we advance a glyph,
    817     // we skip over all the codepoints that contributed to the current
    818     // glyph.
    819     unsigned logClustersIndex = isRTL && m_item.num_glyphs ? m_item.num_glyphs - 1 : 0;
    820 
    821     for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) {
    822         // Glyphs are stored in logical order, but for layout purposes we
    823         // always go left to right.
    824         int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
    825 
    826         m_glyphs16[i] = m_item.glyphs[i];
    827         int offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
    828         int offsetY = truncateFixedPointToInteger(m_item.offsets[i].y);
    829         m_positions[i].set(SkIntToScalar(m_offsetX + position) + offsetX, m_startingY + offsetY);
    830 
    831         int advance = truncateFixedPointToInteger(m_item.advances[i]);
    832         // The first half of the conjunction works around the case where
    833         // output glyphs aren't associated with any codepoints by the
    834         // clusters log.
    835         if (logClustersIndex < m_item.item.length
    836             && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) {
    837             advance += m_wordSpacingAdjustment;
    838 
    839             if (m_padding > 0) {
    840                 int toPad = roundf(m_padPerWordBreak + m_padError);
    841                 m_padError += m_padPerWordBreak - toPad;
    842 
    843                 if (m_padding < toPad)
    844                     toPad = m_padding;
    845                 m_padding -= toPad;
    846                 advance += toPad;
    847             }
    848         }
    849 
    850         // ZeroWidthJoiners and ZeroWidthNonJoiners should be stripped by
    851         // Harfbuzz, but aren't. Check for zwj and zwnj and replace with a
    852         // zero width space. We get the glyph data for space instead of
    853         // zeroWidthSpace because the latter was seen to render with an
    854         // unexpected code point (the symbol for a cloud). Since the standard
    855         // space is in page zero and since we've also confirmed that there is
    856         // no advance on this glyph, that should be ok.
    857         if (0 == m_item.advances[i]) {
    858             const HB_UChar16 c = m_item.string[m_item.item.pos + logClustersIndex];
    859             if ((c == zeroWidthJoiner) || (c == zeroWidthNonJoiner)) {
    860                 static Glyph spaceGlyph = m_font->glyphDataForCharacter(space, false).glyph;
    861                 m_glyphs16[i] = spaceGlyph;
    862             }
    863         }
    864 
    865         // TODO We would like to add m_letterSpacing after each cluster, but I
    866         // don't know where the cluster information is. This is typically
    867         // fine for Roman languages, but breaks more complex languages
    868         // terribly.
    869         // advance += m_letterSpacing;
    870 
    871         if (isRTL) {
    872             while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
    873                 logClustersIndex--;
    874         } else {
    875             while (logClustersIndex < m_item.item.length
    876                    && logClusters()[logClustersIndex] == i)
    877                 logClustersIndex++;
    878         }
    879 
    880         position += advance;
    881     }
    882 
    883     m_pixelWidth = position;
    884     m_offsetX += m_pixelWidth;
    885 }
    886 
    887 void TextRunWalker::normalizeSpacesAndMirrorChars(const UChar* source, bool rtl,
    888     UChar* destination, int length)
    889 {
    890     int position = 0;
    891     bool error = false;
    892     // Iterate characters in source and mirror character if needed.
    893     while (position < length) {
    894         UChar32 character;
    895         int nextPosition = position;
    896         U16_NEXT(source, nextPosition, length, character);
    897 
    898         if (Font::treatAsSpace(character))
    899             character = space;
    900         else if (Font::treatAsZeroWidthSpaceInComplexScript(character))
    901             character = zeroWidthSpace;
    902         else if (rtl)
    903             character = u_charMirror(character);
    904 
    905         U16_APPEND(destination, position, length, character, error);
    906         ASSERT(!error);
    907         position = nextPosition;
    908     }
    909 }
    910 
    911 const TextRun& TextRunWalker::getNormalizedTextRun(const TextRun& originalRun,
    912     OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer)
    913 {
    914     // Normalize the text run in three ways:
    915     // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
    916     // (U+0300..) are used in the run. This conversion is necessary since most OpenType
    917     // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
    918     // their GSUB tables.
    919     //
    920     // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
    921     // the API returns FALSE (= not normalized) for complex runs that don't require NFC
    922     // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
    923     // Harfbuzz will do the same thing for us using the GSUB table.
    924     // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
    925     // for characters like '\n' otherwise.
    926     // 3) Convert mirrored characters such as parenthesis for rtl text.
    927 
    928     // Convert to NFC form if the text has diacritical marks.
    929     icu::UnicodeString normalizedString;
    930     UErrorCode error = U_ZERO_ERROR;
    931 
    932     for (int16_t i = 0; i < originalRun.length(); ++i) {
    933         UChar ch = originalRun[i];
    934         if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
    935             icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(),
    936                                        originalRun.length()), UNORM_NFC, 0 /* no options */,
    937                                        normalizedString, error);
    938             if (U_FAILURE(error))
    939                 return originalRun;
    940             break;
    941         }
    942     }
    943 
    944     // Normalize space and mirror parenthesis for rtl text.
    945     int normalizedBufferLength;
    946     const UChar* sourceText;
    947     if (normalizedString.isEmpty()) {
    948         normalizedBufferLength = originalRun.length();
    949         sourceText = originalRun.characters();
    950     } else {
    951         normalizedBufferLength = normalizedString.length();
    952         sourceText = normalizedString.getBuffer();
    953     }
    954 
    955     normalizedBuffer = adoptArrayPtr(new UChar[normalizedBufferLength + 1]);
    956 
    957     normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(),
    958                                   normalizedBufferLength);
    959 
    960     normalizedRun = adoptPtr(new TextRun(originalRun));
    961     normalizedRun->setText(normalizedBuffer.get(), normalizedBufferLength);
    962     return *normalizedRun;
    963 }
    964 
    965 FloatRect Font::selectionRectForComplexText(const TextRun& run,
    966     const FloatPoint& point, int height, int from, int to) const
    967 {
    968     int fromX = -1;
    969     int toX = -1;
    970     TextRunWalker walker(run, 0, 0, this);
    971     walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
    972 
    973     // Base will point to the x offset for the current script run. Note that, in
    974     // the LTR case, width will be 0.
    975     int base = walker.rtl() ? walker.widthOfFullRun() : 0;
    976     const int leftEdge = base;
    977 
    978     // We want to enumerate the script runs in code point order in the following
    979     // code. This call also resets |walker|.
    980     walker.setBackwardsIteration(false);
    981     if (!from)
    982         fromX = leftEdge;
    983     if (!to)
    984         toX = leftEdge;
    985 
    986     while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) {
    987         // TextRunWalker will helpfully accumulate the x offsets for different
    988         // script runs for us. For this code, however, we always want the x
    989         // offsets to start from zero so we call this before each script run.
    990         walker.setXOffsetToZero();
    991 
    992         if (walker.rtl())
    993             base -= walker.width();
    994 
    995         int numCodePoints = static_cast<int>(walker.numCodePoints());
    996         if (fromX == -1 && from < numCodePoints) {
    997             // |from| is within this script run. So we index the clusters log to
    998             // find which glyph this code-point contributed to and find its x
    999             // position.
   1000             int glyph = walker.logClusters()[from];
   1001             fromX = base + walker.positions()[glyph].x();
   1002             if (walker.rtl())
   1003                 fromX += truncateFixedPointToInteger(walker.advances()[glyph]);
   1004         } else
   1005             from -= numCodePoints;
   1006 
   1007         if (toX == -1 && to < numCodePoints) {
   1008             int glyph = walker.logClusters()[to];
   1009             toX = base + walker.positions()[glyph].x();
   1010             if (walker.rtl())
   1011                 toX += truncateFixedPointToInteger(walker.advances()[glyph]);
   1012         } else
   1013             to -= numCodePoints;
   1014 
   1015         if (!walker.rtl())
   1016             base += walker.width();
   1017     }
   1018 
   1019     // The position in question might be just after the text.
   1020     const int rightEdge = base;
   1021     if (fromX == -1 && !from)
   1022         fromX = rightEdge;
   1023     if (toX == -1 && !to)
   1024         toX = rightEdge;
   1025 
   1026     ASSERT(fromX != -1 && toX != -1);
   1027 
   1028     if (fromX < toX)
   1029         return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
   1030 
   1031     return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
   1032 }
   1033 
   1034 void Font::drawComplexText(GraphicsContext* gc, TextRun const& run,
   1035                            FloatPoint const& point, int, int) const
   1036 {
   1037     if (!run.length())
   1038         return;
   1039 
   1040     int mode = gc->textDrawingMode();
   1041     bool fill = mode & TextModeFill;
   1042     bool stroke = mode & TextModeStroke;
   1043     if (!fill && !stroke)
   1044         return;
   1045 
   1046     SkPaint fillPaint, strokePaint;
   1047     if (fill)
   1048         setupFill(&fillPaint, gc, primaryFont());
   1049     if (stroke)
   1050         setupStroke(&strokePaint, gc, primaryFont());
   1051 
   1052     SkCanvas* canvas = gc->platformContext()->recordingCanvas();
   1053 
   1054     bool haveMultipleLayers = isCanvasMultiLayered(canvas);
   1055     TextRunWalker walker(run, point.x(), point.y(), this);
   1056     walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
   1057     walker.setPadding(run.expansion());
   1058 
   1059     while (walker.nextScriptRun()) {
   1060         if (fill) {
   1061             walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
   1062             adjustTextRenderMode(&fillPaint, haveMultipleLayers);
   1063             canvas->drawPosText(walker.glyphs(),
   1064                 walker.length() << 1, walker.positions(), fillPaint);
   1065         }
   1066         if (stroke) {
   1067             walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
   1068             adjustTextRenderMode(&strokePaint, haveMultipleLayers);
   1069             canvas->drawPosText(walker.glyphs(),
   1070                 walker.length() << 1, walker.positions(), strokePaint);
   1071         }
   1072     }
   1073 
   1074 }
   1075 
   1076 float Font::floatWidthForComplexText(const TextRun& run,
   1077             HashSet<const SimpleFontData*>*, GlyphOverflow*) const
   1078 {
   1079     TextRunWalker walker(run, 0, 0, this);
   1080     walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
   1081     return walker.widthOfFullRun();
   1082 }
   1083 
   1084 static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x)
   1085 {
   1086     const HB_Fixed* advances = walker.advances();
   1087     int glyphIndex;
   1088     if (walker.rtl()) {
   1089         for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) {
   1090             if (x < truncateFixedPointToInteger(advances[glyphIndex]))
   1091                 break;
   1092             x -= truncateFixedPointToInteger(advances[glyphIndex]);
   1093         }
   1094     } else {
   1095         for (glyphIndex = 0; glyphIndex < static_cast<int>(walker.length());
   1096              ++glyphIndex) {
   1097             if (x < truncateFixedPointToInteger(advances[glyphIndex]))
   1098                 break;
   1099             x -= truncateFixedPointToInteger(advances[glyphIndex]);
   1100         }
   1101     }
   1102 
   1103     return glyphIndex;
   1104 }
   1105 
   1106 int Font::offsetForPositionForComplexText(const TextRun& run, float x,
   1107                                           bool includePartialGlyphs) const
   1108 {
   1109     // (Mac code ignores includePartialGlyphs, and they don't know what it's
   1110     // supposed to do, so we just ignore it as well.)
   1111     TextRunWalker walker(run, 0, 0, this);
   1112     walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
   1113 
   1114     // If this is RTL text, the first glyph from the left is actually the last
   1115     // code point. So we need to know how many code points there are total in
   1116     // order to subtract. This is different from the length of the TextRun
   1117     // because UTF-16 surrogate pairs are a single code point, but 32-bits long.
   1118     // In LTR we leave this as 0 so that we get the correct value for
   1119     // |basePosition|, below.
   1120     unsigned totalCodePoints = 0;
   1121     if (walker.rtl()) {
   1122         ssize_t offset = 0;
   1123         while (offset < run.length()) {
   1124             utf16_to_code_point(run.characters(), run.length(), &offset);
   1125             totalCodePoints++;
   1126         }
   1127     }
   1128 
   1129     unsigned basePosition = totalCodePoints;
   1130 
   1131     // For RTL:
   1132     //   code-point order:  abcd efg hijkl
   1133     //   on screen:         lkjih gfe dcba
   1134     //                                ^   ^
   1135     //                                |   |
   1136     //                  basePosition--|   |
   1137     //                 totalCodePoints----|
   1138     // Since basePosition is currently the total number of code-points, the
   1139     // first thing we do is decrement it so that it's pointing to the start of
   1140     // the current script-run.
   1141     //
   1142     // For LTR, basePosition is zero so it already points to the start of the
   1143     // first script run.
   1144     while (walker.nextScriptRun()) {
   1145         if (walker.rtl())
   1146             basePosition -= walker.numCodePoints();
   1147 
   1148         if (x >= 0 && x < static_cast<int>(walker.width())) {
   1149             // The x value in question is within this script run. We consider
   1150             // each glyph in presentation order and stop when we find the one
   1151             // covering this position.
   1152             const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x);
   1153 
   1154             // Now that we have a glyph index, we have to turn that into a
   1155             // code-point index. Because of ligatures, several code-points may
   1156             // have gone into a single glyph. We iterate over the clusters log
   1157             // and find the first code-point which contributed to the glyph.
   1158 
   1159             // Some shapers (i.e. Khmer) will produce cluster logs which report
   1160             // that /no/ code points contributed to certain glyphs. Because of
   1161             // this, we take any code point which contributed to the glyph in
   1162             // question, or any subsequent glyph. If we run off the end, then
   1163             // we take the last code point.
   1164             const unsigned short* log = walker.logClusters();
   1165             for (unsigned j = 0; j < walker.numCodePoints(); ++j) {
   1166                 if (log[j] >= glyphIndex)
   1167                     return basePosition + j;
   1168             }
   1169 
   1170             return basePosition + walker.numCodePoints() - 1;
   1171         }
   1172 
   1173         x -= walker.width();
   1174 
   1175         if (!walker.rtl())
   1176             basePosition += walker.numCodePoints();
   1177     }
   1178 
   1179     return basePosition;
   1180 }
   1181 #endif
   1182 
   1183 }
   1184