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