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