xref: /aosp_15_r20/frameworks/minikin/tests/unittest/FontCollectionTest.cpp (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
1 /*
2  * Copyright (C) 2015 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 
21 #include "FontTestUtils.h"
22 #include "FontVariationTestUtils.h"
23 #include "FreeTypeMinikinFontForTest.h"
24 #include "MinikinInternal.h"
25 #include "minikin/Constants.h"
26 #include "minikin/FontCollection.h"
27 
28 namespace minikin {
29 
30 // The test font has following glyphs.
31 // U+82A6
32 // U+82A6 U+FE00 (VS1)
33 // U+82A6 U+E0100 (VS17)
34 // U+82A6 U+E0101 (VS18)
35 // U+82A6 U+E0102 (VS19)
36 // U+845B
37 // U+845B U+FE01 (VS2)
38 // U+845B U+E0101 (VS18)
39 // U+845B U+E0102 (VS19)
40 // U+845B U+E0103 (VS20)
41 // U+537F
42 // U+717D U+FE02 (VS3)
43 // U+717D U+E0102 (VS19)
44 // U+717D U+E0103 (VS20)
45 const char kVsTestFont[] = "VariationSelectorTest-Regular.ttf";
46 
expectVSGlyphs(const FontCollection * fc,uint32_t codepoint,const std::set<uint32_t> & vsSet)47 void expectVSGlyphs(const FontCollection* fc, uint32_t codepoint, const std::set<uint32_t>& vsSet) {
48     for (uint32_t vs = 0xFE00; vs <= 0xE01EF; ++vs) {
49         // Move to variation selectors supplements after variation selectors.
50         if (vs == 0xFF00) {
51             vs = 0xE0100;
52         }
53         if (vsSet.find(vs) == vsSet.end()) {
54             EXPECT_FALSE(fc->hasVariationSelector(codepoint, vs))
55                     << "Glyph for U+" << std::hex << codepoint << " U+" << vs;
56         } else {
57             EXPECT_TRUE(fc->hasVariationSelector(codepoint, vs))
58                     << "Glyph for U+" << std::hex << codepoint << " U+" << vs;
59         }
60     }
61 }
62 
expectVSGlyphsForVsTestFont(const FontCollection * fc)63 void expectVSGlyphsForVsTestFont(const FontCollection* fc) {
64     EXPECT_FALSE(fc->hasVariationSelector(0x82A6, 0));
65     expectVSGlyphs(fc, 0x82A6, std::set<uint32_t>({0xFE00, 0xFE0E, 0xE0100, 0xE0101, 0xE0102}));
66 
67     EXPECT_FALSE(fc->hasVariationSelector(0x845B, 0));
68     expectVSGlyphs(fc, 0x845B, std::set<uint32_t>({0xFE01, 0xFE0E, 0xE0101, 0xE0102, 0xE0103}));
69 
70     EXPECT_FALSE(fc->hasVariationSelector(0x537F, 0));
71     expectVSGlyphs(fc, 0x537F, std::set<uint32_t>({0xFE0E}));
72 
73     EXPECT_FALSE(fc->hasVariationSelector(0x717D, 0));
74     expectVSGlyphs(fc, 0x717D, std::set<uint32_t>({0xFE02, 0xE0102, 0xE0103}));
75 }
76 
TEST(FontCollectionTest,hasVariationSelectorTest)77 TEST(FontCollectionTest, hasVariationSelectorTest) {
78     auto fc = buildFontCollection(kVsTestFont);
79     expectVSGlyphsForVsTestFont(fc.get());
80 }
81 
82 const char kEmojiXmlFile[] = "emoji.xml";
83 
TEST(FontCollectionTest,hasVariationSelectorTest_emoji)84 TEST(FontCollectionTest, hasVariationSelectorTest_emoji) {
85     auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
86 
87     // Both text/color font have cmap format 14 subtable entry for VS15/VS16 respectively.
88     EXPECT_TRUE(collection->hasVariationSelector(0x2623, 0xFE0E));
89     EXPECT_TRUE(collection->hasVariationSelector(0x2623, 0xFE0F));
90 
91     // The text font has cmap format 14 subtable entry for VS15 but the color font doesn't have for
92     // VS16
93     EXPECT_TRUE(collection->hasVariationSelector(0x2626, 0xFE0E));
94     EXPECT_FALSE(collection->hasVariationSelector(0x2626, 0xFE0F));
95 
96     // The color font has cmap format 14 subtable entry for VS16 but the text font doesn't have for
97     // VS15.
98     EXPECT_TRUE(collection->hasVariationSelector(0x262A, 0xFE0E));
99     EXPECT_TRUE(collection->hasVariationSelector(0x262A, 0xFE0F));
100 
101     // Neither text/color font have cmap format 14 subtable entry for VS15/VS16.
102     EXPECT_TRUE(collection->hasVariationSelector(0x262E, 0xFE0E));
103     EXPECT_FALSE(collection->hasVariationSelector(0x262E, 0xFE0F));
104 
105     // Text font doesn't support U+1F3FD. Only the color emoji fonts has. So VS15 is not supported.
106     EXPECT_FALSE(collection->hasVariationSelector(0x1F3FD, 0xFE0E));
107 
108     // Text font doesn't have U+262F U+FE0E or even its base code point U+262F.
109     EXPECT_FALSE(collection->hasVariationSelector(0x262F, 0xFE0E));
110 
111     // None of the fonts support U+2229.
112     EXPECT_FALSE(collection->hasVariationSelector(0x2229, 0xFE0E));
113     EXPECT_FALSE(collection->hasVariationSelector(0x2229, 0xFE0F));
114 }
115 
TEST(FontCollectionTest,newEmojiTest)116 TEST(FontCollectionTest, newEmojiTest) {
117     auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
118 
119     // U+2695, U+2640, U+2642 are not in emoji catrgory in Unicode 9 but they are now in emoji
120     // category. Should return true even if U+FE0E was appended.
121     // These three emojis are only avalilable in TextEmoji.ttf but U+2695 is excluded here since it
122     // is used in other tests.
123     EXPECT_TRUE(collection->hasVariationSelector(0x2640, 0xFE0E));
124     EXPECT_FALSE(collection->hasVariationSelector(0x2640, 0xFE0F));
125     EXPECT_TRUE(collection->hasVariationSelector(0x2642, 0xFE0E));
126     EXPECT_FALSE(collection->hasVariationSelector(0x2642, 0xFE0F));
127 }
128 
TEST(FontCollectionTest,createWithVariations)129 TEST(FontCollectionTest, createWithVariations) {
130     // This font has 'wdth' and 'wght' axes.
131     const char kMultiAxisFont[] = "MultiAxis.ttf";
132     const char kNoAxisFont[] = "Regular.ttf";
133 
134     std::shared_ptr<FontCollection> multiAxisFc = buildFontCollection(kMultiAxisFont);
135     std::shared_ptr<FontCollection> noAxisFc = buildFontCollection(kNoAxisFont);
136 
137     {
138         // Do not ceate new instance if none of variations are specified.
139         EXPECT_EQ(nullptr,
140                   multiAxisFc->createCollectionWithVariation(std::vector<FontVariation>()));
141         EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(std::vector<FontVariation>()));
142     }
143     {
144         // New instance should be used for supported variation.
145         std::vector<FontVariation> variations = {{MakeTag('w', 'd', 't', 'h'), 1.0f}};
146         std::shared_ptr<FontCollection> newFc(
147                 multiAxisFc->createCollectionWithVariation(variations));
148         EXPECT_NE(nullptr, newFc.get());
149         EXPECT_NE(multiAxisFc.get(), newFc.get());
150 
151         EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
152     }
153     {
154         // New instance should be used for supported variation (multiple variations case).
155         std::vector<FontVariation> variations = {{MakeTag('w', 'd', 't', 'h'), 1.0f},
156                                                  {MakeTag('w', 'g', 'h', 't'), 1.0f}};
157         std::shared_ptr<FontCollection> newFc(
158                 multiAxisFc->createCollectionWithVariation(variations));
159         EXPECT_NE(nullptr, newFc.get());
160         EXPECT_NE(multiAxisFc.get(), newFc.get());
161 
162         EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
163     }
164     {
165         // Do not ceate new instance if none of variations are supported.
166         std::vector<FontVariation> variations = {{MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}};
167         EXPECT_EQ(nullptr, multiAxisFc->createCollectionWithVariation(variations));
168         EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
169     }
170     {
171         // At least one axis is supported, should create new instance.
172         std::vector<FontVariation> variations = {{MakeTag('w', 'd', 't', 'h'), 1.0f},
173                                                  {MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}};
174         std::shared_ptr<FontCollection> newFc(
175                 multiAxisFc->createCollectionWithVariation(variations));
176         EXPECT_NE(nullptr, newFc.get());
177         EXPECT_NE(multiAxisFc.get(), newFc.get());
178 
179         EXPECT_EQ(nullptr, noAxisFc->createCollectionWithVariation(variations));
180     }
181 }
182 
TEST(FontCollectionTest,createCollectionWithFamilies)183 TEST(FontCollectionTest, createCollectionWithFamilies) {
184     auto fallback = buildFontCollectionFromXml(kEmojiXmlFile);
185     std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont);
186     std::shared_ptr<FontCollection> created = fallback->createCollectionWithFamilies({family});
187     ASSERT_EQ(fallback->getFamilyCount() + 1, created->getFamilyCount());
188     EXPECT_EQ(family, created->getFamilyAt(0));
189     for (size_t i = 0; i < fallback->getFamilyCount(); i++) {
190         EXPECT_EQ(fallback->getFamilyAt(i), created->getFamilyAt(i + 1));
191     }
192 }
193 
writeToBuffer(const std::vector<std::shared_ptr<FontCollection>> & collections)194 std::vector<uint8_t> writeToBuffer(
195         const std::vector<std::shared_ptr<FontCollection>>& collections) {
196     BufferWriter fakeWriter(nullptr);
197     FontCollection::writeVector(&fakeWriter, collections);
198     std::vector<uint8_t> buffer(fakeWriter.size());
199     BufferWriter writer(buffer.data());
200     FontCollection::writeVector(&writer, collections);
201     return buffer;
202 }
203 
TEST(FontCollectionTest,bufferTest)204 TEST(FontCollectionTest, bufferTest) {
205     FreeTypeMinikinFontForTestFactory::init();
206     {
207         std::vector<std::shared_ptr<FontCollection>> original({buildFontCollection(kVsTestFont)});
208         std::vector<uint8_t> buffer = writeToBuffer(original);
209         BufferReader reader(buffer.data());
210         auto copied = FontCollection::readVector(&reader);
211         EXPECT_EQ(1u, copied.size());
212         expectVSGlyphsForVsTestFont(copied[0].get());
213         ASSERT_EQ(original[0]->getSupportedAxesCount(), copied[0]->getSupportedAxesCount());
214         for (size_t i = 0; i < original[0]->getSupportedAxesCount(); i++) {
215             EXPECT_EQ(original[0]->getSupportedAxisAt(i), copied[0]->getSupportedAxisAt(i));
216         }
217         // Id will be different.
218         EXPECT_NE(original[0]->getId(), copied[0]->getId());
219         std::vector<uint8_t> newBuffer = writeToBuffer(copied);
220         EXPECT_EQ(buffer, newBuffer);
221     }
222     {
223         // Test that FontFamily instances are shared.
224         std::vector<std::shared_ptr<FontFamily>> families = {buildFontFamily(kVsTestFont)};
225         auto fc1 = FontCollection::create(families);
226         auto fc2 = FontCollection::create(families);
227         std::vector<std::shared_ptr<FontCollection>> original({fc1, fc2});
228         std::vector<uint8_t> buffer = writeToBuffer(original);
229         BufferReader reader(buffer.data());
230         auto copied = FontCollection::readVector(&reader);
231         EXPECT_EQ(2u, copied.size());
232         EXPECT_EQ(copied[0]->getFamilyAt(0), copied[1]->getFamilyAt(0));
233         std::vector<uint8_t> newBuffer = writeToBuffer(copied);
234         EXPECT_EQ(buffer, newBuffer);
235     }
236     {
237         // Test axes.
238         // This font has 'wdth' and 'wght' axes.
239         const char kMultiAxisFont[] = "MultiAxis.ttf";
240         std::vector<std::shared_ptr<FontCollection>> original(
241                 {buildFontCollection(kMultiAxisFont)});
242         std::vector<uint8_t> buffer = writeToBuffer(original);
243         BufferReader reader(buffer.data());
244         auto copied = FontCollection::readVector(&reader);
245         EXPECT_EQ(1u, copied.size());
246         ASSERT_EQ(2u, copied[0]->getSupportedAxesCount());
247         // mSupportedAxes must be sorted.
248         EXPECT_EQ(MakeTag('w', 'd', 't', 'h'), copied[0]->getSupportedAxisAt(0));
249         EXPECT_EQ(MakeTag('w', 'g', 'h', 't'), copied[0]->getSupportedAxisAt(1));
250         std::vector<uint8_t> newBuffer = writeToBuffer(copied);
251         EXPECT_EQ(buffer, newBuffer);
252     }
253 }
254 
TEST(FontCollectionTest,FamilyMatchResultBuilderTest)255 TEST(FontCollectionTest, FamilyMatchResultBuilderTest) {
256     using Builder = FontCollection::FamilyMatchResult::Builder;
257     EXPECT_TRUE(Builder().empty());
258     EXPECT_EQ(0u, Builder().size());
259     EXPECT_EQ(1u, Builder().add(5).size());
260     EXPECT_EQ(2u, Builder().add(5).add(4).size());
261 
262     // Reset
263     EXPECT_TRUE(Builder().add(5).reset().empty());
264     EXPECT_EQ(0u, Builder().add(5).reset().size());
265 }
266 
TEST(FontCollectionTest,FamilyMatchResultTest)267 TEST(FontCollectionTest, FamilyMatchResultTest) {
268     using Builder = FontCollection::FamilyMatchResult::Builder;
269 
270     auto r = Builder().build();
271     EXPECT_EQ(0u, r.size());
272     EXPECT_TRUE(r.empty());
273 
274     r = Builder().add(1).build();
275     EXPECT_EQ(1u, r.size());
276     EXPECT_FALSE(r.empty());
277     EXPECT_EQ(1u, r[0]);
278 
279     r = Builder().add(1).add(2).build();
280     EXPECT_EQ(2u, r.size());
281     EXPECT_FALSE(r.empty());
282     EXPECT_EQ(1u, r[0]);
283     EXPECT_EQ(2u, r[1]);
284 }
285 
TEST(FontCollectionTest,FamilyMatchResultTest_BuilderHoldeFirst7)286 TEST(FontCollectionTest, FamilyMatchResultTest_BuilderHoldeFirst7) {
287     auto b = FontCollection::FamilyMatchResult::Builder();
288     for (uint8_t i = 0; i < 128; ++i) {
289         b.add(i);
290     }
291     auto r = b.build();
292     EXPECT_EQ(7u, r.size());
293     EXPECT_FALSE(r.empty());
294     EXPECT_EQ(0u, r[0]);
295     EXPECT_EQ(1u, r[1]);
296     EXPECT_EQ(2u, r[2]);
297     EXPECT_EQ(3u, r[3]);
298     EXPECT_EQ(4u, r[4]);
299     EXPECT_EQ(5u, r[5]);
300     EXPECT_EQ(6u, r[6]);
301 }
302 
TEST(FontCollectionTest,FamilyMatchResultTest_iterator)303 TEST(FontCollectionTest, FamilyMatchResultTest_iterator) {
304     auto b = FontCollection::FamilyMatchResult::Builder();
305     for (uint8_t i = 0; i < 7; ++i) {
306         b.add(i);
307     }
308     auto r = b.build();
309     EXPECT_EQ(7u, r.size());
310     EXPECT_FALSE(r.empty());
311     int i = 0;
312     for (auto v : r) {
313         EXPECT_EQ(i, v);
314         i++;
315     }
316 }
317 
TEST(FontCollectionTest,FamilyMatchResultTest_intersect)318 TEST(FontCollectionTest, FamilyMatchResultTest_intersect) {
319     using Builder = FontCollection::FamilyMatchResult::Builder;
320 
321     EXPECT_EQ(Builder().add(1).add(2).add(3).build(),
322               FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(),
323                                                            Builder().add(1).add(2).add(3).build()));
324 
325     EXPECT_EQ(Builder().build(),
326               FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(),
327                                                            Builder().build()));
328 
329     EXPECT_EQ(Builder().build(),
330               FontCollection::FamilyMatchResult::intersect(Builder().add(2).add(4).add(6).build(),
331                                                            Builder().add(1).add(3).add(5).build()));
332 
333     EXPECT_EQ(Builder().add(1).add(3).build(),
334               FontCollection::FamilyMatchResult::intersect(Builder().add(1).add(2).add(3).build(),
335                                                            Builder().add(1).add(3).add(5).build()));
336 }
337 
TEST_WITH_FLAGS(FontCollectionTest,getBestFont,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,typeface_redesign_readonly)))338 TEST_WITH_FLAGS(FontCollectionTest, getBestFont,
339                 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
340                                                     typeface_redesign_readonly))) {
341     FreeTypeMinikinFontForTestFactory::init();
342 
343     const uint32_t localeListId = registerLocaleList("en-US");
344 
345     auto minikinFont = std::make_shared<FreeTypeMinikinFontForTest>(
346             getTestFontPath("WeightEqualsEmVariableFont.ttf"));
347     auto font = Font::Builder(minikinFont).build();
348     auto family = FontFamily::create({font});
349     auto fc = FontCollection::create({family});
350 
351     auto getBestFont = [&](FontStyle style, const VariationSettings& varSettings) -> FakedFont {
352         std::vector<uint16_t> text = {'a'};
353         auto runs = fc->itemize(text, style, localeListId, FamilyVariant::DEFAULT, 1);
354         EXPECT_EQ(1u, runs.size());
355         return fc->getBestFont(text, runs[0], style, varSettings);
356     };
357 
358     EXPECT_EQ(parseVariationSettings(""),
359               getBestFont(FontStyle(), VariationSettings()).fakery.variationSettings());
360     EXPECT_EQ(parseVariationSettings("'wght' 700"),
361               getBestFont(FontStyle(FontStyle::Weight::BOLD), VariationSettings())
362                       .fakery.variationSettings());
363     EXPECT_EQ(parseVariationSettings("'wght' 700"),
364               getBestFont(FontStyle(), parseVariationSettings("'wght' 700"))
365                       .fakery.variationSettings());
366     EXPECT_EQ(parseVariationSettings("'ital' 1"),
367               getBestFont(FontStyle(FontStyle::Slant::ITALIC), VariationSettings())
368                       .fakery.variationSettings());
369     EXPECT_EQ(parseVariationSettings("'ital' 1, 'wght' 500"),
370               getBestFont(FontStyle(FontStyle::Weight::MEDIUM, FontStyle::Slant::ITALIC),
371                           VariationSettings())
372                       .fakery.variationSettings());
373     EXPECT_EQ(parseVariationSettings("'ital' 1, 'wght' 500"),
374               getBestFont(FontStyle(FontStyle::Slant::ITALIC), parseVariationSettings("'wght' 500"))
375                       .fakery.variationSettings());
376 }
377 
378 }  // namespace minikin
379