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