• 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 
10 #include "SkCanvas.h"
11 #include "SkPoint.h"
12 #include "SkTextBlob.h"
13 #include "SkTDArray.h"
14 
15 namespace  {
16 
17 enum Pos {
18     kDefault_Pos = 0,
19     kScalar_Pos  = 1,
20     kPoint_Pos   = 2,
21 };
22 
23 const 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 
64 const SkScalar kFontSize = 16;
65 }
66 
67 class TextBlobGM : public skiagm::GM {
68 public:
TextBlobGM(const char * txt)69     TextBlobGM(const char* txt)
70         : fText(txt) {
71     }
72 
73 protected:
onOnceBeforeDraw()74     void onOnceBeforeDraw() override {
75         fTypeface.reset(sk_tool_utils::create_portable_typeface("serif", SkTypeface::kNormal));
76         SkPaint p;
77         p.setTypeface(fTypeface);
78         size_t txtLen = strlen(fText);
79         int glyphCount = p.textToGlyphs(fText, txtLen, nullptr);
80 
81         fGlyphs.append(glyphCount);
82         p.textToGlyphs(fText, txtLen, fGlyphs.begin());
83     }
84 
onShortName()85     SkString onShortName() override {
86         return SkString("textblob");
87     }
88 
onISize()89     SkISize onISize() override {
90         return SkISize::Make(640, 480);
91     }
92 
onDraw(SkCanvas * canvas)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 
112 private:
makeBlob(unsigned blobIndex)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                     SK_ABORT("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 
189 DEF_GM(return new TextBlobGM("hamburgefons");)
190