textblob.cpp revision b4a797f3aa8c10387f01cf51a65dd1a8aa5eec9d
1/*
2 * Copyright 2014 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
10#include "SkCanvas.h"
11#include "SkPoint.h"
12#include "SkTextBlob.h"
13#include "SkTDArray.h"
14
15namespace  {
16
17enum Pos {
18    kDefault_Pos = 0,
19    kScalar_Pos  = 1,
20    kPoint_Pos   = 2,
21};
22
23const struct BlobCfg {
24    unsigned count;
25    Pos      pos;
26    SkScalar scale;
27} blobConfigs[][3][3] = {
28    {
29        { { 1024, kDefault_Pos, 1 }, { 0, kDefault_Pos, 0 }, { 0, kDefault_Pos, 0 } },
30        { { 1024,  kScalar_Pos, 1 }, { 0,  kScalar_Pos, 0 }, { 0,  kScalar_Pos, 0 } },
31        { { 1024,   kPoint_Pos, 1 }, { 0,   kPoint_Pos, 0 }, { 0,   kPoint_Pos, 0 } },
32    },
33    {
34        { { 4, kDefault_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4, kDefault_Pos, 1 } },
35        { { 4,  kScalar_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
36        { { 4,   kPoint_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
37    },
38
39    {
40        { { 4, kDefault_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
41        { { 4,  kScalar_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
42        { { 4,   kPoint_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1 } },
43    },
44
45    {
46        { { 4, kDefault_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
47        { { 4,  kScalar_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1 } },
48        { { 4,   kPoint_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
49    },
50
51    {
52        { { 4, kDefault_Pos, .75f },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1.25f } },
53        { { 4,  kScalar_Pos, .75f },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1.25f } },
54        { { 4,   kPoint_Pos, .75f },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1.25f } },
55    },
56
57    {
58        { { 4, kDefault_Pos, 1 },     { 4,  kScalar_Pos, .75f },  { 4,   kPoint_Pos, 1.25f } },
59        { { 4,  kScalar_Pos, 1 },     { 4,   kPoint_Pos, .75f },  { 4, kDefault_Pos, 1.25f } },
60        { { 4,   kPoint_Pos, 1 },     { 4, kDefault_Pos, .75f },  { 4,  kScalar_Pos, 1.25f } },
61    },
62};
63
64const SkScalar kFontSize = 16;
65}
66
67class TextBlobGM : public skiagm::GM {
68public:
69    TextBlobGM(const char* txt)
70        : fText(txt) {
71    }
72
73protected:
74    void onOnceBeforeDraw() override {
75        fTypeface.reset(sk_tool_utils::create_portable_typeface("Times", SkTypeface::kNormal));
76        SkPaint p;
77        p.setTypeface(fTypeface);
78        size_t txtLen = strlen(fText);
79        int glyphCount = p.textToGlyphs(fText, txtLen, NULL);
80
81        fGlyphs.append(glyphCount);
82        p.textToGlyphs(fText, txtLen, fGlyphs.begin());
83    }
84
85    SkString onShortName() override {
86        return SkString("textblob");
87    }
88
89    SkISize onISize() override {
90        return SkISize::Make(640, 480);
91    }
92
93    void onDraw(SkCanvas* canvas) override {
94        for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
95            SkAutoTUnref<const SkTextBlob> blob(this->makeBlob(b));
96
97            SkPaint p;
98            SkPoint offset = SkPoint::Make(SkIntToScalar(10 + 300 * (b % 2)),
99                                           SkIntToScalar(20 + 150 * (b / 2)));
100
101            canvas->drawTextBlob(blob, offset.x(), offset.y(), p);
102
103            p.setColor(SK_ColorBLUE);
104            p.setStyle(SkPaint::kStroke_Style);
105            SkRect box = blob->bounds();
106            box.offset(offset);
107            canvas->drawRect(box, p);
108
109        }
110    }
111
112private:
113    const SkTextBlob* makeBlob(unsigned blobIndex) {
114        SkTextBlobBuilder builder;
115
116        SkPaint font;
117        font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
118        font.setAntiAlias(true);
119        font.setSubpixelText(true);
120        font.setTypeface(fTypeface);
121
122        for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) {
123            unsigned currentGlyph = 0;
124
125            for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) {
126                const BlobCfg* cfg = &blobConfigs[blobIndex][l][c];
127                unsigned count = cfg->count;
128
129                if (count > fGlyphs.count() - currentGlyph) {
130                    count = fGlyphs.count() - currentGlyph;
131                }
132                if (0 == count) {
133                    break;
134                }
135
136                font.setTextSize(kFontSize * cfg->scale);
137                const SkScalar advanceX = font.getTextSize() * 0.85f;
138                const SkScalar advanceY = font.getTextSize() * 1.5f;
139
140                SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX,
141                                               advanceY * l);
142                switch (cfg->pos) {
143                case kDefault_Pos: {
144                    const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count,
145                                                                               offset.x(),
146                                                                               offset.y());
147                    memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
148                } break;
149                case kScalar_Pos: {
150                    const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count,
151                                                                                   offset.y());
152                    SkTDArray<SkScalar> pos;
153                    for (unsigned i = 0; i < count; ++i) {
154                        *pos.append() = offset.x() + i * advanceX;
155                    }
156
157                    memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
158                    memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar));
159                } break;
160                case kPoint_Pos: {
161                    const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count);
162
163                    SkTDArray<SkScalar> pos;
164                    for (unsigned i = 0; i < count; ++i) {
165                        *pos.append() = offset.x() + i * advanceX;
166                        *pos.append() = offset.y() + i * (advanceY / count);
167                    }
168
169                    memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
170                    memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2);
171                } break;
172                default:
173                    SkFAIL("unhandled pos value");
174                }
175
176                currentGlyph += count;
177            }
178        }
179
180        return builder.build();
181    }
182
183    SkTDArray<uint16_t>      fGlyphs;
184    SkAutoTUnref<SkTypeface> fTypeface;
185    const char*              fText;
186    typedef skiagm::GM INHERITED;
187};
188
189DEF_GM( return SkNEW_ARGS(TextBlobGM, ("hamburgefons")); )
190