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