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