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: 69 TextBlobGM(const char* txt) 70 : fTypeface(sk_tool_utils::create_portable_typeface("Times", SkTypeface::kNormal)) { 71 SkPaint p; 72 p.setTypeface(fTypeface); 73 size_t txtLen = strlen(txt); 74 int glyphCount = p.textToGlyphs(txt, txtLen, NULL); 75 76 fGlyphs.append(glyphCount); 77 p.textToGlyphs(txt, txtLen, fGlyphs.begin()); 78 } 79 80 protected: 81 virtual SkString onShortName() SK_OVERRIDE { 82 return SkString("textblob"); 83 } 84 85 virtual SkISize onISize() SK_OVERRIDE { 86 return SkISize::Make(640, 480); 87 } 88 89 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { 90 for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) { 91 SkAutoTUnref<const SkTextBlob> blob(this->makeBlob(b)); 92 93 SkPaint p; 94 SkPoint offset = SkPoint::Make(SkIntToScalar(10 + 300 * (b % 2)), 95 SkIntToScalar(20 + 150 * (b / 2))); 96 97 canvas->drawTextBlob(blob, offset.x(), offset.y(), p); 98 99 p.setColor(SK_ColorBLUE); 100 p.setStyle(SkPaint::kStroke_Style); 101 SkRect box = blob->bounds(); 102 box.offset(offset); 103 canvas->drawRect(box, p); 104 105 } 106 } 107 108 private: 109 const SkTextBlob* makeBlob(unsigned blobIndex) { 110 SkTextBlobBuilder builder; 111 112 SkPaint font; 113 font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 114 font.setAntiAlias(true); 115 font.setSubpixelText(true); 116 font.setTypeface(fTypeface); 117 118 for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) { 119 unsigned currentGlyph = 0; 120 121 for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) { 122 const BlobCfg* cfg = &blobConfigs[blobIndex][l][c]; 123 unsigned count = cfg->count; 124 125 if (count > fGlyphs.count() - currentGlyph) { 126 count = fGlyphs.count() - currentGlyph; 127 } 128 if (0 == count) { 129 break; 130 } 131 132 font.setTextSize(kFontSize * cfg->scale); 133 const SkScalar advanceX = font.getTextSize() * 0.85f; 134 const SkScalar advanceY = font.getTextSize() * 1.5f; 135 136 SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX, 137 advanceY * l); 138 switch (cfg->pos) { 139 case kDefault_Pos: { 140 const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count, 141 offset.x(), 142 offset.y()); 143 memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); 144 } break; 145 case kScalar_Pos: { 146 const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count, 147 offset.y()); 148 SkTDArray<SkScalar> pos; 149 for (unsigned i = 0; i < count; ++i) { 150 *pos.append() = offset.x() + i * advanceX; 151 } 152 153 memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); 154 memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar)); 155 } break; 156 case kPoint_Pos: { 157 const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count); 158 159 SkTDArray<SkScalar> pos; 160 for (unsigned i = 0; i < count; ++i) { 161 *pos.append() = offset.x() + i * advanceX; 162 *pos.append() = offset.y() + i * (advanceY / count); 163 } 164 165 memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t)); 166 memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2); 167 } break; 168 default: 169 SkFAIL("unhandled pos value"); 170 } 171 172 currentGlyph += count; 173 } 174 } 175 176 return builder.build(); 177 } 178 179 SkTDArray<uint16_t> fGlyphs; 180 SkAutoTUnref<SkTypeface> fTypeface; 181 182 typedef skiagm::GM INHERITED; 183 }; 184 185 DEF_GM( return SkNEW_ARGS(TextBlobGM, ("hamburgefons")); ) 186