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