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