xref: /aosp_15_r20/external/skia/tests/FontationsTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 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 "include/core/SkStream.h"
9 #include "include/core/SkTypeface.h"
10 #include "include/ports/SkTypeface_fontations.h"
11 #include "tests/Test.h"
12 #include "tools/Resources.h"
13 
14 #include <memory>
15 
16 namespace {
17 const char kFontResource[] = "fonts/ahem.ttf";
18 const char kTtcResource[] = "fonts/test.ttc";
19 const char kVariableResource[] = "fonts/test_glyphs-glyf_colr_1_variable.ttf";
20 constexpr size_t kNumVariableAxes = 44;
21 
22 struct AxisExpectation {
23     SkFourByteTag tag;
24     float minValue;
25     float defValue;
26     float maxValue;
27 } axisExpectations[] = {
28         {SkSetFourByteTag('S', 'W', 'P', 'S'), -90.0, 0.0, 90.0},
29         {SkSetFourByteTag('S', 'W', 'P', 'E'), -90.0, 0.0, 90.0},
30         {SkSetFourByteTag('S', 'W', 'C', '1'), -2.0, 0.0, 2.0},
31         {SkSetFourByteTag('S', 'W', 'C', '2'), -2.0, 0.0, 2.0},
32         {SkSetFourByteTag('S', 'W', 'C', '3'), -2.0, 0.0, 2.0},
33         {SkSetFourByteTag('S', 'W', 'C', '4'), -2.0, 0.0, 2.0},
34         {SkSetFourByteTag('S', 'C', 'O', 'X'), -200., 0.0, 200.},
35         {SkSetFourByteTag('S', 'C', 'O', 'Y'), -200., 0.0, 200.},
36         {SkSetFourByteTag('S', 'C', 'S', 'X'), -2.0, 0.0, 1.9999389648437},
37         {SkSetFourByteTag('S', 'C', 'S', 'Y'), -2.0, 0.0, 1.9999389648437},
38         {SkSetFourByteTag('G', 'R', 'X', '0'), -1000, 0.0, 1000},
39         {SkSetFourByteTag('G', 'R', 'Y', '0'), -1000, 0.0, 1000},
40         {SkSetFourByteTag('G', 'R', 'X', '1'), -1000, 0.0, 1000},
41         {SkSetFourByteTag('G', 'R', 'Y', '1'), -1000, 0.0, 1000},
42         {SkSetFourByteTag('G', 'R', 'X', '2'), -1000, 0.0, 1000},
43         {SkSetFourByteTag('G', 'R', 'Y', '2'), -1000, 0.0, 1000},
44         {SkSetFourByteTag('G', 'R', 'R', '0'), -1000, 0.0, 1000},
45         {SkSetFourByteTag('G', 'R', 'R', '1'), -1000, 0.0, 1000},
46         {SkSetFourByteTag('C', 'O', 'L', '1'), -2.0, 0.0, 2.0},
47         {SkSetFourByteTag('C', 'O', 'L', '2'), -2.0, 0.0, 2.0},
48         {SkSetFourByteTag('C', 'O', 'L', '3'), -2.0, 0.0, 2.0},
49         {SkSetFourByteTag('R', 'O', 'T', 'A'), 0.0, 0.0, 539.989013671875},
50         {SkSetFourByteTag('R', 'O', 'T', 'X'), -500.0, 0.0, 500.0},
51         {SkSetFourByteTag('R', 'O', 'T', 'Y'), -500.0, 0.0, 500.0},
52         {SkSetFourByteTag('S', 'K', 'X', 'A'), -90.0, 0.0, 90.0},
53         {SkSetFourByteTag('S', 'K', 'Y', 'A'), -90.0, 0.0, 90.0},
54         {SkSetFourByteTag('S', 'K', 'C', 'X'), -500.0, 0.0, 500.0},
55         {SkSetFourByteTag('S', 'K', 'C', 'Y'), -500.0, 0.0, 500.0},
56         {SkSetFourByteTag('T', 'R', 'X', 'X'), -2.0, 0.0, 2.0},
57         {SkSetFourByteTag('T', 'R', 'Y', 'X'), -2.0, 0.0, 2.0},
58         {SkSetFourByteTag('T', 'R', 'X', 'Y'), -2.0, 0.0, 2.0},
59         {SkSetFourByteTag('T', 'R', 'Y', 'Y'), -2.0, 0.0, 2.0},
60         {SkSetFourByteTag('T', 'R', 'D', 'X'), -500.0, 0.0, 500.0},
61         {SkSetFourByteTag('T', 'R', 'D', 'Y'), -500.0, 0.0, 500.0},
62         {SkSetFourByteTag('T', 'L', 'D', 'X'), -500.0, 0.0, 500.0},
63         {SkSetFourByteTag('T', 'L', 'D', 'Y'), -500.0, 0.0, 500.0},
64         {SkSetFourByteTag('C', 'L', 'X', 'I'), -500.0, 0.0, 500.0},
65         {SkSetFourByteTag('C', 'L', 'Y', 'I'), -500.0, 0.0, 500.0},
66         {SkSetFourByteTag('C', 'L', 'X', 'A'), -500.0, 0.0, 500.0},
67         {SkSetFourByteTag('C', 'L', 'Y', 'A'), -500.0, 0.0, 500.0},
68         {SkSetFourByteTag('C', 'L', 'I', 'O'), -500.0, 0.0, 500.0},
69         {SkSetFourByteTag('A', 'P', 'H', '1'), -1.0, 0.0, 0.0},
70         {SkSetFourByteTag('A', 'P', 'H', '2'), -1.0, 0.0, 0.0},
71         {SkSetFourByteTag('A', 'P', 'H', '3'), -1.0, 0.0, 0.0},
72 };
73 }  // namespace
74 
DEF_TEST(Fontations_DoNotMakeFromNull,reporter)75 DEF_TEST(Fontations_DoNotMakeFromNull, reporter) {
76     std::unique_ptr<SkStreamAsset> nullStream = SkMemoryStream::MakeDirect(nullptr, 0);
77     sk_sp<SkTypeface> probeTypeface(
78             SkTypeface_Make_Fontations(std::move(nullStream), SkFontArguments()));
79     REPORTER_ASSERT(reporter, !probeTypeface);
80 }
81 
DEF_TEST(Fontations_DoNotMakeFromNonSfnt,reporter)82 DEF_TEST(Fontations_DoNotMakeFromNonSfnt, reporter) {
83     char notAnSfnt[] = "I_AM_NOT_AN_SFNT";
84     std::unique_ptr<SkStreamAsset> notSfntStream =
85             SkMemoryStream::MakeDirect(notAnSfnt, std::size(notAnSfnt));
86     sk_sp<SkTypeface> probeTypeface(
87             SkTypeface_Make_Fontations(std::move(notSfntStream), SkFontArguments()));
88     REPORTER_ASSERT(reporter, !probeTypeface);
89 }
90 
DEF_TEST(Fontations_MakeFromFont,reporter)91 DEF_TEST(Fontations_MakeFromFont, reporter) {
92     sk_sp<SkTypeface> probeTypeface(
93             SkTypeface_Make_Fontations(GetResourceAsStream(kFontResource), SkFontArguments()));
94     REPORTER_ASSERT(reporter, probeTypeface);
95 }
96 
DEF_TEST(Fontations_MakeFromCollection,reporter)97 DEF_TEST(Fontations_MakeFromCollection, reporter) {
98     sk_sp<SkTypeface> probeTypeface(
99             SkTypeface_Make_Fontations(GetResourceAsStream(kTtcResource), SkFontArguments()));
100     REPORTER_ASSERT(reporter, probeTypeface);
101 }
102 
DEF_TEST(Fontations_MakeFromCollectionNonNullIndex,reporter)103 DEF_TEST(Fontations_MakeFromCollectionNonNullIndex, reporter) {
104     SkFontArguments args;
105     args.setCollectionIndex(1);
106     sk_sp<SkTypeface> probeTypeface(
107             SkTypeface_Make_Fontations(GetResourceAsStream(kTtcResource), args));
108     REPORTER_ASSERT(reporter, probeTypeface);
109 }
110 
DEF_TEST(Fontations_DoNotMakeFromCollection_Invalid_Index,reporter)111 DEF_TEST(Fontations_DoNotMakeFromCollection_Invalid_Index, reporter) {
112     SkFontArguments args;
113     args.setCollectionIndex(1000);
114     sk_sp<SkTypeface> probeTypeface(
115             SkTypeface_Make_Fontations(GetResourceAsStream(kTtcResource), args));
116     REPORTER_ASSERT(reporter, !probeTypeface);
117 }
118 
DEF_TEST(Fontations_TableData,reporter)119 DEF_TEST(Fontations_TableData, reporter) {
120     constexpr size_t kNameTableSize = 11310;
121     constexpr size_t kTestOffset = 1310;
122     constexpr size_t kTestLength = 500;
123     char destBuffer[kNameTableSize] = {0};
124     sk_sp<SkTypeface> testTypeface(
125             SkTypeface_Make_Fontations(GetResourceAsStream(kFontResource), SkFontArguments()));
126     SkFourByteTag nameTableTag = SkSetFourByteTag('n', 'a', 'm', 'e');
127     SkFourByteTag nonExistantTag = SkSetFourByteTag('0', 'X', '0', 'X');
128 
129     // Getting size without buffer.
130     REPORTER_ASSERT(reporter,
131                     testTypeface->getTableData(nameTableTag, 0, kNameTableSize, nullptr) ==
132                             kNameTableSize);
133     // Reading full table.
134     REPORTER_ASSERT(reporter,
135                     testTypeface->getTableData(nameTableTag, 0, kNameTableSize, destBuffer) ==
136                             kNameTableSize);
137     // Reading restricted length.
138     REPORTER_ASSERT(
139             reporter,
140             testTypeface->getTableData(nameTableTag, 0, kTestLength, destBuffer) == kTestLength);
141     REPORTER_ASSERT(reporter,
142                     testTypeface->getTableData(
143                             nameTableTag, kTestOffset, kTestLength, destBuffer) == kTestLength);
144     // Reading at an offset.
145     REPORTER_ASSERT(
146             reporter,
147             testTypeface->getTableData(nameTableTag, kTestOffset, kNameTableSize, destBuffer) ==
148                     kNameTableSize - kTestOffset);
149 
150     // Reading from offset past table.
151     REPORTER_ASSERT(reporter,
152                     testTypeface->getTableData(
153                             nameTableTag, kNameTableSize, kNameTableSize, destBuffer) == 0);
154     REPORTER_ASSERT(reporter,
155                     testTypeface->getTableData(nameTableTag, kNameTableSize, 0, nullptr) == 0);
156     // Reading one byte before end of table.
157     REPORTER_ASSERT(reporter,
158                     testTypeface->getTableData(
159                             nameTableTag, kNameTableSize - 1, kNameTableSize, destBuffer) == 1);
160     // Trying to start reading at an offset past table start.
161     REPORTER_ASSERT(reporter,
162                     testTypeface->getTableData(nameTableTag, 0, kNameTableSize + 10, destBuffer) ==
163                             kNameTableSize);
164     // Restricting length without target buffer.
165     REPORTER_ASSERT(reporter,
166                     testTypeface->getTableData(nameTableTag, 0, kTestLength, nullptr) ==
167                             kTestLength);
168 
169     // Trying to access non-existant table.
170     REPORTER_ASSERT(reporter,
171                     testTypeface->getTableData(nonExistantTag, 0, kNameTableSize, destBuffer) ==
172                             0);
173     REPORTER_ASSERT(reporter,
174                     testTypeface->getTableData(nonExistantTag, 0, 0, nullptr) ==
175                             0);
176     REPORTER_ASSERT(reporter,
177                     testTypeface->getTableData(nonExistantTag, kTestOffset, 0, nullptr) == 0);
178 }
179 
DEF_TEST(Fontations_TableTags,reporter)180 DEF_TEST(Fontations_TableTags, reporter) {
181     constexpr size_t kNumTags = 11;
182     SkFourByteTag tagsBuffer[kNumTags] = {0};
183     sk_sp<SkTypeface> testTypeface(
184             SkTypeface_Make_Fontations(GetResourceAsStream(kFontResource), SkFontArguments()));
185     SkFourByteTag firstTag = SkSetFourByteTag('O', 'S', '/', '2');
186     SkFourByteTag lastTag = SkSetFourByteTag('p', 'o', 's', 't');
187 
188     REPORTER_ASSERT(reporter, testTypeface->getTableTags(nullptr) == kNumTags);
189 
190     REPORTER_ASSERT(reporter, testTypeface->getTableTags(tagsBuffer) == kNumTags);
191     REPORTER_ASSERT(reporter, tagsBuffer[0] == firstTag);
192     REPORTER_ASSERT(reporter, tagsBuffer[kNumTags - 1] == lastTag);
193 }
194 
DEF_TEST(Fontations_VariationPosition,reporter)195 DEF_TEST(Fontations_VariationPosition, reporter) {
196     sk_sp<SkTypeface> variableTypeface(
197             SkTypeface_Make_Fontations(GetResourceAsStream(kVariableResource), SkFontArguments()));
198     // Everything at default.
199     const int numAxes = variableTypeface->getVariationDesignPosition(nullptr, 0);
200     REPORTER_ASSERT(reporter, numAxes == kNumVariableAxes, "numAxes: %d", numAxes);
201 
202     SkFontArguments::VariationPosition::Coordinate kSwpsCoordinateFirst = {SkSetFourByteTag('S', 'W', 'P', 'S'), 25};
203     SkFontArguments::VariationPosition::Coordinate kSwpsCoordinateSecond = {SkSetFourByteTag('S', 'W', 'P', 'S'), 55};
204     SkFontArguments::VariationPosition::Coordinate kSwpeCoordinate = {SkSetFourByteTag('S', 'W', 'P', 'E'), 45};
205     SkFontArguments::VariationPosition::Coordinate kInvalidCoordinate = {SkSetFourByteTag('_', '_', '_', '_'), 0};
206 
207     // 'SWPS' and 'SWPE' exist. Second 'SWPS' should override first, invalid tag should be stripped.
208     SkFontArguments::VariationPosition::Coordinate cloneCoordinates[4] = {
209             kSwpsCoordinateFirst, kSwpsCoordinateSecond, kSwpeCoordinate, kInvalidCoordinate};
210 
211     SkFontArguments::VariationPosition clonePosition;
212     clonePosition.coordinates = cloneCoordinates;
213     clonePosition.coordinateCount = 4;
214 
215     sk_sp<SkTypeface> cloneTypeface = variableTypeface->makeClone(
216             SkFontArguments().setVariationDesignPosition(clonePosition));
217     const int cloneNumAxes = cloneTypeface->getVariationDesignPosition(nullptr, 0);
218     REPORTER_ASSERT(reporter, cloneNumAxes == kNumVariableAxes, "clonedNumAxes: %d", cloneNumAxes);
219 
220     SkFontArguments::VariationPosition::Coordinate retrieveCoordinates[kNumVariableAxes] = {};
221 
222     // Error when providing too little space.
223     const int badClonedNumAxes = cloneTypeface->getVariationDesignPosition(retrieveCoordinates, 1);
224     REPORTER_ASSERT(reporter, badClonedNumAxes == -1, "badClonedNumAxes: %d", badClonedNumAxes);
225 
226     const int retrievedClonedNumAxes =
227             cloneTypeface->getVariationDesignPosition(retrieveCoordinates, kNumVariableAxes);
228     REPORTER_ASSERT(reporter, retrievedClonedNumAxes == kNumVariableAxes,
229                     "retrievedClonedNumAxes: %d", retrievedClonedNumAxes);
230     REPORTER_ASSERT(reporter,
231                     retrieveCoordinates[0].axis  == kSwpsCoordinateSecond.axis &&
232                     retrieveCoordinates[0].value == kSwpsCoordinateSecond.value);
233     REPORTER_ASSERT(reporter,
234                     retrieveCoordinates[1].axis  == kSwpeCoordinate.axis &&
235                     retrieveCoordinates[1].value == kSwpeCoordinate.value);
236 }
237 
DEF_TEST(Fontations_VariationParameters,reporter)238 DEF_TEST(Fontations_VariationParameters, reporter) {
239     sk_sp<SkTypeface> variableTypeface(
240             SkTypeface_Make_Fontations(GetResourceAsStream(kVariableResource), SkFontArguments()));
241     REPORTER_ASSERT(reporter,
242                     variableTypeface->getVariationDesignParameters(nullptr, 0) == kNumVariableAxes);
243 
244     SkFontParameters::Variation::Axis axes[kNumVariableAxes] = {};
245     REPORTER_ASSERT(reporter,
246                     variableTypeface->getVariationDesignParameters(axes, kNumVariableAxes) ==
247                             kNumVariableAxes);
248 
249     for (size_t i = 0; i < kNumVariableAxes; ++i) {
250         REPORTER_ASSERT(reporter, axes[i].tag == axisExpectations[i].tag);
251         REPORTER_ASSERT(reporter, axes[i].min == axisExpectations[i].minValue);
252         REPORTER_ASSERT(reporter, axes[i].def == axisExpectations[i].defValue);
253         REPORTER_ASSERT(reporter, axes[i].max == axisExpectations[i].maxValue);
254     }
255 }
256 
DEF_TEST(Fontations_VariationParameters_BufferTooSmall,reporter)257 DEF_TEST(Fontations_VariationParameters_BufferTooSmall, reporter) {
258     sk_sp<SkTypeface> variableTypeface(
259             SkTypeface_Make_Fontations(GetResourceAsStream(kVariableResource), SkFontArguments()));
260     REPORTER_ASSERT(reporter,
261                     variableTypeface->getVariationDesignParameters(nullptr, 0) == kNumVariableAxes);
262 
263     constexpr size_t kArrayTooSmall = 3;
264     SkFontParameters::Variation::Axis axes[kArrayTooSmall] = {};
265     REPORTER_ASSERT(reporter,
266                     variableTypeface->getVariationDesignParameters(axes, kArrayTooSmall) == -1);
267 }
268