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