xref: /aosp_15_r20/external/skia/gm/drawglyphs.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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