1 /* 2 * Copyright 2021 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/SkFont.h" 11 #include "include/core/SkPaint.h" 12 #include "include/core/SkRSXform.h" 13 #include "include/core/SkSpan.h" 14 #include "include/private/SkTDArray.h" 15 #include "src/core/SkZip.h" 16 #include "tools/ToolUtils.h" 17 18 static const char gText[] = "Call me Ishmael. Some years ago—never mind how long precisely"; 19 20 class DrawGlyphsGM : public skiagm::GM { 21 public: onOnceBeforeDraw()22 void onOnceBeforeDraw() override { 23 fTypeface = ToolUtils::create_portable_typeface("serif", SkFontStyle()); 24 fFont = SkFont(fTypeface); 25 fFont.setSubpixel(true); 26 fFont.setSize(18); 27 const size_t txtLen = strlen(gText); 28 fGlyphCount = fFont.countText(gText, txtLen, SkTextEncoding::kUTF8); 29 30 fGlyphs.append(fGlyphCount); 31 fFont.textToGlyphs(gText, txtLen, SkTextEncoding::kUTF8, fGlyphs.begin(), fGlyphCount); 32 33 fPositions.append(fGlyphCount); 34 fFont.getPos(fGlyphs.begin(), fGlyphCount, fPositions.begin()); 35 auto positions = SkMakeSpan(fPositions.begin(), fGlyphCount); 36 37 fLength = positions.back().x() - positions.front().x(); 38 fRadius = fLength / SK_FloatPI; 39 fXforms.append(fGlyphCount); 40 41 for (auto [xform, pos] : SkMakeZip(fXforms.begin(), positions)) { 42 const SkScalar lengthToGlyph = pos.x() - positions.front().x(); 43 const SkScalar angle = SK_FloatPI * (fLength - lengthToGlyph) / fLength; 44 const SkScalar cos = std::cos(angle); 45 const SkScalar sin = std::sin(angle); 46 xform = SkRSXform::Make(sin, cos, fRadius*cos, -fRadius*sin); 47 } 48 } 49 onShortName()50 SkString onShortName() override { 51 return SkString("drawglyphs"); 52 } 53 onISize()54 SkISize onISize() override { 55 return SkISize::Make(640, 480); 56 } 57 onDraw(SkCanvas * canvas)58 void onDraw(SkCanvas* canvas) override { 59 canvas->drawGlyphs(fGlyphCount, fGlyphs.begin(), fPositions.begin(), {50, 100}, fFont, 60 SkPaint{}); 61 62 canvas->drawGlyphs(fGlyphCount, fGlyphs.begin(), fPositions.begin(), {50, 120}, fFont, 63 SkPaint{}); 64 65 // Check bounding box calculation. 66 for (auto& pos : fPositions) { 67 pos += {0, -500}; 68 } 69 canvas->drawGlyphs(fGlyphCount, fGlyphs.begin(), fPositions.begin(), {50, 640}, fFont, 70 SkPaint{}); 71 72 canvas->drawGlyphs(fGlyphCount, fGlyphs.begin(), fXforms.begin(), 73 {50 + fLength / 2, 160 + fRadius}, fFont, SkPaint{}); 74 75 // TODO: add tests for cluster versions of drawGlyphs. 76 } 77 78 private: 79 sk_sp<SkTypeface> fTypeface; 80 SkFont fFont; 81 SkTDArray<SkGlyphID> fGlyphs; 82 SkTDArray<SkPoint> fPositions; 83 SkTDArray<SkRSXform> fXforms; 84 int fGlyphCount; 85 SkScalar fRadius; 86 SkScalar fLength; 87 }; 88 89 DEF_GM(return new DrawGlyphsGM{};) 90