1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm.h"
9#include "SkCanvas.h"
10#include "SkString.h"
11#include "SkTypeface.h"
12#include "SkTypes.h"
13
14static const char* gFaces[] = {
15    "Times Roman",
16    "Hiragino Maru Gothic Pro",
17    "Papyrus",
18    "Helvetica",
19    "Courier New"
20};
21
22class TypefaceGM : public skiagm::GM {
23public:
24    TypefaceGM() {
25        fFaces = new SkTypeface*[SK_ARRAY_COUNT(gFaces)];
26        for (size_t i = 0; i < SK_ARRAY_COUNT(gFaces); i++) {
27            fFaces[i] = sk_tool_utils::create_portable_typeface(gFaces[i], SkTypeface::kNormal);
28        }
29    }
30
31    virtual ~TypefaceGM() {
32        for (size_t i = 0; i < SK_ARRAY_COUNT(gFaces); i++) {
33            SkSafeUnref(fFaces[i]);
34        }
35        delete [] fFaces;
36    }
37
38protected:
39    virtual SkString onShortName() SK_OVERRIDE {
40        return SkString("typeface");
41    }
42
43    virtual SkISize onISize() SK_OVERRIDE {
44        return SkISize::Make(640, 480);
45    }
46
47    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
48        SkString text("Typefaces are fun!");
49        SkScalar y = 0;
50
51        SkPaint paint;
52        paint.setAntiAlias(true);
53        for (int i = 0; i < (int)SK_ARRAY_COUNT(gFaces); i++) {
54            this->drawWithFace(text, i, y, paint, canvas);
55        }
56        // Now go backwards
57        for (int i = SK_ARRAY_COUNT(gFaces) - 1; i >= 0; i--) {
58            this->drawWithFace(text, i, y, paint, canvas);
59        }
60    }
61
62private:
63    void drawWithFace(const SkString& text, int i, SkScalar& y, SkPaint& paint,
64                      SkCanvas* canvas) {
65        paint.setTypeface(fFaces[i]);
66        y += paint.getFontMetrics(NULL);
67        canvas->drawText(text.c_str(), text.size(), 0, y, paint);
68    }
69
70    SkTypeface** fFaces;
71
72    typedef skiagm::GM INHERITED;
73};
74
75///////////////////////////////////////////////////////////////////////////////
76
77static void getGlyphPositions(const SkPaint& paint, const uint16_t glyphs[],
78                             int count, SkScalar x, SkScalar y, SkPoint pos[]) {
79    SkASSERT(SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding());
80
81    SkAutoSTMalloc<128, SkScalar> widthStorage(count);
82    SkScalar* widths = widthStorage.get();
83    paint.getTextWidths(glyphs, count * sizeof(uint16_t), widths);
84
85    for (int i = 0; i < count; ++i) {
86        pos[i].set(x, y);
87        x += widths[i];
88    }
89}
90
91static void applyKerning(SkPoint pos[], const int32_t adjustments[], int count,
92                         const SkPaint& paint) {
93    SkScalar scale = paint.getTextSize() / paint.getTypeface()->getUnitsPerEm();
94
95    SkScalar globalAdj = 0;
96    for (int i = 0; i < count - 1; ++i) {
97        globalAdj += adjustments[i] * scale;
98        pos[i + 1].fX += globalAdj;
99    }
100}
101
102static void drawKernText(SkCanvas* canvas, const void* text, size_t len,
103                         SkScalar x, SkScalar y, const SkPaint& paint) {
104    SkTypeface* face = paint.getTypeface();
105    if (!face) {
106        canvas->drawText(text, len, x, y, paint);
107        return;
108    }
109
110    SkAutoSTMalloc<128, uint16_t> glyphStorage(len);
111    uint16_t* glyphs = glyphStorage.get();
112    int glyphCount = paint.textToGlyphs(text, len, glyphs);
113    if (glyphCount < 1) {
114        return;
115    }
116
117    SkAutoSTMalloc<128, int32_t> adjustmentStorage(glyphCount - 1);
118    int32_t* adjustments = adjustmentStorage.get();
119    if (!face->getKerningPairAdjustments(glyphs, glyphCount, adjustments)) {
120        canvas->drawText(text, len, x, y, paint);
121        return;
122    }
123
124    SkPaint glyphPaint(paint);
125    glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
126
127    SkAutoSTMalloc<128, SkPoint> posStorage(glyphCount);
128    SkPoint* pos = posStorage.get();
129    getGlyphPositions(glyphPaint, glyphs, glyphCount, x, y, pos);
130
131    applyKerning(pos, adjustments, glyphCount, glyphPaint);
132    canvas->drawPosText(glyphs, glyphCount * sizeof(uint16_t), pos, glyphPaint);
133}
134
135static const struct {
136    const char* fName;
137    SkTypeface::Style   fStyle;
138} gFaceStyles[] = {
139    { "sans-serif", SkTypeface::kNormal },
140    { "sans-serif", SkTypeface::kBold },
141    { "sans-serif", SkTypeface::kItalic },
142    { "sans-serif", SkTypeface::kBoldItalic },
143    { "serif", SkTypeface::kNormal },
144    { "serif", SkTypeface::kBold },
145    { "serif", SkTypeface::kItalic },
146    { "serif", SkTypeface::kBoldItalic },
147    { "monospace", SkTypeface::kNormal },
148    { "monospace", SkTypeface::kBold },
149    { "monospace", SkTypeface::kItalic },
150    { "monospace", SkTypeface::kBoldItalic },
151};
152
153static const int gFaceStylesCount = SK_ARRAY_COUNT(gFaceStyles);
154
155class TypefaceStylesGM : public skiagm::GM {
156    SkTypeface* fFaces[gFaceStylesCount];
157    bool fApplyKerning;
158
159public:
160    TypefaceStylesGM(bool applyKerning) : fApplyKerning(applyKerning) {
161        for (int i = 0; i < gFaceStylesCount; i++) {
162            fFaces[i] = sk_tool_utils::create_portable_typeface(gFaceStyles[i].fName,
163                                                         gFaceStyles[i].fStyle);
164        }
165    }
166
167    virtual ~TypefaceStylesGM() {
168        for (int i = 0; i < gFaceStylesCount; i++) {
169            SkSafeUnref(fFaces[i]);
170        }
171    }
172
173protected:
174    virtual SkString onShortName() SK_OVERRIDE {
175        SkString name("typefacestyles");
176        if (fApplyKerning) {
177            name.append("_kerning");
178        }
179        return name;
180    }
181
182    virtual SkISize onISize() SK_OVERRIDE {
183        return SkISize::Make(640, 480);
184    }
185
186    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
187        SkPaint paint;
188        paint.setAntiAlias(true);
189        paint.setTextSize(SkIntToScalar(30));
190
191        const char* text = fApplyKerning ? "Type AWAY" : "Hamburgefons";
192        const size_t textLen = strlen(text);
193
194        SkScalar x = SkIntToScalar(10);
195        SkScalar dy = paint.getFontMetrics(NULL);
196        SkScalar y = dy;
197
198        if (fApplyKerning) {
199            paint.setSubpixelText(true);
200        } else {
201            paint.setLinearText(true);
202        }
203        for (int i = 0; i < gFaceStylesCount; i++) {
204            paint.setTypeface(fFaces[i]);
205            canvas->drawText(text, textLen, x, y, paint);
206            if (fApplyKerning) {
207                drawKernText(canvas, text, textLen, x + 240, y, paint);
208            }
209            y += dy;
210        }
211    }
212
213private:
214    typedef skiagm::GM INHERITED;
215};
216
217///////////////////////////////////////////////////////////////////////////////
218
219DEF_GM( return new TypefaceGM; )
220DEF_GM( return new TypefaceStylesGM(false); )
221DEF_GM( return new TypefaceStylesGM(true); )
222