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