1 /*
2 * Copyright 2024 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 #include "include/core/SkFontScanner.h"
8 #include "src/base/SkAutoMalloc.h"
9 #include "src/core/SkTHash.h"
10 #include "src/core/SkWriteBuffer.h"
11
12 #include "tests/FontScanner.h"
13 #include "tests/Test.h"
14 #include "tools/Resources.h"
15 #include "tools/fonts/FontToolUtils.h"
16
FontScanner_VariableFont(skiatest::Reporter * reporter,SkFontScanner * scanner)17 void FontScanner_VariableFont(skiatest::Reporter* reporter,
18 SkFontScanner* scanner) {
19 SkString name = GetResourcePath("fonts/Variable.ttf");
20
21 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(name.c_str());
22 if (!stream) {
23 REPORTER_ASSERT(reporter, false, "Cannot open the font file %s\n", name.c_str());
24 }
25
26 int numFaces;
27 if (!scanner->scanFile(stream.get(), &numFaces)) {
28 REPORTER_ASSERT(reporter, false, "Cannot scanFile\n");
29 }
30 REPORTER_ASSERT(reporter, numFaces == 1);
31
32 skia_private::THashSet<SkFontStyle> uniqueStyles;
33 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
34 int numInstances;
35 if (!scanner->scanFace(stream.get(), faceIndex, &numInstances)) {
36 REPORTER_ASSERT(reporter, false, "Cannot scanFace\n");
37 continue;
38 }
39
40 REPORTER_ASSERT(reporter, numInstances == 5);
41 // Not including the default instance
42 for (int instanceIndex = 1; instanceIndex <= numInstances; ++instanceIndex) {
43 bool isFixedPitch;
44 SkString realName;
45 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
46 if (!scanner->scanInstance(stream.get(), faceIndex, instanceIndex,
47 &realName, &style, &isFixedPitch,
48 nullptr, nullptr)) {
49 REPORTER_ASSERT(reporter,
50 false,
51 "Cannot scanInstance %s %d\n",
52 name.c_str(),
53 faceIndex);
54 continue;
55 } else {
56 if (instanceIndex == 0) {
57 // Do not add it to the set
58 } else if (uniqueStyles.find(style) == nullptr) {
59 uniqueStyles.add(style);
60 } else {
61 REPORTER_ASSERT(
62 reporter,
63 false,
64 "Font: %s (%d %d %d)\n",
65 realName.c_str(), style.weight(), style.width(), style.slant());
66 }
67 }
68 }
69 REPORTER_ASSERT(reporter, uniqueStyles.count() == numInstances);
70 }
71 }
72
FontScanner_NamedInstances1(skiatest::Reporter * reporter,SkFontScanner * scanner)73 void FontScanner_NamedInstances1(skiatest::Reporter* reporter, SkFontScanner* scanner) {
74 SkString name = GetResourcePath("fonts/Variable.ttf");
75
76 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(name.c_str());
77 if (!stream) {
78 REPORTER_ASSERT(reporter, false, "Cannot open the font file %s\n", name.c_str());
79 }
80
81 int numFaces;
82 if (!scanner->scanFile(stream.get(), &numFaces)) {
83 REPORTER_ASSERT(reporter, false, "Cannot scanFile\n");
84 }
85 REPORTER_ASSERT(reporter, numFaces == 1);
86
87 skia_private::THashSet<SkFontStyle> uniqueStyles;
88 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
89 int numInstances;
90 if (!scanner->scanFace(stream.get(), faceIndex, &numInstances)) {
91 REPORTER_ASSERT(reporter, false, "Cannot scanFace\n");
92 continue;
93 }
94 REPORTER_ASSERT(reporter, numInstances == 5);
95 // Not including the default instance (most time it will be listed anyway)
96 for (int instanceIndex = 1; instanceIndex <= numInstances; ++instanceIndex) {
97 bool isFixedPitch;
98 SkString realName;
99 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
100 SkFontScanner::AxisDefinitions axes;
101 if (!scanner->scanInstance(stream.get(), faceIndex, instanceIndex,
102 &realName, &style, &isFixedPitch,
103 &axes, nullptr)) {
104 REPORTER_ASSERT(reporter,
105 false,
106 "Cannot scanInstance %s %d\n",
107 name.c_str(),
108 faceIndex);
109 continue;
110 } else {
111 if (uniqueStyles.find(style) == nullptr) {
112 uniqueStyles.add(style);
113 REPORTER_ASSERT(reporter, axes.size() == 2);
114 if (instanceIndex == 5) {
115 SkFourByteTag weight = SkSetFourByteTag('w', 'g', 'h', 't');
116 SkFourByteTag width = SkSetFourByteTag('w', 'd', 't', 'h');
117 REPORTER_ASSERT(reporter, axes[0].tag == weight);
118 REPORTER_ASSERT(reporter, axes[0].def == 400.0f);
119 REPORTER_ASSERT(reporter, axes[0].min == 100.0f);
120 REPORTER_ASSERT(reporter, axes[0].max == 900.0f);
121 REPORTER_ASSERT(reporter, axes[1].tag == width);
122 REPORTER_ASSERT(reporter, axes[1].def == 100.0f);
123 REPORTER_ASSERT(reporter, axes[1].min == 050.0f);
124 REPORTER_ASSERT(reporter, axes[1].max == 200.0f);
125 }
126 } else {
127 REPORTER_ASSERT(reporter,
128 false,
129 "Font #%d: %s (%d %d %d)\n",
130 instanceIndex,
131 realName.c_str(),
132 style.weight(),
133 style.width(),
134 style.slant());
135 }
136 }
137 }
138 }
139 }
140
FontScanner_NamedInstances2(skiatest::Reporter * reporter,SkFontScanner * scanner)141 void FontScanner_NamedInstances2(skiatest::Reporter* reporter, SkFontScanner* scanner) {
142 SkString name = GetResourcePath("fonts/VaryAlongQuads.ttf");
143
144 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(name.c_str());
145 if (!stream) {
146 REPORTER_ASSERT(reporter, false, "Cannot open the font file %s\n", name.c_str());
147 }
148
149 int numFaces;
150 if (!scanner->scanFile(stream.get(), &numFaces)) {
151 REPORTER_ASSERT(reporter, false, "Cannot scanFile\n");
152 }
153 REPORTER_ASSERT(reporter, numFaces == 1);
154
155 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
156 int numInstances;
157 if (!scanner->scanFace(stream.get(), faceIndex, &numInstances)) {
158 REPORTER_ASSERT(reporter, false, "Cannot scanFace\n");
159 continue;
160 }
161 REPORTER_ASSERT(reporter, numInstances == 3);
162 // Not including the default instance (most time it will be listed anyway)
163 for (int instanceIndex = 1; instanceIndex <= numInstances; ++instanceIndex) {
164 bool isFixedPitch;
165 SkString realName;
166 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
167 SkFontScanner::AxisDefinitions axes;
168 if (!scanner->scanInstance(stream.get(), faceIndex, instanceIndex,
169 &realName, &style, &isFixedPitch,
170 &axes, nullptr)) {
171 REPORTER_ASSERT(reporter,
172 false,
173 "Cannot scanInstance %s %d\n",
174 name.c_str(),
175 faceIndex);
176 continue;
177 }
178 REPORTER_ASSERT(reporter, axes.size() == 2);
179 SkFourByteTag weight = SkSetFourByteTag('w', 'g', 'h', 't');
180 for (auto i = 0; i < axes.size(); ++i) {
181 const auto& axis = axes[i];
182 REPORTER_ASSERT(reporter, (instanceIndex != 1) || (style.weight() == 100.0f));
183 REPORTER_ASSERT(reporter, (instanceIndex != 2) || (style.weight() == 400.0f));
184 REPORTER_ASSERT(reporter, (instanceIndex != 3) || (style.weight() == 900.0f));
185 REPORTER_ASSERT(reporter, axis.tag == weight);
186 REPORTER_ASSERT(reporter, axis.def == 400.0f);
187 REPORTER_ASSERT(reporter, axis.min == 100.0f);
188 REPORTER_ASSERT(reporter, axis.max == 900.0f);
189 }
190 }
191 }
192 }
193
FontScanner_FontCollection(skiatest::Reporter * reporter,SkFontScanner * scanner)194 void FontScanner_FontCollection(skiatest::Reporter* reporter, SkFontScanner* scanner) {
195 SkString name = SkString("fonts/test.ttc");
196 std::unique_ptr<SkStreamAsset> stream = GetResourceAsStream(name.c_str());
197 if (!stream) {
198 REPORTER_ASSERT(reporter, false, "Cannot open the font file %s\n", name.c_str());
199 }
200
201 int numFaces;
202 if (!scanner->scanFile(stream.get(), &numFaces)) {
203 REPORTER_ASSERT(reporter, false, "Cannot scanFile\n");
204 }
205 REPORTER_ASSERT(reporter, numFaces == 2);
206
207 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
208 int numInstances;
209 if (!scanner->scanFace(stream.get(), faceIndex, &numInstances)) {
210 REPORTER_ASSERT(reporter, false, "Cannot scanFace\n");
211 continue;
212 }
213 REPORTER_ASSERT(reporter, numInstances == 0);
214 const auto defaultInstance = 0;
215 bool isFixedPitch;
216 SkString realName;
217 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
218 SkFontScanner::AxisDefinitions axes;
219 if (!scanner->scanInstance(stream.get(), faceIndex, defaultInstance,
220 &realName, &style, &isFixedPitch,
221 &axes, nullptr)) {
222 REPORTER_ASSERT(reporter,
223 false,
224 "Cannot scanInstance %s %d\n",
225 name.c_str(),
226 faceIndex);
227 continue;
228 }
229 REPORTER_ASSERT(reporter, axes.size() == 0);
230 REPORTER_ASSERT(reporter, (faceIndex != 0) || (style.weight() == 400.0f));
231 REPORTER_ASSERT(reporter, (faceIndex != 1) || (style.weight() == 700.0f));
232 }
233 }
234