blob: d22a35ccd40a193e257ca2795b8364a563c8f387 [file] [log] [blame]
fmalita00d5c2c2014-08-21 08:53:26 -07001/*
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
Ben Wagnercb3d49c2018-03-14 15:07:43 -04008#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"
fmalita00d5c2c2014-08-21 08:53:26 -070022#include "gm.h"
Mike Klein33d20552017-03-22 13:47:51 -040023#include "sk_tool_utils.h"
fmalita00d5c2c2014-08-21 08:53:26 -070024
Ben Wagnercb3d49c2018-03-14 15:07:43 -040025#include <cstring>
fmalita00d5c2c2014-08-21 08:53:26 -070026
27namespace {
28
29enum Pos {
30 kDefault_Pos = 0,
31 kScalar_Pos = 1,
32 kPoint_Pos = 2,
33};
34
35const 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 {
fmalita37ecbaf2014-08-22 09:01:19 -070046 { { 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 } },
fmalita00d5c2c2014-08-21 08:53:26 -070049 },
50
51 {
fmalita37ecbaf2014-08-22 09:01:19 -070052 { { 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 } },
fmalita00d5c2c2014-08-21 08:53:26 -070055 },
56
57 {
fmalita37ecbaf2014-08-22 09:01:19 -070058 { { 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 } },
fmalita00d5c2c2014-08-21 08:53:26 -070073 },
74};
75
76const SkScalar kFontSize = 16;
77}
78
79class TextBlobGM : public skiagm::GM {
80public:
fmalitaacb882c2014-09-16 17:58:34 -070081 TextBlobGM(const char* txt)
kkinnunenb4a797f2015-05-21 06:15:28 -070082 : fText(txt) {
fmalita00d5c2c2014-08-21 08:53:26 -070083 }
84
85protected:
kkinnunenb4a797f2015-05-21 06:15:28 -070086 void onOnceBeforeDraw() override {
mbocee6a9912016-05-31 11:42:36 -070087 fTypeface = sk_tool_utils::create_portable_typeface("serif", SkFontStyle());
Mike Reedf78b7ea2018-12-25 22:06:17 -050088 SkFont font(fTypeface);
kkinnunenb4a797f2015-05-21 06:15:28 -070089 size_t txtLen = strlen(fText);
Mike Reedf78b7ea2018-12-25 22:06:17 -050090 int glyphCount = font.countText(fText, txtLen, kUTF8_SkTextEncoding);
kkinnunenb4a797f2015-05-21 06:15:28 -070091
92 fGlyphs.append(glyphCount);
Mike Reedf78b7ea2018-12-25 22:06:17 -050093 font.textToGlyphs(fText, txtLen, kUTF8_SkTextEncoding, fGlyphs.begin(), glyphCount);
kkinnunenb4a797f2015-05-21 06:15:28 -070094 }
95
mtklein36352bf2015-03-25 18:17:31 -070096 SkString onShortName() override {
fmalita00d5c2c2014-08-21 08:53:26 -070097 return SkString("textblob");
98 }
99
mtklein36352bf2015-03-25 18:17:31 -0700100 SkISize onISize() override {
fmalita00d5c2c2014-08-21 08:53:26 -0700101 return SkISize::Make(640, 480);
102 }
103
mtklein36352bf2015-03-25 18:17:31 -0700104 void onDraw(SkCanvas* canvas) override {
fmalita00d5c2c2014-08-21 08:53:26 -0700105 for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
fmalita37283c22016-09-13 10:00:23 -0700106 sk_sp<SkTextBlob> blob(this->makeBlob(b));
fmalita00d5c2c2014-08-21 08:53:26 -0700107
108 SkPaint p;
Mike Reed3185f902018-10-26 16:33:00 -0400109 p.setAntiAlias(true);
fmalita00d5c2c2014-08-21 08:53:26 -0700110 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);
Mike Reed3185f902018-10-26 16:33:00 -0400119 p.setAntiAlias(false);
fmalita00d5c2c2014-08-21 08:53:26 -0700120 canvas->drawRect(box, p);
121
122 }
123 }
124
125private:
fmalita37283c22016-09-13 10:00:23 -0700126 sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) {
fmalita00d5c2c2014-08-21 08:53:26 -0700127 SkTextBlobBuilder builder;
128
Mike Reed3185f902018-10-26 16:33:00 -0400129 SkFont font;
Mike Reed5f50f572018-11-12 13:19:37 -0500130 font.setSubpixel(true);
131 font.setEdging(SkFont::Edging::kAntiAlias);
fmalitaacb882c2014-09-16 17:58:34 -0700132 font.setTypeface(fTypeface);
fmalita00d5c2c2014-08-21 08:53:26 -0700133
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
Mike Reed3185f902018-10-26 16:33:00 -0400148 font.setSize(kFontSize * cfg->scale);
149 const SkScalar advanceX = font.getSize() * 0.85f;
150 const SkScalar advanceY = font.getSize() * 1.5f;
fmalita00d5c2c2014-08-21 08:53:26 -0700151
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:
djsollenf2b340f2016-01-29 08:51:04 -0800185 SK_ABORT("unhandled pos value");
fmalita00d5c2c2014-08-21 08:53:26 -0700186 }
187
188 currentGlyph += count;
189 }
190 }
191
fmalita37283c22016-09-13 10:00:23 -0700192 return builder.make();
fmalita00d5c2c2014-08-21 08:53:26 -0700193 }
194
bungeman13b9c952016-05-12 10:09:30 -0700195 SkTDArray<uint16_t> fGlyphs;
196 sk_sp<SkTypeface> fTypeface;
197 const char* fText;
fmalita00d5c2c2014-08-21 08:53:26 -0700198 typedef skiagm::GM INHERITED;
199};
200
halcanary385fe4d2015-08-26 13:07:48 -0700201DEF_GM(return new TextBlobGM("hamburgefons");)