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
64using namespace android;
65
66namespace WebCore {
67
68typedef std::pair<int, float> FallbackFontKey;
69
70typedef HashMap<FallbackFontKey, FontPlatformData*> FallbackHash;
71
72static void updateForFont(SkPaint* paint, const SimpleFontData* font) {
73    font->platformData().setupPaint(paint);
74    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
75}
76
77static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc,
78                          const SimpleFontData* font) {
79    gc->setupFillPaint(paint);
80    updateForFont(paint, font);
81    return paint;
82}
83
84static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc,
85                            const SimpleFontData* font) {
86    gc->setupStrokePaint(paint);
87    updateForFont(paint, font);
88    return paint;
89}
90
91static 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
180bool Font::canReturnFallbackFontsForComplexText()
181{
182    return false;
183}
184
185bool Font::canExpandAroundIdeographsInComplexText()
186{
187    return false;
188}
189
190void 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
298void 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
305FloatRect 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
323void 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
341float 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
353int 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().
382static bool isCanvasMultiLayered(SkCanvas* canvas)
383{
384    SkCanvas::LayerIter layerIterator(canvas, false);
385    layerIterator.next();
386    return !layerIterator.done();
387}
388
389static 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.
402static 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.
421class TextRunWalker {
422public:
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
494private:
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
538TextRunWalker::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
573TextRunWalker::~TextRunWalker()
574{
575    fastFree(m_item.font);
576    deleteGlyphArrays();
577    delete[] m_item.log_clusters;
578}
579
580bool 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.
591void 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
614void 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
623void 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.
631bool 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
675float TextRunWalker::widthOfFullRun()
676{
677    float widthSum = 0;
678    while (nextScriptRun())
679        widthSum += width();
680
681    return widthSum;
682}
683
684void TextRunWalker::setWordAndLetterSpacing(int wordSpacingAdjustment,
685                                            int letterSpacingAdjustment)
686{
687    setWordSpacingAdjustment(wordSpacingAdjustment);
688    setLetterSpacingAdjustment(letterSpacingAdjustment);
689}
690
691const 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
727void 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
748HB_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
758void 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
768void 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
782void 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
795void 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
812void 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
887void 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
911const 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
965FloatRect 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
1034void 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
1076float 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
1084static 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
1106int 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