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