xref: /aosp_15_r20/frameworks/minikin/tests/unittest/FontTest.cpp (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
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