| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 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 |  | 
| Ben Wagner | cb3d49c | 2018-03-14 15:07:43 -0400 | [diff] [blame] | 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" | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 22 | #include "gm.h" | 
| Mike Klein | 33d2055 | 2017-03-22 13:47:51 -0400 | [diff] [blame] | 23 | #include "sk_tool_utils.h" | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 24 |  | 
| Ben Wagner | cb3d49c | 2018-03-14 15:07:43 -0400 | [diff] [blame] | 25 | #include <cstring> | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 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 |     { | 
| fmalita | 37ecbaf | 2014-08-22 09:01:19 -0700 | [diff] [blame] | 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 } }, | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 49 |     }, | 
 | 50 |  | 
 | 51 |     { | 
| fmalita | 37ecbaf | 2014-08-22 09:01:19 -0700 | [diff] [blame] | 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 } }, | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 55 |     }, | 
 | 56 |  | 
 | 57 |     { | 
| fmalita | 37ecbaf | 2014-08-22 09:01:19 -0700 | [diff] [blame] | 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 } }, | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 73 |     }, | 
 | 74 | }; | 
 | 75 |  | 
 | 76 | const SkScalar kFontSize = 16; | 
 | 77 | } | 
 | 78 |  | 
 | 79 | class TextBlobGM : public skiagm::GM { | 
 | 80 | public: | 
| fmalita | acb882c | 2014-09-16 17:58:34 -0700 | [diff] [blame] | 81 |     TextBlobGM(const char* txt) | 
| kkinnunen | b4a797f | 2015-05-21 06:15:28 -0700 | [diff] [blame] | 82 |         : fText(txt) { | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 83 |     } | 
 | 84 |  | 
 | 85 | protected: | 
| kkinnunen | b4a797f | 2015-05-21 06:15:28 -0700 | [diff] [blame] | 86 |     void onOnceBeforeDraw() override { | 
| mboc | ee6a991 | 2016-05-31 11:42:36 -0700 | [diff] [blame] | 87 |         fTypeface = sk_tool_utils::create_portable_typeface("serif", SkFontStyle()); | 
| Mike Reed | f78b7ea | 2018-12-25 22:06:17 -0500 | [diff] [blame] | 88 |         SkFont font(fTypeface); | 
| kkinnunen | b4a797f | 2015-05-21 06:15:28 -0700 | [diff] [blame] | 89 |         size_t txtLen = strlen(fText); | 
| Mike Reed | f78b7ea | 2018-12-25 22:06:17 -0500 | [diff] [blame] | 90 |         int glyphCount = font.countText(fText, txtLen, kUTF8_SkTextEncoding); | 
| kkinnunen | b4a797f | 2015-05-21 06:15:28 -0700 | [diff] [blame] | 91 |  | 
 | 92 |         fGlyphs.append(glyphCount); | 
| Mike Reed | f78b7ea | 2018-12-25 22:06:17 -0500 | [diff] [blame] | 93 |         font.textToGlyphs(fText, txtLen, kUTF8_SkTextEncoding, fGlyphs.begin(), glyphCount); | 
| kkinnunen | b4a797f | 2015-05-21 06:15:28 -0700 | [diff] [blame] | 94 |     } | 
 | 95 |  | 
| mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 96 |     SkString onShortName() override { | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 97 |         return SkString("textblob"); | 
 | 98 |     } | 
 | 99 |  | 
| mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 100 |     SkISize onISize() override { | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 101 |         return SkISize::Make(640, 480); | 
 | 102 |     } | 
 | 103 |  | 
| mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 104 |     void onDraw(SkCanvas* canvas) override { | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 105 |         for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) { | 
| fmalita | 37283c2 | 2016-09-13 10:00:23 -0700 | [diff] [blame] | 106 |             sk_sp<SkTextBlob> blob(this->makeBlob(b)); | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 107 |  | 
 | 108 |             SkPaint p; | 
| Mike Reed | 3185f90 | 2018-10-26 16:33:00 -0400 | [diff] [blame] | 109 |             p.setAntiAlias(true); | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 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); | 
| Mike Reed | 3185f90 | 2018-10-26 16:33:00 -0400 | [diff] [blame] | 119 |             p.setAntiAlias(false); | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 120 |             canvas->drawRect(box, p); | 
 | 121 |  | 
 | 122 |         } | 
 | 123 |     } | 
 | 124 |  | 
 | 125 | private: | 
| fmalita | 37283c2 | 2016-09-13 10:00:23 -0700 | [diff] [blame] | 126 |     sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) { | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 127 |         SkTextBlobBuilder builder; | 
 | 128 |  | 
| Mike Reed | 3185f90 | 2018-10-26 16:33:00 -0400 | [diff] [blame] | 129 |         SkFont font; | 
| Mike Reed | 5f50f57 | 2018-11-12 13:19:37 -0500 | [diff] [blame] | 130 |         font.setSubpixel(true); | 
 | 131 |         font.setEdging(SkFont::Edging::kAntiAlias); | 
| fmalita | acb882c | 2014-09-16 17:58:34 -0700 | [diff] [blame] | 132 |         font.setTypeface(fTypeface); | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 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 |  | 
| Mike Reed | 3185f90 | 2018-10-26 16:33:00 -0400 | [diff] [blame] | 148 |                 font.setSize(kFontSize * cfg->scale); | 
 | 149 |                 const SkScalar advanceX = font.getSize() * 0.85f; | 
 | 150 |                 const SkScalar advanceY = font.getSize() * 1.5f; | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 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: | 
| djsollen | f2b340f | 2016-01-29 08:51:04 -0800 | [diff] [blame] | 185 |                     SK_ABORT("unhandled pos value"); | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 186 |                 } | 
 | 187 |  | 
 | 188 |                 currentGlyph += count; | 
 | 189 |             } | 
 | 190 |         } | 
 | 191 |  | 
| fmalita | 37283c2 | 2016-09-13 10:00:23 -0700 | [diff] [blame] | 192 |         return builder.make(); | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 193 |     } | 
 | 194 |  | 
| bungeman | 13b9c95 | 2016-05-12 10:09:30 -0700 | [diff] [blame] | 195 |     SkTDArray<uint16_t> fGlyphs; | 
 | 196 |     sk_sp<SkTypeface>   fTypeface; | 
 | 197 |     const char*         fText; | 
| fmalita | 00d5c2c | 2014-08-21 08:53:26 -0700 | [diff] [blame] | 198 |     typedef skiagm::GM INHERITED; | 
 | 199 | }; | 
 | 200 |  | 
| halcanary | 385fe4d | 2015-08-26 13:07:48 -0700 | [diff] [blame] | 201 | DEF_GM(return new TextBlobGM("hamburgefons");) |