xref: /aosp_15_r20/external/skia/gm/fontations.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 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/SkRefCnt.h"
12 #include "include/core/SkStream.h"
13 #include "include/core/SkString.h"
14 #include "include/core/SkTypeface.h"
15 #include "include/ports/SkTypeface_fontations.h"
16 #include "tools/Resources.h"
17 
18 
19 namespace skiagm {
20 
21 namespace {
22 const SkScalar kTextSizes[] = {12, 18, 30, 120};
23 const char kReportFontName[] = "fonts/Roboto-Regular.ttf";
24 const SkScalar kDumpFontSize = 20.0f;
25 
26 // TODO(drott): Test these dumps is in a unit test instead of dumping them to GM surface.
dumpToCanvas(SkCanvas * canvas,SkString text,sk_sp<SkTypeface> reportTypeface)27 void dumpToCanvas(SkCanvas* canvas, SkString text, sk_sp<SkTypeface> reportTypeface) {
28     canvas->drawSimpleText(text.c_str(),
29                            text.size() - 1,
30                            SkTextEncoding::kUTF8,
31                            0,
32                            0,
33                            SkFont(reportTypeface, kDumpFontSize),
34                            SkPaint());
35 }
36 
dumpLocalizedStrings(SkCanvas * canvas,sk_sp<SkTypeface> typeface,sk_sp<SkTypeface> reportTypeface)37 void dumpLocalizedStrings(SkCanvas* canvas,
38                           sk_sp<SkTypeface> typeface,
39                           sk_sp<SkTypeface> reportTypeface) {
40     auto family_names = typeface->createFamilyNameIterator();
41     SkTypeface::LocalizedString famName;
42     SkString localizedName;
43     while (family_names->next(&famName)) {
44         localizedName.printf(
45                 "Name: %s Language: %s\n", famName.fString.c_str(), famName.fLanguage.c_str());
46         dumpToCanvas(canvas, localizedName, reportTypeface);
47         canvas->translate(0, kDumpFontSize * 1.2);
48     }
49     family_names->unref();
50 }
51 
dumpGlyphCount(SkCanvas * canvas,sk_sp<SkTypeface> typeface,sk_sp<SkTypeface> reportTypeface)52 void dumpGlyphCount(SkCanvas* canvas,
53                     sk_sp<SkTypeface> typeface,
54                     sk_sp<SkTypeface> reportTypeface) {
55     SkString glyphCount;
56     glyphCount.printf("Num glyphs: %d\n", typeface->countGlyphs());
57     dumpToCanvas(canvas, glyphCount, reportTypeface);
58 }
59 
dumpFamilyAndPostscriptName(SkCanvas * canvas,sk_sp<SkTypeface> typeface,sk_sp<SkTypeface> reportTypeface)60 void dumpFamilyAndPostscriptName(SkCanvas* canvas,
61                                  sk_sp<SkTypeface> typeface,
62                                  sk_sp<SkTypeface> reportTypeface) {
63     SkString name;
64     typeface->getFamilyName(&name);
65     SkString nameDump;
66     nameDump.printf("Family name: %s\n", name.c_str());
67     dumpToCanvas(canvas, nameDump, reportTypeface);
68 
69     if (typeface->getPostScriptName(&name)) {
70         canvas->translate(0, kDumpFontSize * 1.2);
71         nameDump.printf("PS Name: %s\n", name.c_str());
72         dumpToCanvas(canvas, nameDump, reportTypeface);
73     } else {
74         canvas->translate(0, kDumpFontSize * 1.2);
75         nameDump.printf("No Postscript name.");
76         dumpToCanvas(canvas, nameDump, reportTypeface);
77     }
78 }
79 
80 }  // namespace
81 
82 class FontationsTypefaceGM : public GM {
83 public:
84     enum class TypefaceConstruction {
85         kMakeWithFontArguments,
86         kCloneWithFontArguments,
87     };
FontationsTypefaceGM(const char * testName,const char * testFontFilename,std::initializer_list<SkFontArguments::VariationPosition::Coordinate> specifiedVariations,TypefaceConstruction construction=TypefaceConstruction::kMakeWithFontArguments)88     FontationsTypefaceGM(const char* testName,
89                          const char* testFontFilename,
90                          std::initializer_list<SkFontArguments::VariationPosition::Coordinate>
91                                  specifiedVariations,
92                          TypefaceConstruction construction = TypefaceConstruction::kMakeWithFontArguments)
93             : fTestName(testName)
94             , fTestFontFilename(testFontFilename)
95             , fConstruction(construction) {
96         this->setBGColor(SK_ColorWHITE);
97         fVariationPosition.coordinateCount = specifiedVariations.size();
98         fCoordinates = std::make_unique<SkFontArguments::VariationPosition::Coordinate[]>(
99                 specifiedVariations.size());
100         for (size_t i = 0; i < specifiedVariations.size(); ++i) {
101             fCoordinates[i] = std::data(specifiedVariations)[i];
102         }
103 
104         fVariationPosition.coordinates = fCoordinates.get();
105     }
106 
107 protected:
onOnceBeforeDraw()108     void onOnceBeforeDraw() override {
109         if (fConstruction == TypefaceConstruction::kMakeWithFontArguments) {
110           fTestTypeface = SkTypeface_Make_Fontations(
111                 GetResourceAsStream(fTestFontFilename),
112                 SkFontArguments().setVariationDesignPosition(fVariationPosition));
113         } else {
114           fTestTypeface = SkTypeface_Make_Fontations(GetResourceAsStream(fTestFontFilename),
115                                                      SkFontArguments())
116                                   ->makeClone(SkFontArguments().setVariationDesignPosition(
117                                           fVariationPosition));
118         }
119         fReportTypeface =
120                 SkTypeface_Make_Fontations(GetResourceAsStream(kReportFontName), SkFontArguments());
121     }
122 
getName() const123     SkString getName() const override {
124         return SkStringPrintf("typeface_fontations_%s", fTestName.c_str());
125     }
126 
getISize()127     SkISize getISize() override { return SkISize::Make(400, 200); }
128 
onDraw(SkCanvas * canvas,SkString * errorMsg)129     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
130         SkPaint paint;
131         paint.setColor(SK_ColorBLACK);
132 
133         if (!fTestTypeface) {
134             *errorMsg = "Unable to initialize typeface.";
135             return DrawResult::kSkip;
136         }
137 
138         SkFont font(fTestTypeface);
139         const char32_t testText[] = U"abc";
140         size_t testTextBytesize = std::char_traits<char32_t>::length(testText) * sizeof(char32_t);
141         SkScalar x = 100;
142         SkScalar y = 150;
143 
144         for (SkScalar textSize : kTextSizes) {
145             font.setSize(textSize);
146             y += font.getSpacing();
147 
148             /* Draw origin marker as a green dot. */
149             paint.setColor(SK_ColorGREEN);
150             canvas->drawRect(SkRect::MakeXYWH(x, y, 2, 2), paint);
151             paint.setColor(SK_ColorBLACK);
152 
153             canvas->drawSimpleText(
154                     testText, testTextBytesize, SkTextEncoding::kUTF32, x, y, font, paint);
155         }
156 
157         canvas->translate(100, 470);
158         dumpGlyphCount(canvas, fTestTypeface, fReportTypeface);
159         canvas->translate(0, kDumpFontSize * 1.2);
160         dumpLocalizedStrings(canvas, fTestTypeface, fReportTypeface);
161         canvas->translate(0, kDumpFontSize * 1.2);
162         dumpFamilyAndPostscriptName(canvas, fTestTypeface, fReportTypeface);
163 
164         return DrawResult::kOk;
165     }
166 
167 private:
168     using INHERITED = GM;
169 
170     const SkString fTestName;
171     const char* fTestFontFilename;
172     sk_sp<SkTypeface> fTestTypeface;
173     sk_sp<SkTypeface> fReportTypeface;
174     SkFontArguments::VariationPosition fVariationPosition;
175     std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> fCoordinates;
176     TypefaceConstruction fConstruction;
177 };
178 
179 namespace {
operator ""_t(const char * tagName,size_t size)180 SkFourByteTag constexpr operator"" _t(const char* tagName, size_t size) {
181     SkASSERT(size == 4);
182     return SkSetFourByteTag(tagName[0], tagName[1], tagName[2], tagName[3]);
183 }
184 }  // namespace
185 DEF_GM(return new FontationsTypefaceGM("roboto", "fonts/Roboto-Regular.ttf", {});)
186 DEF_GM(return new FontationsTypefaceGM(
187                       "distortable_light",
188                       "fonts/Distortable.ttf",
189                       {{"wght"_t, 0.5f}}))
190 DEF_GM(return new FontationsTypefaceGM(
191         "distortable_bold",
192         "fonts/Distortable.ttf",
193         {{"wght"_t, 2.0f}},
194         FontationsTypefaceGM::TypefaceConstruction::kCloneWithFontArguments);)
195 
196 }  // namespace skiagm
197