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