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