1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <com_android_text_flags.h>
18 #include <flag_macros.h>
19 #include <gtest/gtest.h>
20 #include <minikin/Constants.h>
21
22 #include "BufferUtils.h"
23 #include "FontTestUtils.h"
24 #include "FontVariationTestUtils.h"
25 #include "FreeTypeMinikinFontForTest.h"
26 #include "minikin/Font.h"
27
28 namespace minikin {
29
30 namespace {
31
getHeapSize()32 size_t getHeapSize() {
33 struct mallinfo info = mallinfo();
34 return info.uordblks;
35 }
36
37 } // namespace
38
TEST(FontTest,BufferTest)39 TEST(FontTest, BufferTest) {
40 FreeTypeMinikinFontForTestFactory::init();
41 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
42 std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
43 std::vector<uint8_t> buffer = writeToBuffer<Font>(*original);
44
45 BufferReader reader(buffer.data());
46 Font font(&reader);
47 EXPECT_EQ(minikinFont->GetFontPath(), font.baseTypeface()->GetFontPath());
48 EXPECT_EQ(original->style(), font.style());
49 EXPECT_EQ(original->getLocaleListId(), font.getLocaleListId());
50 // baseFont() should return the same non-null instance when called twice.
51 const auto& baseFont = font.baseFont();
52 EXPECT_NE(nullptr, baseFont);
53 EXPECT_EQ(baseFont, font.baseFont());
54 // baseTypeface() should return the same non-null instance when called twice.
55 const auto& typeface = font.baseTypeface();
56 EXPECT_NE(nullptr, typeface);
57 EXPECT_EQ(typeface, font.baseTypeface());
58 std::vector<uint8_t> newBuffer = writeToBuffer<Font>(font);
59 EXPECT_EQ(buffer, newBuffer);
60 }
61
TEST(FontTest,MoveConstructorTest)62 TEST(FontTest, MoveConstructorTest) {
63 FreeTypeMinikinFontForTestFactory::init();
64 // Note: by definition, only BufferReader-based Font can be moved.
65 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
66 std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
67 std::vector<uint8_t> buffer = writeToBuffer<Font>(*original);
68
69 size_t baseHeapSize = getHeapSize();
70 {
71 BufferReader reader(buffer.data());
72 Font moveFrom(&reader);
73 Font moveTo(std::move(moveFrom));
74 EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
75 EXPECT_EQ(nullptr, moveTo.mExternalRefsHolder.load());
76 }
77 EXPECT_EQ(baseHeapSize, getHeapSize());
78 {
79 BufferReader reader(buffer.data());
80 Font moveFrom(&reader);
81 std::shared_ptr<MinikinFont> typeface = moveFrom.baseTypeface();
82 Font moveTo(std::move(moveFrom));
83 EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
84 EXPECT_EQ(typeface, moveTo.baseTypeface());
85 }
86 EXPECT_EQ(baseHeapSize, getHeapSize());
87 }
88
TEST(FontTest,MoveAssignmentTest)89 TEST(FontTest, MoveAssignmentTest) {
90 FreeTypeMinikinFontForTestFactory::init();
91 // Note: by definition, only BufferReader-based Font can be moved.
92 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("Ascii.ttf"));
93 std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
94 std::vector<uint8_t> buffer = writeToBuffer<Font>(*original);
95
96 size_t baseHeapSize = getHeapSize();
97 {
98 // mExternalRefsHolder: null -> null
99 BufferReader reader(buffer.data());
100 Font moveFrom(&reader);
101 BufferReader reader2(buffer.data());
102 Font moveTo(&reader2);
103 moveTo = std::move(moveFrom);
104 EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
105 EXPECT_EQ(nullptr, moveTo.mExternalRefsHolder.load());
106 }
107 EXPECT_EQ(baseHeapSize, getHeapSize());
108 {
109 // mExternalRefsHolder: non-null -> null
110 BufferReader reader(buffer.data());
111 Font moveFrom(&reader);
112 std::shared_ptr<MinikinFont> typeface = moveFrom.baseTypeface();
113 BufferReader reader2(buffer.data());
114 Font moveTo(&reader2);
115 moveTo = std::move(moveFrom);
116 EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
117 EXPECT_EQ(typeface, moveTo.baseTypeface());
118 }
119 EXPECT_EQ(baseHeapSize, getHeapSize());
120 {
121 // mExternalRefsHolder: null -> non-null
122 BufferReader reader(buffer.data());
123 Font moveFrom(&reader);
124 BufferReader reader2(buffer.data());
125 Font moveTo(&reader2);
126 moveTo.baseTypeface();
127 moveTo = std::move(moveFrom);
128 EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
129 EXPECT_EQ(nullptr, moveTo.mExternalRefsHolder.load());
130 }
131 EXPECT_EQ(baseHeapSize, getHeapSize());
132 {
133 // mExternalRefsHolder: non-null -> non-null
134 BufferReader reader(buffer.data());
135 Font moveFrom(&reader);
136 std::shared_ptr<MinikinFont> typeface = moveFrom.baseTypeface();
137 BufferReader reader2(buffer.data());
138 Font moveTo(&reader2);
139 moveTo.baseTypeface();
140 moveTo = std::move(moveFrom);
141 EXPECT_EQ(nullptr, moveFrom.mExternalRefsHolder.load());
142 EXPECT_EQ(typeface, moveTo.baseTypeface());
143 }
144 EXPECT_EQ(baseHeapSize, getHeapSize());
145 }
146
TEST(FontTest,getAdjustedFontTest)147 TEST(FontTest, getAdjustedFontTest) {
148 FreeTypeMinikinFontForTestFactory::init();
149 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(
150 getTestFontPath("WeightEqualsEmVariableFont.ttf"));
151 std::shared_ptr<Font> font = Font::Builder(minikinFont).build();
152
153 {
154 auto hbFont = font->getAdjustedFont(-1, -1);
155 EXPECT_EQ(hbFont.get(), font->baseFont().get());
156 }
157 {
158 // Set correct wight axis value.
159 auto hbFont = font->getAdjustedFont(400, -1);
160 EXPECT_EQ(hb_font_get_parent(hbFont.get()), font->baseFont().get());
161 EXPECT_NE(hbFont.get(), font->baseFont().get());
162 unsigned int length;
163 const float* coords = hb_font_get_var_coords_design(hbFont.get(), &length);
164 ASSERT_EQ(2u, length); // The test font has 'wght', 'ital' axes in this order
165 EXPECT_EQ(400, coords[0]);
166 EXPECT_EQ(0, coords[1]);
167 }
168 {
169 // Override existing wght axis.
170 std::shared_ptr<Font> newFont = Font::Builder(font->getAdjustedTypeface(700, -1)).build();
171 auto hbFont = newFont->getAdjustedFont(500, -1);
172 EXPECT_EQ(hb_font_get_parent(hbFont.get()), newFont->baseFont().get());
173 EXPECT_NE(hbFont.get(), newFont->baseFont().get());
174 unsigned int length;
175 const float* coords = hb_font_get_var_coords_design(hbFont.get(), &length);
176 ASSERT_EQ(2u, length); // The test font has 'wght', 'ital' axes in this order
177 EXPECT_EQ(500, coords[0]);
178 EXPECT_EQ(0, coords[1]);
179 }
180 {
181 // Set correct wight axis value.
182 auto hbFont = font->getAdjustedFont(-1, 1);
183 EXPECT_EQ(hb_font_get_parent(hbFont.get()), font->baseFont().get());
184 EXPECT_NE(hbFont.get(), font->baseFont().get());
185 unsigned int length;
186 const float* coords = hb_font_get_var_coords_design(hbFont.get(), &length);
187 ASSERT_EQ(2u, length); // The test font has 'wght', 'ital' axes in this order
188 EXPECT_EQ(400, coords[0]); // 400 is a default value of `wght` axis
189 EXPECT_EQ(1, coords[1]);
190 }
191 {
192 // Override existing wght axis.
193 std::shared_ptr<Font> newFont = Font::Builder(font->getAdjustedTypeface(-1, 0)).build();
194 auto hbFont = newFont->getAdjustedFont(-1, 1);
195 EXPECT_EQ(hb_font_get_parent(hbFont.get()), newFont->baseFont().get());
196 EXPECT_NE(hbFont.get(), newFont->baseFont().get());
197 unsigned int length;
198 const float* coords = hb_font_get_var_coords_design(hbFont.get(), &length);
199 ASSERT_EQ(2u, length); // The test font has 'wght', 'ital' axes in this order
200 EXPECT_EQ(400, coords[0]); // 400 is a default value of `wght` axis
201 EXPECT_EQ(1, coords[1]);
202 }
203 {
204 // Set correct wight axis value.
205 auto hbFont = font->getAdjustedFont(500, 1);
206 EXPECT_EQ(hb_font_get_parent(hbFont.get()), font->baseFont().get());
207 EXPECT_NE(hbFont.get(), font->baseFont().get());
208 unsigned int length;
209 const float* coords = hb_font_get_var_coords_design(hbFont.get(), &length);
210 ASSERT_EQ(2u, length); // The test font has 'wght', 'ital' axes in this order
211 EXPECT_EQ(500, coords[0]);
212 EXPECT_EQ(1, coords[1]);
213 }
214 {
215 // Override existing wght axis.
216 std::shared_ptr<Font> newFont = Font::Builder(font->getAdjustedTypeface(500, 1)).build();
217 auto hbFont = newFont->getAdjustedFont(700, 0);
218 EXPECT_EQ(hb_font_get_parent(hbFont.get()), newFont->baseFont().get());
219 EXPECT_NE(hbFont.get(), newFont->baseFont().get());
220 unsigned int length;
221 const float* coords = hb_font_get_var_coords_design(hbFont.get(), &length);
222 ASSERT_EQ(2u, length); // The test font has 'wght', 'ital' axes in this order
223 EXPECT_EQ(700, coords[0]);
224 EXPECT_EQ(0, coords[1]);
225 }
226 }
227
TEST(FontTest,getAdjustedTypefaceTest)228 TEST(FontTest, getAdjustedTypefaceTest) {
229 FreeTypeMinikinFontForTestFactory::init();
230 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(
231 getTestFontPath("WeightEqualsEmVariableFont.ttf"));
232 std::shared_ptr<Font> font = Font::Builder(minikinFont).build();
233
234 {
235 auto minikinFontBase = font->getAdjustedTypeface(-1, -1);
236 EXPECT_EQ(minikinFontBase.get(), font->baseTypeface().get());
237 }
238 {
239 // Set correct wght axis value.
240 auto minikinFontBase = font->getAdjustedTypeface(400, -1);
241 EXPECT_NE(minikinFontBase.get(), font->baseTypeface().get());
242 auto axes = minikinFontBase->GetAxes();
243 ASSERT_EQ(1u, axes.size());
244 EXPECT_EQ(TAG_wght, axes[0].axisTag);
245 EXPECT_EQ(400, axes[0].value);
246 }
247 {
248 // Override existing wght axis.
249 std::shared_ptr<Font> newFont = Font::Builder(font->getAdjustedTypeface(700, -1)).build();
250 auto minikinFontBase = newFont->getAdjustedTypeface(500, -1);
251 EXPECT_NE(minikinFontBase.get(), font->baseTypeface().get());
252 auto axes = minikinFontBase->GetAxes();
253 ASSERT_EQ(1u, axes.size());
254 EXPECT_EQ(TAG_wght, axes[0].axisTag);
255 EXPECT_EQ(500, axes[0].value);
256 }
257 {
258 // Set correct wght axis value.
259 auto minikinFontBase = font->getAdjustedTypeface(-1, 1);
260 EXPECT_NE(minikinFontBase.get(), font->baseTypeface().get());
261 auto axes = minikinFontBase->GetAxes();
262 ASSERT_EQ(1u, axes.size());
263 EXPECT_EQ(TAG_ital, axes[0].axisTag);
264 EXPECT_EQ(1, axes[0].value);
265 }
266 {
267 // Override existing wght axis.
268 std::shared_ptr<Font> newFont = Font::Builder(font->getAdjustedTypeface(-1, 1)).build();
269 auto minikinFontBase = newFont->getAdjustedTypeface(-1, 0);
270 EXPECT_NE(minikinFontBase.get(), font->baseTypeface().get());
271 auto axes = minikinFontBase->GetAxes();
272 ASSERT_EQ(1u, axes.size());
273 EXPECT_EQ(TAG_ital, axes[0].axisTag);
274 EXPECT_EQ(0, axes[0].value);
275 }
276 {
277 // Set correct ital axis value.
278 auto minikinFontBase = font->getAdjustedTypeface(400, 1);
279 EXPECT_NE(minikinFontBase.get(), font->baseTypeface().get());
280 auto axes = minikinFontBase->GetAxes();
281 ASSERT_EQ(2u, axes.size());
282 EXPECT_EQ(TAG_ital, axes[0].axisTag);
283 EXPECT_EQ(TAG_wght, axes[1].axisTag);
284 EXPECT_EQ(1, axes[0].value);
285 EXPECT_EQ(400, axes[1].value);
286 }
287 {
288 // Override existing ital axis.
289 std::shared_ptr<Font> newFont = Font::Builder(font->getAdjustedTypeface(500, 0)).build();
290 auto minikinFontBase = newFont->getAdjustedTypeface(700, 1);
291 EXPECT_NE(minikinFontBase.get(), font->baseTypeface().get());
292 auto axes = minikinFontBase->GetAxes();
293 ASSERT_EQ(2u, axes.size());
294 EXPECT_EQ(TAG_ital, axes[0].axisTag);
295 EXPECT_EQ(TAG_wght, axes[1].axisTag);
296 EXPECT_EQ(1, axes[0].value);
297 EXPECT_EQ(700, axes[1].value);
298 }
299 }
300
TEST(FontTest,ChildLazyCreationTest)301 TEST(FontTest, ChildLazyCreationTest) {
302 FreeTypeMinikinFontForTestFactory::init();
303 // Note: by definition, only BufferReader-based Font can be moved.
304 auto minikinFont =
305 std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath("MultiAxis.ttf"));
306 std::shared_ptr<Font> original = Font::Builder(minikinFont).build();
307
308 // The original font doesn't axes settings.
309 EXPECT_TRUE(original->baseTypeface()->GetAxes().empty());
310
311 std::shared_ptr<Font> overridden = std::make_shared<Font>(
312 original, std::vector<FontVariation>{FontVariation(MakeTag('w', 'g', 'h', 't'), 0)});
313
314 EXPECT_EQ(1u, overridden->baseTypeface()->GetAxes().size());
315 EXPECT_EQ(MakeTag('w', 'g', 'h', 't'), overridden->baseTypeface()->GetAxes()[0].axisTag);
316 }
317
TEST(FontTest,FVarTableTest)318 TEST(FontTest, FVarTableTest) {
319 FreeTypeMinikinFontForTestFactory::init();
320 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(
321 getTestFontPath("WeightEqualsEmVariableFont.ttf"));
322 std::shared_ptr<Font> font = Font::Builder(minikinFont).build();
323
324 uint32_t wght = MakeTag('w', 'g', 'h', 't');
325 uint32_t ital = MakeTag('i', 't', 'a', 'l');
326
327 const FVarTable& fvar = font->getFVarTable();
328 EXPECT_TRUE(fvar.contains(wght));
329 EXPECT_TRUE(fvar.contains(ital));
330 EXPECT_FALSE(fvar.contains(MakeTag('w', 'd', 't', 'h')));
331
332 const FVarEntry& wghtTable = fvar.find(wght)->second;
333 EXPECT_EQ(0, wghtTable.minValue);
334 EXPECT_EQ(400, wghtTable.defValue);
335 EXPECT_EQ(1000, wghtTable.maxValue);
336
337 const FVarEntry& italTable = fvar.find(ital)->second;
338 EXPECT_EQ(0, italTable.minValue);
339 EXPECT_EQ(0, italTable.defValue);
340 EXPECT_EQ(1, italTable.maxValue);
341 }
342
fakedFont(const std::shared_ptr<Font> & font,const std::string & varSettings)343 FakedFont fakedFont(const std::shared_ptr<Font>& font, const std::string& varSettings) {
344 return {font, FontFakery(false, false, parseVariationSettings(varSettings))};
345 }
346
TEST_WITH_FLAGS(FontTest,FakedFont_cached_hbFont,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,typeface_redesign_readonly)))347 TEST_WITH_FLAGS(FontTest, FakedFont_cached_hbFont,
348 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
349 typeface_redesign_readonly))) {
350 FreeTypeMinikinFontForTestFactory::init();
351
352 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(
353 getTestFontPath("WeightEqualsEmVariableFont.ttf"));
354 std::shared_ptr<Font> font = Font::Builder(minikinFont).build();
355
356 FakedFont faked300 = fakedFont(font, "'wght' 300");
357 FakedFont faked400 = fakedFont(font, "'wght' 400");
358 FakedFont faked300_2 = fakedFont(font, "'wght' 300");
359
360 EXPECT_EQ(faked300.hbFont().get(), faked300.hbFont().get());
361 EXPECT_EQ(faked300.hbFont().get(), faked300_2.hbFont().get());
362 EXPECT_NE(faked300.hbFont().get(), faked400.hbFont().get());
363 }
364
TEST_WITH_FLAGS(FontTest,FakedFont_cached_typeface,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,typeface_redesign_readonly)))365 TEST_WITH_FLAGS(FontTest, FakedFont_cached_typeface,
366 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
367 typeface_redesign_readonly))) {
368 FreeTypeMinikinFontForTestFactory::init();
369
370 auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(
371 getTestFontPath("WeightEqualsEmVariableFont.ttf"));
372 std::shared_ptr<Font> font = Font::Builder(minikinFont).build();
373
374 FakedFont faked300 = fakedFont(font, "'wght' 300");
375 FakedFont faked400 = fakedFont(font, "'wght' 400");
376 FakedFont faked300_2 = fakedFont(font, "'wght' 300");
377
378 EXPECT_EQ(faked300.typeface(), faked300.typeface());
379 EXPECT_EQ(faked300.typeface(), faked300_2.typeface());
380 EXPECT_NE(faked300.typeface(), faked400.typeface());
381 }
382
383 } // namespace minikin
384