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 "minikin/FontCollection.h"
18
19 #include <memory>
20
21 #include <gtest/gtest.h>
22
23 #include "minikin/FontFamily.h"
24 #include "minikin/FontFileParser.h"
25 #include "minikin/LocaleList.h"
26 #include "minikin/MinikinPaint.h"
27
28 #include "FontTestUtils.h"
29 #include "FreeTypeMinikinFontForTest.h"
30 #include "Locale.h"
31 #include "LocaleListCache.h"
32 #include "MinikinInternal.h"
33 #include "UnicodeUtils.h"
34
35 namespace minikin {
36
37 const char kItemizeFontXml[] = "itemize.xml";
38 const char kCherokeeFont[] = "Cherokee.ttf";
39 const char kEmojiFont[] = "Emoji.ttf";
40 const char kJAFont[] = "Ja.ttf";
41 const char kKOFont[] = "Ko.ttf";
42 const char kLatinBoldFont[] = "Bold.ttf";
43 const char kLatinBoldItalicFont[] = "BoldItalic.ttf";
44 const char kLatinFont[] = "Regular.ttf";
45 const char kLatinItalicFont[] = "Italic.ttf";
46 const char kZH_HansFont[] = "ZhHans.ttf";
47 const char kZH_HantFont[] = "ZhHant.ttf";
48 const char kAsciiFont[] = "Ascii.ttf";
49
50 const char kEmojiXmlFile[] = "emoji.xml";
51 const char kNoGlyphFont[] = "NoGlyphFont.ttf";
52 const char kColorEmojiFont[] = "ColorEmojiFont.ttf";
53 const char kTextEmojiFont[] = "TextEmojiFont.ttf";
54 const char kMixedEmojiFont[] = "ColorTextMixedEmojiFont.ttf";
55
56 const char kHasCmapFormat14Font[] = "NoCmapFormat14.ttf";
57 const char kNoCmapFormat14Font[] = "VariationSelectorTest-Regular.ttf";
58
59 struct Run {
60 FakedFont fakedFont;
61 int start;
62 int end;
63 };
64
65 // Utility functions for calling itemize function.
itemize(const std::shared_ptr<FontCollection> & collection,const char * str,FontStyle style,const std::string & localeList)66 std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
67 FontStyle style, const std::string& localeList) {
68 const size_t BUF_SIZE = 256;
69 uint16_t buf[BUF_SIZE];
70 size_t len;
71
72 ParseUnicode(buf, BUF_SIZE, str, &len, NULL);
73 const uint32_t localeListId = registerLocaleList(localeList);
74 auto result = collection->itemize(U16StringPiece(buf, len), style, localeListId,
75 FamilyVariant::DEFAULT);
76
77 // Check the same result has returned by calling with maxRun.
78 for (uint32_t runMax = 1; runMax <= result.size(); runMax++) {
79 auto resultWithRunMax = collection->itemize(U16StringPiece(buf, len), style, localeListId,
80 FamilyVariant::DEFAULT, runMax);
81 EXPECT_EQ(runMax, resultWithRunMax.size());
82 for (uint32_t i = 0; i < runMax; ++i) {
83 EXPECT_EQ(result[i].start, resultWithRunMax[i].start);
84 EXPECT_EQ(result[i].end, resultWithRunMax[i].end);
85 EXPECT_EQ(result[i].familyMatch, resultWithRunMax[i].familyMatch);
86 }
87 }
88 std::vector<Run> runs;
89 for (const auto& r : result) {
90 runs.push_back(
91 {collection->getBestFont(U16StringPiece(buf, len), r, style), r.start, r.end});
92 }
93 return runs;
94 }
95
96 // Overloaded version for default font style.
itemize(const std::shared_ptr<FontCollection> & collection,const char * str,const std::string & localeList)97 std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
98 const std::string& localeList) {
99 return itemize(collection, str, FontStyle(), localeList);
100 }
101
102 // Overloaded version for empty locale list id.
itemize(const std::shared_ptr<FontCollection> & collection,const char * str,FontStyle style)103 std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str,
104 FontStyle style) {
105 return itemize(collection, str, style, "");
106 }
107
108 // Overloaded version for default font style and empty locale list id.
itemize(const std::shared_ptr<FontCollection> & collection,const char * str)109 std::vector<Run> itemize(const std::shared_ptr<FontCollection>& collection, const char* str) {
110 return itemize(collection, str, FontStyle(), "");
111 }
112
113 // Utility function to obtain font path associated with run.
getFontName(const Run & run)114 std::string getFontName(const Run& run) {
115 EXPECT_NE(nullptr, run.fakedFont.font.get());
116 return getBasename(run.fakedFont.font.get()->typeface()->GetFontPath());
117 }
118
119 // Utility function to obtain LocaleList from string.
registerAndGetLocaleList(const std::string & locale_string)120 const LocaleList& registerAndGetLocaleList(const std::string& locale_string) {
121 return LocaleListCache::getById(LocaleListCache::getId(locale_string));
122 }
123
TEST(FontCollectionItemizeTest,itemize_latin)124 TEST(FontCollectionItemizeTest, itemize_latin) {
125 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
126
127 const FontStyle kRegularStyle = FontStyle();
128 const FontStyle kItalicStyle = FontStyle(FontStyle::Slant::ITALIC);
129 const FontStyle kBoldStyle = FontStyle(FontStyle::Weight::BOLD);
130 const FontStyle kBoldItalicStyle = FontStyle(FontStyle::Weight::BOLD, FontStyle::Slant::ITALIC);
131
132 auto runs = itemize(collection, "'a' 'b' 'c' 'd' 'e'", kRegularStyle);
133 ASSERT_EQ(1U, runs.size());
134 EXPECT_EQ(0, runs[0].start);
135 EXPECT_EQ(5, runs[0].end);
136 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
137 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
138 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
139
140 runs = itemize(collection, "'a' 'b' 'c' 'd' 'e'", kItalicStyle);
141 ASSERT_EQ(1U, runs.size());
142 EXPECT_EQ(0, runs[0].start);
143 EXPECT_EQ(5, runs[0].end);
144 EXPECT_EQ(kLatinItalicFont, getFontName(runs[0]));
145 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
146 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
147
148 runs = itemize(collection, "'a' 'b' 'c' 'd' 'e'", kBoldStyle);
149 ASSERT_EQ(1U, runs.size());
150 EXPECT_EQ(0, runs[0].start);
151 EXPECT_EQ(5, runs[0].end);
152 EXPECT_EQ(kLatinBoldFont, getFontName(runs[0]));
153 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
154 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
155
156 runs = itemize(collection, "'a' 'b' 'c' 'd' 'e'", kBoldItalicStyle);
157 ASSERT_EQ(1U, runs.size());
158 EXPECT_EQ(0, runs[0].start);
159 EXPECT_EQ(5, runs[0].end);
160 EXPECT_EQ(kLatinBoldItalicFont, getFontName(runs[0]));
161 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
162 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
163
164 // Continue if the specific characters (e.g. hyphen, comma, etc.) is
165 // followed.
166 runs = itemize(collection, "'a' ',' '-' 'd' '!'", kRegularStyle);
167 ASSERT_EQ(1U, runs.size());
168 EXPECT_EQ(0, runs[0].start);
169 EXPECT_EQ(5, runs[0].end);
170 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
171 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
172 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
173
174 runs = itemize(collection, "'a' ',' '-' 'd' '!'", kRegularStyle);
175 ASSERT_EQ(1U, runs.size());
176 EXPECT_EQ(0, runs[0].start);
177 EXPECT_EQ(5, runs[0].end);
178 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
179 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
180 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
181
182 // U+0301 (COMBINING ACUTE ACCENT) must be in the same run with preceding
183 // chars if the font supports it.
184 runs = itemize(collection, "'a' U+0301", kRegularStyle);
185 ASSERT_EQ(1U, runs.size());
186 EXPECT_EQ(0, runs[0].start);
187 EXPECT_EQ(2, runs[0].end);
188 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
189 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
190 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
191 }
192
TEST(FontCollectionItemizeTest,itemize_combining)193 TEST(FontCollectionItemizeTest, itemize_combining) {
194 // The regular font and the Cherokee font both support U+0301 (COMBINING ACUTE ACCENT). Since
195 // it's a combining mark, it should come from whatever font the base character comes from.
196 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
197
198 auto runs = itemize(collection, "'a' U+0301");
199 ASSERT_EQ(1U, runs.size());
200 EXPECT_EQ(0, runs[0].start);
201 EXPECT_EQ(2, runs[0].end);
202 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
203
204 // CHEROKEE LETTER A, COMBINING ACUTE ACCENT
205 runs = itemize(collection, "U+13A0 U+0301");
206 ASSERT_EQ(1U, runs.size());
207 EXPECT_EQ(0, runs[0].start);
208 EXPECT_EQ(2, runs[0].end);
209 EXPECT_EQ(kCherokeeFont, getFontName(runs[0]));
210
211 // CHEROKEE LETTER A, COMBINING ACUTE ACCENT, COMBINING ACUTE ACCENT
212 runs = itemize(collection, "U+13A0 U+0301 U+0301");
213 ASSERT_EQ(1U, runs.size());
214 EXPECT_EQ(0, runs[0].start);
215 EXPECT_EQ(3, runs[0].end);
216 EXPECT_EQ(kCherokeeFont, getFontName(runs[0]));
217
218 runs = itemize(collection, "U+0301");
219 ASSERT_EQ(1U, runs.size());
220 EXPECT_EQ(0, runs[0].start);
221 EXPECT_EQ(1, runs[0].end);
222 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
223
224 // COMBINING ACUTE ACCENT, CHEROKEE LETTER A, COMBINING ACUTE ACCENT
225 runs = itemize(collection, "U+0301 U+13A0 U+0301");
226 ASSERT_EQ(2U, runs.size());
227 EXPECT_EQ(0, runs[0].start);
228 EXPECT_EQ(1, runs[0].end);
229 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
230 EXPECT_EQ(1, runs[1].start);
231 EXPECT_EQ(3, runs[1].end);
232 EXPECT_EQ(kCherokeeFont, getFontName(runs[1]));
233 }
234
TEST(FontCollectionItemizeTest,itemize_emoji)235 TEST(FontCollectionItemizeTest, itemize_emoji) {
236 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
237
238 auto runs = itemize(collection, "U+1F469 U+1F467");
239 ASSERT_EQ(1U, runs.size());
240 EXPECT_EQ(0, runs[0].start);
241 EXPECT_EQ(4, runs[0].end);
242 EXPECT_EQ(kEmojiFont, getFontName(runs[0]));
243 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
244 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
245
246 // U+20E3(COMBINING ENCLOSING KEYCAP) must be in the same run with preceding
247 // character if the font supports.
248 runs = itemize(collection, "'0' U+20E3");
249 ASSERT_EQ(1U, runs.size());
250 EXPECT_EQ(0, runs[0].start);
251 EXPECT_EQ(2, runs[0].end);
252 EXPECT_EQ(kEmojiFont, getFontName(runs[0]));
253 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
254 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
255
256 runs = itemize(collection, "U+1F470 U+20E3");
257 ASSERT_EQ(1U, runs.size());
258 EXPECT_EQ(0, runs[0].start);
259 EXPECT_EQ(3, runs[0].end);
260 EXPECT_EQ(kEmojiFont, getFontName(runs[0]));
261 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
262 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
263
264 runs = itemize(collection, "U+242EE U+1F470 U+20E3");
265 ASSERT_EQ(2U, runs.size());
266 EXPECT_EQ(0, runs[0].start);
267 EXPECT_EQ(2, runs[0].end);
268 EXPECT_EQ(kJAFont, getFontName(runs[0]));
269 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
270 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
271
272 EXPECT_EQ(2, runs[1].start);
273 EXPECT_EQ(5, runs[1].end);
274 EXPECT_EQ(kEmojiFont, getFontName(runs[1]));
275 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
276 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
277
278 // Currently there is no fonts which has a glyph for 'a' + U+20E3, so they
279 // are splitted into two.
280 runs = itemize(collection, "'a' U+20E3");
281 ASSERT_EQ(2U, runs.size());
282 EXPECT_EQ(0, runs[0].start);
283 EXPECT_EQ(1, runs[0].end);
284 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
285 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
286 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
287
288 EXPECT_EQ(1, runs[1].start);
289 EXPECT_EQ(2, runs[1].end);
290 EXPECT_EQ(kEmojiFont, getFontName(runs[1]));
291 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
292 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
293 }
294
TEST(FontCollectionItemizeTest,itemize_non_latin)295 TEST(FontCollectionItemizeTest, itemize_non_latin) {
296 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
297
298 // All Japanese Hiragana characters.
299 auto runs = itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", "ja-JP");
300 ASSERT_EQ(1U, runs.size());
301 EXPECT_EQ(0, runs[0].start);
302 EXPECT_EQ(5, runs[0].end);
303 EXPECT_EQ(kJAFont, getFontName(runs[0]));
304 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
305 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
306
307 // All Korean Hangul characters.
308 runs = itemize(collection, "U+B300 U+D55C U+BBFC U+AD6D", "en-US");
309 ASSERT_EQ(1U, runs.size());
310 EXPECT_EQ(0, runs[0].start);
311 EXPECT_EQ(4, runs[0].end);
312 EXPECT_EQ(kKOFont, getFontName(runs[0]));
313 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
314 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
315
316 // All Han characters ja, zh-Hans font having.
317 // Japanese font should be selected if the specified language is Japanese.
318 runs = itemize(collection, "U+81ED U+82B1 U+5FCD", "ja-JP");
319 ASSERT_EQ(1U, runs.size());
320 EXPECT_EQ(0, runs[0].start);
321 EXPECT_EQ(3, runs[0].end);
322 EXPECT_EQ(kJAFont, getFontName(runs[0]));
323 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
324 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
325
326 // Simplified Chinese font should be selected if the specified language is Simplified
327 // Chinese.
328 runs = itemize(collection, "U+81ED U+82B1 U+5FCD", "zh-Hans");
329 ASSERT_EQ(1U, runs.size());
330 EXPECT_EQ(0, runs[0].start);
331 EXPECT_EQ(3, runs[0].end);
332 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
333 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
334 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
335
336 // Fallbacks to other fonts if there is no glyph in the specified language's
337 // font. There is no character U+4F60 in Japanese.
338 runs = itemize(collection, "U+81ED U+4F60 U+5FCD", "ja-JP");
339 ASSERT_EQ(3U, runs.size());
340 EXPECT_EQ(0, runs[0].start);
341 EXPECT_EQ(1, runs[0].end);
342 EXPECT_EQ(kJAFont, getFontName(runs[0]));
343 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
344 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
345
346 EXPECT_EQ(1, runs[1].start);
347 EXPECT_EQ(2, runs[1].end);
348 EXPECT_EQ(kZH_HansFont, getFontName(runs[1]));
349 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
350 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
351
352 EXPECT_EQ(2, runs[2].start);
353 EXPECT_EQ(3, runs[2].end);
354 EXPECT_EQ(kJAFont, getFontName(runs[2]));
355 EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeBold());
356 EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeItalic());
357
358 // Tone mark.
359 runs = itemize(collection, "U+4444 U+302D", "");
360 ASSERT_EQ(1U, runs.size());
361 EXPECT_EQ(0, runs[0].start);
362 EXPECT_EQ(2, runs[0].end);
363 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
364 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
365 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
366
367 // Both zh-Hant and ja fonts support U+242EE, but zh-Hans doesn't.
368 // Here, ja and zh-Hant font should have the same score but ja should be selected since it is
369 // listed before zh-Hant.
370 runs = itemize(collection, "U+242EE", "zh-Hans");
371 ASSERT_EQ(1U, runs.size());
372 EXPECT_EQ(0, runs[0].start);
373 EXPECT_EQ(2, runs[0].end);
374 EXPECT_EQ(kJAFont, getFontName(runs[0]));
375 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
376 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
377 }
378
TEST(FontCollectionItemizeTest,itemize_mixed)379 TEST(FontCollectionItemizeTest, itemize_mixed) {
380 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
381
382 auto runs = itemize(collection, "'a' U+4F60 'b' U+4F60 'c'", "en-US");
383 ASSERT_EQ(5U, runs.size());
384 EXPECT_EQ(0, runs[0].start);
385 EXPECT_EQ(1, runs[0].end);
386 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
387 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
388 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
389
390 EXPECT_EQ(1, runs[1].start);
391 EXPECT_EQ(2, runs[1].end);
392 EXPECT_EQ(kZH_HansFont, getFontName(runs[1]));
393 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeBold());
394 EXPECT_FALSE(runs[1].fakedFont.fakery.isFakeItalic());
395
396 EXPECT_EQ(2, runs[2].start);
397 EXPECT_EQ(3, runs[2].end);
398 EXPECT_EQ(kLatinFont, getFontName(runs[2]));
399 EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeBold());
400 EXPECT_FALSE(runs[2].fakedFont.fakery.isFakeItalic());
401
402 EXPECT_EQ(3, runs[3].start);
403 EXPECT_EQ(4, runs[3].end);
404 EXPECT_EQ(kZH_HansFont, getFontName(runs[3]));
405 EXPECT_FALSE(runs[3].fakedFont.fakery.isFakeBold());
406 EXPECT_FALSE(runs[3].fakedFont.fakery.isFakeItalic());
407
408 EXPECT_EQ(4, runs[4].start);
409 EXPECT_EQ(5, runs[4].end);
410 EXPECT_EQ(kLatinFont, getFontName(runs[4]));
411 EXPECT_FALSE(runs[4].fakedFont.fakery.isFakeBold());
412 EXPECT_FALSE(runs[4].fakedFont.fakery.isFakeItalic());
413 }
414
TEST(FontCollectionItemizeTest,itemize_variationSelector)415 TEST(FontCollectionItemizeTest, itemize_variationSelector) {
416 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
417
418 // A glyph for U+4FAE is provided by both Japanese font and Simplified
419 // Chinese font. Also a glyph for U+242EE is provided by both Japanese and
420 // Traditional Chinese font. To avoid effects of device default locale,
421 // explicitly specify the locale.
422
423 // U+4FAE is available in both zh_Hans and ja font, but U+4FAE,U+FE00 is
424 // only available in ja font.
425 auto runs = itemize(collection, "U+4FAE", "zh-Hans");
426 ASSERT_EQ(1U, runs.size());
427 EXPECT_EQ(0, runs[0].start);
428 EXPECT_EQ(1, runs[0].end);
429 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
430
431 runs = itemize(collection, "U+4FAE U+FE00", "zh-Hans");
432 ASSERT_EQ(1U, runs.size());
433 EXPECT_EQ(0, runs[0].start);
434 EXPECT_EQ(2, runs[0].end);
435 EXPECT_EQ(kJAFont, getFontName(runs[0]));
436
437 runs = itemize(collection, "U+4FAE U+4FAE U+FE00", "zh-Hans");
438 ASSERT_EQ(2U, runs.size());
439 EXPECT_EQ(0, runs[0].start);
440 EXPECT_EQ(1, runs[0].end);
441 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
442 EXPECT_EQ(1, runs[1].start);
443 EXPECT_EQ(3, runs[1].end);
444 EXPECT_EQ(kJAFont, getFontName(runs[1]));
445
446 runs = itemize(collection, "U+4FAE U+4FAE U+FE00 U+4FAE", "zh-Hans");
447 ASSERT_EQ(3U, runs.size());
448 EXPECT_EQ(0, runs[0].start);
449 EXPECT_EQ(1, runs[0].end);
450 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
451 EXPECT_EQ(1, runs[1].start);
452 EXPECT_EQ(3, runs[1].end);
453 EXPECT_EQ(kJAFont, getFontName(runs[1]));
454 EXPECT_EQ(3, runs[2].start);
455 EXPECT_EQ(4, runs[2].end);
456 EXPECT_EQ(kZH_HansFont, getFontName(runs[2]));
457
458 // Validation selector after validation selector.
459 runs = itemize(collection, "U+4FAE U+FE00 U+FE00", "zh-Hans");
460 ASSERT_EQ(1U, runs.size());
461 EXPECT_EQ(0, runs[0].start);
462 EXPECT_EQ(3, runs[0].end);
463 EXPECT_EQ(kJAFont, getFontName(runs[0]));
464
465 // No font supports U+242EE U+FE0E.
466 runs = itemize(collection, "U+4FAE U+FE0E", "zh-Hans");
467 ASSERT_EQ(1U, runs.size());
468 EXPECT_EQ(0, runs[0].start);
469 EXPECT_EQ(2, runs[0].end);
470 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
471
472 // Surrogate pairs handling.
473 // U+242EE is available in ja font and zh_Hant font.
474 // U+242EE U+FE00 is available only in ja font.
475 runs = itemize(collection, "U+242EE", "zh-Hant");
476 ASSERT_EQ(1U, runs.size());
477 EXPECT_EQ(0, runs[0].start);
478 EXPECT_EQ(2, runs[0].end);
479 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
480
481 runs = itemize(collection, "U+242EE U+FE00", "zh-Hant");
482 ASSERT_EQ(1U, runs.size());
483 EXPECT_EQ(0, runs[0].start);
484 EXPECT_EQ(3, runs[0].end);
485 EXPECT_EQ(kJAFont, getFontName(runs[0]));
486
487 runs = itemize(collection, "U+242EE U+242EE U+FE00", "zh-Hant");
488 ASSERT_EQ(2U, runs.size());
489 EXPECT_EQ(0, runs[0].start);
490 EXPECT_EQ(2, runs[0].end);
491 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
492 EXPECT_EQ(2, runs[1].start);
493 EXPECT_EQ(5, runs[1].end);
494 EXPECT_EQ(kJAFont, getFontName(runs[1]));
495
496 runs = itemize(collection, "U+242EE U+242EE U+FE00 U+242EE", "zh-Hant");
497 ASSERT_EQ(3U, runs.size());
498 EXPECT_EQ(0, runs[0].start);
499 EXPECT_EQ(2, runs[0].end);
500 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
501 EXPECT_EQ(2, runs[1].start);
502 EXPECT_EQ(5, runs[1].end);
503 EXPECT_EQ(kJAFont, getFontName(runs[1]));
504 EXPECT_EQ(5, runs[2].start);
505 EXPECT_EQ(7, runs[2].end);
506 EXPECT_EQ(kZH_HantFont, getFontName(runs[2]));
507
508 // Validation selector after validation selector.
509 runs = itemize(collection, "U+242EE U+FE00 U+FE00", "zh-Hans");
510 ASSERT_EQ(1U, runs.size());
511 EXPECT_EQ(0, runs[0].start);
512 EXPECT_EQ(4, runs[0].end);
513 EXPECT_EQ(kJAFont, getFontName(runs[0]));
514
515 // No font supports U+242EE U+FE0E
516 runs = itemize(collection, "U+242EE U+FE0E", "zh-Hant");
517 ASSERT_EQ(1U, runs.size());
518 EXPECT_EQ(0, runs[0].start);
519 EXPECT_EQ(3, runs[0].end);
520 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
521
522 // Isolated variation selector supplement.
523 runs = itemize(collection, "U+FE00", "");
524 ASSERT_EQ(1U, runs.size());
525 EXPECT_EQ(0, runs[0].start);
526 EXPECT_EQ(1, runs[0].end);
527 EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
528
529 runs = itemize(collection, "U+FE00", "zh-Hant");
530 ASSERT_EQ(1U, runs.size());
531 EXPECT_EQ(0, runs[0].start);
532 EXPECT_EQ(1, runs[0].end);
533 EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
534
535 // First font family (Regular.ttf) supports U+203C but doesn't support U+203C U+FE0F.
536 // Emoji.ttf font supports U+203C U+FE0F. Emoji.ttf should be selected.
537 runs = itemize(collection, "U+203C U+FE0F", "zh-Hant");
538 ASSERT_EQ(1U, runs.size());
539 EXPECT_EQ(0, runs[0].start);
540 EXPECT_EQ(2, runs[0].end);
541 EXPECT_EQ(kEmojiFont, getFontName(runs[0]));
542
543 // First font family (Regular.ttf) supports U+203C U+FE0E.
544 runs = itemize(collection, "U+203C U+FE0E", "zh-Hant");
545 ASSERT_EQ(1U, runs.size());
546 EXPECT_EQ(0, runs[0].start);
547 EXPECT_EQ(2, runs[0].end);
548 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
549 }
550
TEST(FontCollectionItemizeTest,itemize_variationSelectorSupplement)551 TEST(FontCollectionItemizeTest, itemize_variationSelectorSupplement) {
552 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
553
554 // A glyph for U+845B is provided by both Japanese font and Simplified
555 // Chinese font. Also a glyph for U+242EE is provided by both Japanese and
556 // Traditional Chinese font. To avoid effects of device default locale,
557 // explicitly specify the locale.
558
559 // U+845B is available in both zh_Hans and ja font, but U+845B,U+E0100 is
560 // only available in ja font.
561 auto runs = itemize(collection, "U+845B", "zh-Hans");
562 ASSERT_EQ(1U, runs.size());
563 EXPECT_EQ(0, runs[0].start);
564 EXPECT_EQ(1, runs[0].end);
565 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
566
567 runs = itemize(collection, "U+845B U+E0100", "zh-Hans");
568 ASSERT_EQ(1U, runs.size());
569 EXPECT_EQ(0, runs[0].start);
570 EXPECT_EQ(3, runs[0].end);
571 EXPECT_EQ(kJAFont, getFontName(runs[0]));
572
573 runs = itemize(collection, "U+845B U+845B U+E0100", "zh-Hans");
574 ASSERT_EQ(2U, runs.size());
575 EXPECT_EQ(0, runs[0].start);
576 EXPECT_EQ(1, runs[0].end);
577 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
578 EXPECT_EQ(1, runs[1].start);
579 EXPECT_EQ(4, runs[1].end);
580 EXPECT_EQ(kJAFont, getFontName(runs[1]));
581
582 runs = itemize(collection, "U+845B U+845B U+E0100 U+845B", "zh-Hans");
583 ASSERT_EQ(3U, runs.size());
584 EXPECT_EQ(0, runs[0].start);
585 EXPECT_EQ(1, runs[0].end);
586 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
587 EXPECT_EQ(1, runs[1].start);
588 EXPECT_EQ(4, runs[1].end);
589 EXPECT_EQ(kJAFont, getFontName(runs[1]));
590 EXPECT_EQ(4, runs[2].start);
591 EXPECT_EQ(5, runs[2].end);
592 EXPECT_EQ(kZH_HansFont, getFontName(runs[2]));
593
594 // Validation selector after validation selector.
595 runs = itemize(collection, "U+845B U+E0100 U+E0100", "zh-Hans");
596 ASSERT_EQ(1U, runs.size());
597 EXPECT_EQ(0, runs[0].start);
598 EXPECT_EQ(5, runs[0].end);
599 EXPECT_EQ(kJAFont, getFontName(runs[0]));
600
601 // No font supports U+845B U+E01E0.
602 runs = itemize(collection, "U+845B U+E01E0", "zh-Hans");
603 ASSERT_EQ(1U, runs.size());
604 EXPECT_EQ(0, runs[0].start);
605 EXPECT_EQ(3, runs[0].end);
606 EXPECT_EQ(kZH_HansFont, getFontName(runs[0]));
607
608 // Isolated variation selector supplement
609 // Surrogate pairs handling.
610 // U+242EE is available in ja font and zh_Hant font.
611 // U+242EE U+E0100 is available only in ja font.
612 runs = itemize(collection, "U+242EE", "zh-Hant");
613 ASSERT_EQ(1U, runs.size());
614 EXPECT_EQ(0, runs[0].start);
615 EXPECT_EQ(2, runs[0].end);
616 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
617
618 runs = itemize(collection, "U+242EE U+E0101", "zh-Hant");
619 ASSERT_EQ(1U, runs.size());
620 EXPECT_EQ(0, runs[0].start);
621 EXPECT_EQ(4, runs[0].end);
622 EXPECT_EQ(kJAFont, getFontName(runs[0]));
623
624 runs = itemize(collection, "U+242EE U+242EE U+E0101", "zh-Hant");
625 ASSERT_EQ(2U, runs.size());
626 EXPECT_EQ(0, runs[0].start);
627 EXPECT_EQ(2, runs[0].end);
628 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
629 EXPECT_EQ(2, runs[1].start);
630 EXPECT_EQ(6, runs[1].end);
631 EXPECT_EQ(kJAFont, getFontName(runs[1]));
632
633 runs = itemize(collection, "U+242EE U+242EE U+E0101 U+242EE", "zh-Hant");
634 ASSERT_EQ(3U, runs.size());
635 EXPECT_EQ(0, runs[0].start);
636 EXPECT_EQ(2, runs[0].end);
637 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
638 EXPECT_EQ(2, runs[1].start);
639 EXPECT_EQ(6, runs[1].end);
640 EXPECT_EQ(kJAFont, getFontName(runs[1]));
641 EXPECT_EQ(6, runs[2].start);
642 EXPECT_EQ(8, runs[2].end);
643 EXPECT_EQ(kZH_HantFont, getFontName(runs[2]));
644
645 // Validation selector after validation selector.
646 runs = itemize(collection, "U+242EE U+E0100 U+E0100", "zh-Hant");
647 ASSERT_EQ(1U, runs.size());
648 EXPECT_EQ(0, runs[0].start);
649 EXPECT_EQ(6, runs[0].end);
650 EXPECT_EQ(kJAFont, getFontName(runs[0]));
651
652 // No font supports U+242EE U+E01E0.
653 runs = itemize(collection, "U+242EE U+E01E0", "zh-Hant");
654 ASSERT_EQ(1U, runs.size());
655 EXPECT_EQ(0, runs[0].start);
656 EXPECT_EQ(4, runs[0].end);
657 EXPECT_EQ(kZH_HantFont, getFontName(runs[0]));
658
659 // Isolated variation selector supplement.
660 runs = itemize(collection, "U+E0100", "");
661 ASSERT_EQ(1U, runs.size());
662 EXPECT_EQ(0, runs[0].start);
663 EXPECT_EQ(2, runs[0].end);
664 EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
665
666 runs = itemize(collection, "U+E0100", "zh-Hant");
667 ASSERT_EQ(1U, runs.size());
668 EXPECT_EQ(0, runs[0].start);
669 EXPECT_EQ(2, runs[0].end);
670 EXPECT_TRUE(runs[0].fakedFont.font.get() == nullptr || kLatinFont == getFontName(runs[0]));
671 }
672
TEST(FontCollectionItemizeTest,itemize_no_crash)673 TEST(FontCollectionItemizeTest, itemize_no_crash) {
674 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
675
676 // Broken Surrogate pairs. Check only not crashing.
677 auto runs = itemize(collection, "'a' U+D83D 'a'");
678 runs = itemize(collection, "'a' U+DC69 'a'");
679 runs = itemize(collection, "'a' U+D83D U+D83D 'a'");
680 runs = itemize(collection, "'a' U+DC69 U+DC69 'a'");
681
682 // Isolated variation selector. Check only not crashing.
683 runs = itemize(collection, "U+FE00 U+FE00");
684 runs = itemize(collection, "U+E0100 U+E0100");
685 runs = itemize(collection, "U+FE00 U+E0100");
686 runs = itemize(collection, "U+E0100 U+FE00");
687
688 // Tone mark only. Check only not crashing.
689 runs = itemize(collection, "U+302D");
690 runs = itemize(collection, "U+302D U+302D");
691
692 // Tone mark and variation selector mixed. Check only not crashing.
693 runs = itemize(collection, "U+FE00 U+302D U+E0100");
694 }
695
TEST(FontCollectionItemizeTest,itemize_fakery)696 TEST(FontCollectionItemizeTest, itemize_fakery) {
697 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
698
699 FontStyle kBoldStyle(FontStyle::Weight::BOLD);
700 FontStyle kItalicStyle(FontStyle::Slant::ITALIC);
701 FontStyle kBoldItalicStyle(FontStyle::Weight::BOLD, FontStyle::Slant::ITALIC);
702
703 // Currently there is no italic or bold font for Japanese. FontFakery has
704 // the differences between desired and actual font style.
705
706 // All Japanese Hiragana characters.
707 auto runs = itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kBoldStyle, "ja-JP");
708 ASSERT_EQ(1U, runs.size());
709 EXPECT_EQ(0, runs[0].start);
710 EXPECT_EQ(5, runs[0].end);
711 EXPECT_EQ(kJAFont, getFontName(runs[0]));
712 EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeBold());
713 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeItalic());
714
715 // All Japanese Hiragana characters.
716 runs = itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kItalicStyle, "ja-JP");
717 ASSERT_EQ(1U, runs.size());
718 EXPECT_EQ(0, runs[0].start);
719 EXPECT_EQ(5, runs[0].end);
720 EXPECT_EQ(kJAFont, getFontName(runs[0]));
721 EXPECT_FALSE(runs[0].fakedFont.fakery.isFakeBold());
722 EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeItalic());
723
724 // All Japanese Hiragana characters.
725 runs = itemize(collection, "U+3042 U+3044 U+3046 U+3048 U+304A", kBoldItalicStyle, "ja-JP");
726 ASSERT_EQ(1U, runs.size());
727 EXPECT_EQ(0, runs[0].start);
728 EXPECT_EQ(5, runs[0].end);
729 EXPECT_EQ(kJAFont, getFontName(runs[0]));
730 EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeBold());
731 EXPECT_TRUE(runs[0].fakedFont.fakery.isFakeItalic());
732 }
733
TEST(FontCollectionItemizeTest,itemize_vs_sequence_but_no_base_char)734 TEST(FontCollectionItemizeTest, itemize_vs_sequence_but_no_base_char) {
735 // kVSTestFont supports U+717D U+FE02 but doesn't support U+717D.
736 // kVSTestFont should be selected for U+717D U+FE02 even if it does not support the base code
737 // point.
738 const std::string kVSTestFont = "VariationSelectorTest-Regular.ttf";
739
740 std::vector<std::shared_ptr<FontFamily>> families;
741 families.push_back(buildFontFamily(kLatinFont));
742 families.push_back(buildFontFamily(kVSTestFont));
743
744 std::shared_ptr<FontCollection> collection(new FontCollection(families));
745
746 auto runs = itemize(collection, "U+717D U+FE02");
747 ASSERT_EQ(1U, runs.size());
748 EXPECT_EQ(0, runs[0].start);
749 EXPECT_EQ(2, runs[0].end);
750 EXPECT_EQ(kVSTestFont, getFontName(runs[0]));
751 }
752
TEST(FontCollectionItemizeTest,itemize_format_chars)753 TEST(FontCollectionItemizeTest, itemize_format_chars) {
754 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
755
756 auto runs = itemize(collection, "'a' U+061C 'b'");
757 ASSERT_EQ(1U, runs.size());
758 EXPECT_EQ(0, runs[0].start);
759 EXPECT_EQ(3, runs[0].end);
760 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
761
762 runs = itemize(collection, "'a' U+200D 'b'");
763 ASSERT_EQ(1U, runs.size());
764 EXPECT_EQ(0, runs[0].start);
765 EXPECT_EQ(3, runs[0].end);
766 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
767
768 runs = itemize(collection, "U+3042 U+061C U+3042");
769 ASSERT_EQ(1U, runs.size());
770 EXPECT_EQ(0, runs[0].start);
771 EXPECT_EQ(3, runs[0].end);
772 EXPECT_EQ(kJAFont, getFontName(runs[0]));
773
774 runs = itemize(collection, "U+061C 'b'");
775 ASSERT_EQ(1U, runs.size());
776 EXPECT_EQ(0, runs[0].start);
777 EXPECT_EQ(2, runs[0].end);
778 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
779
780 runs = itemize(collection, "U+061C U+3042");
781 ASSERT_EQ(1U, runs.size());
782 EXPECT_EQ(0, runs[0].start);
783 EXPECT_EQ(2, runs[0].end);
784 EXPECT_EQ(kJAFont, getFontName(runs[0]));
785
786 runs = itemize(collection, "U+061C");
787 ASSERT_EQ(1U, runs.size());
788 EXPECT_EQ(0, runs[0].start);
789 EXPECT_EQ(1, runs[0].end);
790 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
791
792 runs = itemize(collection, "U+061C U+061C U+061C");
793 ASSERT_EQ(1U, runs.size());
794 EXPECT_EQ(0, runs[0].start);
795 EXPECT_EQ(3, runs[0].end);
796 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
797
798 runs = itemize(collection, "U+200D U+20E3");
799 ASSERT_EQ(1U, runs.size());
800 EXPECT_EQ(0, runs[0].start);
801 EXPECT_EQ(2, runs[0].end);
802 EXPECT_EQ(kEmojiFont, getFontName(runs[0]));
803
804 runs = itemize(collection, "U+200D");
805 ASSERT_EQ(1U, runs.size());
806 EXPECT_EQ(0, runs[0].start);
807 EXPECT_EQ(1, runs[0].end);
808 EXPECT_EQ(kLatinFont, getFontName(runs[0]));
809
810 runs = itemize(collection, "U+20E3");
811 ASSERT_EQ(1U, runs.size());
812 EXPECT_EQ(0, runs[0].start);
813 EXPECT_EQ(1, runs[0].end);
814 EXPECT_EQ(kEmojiFont, getFontName(runs[0]));
815 }
816
TEST(FontCollectionItemizeTest,itemize_LocaleScore)817 TEST(FontCollectionItemizeTest, itemize_LocaleScore) {
818 struct TestCase {
819 std::string userPreferredLocale;
820 std::vector<std::string> fontLocales;
821 int selectedFontIndex;
822 } testCases[] = {
823 // Font can specify empty locale.
824 {"und", {"", ""}, 0},
825 {"und", {"", "en-Latn"}, 0},
826 {"en-Latn", {"", ""}, 0},
827 {"en-Latn", {"", "en-Latn"}, 1},
828
829 // Single user preferred locale.
830 // Exact match case
831 {"en-Latn", {"en-Latn", "ja-Jpan"}, 0},
832 {"ja-Jpan", {"en-Latn", "ja-Jpan"}, 1},
833 {"en-Latn", {"en-Latn", "nl-Latn", "es-Latn"}, 0},
834 {"nl-Latn", {"en-Latn", "nl-Latn", "es-Latn"}, 1},
835 {"es-Latn", {"en-Latn", "nl-Latn", "es-Latn"}, 2},
836 {"es-Latn", {"en-Latn", "en-Latn", "nl-Latn"}, 0},
837
838 // Exact script match case
839 {"en-Latn", {"nl-Latn", "e-Latn"}, 0},
840 {"en-Arab", {"nl-Latn", "ar-Arab"}, 1},
841 {"en-Latn", {"be-Latn", "ar-Arab", "d-Beng"}, 0},
842 {"en-Arab", {"be-Latn", "ar-Arab", "d-Beng"}, 1},
843 {"en-Beng", {"be-Latn", "ar-Arab", "d-Beng"}, 2},
844 {"en-Beng", {"be-Latn", "ar-Beng", "d-Beng"}, 1},
845 {"zh-Hant", {"zh-Hant", "zh-Hans"}, 0},
846 {"zh-Hans", {"zh-Hant", "zh-Hans"}, 1},
847
848 // Subscript match case, e.g. Jpan supports Hira.
849 {"en-Hira", {"ja-Jpan"}, 0},
850 {"zh-Hani", {"zh-Hans", "zh-Hant"}, 0},
851 {"zh-Hani", {"zh-Hant", "zh-Hans"}, 0},
852 {"en-Hira", {"zh-Hant", "ja-Jpan", "ja-Jpan"}, 1},
853
854 // Language match case
855 {"ja-Latn", {"zh-Latn", "ja-Latn"}, 1},
856 {"zh-Latn", {"zh-Latn", "ja-Latn"}, 0},
857 {"ja-Latn", {"zh-Latn", "ja-Latn"}, 1},
858 {"ja-Latn", {"zh-Latn", "ja-Latn", "ja-Latn"}, 1},
859
860 // Mixed case
861 // Script/subscript match is strongest.
862 {"ja-Jpan", {"en-Latn", "ja-Latn", "en-Jpan"}, 2},
863 {"ja-Hira", {"en-Latn", "ja-Latn", "en-Jpan"}, 2},
864 {"ja-Hira", {"en-Latn", "ja-Latn", "en-Jpan", "en-Jpan"}, 2},
865
866 // Language match only happens if the script matches.
867 {"ja-Hira", {"en-Latn", "ja-Latn"}, 0},
868 {"ja-Hira", {"en-Jpan", "ja-Jpan"}, 1},
869
870 // Multiple locales.
871 // Even if all fonts have the same score, use the 2nd locale for better selection.
872 {"en-Latn,ja-Jpan", {"zh-Hant", "zh-Hans", "ja-Jpan"}, 2},
873 {"en-Latn,nl-Latn", {"es-Latn", "be-Latn", "nl-Latn"}, 2},
874 {"en-Latn,br-Latn,nl-Latn", {"es-Latn", "be-Latn", "nl-Latn"}, 2},
875 {"en-Latn,br-Latn,nl-Latn", {"es-Latn", "be-Latn", "nl-Latn", "nl-Latn"}, 2},
876
877 // Script score.
878 {"en-Latn,ja-Jpan", {"en-Arab", "en-Jpan"}, 1},
879 {"en-Latn,ja-Jpan", {"en-Arab", "en-Jpan", "en-Jpan"}, 1},
880
881 // Language match case
882 {"en-Latn,ja-Latn", {"bd-Latn", "ja-Latn"}, 1},
883 {"en-Latn,ja-Latn", {"bd-Latn", "ja-Latn", "ja-Latn"}, 1},
884
885 // Language match only happens if the script matches.
886 {"en-Latn,ar-Arab", {"en-Beng", "ar-Arab"}, 1},
887
888 // Multiple locales in the font settings.
889 {"ko-Jamo", {"ja-Jpan", "ko-Kore", "ko-Kore,ko-Jamo"}, 2},
890 {"en-Latn", {"ja-Jpan", "en-Latn,ja-Jpan"}, 1},
891 {"en-Latn", {"ja-Jpan", "ja-Jpan,en-Latn"}, 1},
892 {"en-Latn", {"ja-Jpan,zh-Hant", "en-Latn,ja-Jpan", "en-Latn"}, 1},
893 {"en-Latn", {"zh-Hant,ja-Jpan", "ja-Jpan,en-Latn", "en-Latn"}, 1},
894
895 // Kore = Hang + Hani, etc.
896 {"ko-Kore", {"ko-Hang", "ko-Jamo,ko-Hani", "ko-Hang,ko-Hani"}, 2},
897 {"ja-Hrkt", {"ja-Hira", "ja-Kana", "ja-Hira,ja-Kana"}, 2},
898 {"ja-Jpan", {"ja-Hira", "ja-Kana", "ja-Hani", "ja-Hira,ja-Kana,ja-Hani"}, 3},
899 {"zh-Hanb", {"zh-Hant", "zh-Bopo", "zh-Hant,zh-Bopo"}, 2},
900 {"zh-Hanb", {"ja-Hanb", "zh-Hant,zh-Bopo"}, 1},
901
902 // Language match with unified subscript bits.
903 {"zh-Hanb", {"zh-Hant", "zh-Bopo", "ja-Hant,ja-Bopo", "zh-Hant,zh-Bopo"}, 3},
904 {"zh-Hanb", {"zh-Hant", "zh-Bopo", "ja-Hant,zh-Bopo", "zh-Hant,zh-Bopo"}, 3},
905
906 // Two elements subtag matching: language and subtag or language or script.
907 {"ja-Kana-u-em-emoji", {"zh-Hant", "ja-Kana"}, 1},
908 {"ja-Kana-u-em-emoji", {"zh-Hant", "ja-Kana", "ja-Zsye"}, 2},
909 {"ja-Zsym-u-em-emoji", {"ja-Kana", "ja-Zsym", "ja-Zsye"}, 2},
910
911 // One element subtag matching: subtag only or script only.
912 {"en-Latn-u-em-emoji", {"ja-Latn", "ja-Zsye"}, 1},
913 {"en-Zsym-u-em-emoji", {"ja-Zsym", "ja-Zsye"}, 1},
914 {"en-Zsye-u-em-text", {"ja-Zsym", "ja-Zsye"}, 0},
915
916 // Multiple locale list with subtags.
917 {"en-Latn,ja-Jpan-u-em-text", {"en-Latn", "en-Zsye", "en-Zsym"}, 0},
918 {"en-Latn,en-Zsye,ja-Jpan-u-em-text", {"zh", "en-Zsye", "en-Zsym"}, 1},
919 };
920
921 for (auto testCase : testCases) {
922 std::string fontLocaleStr = "{";
923 for (size_t i = 0; i < testCase.fontLocales.size(); ++i) {
924 if (i != 0) {
925 fontLocaleStr += ", ";
926 }
927 fontLocaleStr += "\"" + testCase.fontLocales[i] + "\"";
928 }
929 fontLocaleStr += "}";
930 SCOPED_TRACE("Test of user preferred locale: \"" + testCase.userPreferredLocale +
931 "\" with font locale: " + fontLocaleStr);
932
933 std::vector<std::shared_ptr<FontFamily>> families;
934
935 // Prepare first font which doesn't supports U+9AA8
936 auto firstFamilyMinikinFont =
937 std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kNoGlyphFont));
938 std::vector<std::shared_ptr<Font>> fonts;
939 fonts.push_back(Font::Builder(firstFamilyMinikinFont).build());
940 auto firstFamily =
941 std::make_shared<FontFamily>(registerLocaleList("und"), FamilyVariant::DEFAULT,
942 std::move(fonts), false /* isCustomFallback */);
943 families.push_back(firstFamily);
944
945 // Prepare font families
946 // Each font family is associated with a specified locale. All font families except for
947 // the first font support U+9AA8.
948 std::unordered_map<MinikinFont*, int> fontLocaleIdxMap;
949
950 for (size_t i = 0; i < testCase.fontLocales.size(); ++i) {
951 auto minikinFont =
952 std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(kJAFont));
953 std::vector<std::shared_ptr<Font>> fonts;
954 fonts.push_back(Font::Builder(minikinFont).build());
955 auto family = std::make_shared<FontFamily>(registerLocaleList(testCase.fontLocales[i]),
956 FamilyVariant::DEFAULT, std::move(fonts),
957 false /* isCustomFallback */);
958 families.push_back(family);
959 fontLocaleIdxMap.insert(std::make_pair(minikinFont.get(), i));
960 }
961 std::shared_ptr<FontCollection> collection(new FontCollection(families));
962 // Do itemize
963 auto runs = itemize(collection, "U+9AA8", testCase.userPreferredLocale);
964 ASSERT_EQ(1U, runs.size());
965 ASSERT_NE(nullptr, runs[0].fakedFont.font.get());
966
967 // First family doesn't support U+9AA8 and others support it, so the first font should not
968 // be selected.
969 EXPECT_NE(firstFamilyMinikinFont.get(), runs[0].fakedFont.font.get()->typeface().get());
970
971 // Lookup used font family by MinikinFont*.
972 const int usedLocaleIndex =
973 fontLocaleIdxMap[runs[0].fakedFont.font.get()->typeface().get()];
974 EXPECT_EQ(testCase.selectedFontIndex, usedLocaleIndex);
975 }
976 }
977
TEST(FontCollectionItemizeTest,itemize_LocaleAndCoverage)978 TEST(FontCollectionItemizeTest, itemize_LocaleAndCoverage) {
979 struct TestCase {
980 std::string testString;
981 std::string requestedLocales;
982 std::string expectedFont;
983 } testCases[] = {
984 // Following test cases verify that following rules in font fallback chain.
985 // - If the first font in the collection supports the given character or variation
986 // sequence,
987 // it should be selected.
988 // - If the font doesn't support the given character, variation sequence or its base
989 // character, it should not be selected.
990 // - If two or more fonts match the requested locales, the font matches with the highest
991 // priority locale should be selected.
992 // - If two or more fonts get the same score, the font listed earlier in the XML file
993 // (here, kItemizeFontXml) should be selected.
994
995 // Regardless of locale, the first font is always selected if it covers the code point.
996 {"'a'", "", kLatinFont},
997 {"'a'", "en-Latn", kLatinFont},
998 {"'a'", "ja-Jpan", kLatinFont},
999 {"'a'", "ja-Jpan,en-Latn", kLatinFont},
1000 {"'a'", "zh-Hans,zh-Hant,en-Latn,ja-Jpan,fr-Latn", kLatinFont},
1001
1002 // U+81ED is supported by both the ja font and zh-Hans font.
1003 {"U+81ED", "", kZH_HansFont}, // zh-Hans font is listed before ja font.
1004 {"U+81ED", "en-Latn", kZH_HansFont}, // zh-Hans font is listed before ja font.
1005 {"U+81ED", "ja-Jpan", kJAFont},
1006 {"U+81ED", "zh-Hans", kZH_HansFont},
1007
1008 {"U+81ED", "ja-Jpan,en-Latn", kJAFont},
1009 {"U+81ED", "en-Latn,ja-Jpan", kJAFont},
1010 {"U+81ED", "en-Latn,zh-Hans", kZH_HansFont},
1011 {"U+81ED", "zh-Hans,en-Latn", kZH_HansFont},
1012 {"U+81ED", "ja-Jpan,zh-Hans", kJAFont},
1013 {"U+81ED", "zh-Hans,ja-Jpan", kZH_HansFont},
1014
1015 {"U+81ED", "en-Latn,zh-Hans,ja-Jpan", kZH_HansFont},
1016 {"U+81ED", "en-Latn,ja-Jpan,zh-Hans", kJAFont},
1017 {"U+81ED", "en-Latn,zh-Hans,ja-Jpan", kZH_HansFont},
1018 {"U+81ED", "ja-Jpan,en-Latn,zh-Hans", kJAFont},
1019 {"U+81ED", "ja-Jpan,zh-Hans,en-Latn", kJAFont},
1020 {"U+81ED", "zh-Hans,en-Latn,ja-Jpan", kZH_HansFont},
1021 {"U+81ED", "zh-Hans,ja-Jpan,en-Latn", kZH_HansFont},
1022
1023 // U+304A is only supported by ja font.
1024 {"U+304A", "", kJAFont},
1025 {"U+304A", "ja-Jpan", kJAFont},
1026 {"U+304A", "zh-Hant", kJAFont},
1027 {"U+304A", "zh-Hans", kJAFont},
1028
1029 {"U+304A", "ja-Jpan,zh-Hant", kJAFont},
1030 {"U+304A", "zh-Hant,ja-Jpan", kJAFont},
1031 {"U+304A", "zh-Hans,zh-Hant", kJAFont},
1032 {"U+304A", "zh-Hant,zh-Hans", kJAFont},
1033 {"U+304A", "zh-Hans,ja-Jpan", kJAFont},
1034 {"U+304A", "ja-Jpan,zh-Hans", kJAFont},
1035
1036 {"U+304A", "zh-Hans,ja-Jpan,zh-Hant", kJAFont},
1037 {"U+304A", "zh-Hans,zh-Hant,ja-Jpan", kJAFont},
1038 {"U+304A", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1039 {"U+304A", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1040 {"U+304A", "zh-Hant,zh-Hans,ja-Jpan", kJAFont},
1041 {"U+304A", "zh-Hant,ja-Jpan,zh-Hans", kJAFont},
1042
1043 // U+242EE is supported by both ja font and zh-Hant fonts but not by zh-Hans font.
1044 {"U+242EE", "", kJAFont}, // ja font is listed before zh-Hant font.
1045 {"U+242EE", "ja-Jpan", kJAFont},
1046 {"U+242EE", "zh-Hans", kJAFont},
1047 {"U+242EE", "zh-Hant", kZH_HantFont},
1048
1049 {"U+242EE", "ja-Jpan,zh-Hant", kJAFont},
1050 {"U+242EE", "zh-Hant,ja-Jpan", kZH_HantFont},
1051 {"U+242EE", "zh-Hans,zh-Hant", kZH_HantFont},
1052 {"U+242EE", "zh-Hant,zh-Hans", kZH_HantFont},
1053 {"U+242EE", "zh-Hans,ja-Jpan", kJAFont},
1054 {"U+242EE", "ja-Jpan,zh-Hans", kJAFont},
1055
1056 {"U+242EE", "zh-Hans,ja-Jpan,zh-Hant", kJAFont},
1057 {"U+242EE", "zh-Hans,zh-Hant,ja-Jpan", kZH_HantFont},
1058 {"U+242EE", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1059 {"U+242EE", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1060 {"U+242EE", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont},
1061 {"U+242EE", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont},
1062
1063 // U+9AA8 is supported by all ja-Jpan, zh-Hans, zh-Hant fonts.
1064 {"U+9AA8", "", kZH_HansFont}, // zh-Hans font is listed before ja and zh-Hant fonts.
1065 {"U+9AA8", "ja-Jpan", kJAFont},
1066 {"U+9AA8", "zh-Hans", kZH_HansFont},
1067 {"U+9AA8", "zh-Hant", kZH_HantFont},
1068
1069 {"U+9AA8", "ja-Jpan,zh-Hant", kJAFont},
1070 {"U+9AA8", "zh-Hant,ja-Jpan", kZH_HantFont},
1071 {"U+9AA8", "zh-Hans,zh-Hant", kZH_HansFont},
1072 {"U+9AA8", "zh-Hant,zh-Hans", kZH_HantFont},
1073 {"U+9AA8", "zh-Hans,ja-Jpan", kZH_HansFont},
1074 {"U+9AA8", "ja-Jpan,zh-Hans", kJAFont},
1075
1076 {"U+9AA8", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont},
1077 {"U+9AA8", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont},
1078 {"U+9AA8", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1079 {"U+9AA8", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1080 {"U+9AA8", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont},
1081 {"U+9AA8", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont},
1082
1083 // U+242EE U+FE00 is supported by ja font but not by zh-Hans or zh-Hant fonts.
1084 {"U+242EE U+FE00", "", kJAFont},
1085 {"U+242EE U+FE00", "ja-Jpan", kJAFont},
1086 {"U+242EE U+FE00", "zh-Hant", kJAFont},
1087 {"U+242EE U+FE00", "zh-Hans", kJAFont},
1088
1089 {"U+242EE U+FE00", "ja-Jpan,zh-Hant", kJAFont},
1090 {"U+242EE U+FE00", "zh-Hant,ja-Jpan", kJAFont},
1091 {"U+242EE U+FE00", "zh-Hans,zh-Hant", kJAFont},
1092 {"U+242EE U+FE00", "zh-Hant,zh-Hans", kJAFont},
1093 {"U+242EE U+FE00", "zh-Hans,ja-Jpan", kJAFont},
1094 {"U+242EE U+FE00", "ja-Jpan,zh-Hans", kJAFont},
1095
1096 {"U+242EE U+FE00", "zh-Hans,ja-Jpan,zh-Hant", kJAFont},
1097 {"U+242EE U+FE00", "zh-Hans,zh-Hant,ja-Jpan", kJAFont},
1098 {"U+242EE U+FE00", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1099 {"U+242EE U+FE00", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1100 {"U+242EE U+FE00", "zh-Hant,zh-Hans,ja-Jpan", kJAFont},
1101 {"U+242EE U+FE00", "zh-Hant,ja-Jpan,zh-Hans", kJAFont},
1102
1103 // U+3402 U+E0100 is supported by both zh-Hans and zh-Hant but not by ja font.
1104 {"U+3402 U+E0100", "", kZH_HansFont}, // zh-Hans font is listed before zh-Hant font.
1105 {"U+3402 U+E0100", "ja-Jpan",
1106 kZH_HansFont}, // zh-Hans font is listed before zh-Hant font.
1107 {"U+3402 U+E0100", "zh-Hant", kZH_HantFont},
1108 {"U+3402 U+E0100", "zh-Hans", kZH_HansFont},
1109
1110 {"U+3402 U+E0100", "ja-Jpan,zh-Hant", kZH_HantFont},
1111 {"U+3402 U+E0100", "zh-Hant,ja-Jpan", kZH_HantFont},
1112 {"U+3402 U+E0100", "zh-Hans,zh-Hant", kZH_HansFont},
1113 {"U+3402 U+E0100", "zh-Hant,zh-Hans", kZH_HantFont},
1114 {"U+3402 U+E0100", "zh-Hans,ja-Jpan", kZH_HansFont},
1115 {"U+3402 U+E0100", "ja-Jpan,zh-Hans", kZH_HansFont},
1116
1117 {"U+3402 U+E0100", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont},
1118 {"U+3402 U+E0100", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont},
1119 {"U+3402 U+E0100", "ja-Jpan,zh-Hans,zh-Hant", kZH_HansFont},
1120 {"U+3402 U+E0100", "ja-Jpan,zh-Hant,zh-Hans", kZH_HantFont},
1121 {"U+3402 U+E0100", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont},
1122 {"U+3402 U+E0100", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont},
1123
1124 // No font supports U+4444 U+FE00 but only zh-Hans supports its base character U+4444.
1125 {"U+4444 U+FE00", "", kZH_HansFont},
1126 {"U+4444 U+FE00", "ja-Jpan", kZH_HansFont},
1127 {"U+4444 U+FE00", "zh-Hant", kZH_HansFont},
1128 {"U+4444 U+FE00", "zh-Hans", kZH_HansFont},
1129
1130 {"U+4444 U+FE00", "ja-Jpan,zh-Hant", kZH_HansFont},
1131 {"U+4444 U+FE00", "zh-Hant,ja-Jpan", kZH_HansFont},
1132 {"U+4444 U+FE00", "zh-Hans,zh-Hant", kZH_HansFont},
1133 {"U+4444 U+FE00", "zh-Hant,zh-Hans", kZH_HansFont},
1134 {"U+4444 U+FE00", "zh-Hans,ja-Jpan", kZH_HansFont},
1135 {"U+4444 U+FE00", "ja-Jpan,zh-Hans", kZH_HansFont},
1136
1137 {"U+4444 U+FE00", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont},
1138 {"U+4444 U+FE00", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont},
1139 {"U+4444 U+FE00", "ja-Jpan,zh-Hans,zh-Hant", kZH_HansFont},
1140 {"U+4444 U+FE00", "ja-Jpan,zh-Hant,zh-Hans", kZH_HansFont},
1141 {"U+4444 U+FE00", "zh-Hant,zh-Hans,ja-Jpan", kZH_HansFont},
1142 {"U+4444 U+FE00", "zh-Hant,ja-Jpan,zh-Hans", kZH_HansFont},
1143
1144 // No font supports U+81ED U+E0100 but ja and zh-Hans support its base character U+81ED.
1145 // zh-Hans font is listed before ja font.
1146 {"U+81ED U+E0100", "", kZH_HansFont},
1147 {"U+81ED U+E0100", "ja-Jpan", kJAFont},
1148 {"U+81ED U+E0100", "zh-Hant", kZH_HansFont},
1149 {"U+81ED U+E0100", "zh-Hans", kZH_HansFont},
1150
1151 {"U+81ED U+E0100", "ja-Jpan,zh-Hant", kJAFont},
1152 {"U+81ED U+E0100", "zh-Hant,ja-Jpan", kJAFont},
1153 {"U+81ED U+E0100", "zh-Hans,zh-Hant", kZH_HansFont},
1154 {"U+81ED U+E0100", "zh-Hant,zh-Hans", kZH_HansFont},
1155 {"U+81ED U+E0100", "zh-Hans,ja-Jpan", kZH_HansFont},
1156 {"U+81ED U+E0100", "ja-Jpan,zh-Hans", kJAFont},
1157
1158 {"U+81ED U+E0100", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont},
1159 {"U+81ED U+E0100", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont},
1160 {"U+81ED U+E0100", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1161 {"U+81ED U+E0100", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1162 {"U+81ED U+E0100", "zh-Hant,zh-Hans,ja-Jpan", kZH_HansFont},
1163 {"U+81ED U+E0100", "zh-Hant,ja-Jpan,zh-Hans", kJAFont},
1164
1165 // No font supports U+9AA8 U+E0100 but all zh-Hans zh-hant ja fonts support its base
1166 // character U+9AA8.
1167 // zh-Hans font is listed before ja and zh-Hant fonts.
1168 {"U+9AA8 U+E0100", "", kZH_HansFont},
1169 {"U+9AA8 U+E0100", "ja-Jpan", kJAFont},
1170 {"U+9AA8 U+E0100", "zh-Hans", kZH_HansFont},
1171 {"U+9AA8 U+E0100", "zh-Hant", kZH_HantFont},
1172
1173 {"U+9AA8 U+E0100", "ja-Jpan,zh-Hant", kJAFont},
1174 {"U+9AA8 U+E0100", "zh-Hant,ja-Jpan", kZH_HantFont},
1175 {"U+9AA8 U+E0100", "zh-Hans,zh-Hant", kZH_HansFont},
1176 {"U+9AA8 U+E0100", "zh-Hant,zh-Hans", kZH_HantFont},
1177 {"U+9AA8 U+E0100", "zh-Hans,ja-Jpan", kZH_HansFont},
1178 {"U+9AA8 U+E0100", "ja-Jpan,zh-Hans", kJAFont},
1179
1180 {"U+9AA8 U+E0100", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont},
1181 {"U+9AA8 U+E0100", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont},
1182 {"U+9AA8 U+E0100", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1183 {"U+9AA8 U+E0100", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1184 {"U+9AA8 U+E0100", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont},
1185 {"U+9AA8 U+E0100", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont},
1186
1187 // All zh-Hans,zh-Hant,ja fonts support U+35A8 U+E0100 and its base character U+35A8.
1188 // zh-Hans font is listed before ja and zh-Hant fonts.
1189 {"U+35A8", "", kZH_HansFont},
1190 {"U+35A8", "ja-Jpan", kJAFont},
1191 {"U+35A8", "zh-Hans", kZH_HansFont},
1192 {"U+35A8", "zh-Hant", kZH_HantFont},
1193
1194 {"U+35A8", "ja-Jpan,zh-Hant", kJAFont},
1195 {"U+35A8", "zh-Hant,ja-Jpan", kZH_HantFont},
1196 {"U+35A8", "zh-Hans,zh-Hant", kZH_HansFont},
1197 {"U+35A8", "zh-Hant,zh-Hans", kZH_HantFont},
1198 {"U+35A8", "zh-Hans,ja-Jpan", kZH_HansFont},
1199 {"U+35A8", "ja-Jpan,zh-Hans", kJAFont},
1200
1201 {"U+35A8", "zh-Hans,ja-Jpan,zh-Hant", kZH_HansFont},
1202 {"U+35A8", "zh-Hans,zh-Hant,ja-Jpan", kZH_HansFont},
1203 {"U+35A8", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1204 {"U+35A8", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1205 {"U+35A8", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont},
1206 {"U+35A8", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont},
1207
1208 // All zh-Hans,zh-Hant,ja fonts support U+35B6 U+E0100, but zh-Hant and ja fonts support
1209 // its
1210 // base character U+35B6.
1211 // ja font is listed before zh-Hant font.
1212 {"U+35B6", "", kJAFont},
1213 {"U+35B6", "ja-Jpan", kJAFont},
1214 {"U+35B6", "zh-Hant", kZH_HantFont},
1215 {"U+35B6", "zh-Hans", kJAFont},
1216
1217 {"U+35B6", "ja-Jpan,zh-Hant", kJAFont},
1218 {"U+35B6", "zh-Hant,ja-Jpan", kZH_HantFont},
1219 {"U+35B6", "zh-Hans,zh-Hant", kZH_HantFont},
1220 {"U+35B6", "zh-Hant,zh-Hans", kZH_HantFont},
1221 {"U+35B6", "zh-Hans,ja-Jpan", kJAFont},
1222 {"U+35B6", "ja-Jpan,zh-Hans", kJAFont},
1223
1224 {"U+35B6", "zh-Hans,ja-Jpan,zh-Hant", kJAFont},
1225 {"U+35B6", "zh-Hans,zh-Hant,ja-Jpan", kZH_HantFont},
1226 {"U+35B6", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1227 {"U+35B6", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1228 {"U+35B6", "zh-Hant,zh-Hans,ja-Jpan", kZH_HantFont},
1229 {"U+35B6", "zh-Hant,ja-Jpan,zh-Hans", kZH_HantFont},
1230
1231 // All zh-Hans,zh-Hant,ja fonts support U+35C5 U+E0100, but only ja font supports its
1232 // base
1233 // character U+35C5.
1234 {"U+35C5", "", kJAFont},
1235 {"U+35C5", "ja-Jpan", kJAFont},
1236 {"U+35C5", "zh-Hant", kJAFont},
1237 {"U+35C5", "zh-Hans", kJAFont},
1238
1239 {"U+35C5", "ja-Jpan,zh-Hant", kJAFont},
1240 {"U+35C5", "zh-Hant,ja-Jpan", kJAFont},
1241 {"U+35C5", "zh-Hans,zh-Hant", kJAFont},
1242 {"U+35C5", "zh-Hant,zh-Hans", kJAFont},
1243 {"U+35C5", "zh-Hans,ja-Jpan", kJAFont},
1244 {"U+35C5", "ja-Jpan,zh-Hans", kJAFont},
1245
1246 {"U+35C5", "zh-Hans,ja-Jpan,zh-Hant", kJAFont},
1247 {"U+35C5", "zh-Hans,zh-Hant,ja-Jpan", kJAFont},
1248 {"U+35C5", "ja-Jpan,zh-Hans,zh-Hant", kJAFont},
1249 {"U+35C5", "ja-Jpan,zh-Hant,zh-Hans", kJAFont},
1250 {"U+35C5", "zh-Hant,zh-Hans,ja-Jpan", kJAFont},
1251 {"U+35C5", "zh-Hant,ja-Jpan,zh-Hans", kJAFont},
1252
1253 // None of ja-Jpan, zh-Hant, zh-Hans font supports U+1F469. Emoji font supports it.
1254 {"U+1F469", "", kEmojiFont},
1255 {"U+1F469", "ja-Jpan", kEmojiFont},
1256 {"U+1F469", "zh-Hant", kEmojiFont},
1257 {"U+1F469", "zh-Hans", kEmojiFont},
1258
1259 {"U+1F469", "ja-Jpan,zh-Hant", kEmojiFont},
1260 {"U+1F469", "zh-Hant,ja-Jpan", kEmojiFont},
1261 {"U+1F469", "zh-Hans,zh-Hant", kEmojiFont},
1262 {"U+1F469", "zh-Hant,zh-Hans", kEmojiFont},
1263 {"U+1F469", "zh-Hans,ja-Jpan", kEmojiFont},
1264 {"U+1F469", "ja-Jpan,zh-Hans", kEmojiFont},
1265
1266 {"U+1F469", "zh-Hans,ja-Jpan,zh-Hant", kEmojiFont},
1267 {"U+1F469", "zh-Hans,zh-Hant,ja-Jpan", kEmojiFont},
1268 {"U+1F469", "ja-Jpan,zh-Hans,zh-Hant", kEmojiFont},
1269 {"U+1F469", "ja-Jpan,zh-Hant,zh-Hans", kEmojiFont},
1270 {"U+1F469", "zh-Hant,zh-Hans,ja-Jpan", kEmojiFont},
1271 {"U+1F469", "zh-Hant,ja-Jpan,zh-Hans", kEmojiFont},
1272 };
1273
1274 auto collection = buildFontCollectionFromXml(kItemizeFontXml);
1275
1276 for (const auto& testCase : testCases) {
1277 SCOPED_TRACE("Test for \"" + testCase.testString + "\" with locales " +
1278 testCase.requestedLocales);
1279
1280 auto runs = itemize(collection, testCase.testString.c_str(), testCase.requestedLocales);
1281 ASSERT_EQ(1U, runs.size());
1282 EXPECT_EQ(testCase.expectedFont, getFontName(runs[0]));
1283 }
1284 }
1285
TEST(FontCollectionItemizeTest,itemize_emojiSelection_withFE0E)1286 TEST(FontCollectionItemizeTest, itemize_emojiSelection_withFE0E) {
1287 auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
1288
1289 // U+00A9 is a text default emoji which is only available in TextEmojiFont.ttf.
1290 // TextEmojiFont.ttf should be selected.
1291 auto runs = itemize(collection, "U+00A9 U+FE0E");
1292 ASSERT_EQ(1U, runs.size());
1293 EXPECT_EQ(0, runs[0].start);
1294 EXPECT_EQ(2, runs[0].end);
1295 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1296
1297 // U+00A9 is a text default emoji which is only available in ColorEmojiFont.ttf.
1298 // ColorEmojiFont.ttf should be selected.
1299 runs = itemize(collection, "U+00AE U+FE0E");
1300 ASSERT_EQ(1U, runs.size());
1301 EXPECT_EQ(0, runs[0].start);
1302 EXPECT_EQ(2, runs[0].end);
1303 // Text emoji is specified but it is not available. Use color emoji instead.
1304 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1305
1306 // U+203C is a text default emoji which is available in both TextEmojiFont.ttf and
1307 // ColorEmojiFont.ttf. TextEmojiFont.ttf should be selected.
1308 runs = itemize(collection, "U+203C U+FE0E");
1309 ASSERT_EQ(1U, runs.size());
1310 EXPECT_EQ(0, runs[0].start);
1311 EXPECT_EQ(2, runs[0].end);
1312 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1313
1314 // U+2049 is a text default emoji which is not available either TextEmojiFont.ttf or
1315 // ColorEmojiFont.ttf. No font should be selected.
1316 runs = itemize(collection, "U+2049 U+FE0E");
1317 ASSERT_EQ(1U, runs.size());
1318 EXPECT_EQ(0, runs[0].start);
1319 EXPECT_EQ(2, runs[0].end);
1320 EXPECT_EQ(kNoGlyphFont, getFontName(runs[0]));
1321
1322 // U+231A is a emoji default emoji which is available only in TextEmojifFont.
1323 // TextEmojiFont.ttf sohuld be selected.
1324 runs = itemize(collection, "U+231A U+FE0E");
1325 ASSERT_EQ(1U, runs.size());
1326 EXPECT_EQ(0, runs[0].start);
1327 EXPECT_EQ(2, runs[0].end);
1328 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1329
1330 // U+231B is a emoji default emoji which is available only in ColorEmojiFont.ttf.
1331 // ColorEmojiFont.ttf should be selected.
1332 runs = itemize(collection, "U+231B U+FE0E");
1333 ASSERT_EQ(1U, runs.size());
1334 EXPECT_EQ(0, runs[0].start);
1335 EXPECT_EQ(2, runs[0].end);
1336 // Text emoji is specified but it is not available. Use color emoji instead.
1337 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1338
1339 // U+23E9 is a emoji default emoji which is available in both TextEmojiFont.ttf and
1340 // ColorEmojiFont.ttf. TextEmojiFont.ttf should be selected even if U+23E9 is emoji default
1341 // emoji since U+FE0E is appended.
1342 runs = itemize(collection, "U+23E9 U+FE0E");
1343 ASSERT_EQ(1U, runs.size());
1344 EXPECT_EQ(0, runs[0].start);
1345 EXPECT_EQ(2, runs[0].end);
1346 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1347
1348 // U+23EA is a emoji default emoji but which is not available in either TextEmojiFont.ttf or
1349 // ColorEmojiFont.ttf. No font should be selected.
1350 runs = itemize(collection, "U+23EA U+FE0E");
1351 ASSERT_EQ(1U, runs.size());
1352 EXPECT_EQ(0, runs[0].start);
1353 EXPECT_EQ(2, runs[0].end);
1354 EXPECT_EQ(kNoGlyphFont, getFontName(runs[0]));
1355
1356 // U+26FA U+FE0E is specified but ColorTextMixedEmojiFont has a variation sequence U+26F9 U+FE0F
1357 // in its cmap, so ColorTextMixedEmojiFont should be selected instaed of ColorEmojiFont.
1358 runs = itemize(collection, "U+26FA U+FE0E");
1359 ASSERT_EQ(1U, runs.size());
1360 EXPECT_EQ(0, runs[0].start);
1361 EXPECT_EQ(2, runs[0].end);
1362 EXPECT_EQ(kMixedEmojiFont, getFontName(runs[0]));
1363 }
1364
TEST(FontCollectionItemizeTest,itemize_emojiSelection_withFE0F)1365 TEST(FontCollectionItemizeTest, itemize_emojiSelection_withFE0F) {
1366 auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
1367
1368 // U+00A9 is a text default emoji which is available only in TextEmojiFont.ttf.
1369 // TextEmojiFont.ttf shoudl be selected.
1370 auto runs = itemize(collection, "U+00A9 U+FE0F");
1371 ASSERT_EQ(1U, runs.size());
1372 EXPECT_EQ(0, runs[0].start);
1373 EXPECT_EQ(2, runs[0].end);
1374 // Color emoji is specified but it is not available. Use text representaion instead.
1375 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1376
1377 // U+00AE is a text default emoji which is available only in ColorEmojiFont.ttf.
1378 // ColorEmojiFont.ttf should be selected.
1379 runs = itemize(collection, "U+00AE U+FE0F");
1380 ASSERT_EQ(1U, runs.size());
1381 EXPECT_EQ(0, runs[0].start);
1382 EXPECT_EQ(2, runs[0].end);
1383 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1384
1385 // U+203C is a text default emoji which is available in both TextEmojiFont.ttf and
1386 // ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected even if U+203C is a text default
1387 // emoji since U+FF0F is appended.
1388 runs = itemize(collection, "U+203C U+FE0F");
1389 ASSERT_EQ(1U, runs.size());
1390 EXPECT_EQ(0, runs[0].start);
1391 EXPECT_EQ(2, runs[0].end);
1392 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1393
1394 // U+2049 is a text default emoji which is not available in either TextEmojiFont.ttf or
1395 // ColorEmojiFont.ttf. No font should be selected.
1396 runs = itemize(collection, "U+2049 U+FE0F");
1397 ASSERT_EQ(1U, runs.size());
1398 EXPECT_EQ(0, runs[0].start);
1399 EXPECT_EQ(2, runs[0].end);
1400 EXPECT_EQ(kNoGlyphFont, getFontName(runs[0]));
1401
1402 // U+231A is a emoji default emoji which is available only in TextEmojiFont.ttf.
1403 // TextEmojiFont.ttf should be selected.
1404 runs = itemize(collection, "U+231A U+FE0F");
1405 ASSERT_EQ(1U, runs.size());
1406 EXPECT_EQ(0, runs[0].start);
1407 EXPECT_EQ(2, runs[0].end);
1408 // Color emoji is specified but it is not available. Use text representation instead.
1409 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1410
1411 // U+231B is a emoji default emoji which is available only in ColorEmojiFont.ttf.
1412 // ColorEmojiFont.ttf should be selected.
1413 runs = itemize(collection, "U+231B U+FE0F");
1414 ASSERT_EQ(1U, runs.size());
1415 EXPECT_EQ(0, runs[0].start);
1416 EXPECT_EQ(2, runs[0].end);
1417 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1418
1419 // U+23E9 is a emoji default emoji which is available in both TextEmojiFont.ttf and
1420 // ColorEmojiFont.ttf. ColorEmojiFont.ttf should be selected.
1421 runs = itemize(collection, "U+23E9 U+FE0F");
1422 ASSERT_EQ(1U, runs.size());
1423 EXPECT_EQ(0, runs[0].start);
1424 EXPECT_EQ(2, runs[0].end);
1425 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1426
1427 // U+23EA is a emoji default emoji which is not available in either TextEmojiFont.ttf or
1428 // ColorEmojiFont.ttf. No font should be selected.
1429 runs = itemize(collection, "U+23EA U+FE0F");
1430 ASSERT_EQ(1U, runs.size());
1431 EXPECT_EQ(0, runs[0].start);
1432 EXPECT_EQ(2, runs[0].end);
1433 EXPECT_EQ(kNoGlyphFont, getFontName(runs[0]));
1434
1435 // U+26F9 U+FE0F is specified but ColorTextMixedEmojiFont has a variation sequence U+26F9 U+FE0F
1436 // in its cmap, so ColorTextMixedEmojiFont should be selected instaed of ColorEmojiFont.
1437 runs = itemize(collection, "U+26F9 U+FE0F");
1438 ASSERT_EQ(1U, runs.size());
1439 EXPECT_EQ(0, runs[0].start);
1440 EXPECT_EQ(2, runs[0].end);
1441 EXPECT_EQ(kMixedEmojiFont, getFontName(runs[0]));
1442 }
1443
TEST(FontCollectionItemizeTest,itemize_emojiSelection_with_skinTone)1444 TEST(FontCollectionItemizeTest, itemize_emojiSelection_with_skinTone) {
1445 auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
1446
1447 // TextEmoji font is selected since it is listed before ColorEmoji font.
1448 auto runs = itemize(collection, "U+261D");
1449 ASSERT_EQ(1U, runs.size());
1450 EXPECT_EQ(0, runs[0].start);
1451 EXPECT_EQ(1, runs[0].end);
1452 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1453
1454 // If skin tone is specified, it should be colored.
1455 runs = itemize(collection, "U+261D U+1F3FD");
1456 ASSERT_EQ(1U, runs.size());
1457 EXPECT_EQ(0, runs[0].start);
1458 EXPECT_EQ(3, runs[0].end);
1459 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1460
1461 // Still color font is selected if an emoji variation selector is specified.
1462 runs = itemize(collection, "U+261D U+FE0F U+1F3FD");
1463 ASSERT_EQ(1U, runs.size());
1464 EXPECT_EQ(0, runs[0].start);
1465 EXPECT_EQ(4, runs[0].end);
1466 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1467
1468 // Text font should be selected if a text variation selector is specified and skin tone is
1469 // rendered by itself.
1470 runs = itemize(collection, "U+261D U+FE0E U+1F3FD");
1471 ASSERT_EQ(2U, runs.size());
1472 EXPECT_EQ(0, runs[0].start);
1473 EXPECT_EQ(2, runs[0].end);
1474 EXPECT_EQ(kTextEmojiFont, getFontName(runs[0]));
1475 EXPECT_EQ(2, runs[1].start);
1476 EXPECT_EQ(4, runs[1].end);
1477 EXPECT_EQ(kColorEmojiFont, getFontName(runs[1]));
1478 }
1479
TEST(FontCollectionItemizeTest,itemize_PrivateUseArea)1480 TEST(FontCollectionItemizeTest, itemize_PrivateUseArea) {
1481 auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
1482
1483 // Should not set nullptr to the result run. (Issue 26808815)
1484 auto runs = itemize(collection, "U+FEE10");
1485 ASSERT_EQ(1U, runs.size());
1486 EXPECT_EQ(0, runs[0].start);
1487 EXPECT_EQ(2, runs[0].end);
1488 EXPECT_EQ(kNoGlyphFont, getFontName(runs[0]));
1489
1490 runs = itemize(collection, "U+FEE40 U+FE4C5");
1491 ASSERT_EQ(1U, runs.size());
1492 EXPECT_EQ(0, runs[0].start);
1493 EXPECT_EQ(4, runs[0].end);
1494 EXPECT_EQ(kNoGlyphFont, getFontName(runs[0]));
1495 }
1496
TEST(FontCollectionItemizeTest,itemize_genderBalancedEmoji)1497 TEST(FontCollectionItemizeTest, itemize_genderBalancedEmoji) {
1498 auto collection = buildFontCollectionFromXml(kEmojiXmlFile);
1499
1500 auto runs = itemize(collection, "U+1F469 U+200D U+1F373");
1501 ASSERT_EQ(1U, runs.size());
1502 EXPECT_EQ(0, runs[0].start);
1503 EXPECT_EQ(5, runs[0].end);
1504 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1505
1506 runs = itemize(collection, "U+1F469 U+200D U+2695 U+FE0F");
1507 ASSERT_EQ(1U, runs.size());
1508 EXPECT_EQ(0, runs[0].start);
1509 EXPECT_EQ(5, runs[0].end);
1510 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1511
1512 runs = itemize(collection, "U+1F469 U+200D U+2695");
1513 ASSERT_EQ(1U, runs.size());
1514 EXPECT_EQ(0, runs[0].start);
1515 EXPECT_EQ(4, runs[0].end);
1516 EXPECT_EQ(kColorEmojiFont, getFontName(runs[0]));
1517 }
1518
1519 // For b/29585939
TEST(FontCollectionItemizeTest,itemizeShouldKeepOrderForVS)1520 TEST(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS) {
1521 std::shared_ptr<FontFamily> dummyFamily = buildFontFamily(kNoGlyphFont);
1522 std::shared_ptr<FontFamily> familyA = buildFontFamily(kZH_HansFont);
1523 std::shared_ptr<FontFamily> familyB = buildFontFamily(kZH_HansFont);
1524
1525 std::vector<std::shared_ptr<FontFamily>> families = {dummyFamily, familyA, familyB};
1526 std::vector<std::shared_ptr<FontFamily>> reversedFamilies = {dummyFamily, familyB, familyA};
1527
1528 std::shared_ptr<FontCollection> collection(new FontCollection(families));
1529 std::shared_ptr<FontCollection> reversedCollection(new FontCollection(reversedFamilies));
1530
1531 // Both fontA/fontB support U+35A8 but don't support U+35A8 U+E0100. The first font should be
1532 // selected.
1533 auto runs = itemize(collection, "U+35A8 U+E0100");
1534 EXPECT_EQ(familyA->getFont(0), runs[0].fakedFont.font.get());
1535
1536 runs = itemize(reversedCollection, "U+35A8 U+E0100");
1537 EXPECT_EQ(familyB->getFont(0), runs[0].fakedFont.font.get());
1538 }
1539
1540 // For b/29585939
TEST(FontCollectionItemizeTest,itemizeShouldKeepOrderForVS2)1541 TEST(FontCollectionItemizeTest, itemizeShouldKeepOrderForVS2) {
1542 std::shared_ptr<FontFamily> dummyFamily = buildFontFamily(kNoGlyphFont);
1543 std::shared_ptr<FontFamily> hasCmapFormat14Family = buildFontFamily(kHasCmapFormat14Font);
1544 std::shared_ptr<FontFamily> noCmapFormat14Family = buildFontFamily(kNoCmapFormat14Font);
1545
1546 std::vector<std::shared_ptr<FontFamily>> families = {dummyFamily, hasCmapFormat14Family,
1547 noCmapFormat14Family};
1548 std::vector<std::shared_ptr<FontFamily>> reversedFamilies = {dummyFamily, noCmapFormat14Family,
1549 hasCmapFormat14Family};
1550
1551 std::shared_ptr<FontCollection> collection(new FontCollection(families));
1552 std::shared_ptr<FontCollection> reversedCollection(new FontCollection(reversedFamilies));
1553
1554 // Both hasCmapFormat14Font/noCmapFormat14Font support U+5380 but don't support U+5380 U+E0100.
1555 // The first font should be selected.
1556 auto runs = itemize(collection, "U+5380 U+E0100");
1557 EXPECT_EQ(hasCmapFormat14Family->getFont(0), runs[0].fakedFont.font.get());
1558
1559 runs = itemize(reversedCollection, "U+5380 U+E0100");
1560 EXPECT_EQ(noCmapFormat14Family->getFont(0), runs[0].fakedFont.font.get());
1561 }
1562
TEST(FontCollectionItemizeTest,colorEmojiSelectionTest)1563 TEST(FontCollectionItemizeTest, colorEmojiSelectionTest) {
1564 auto dummyFamily = buildFontFamily(kNoGlyphFont);
1565 auto textEmojiFamily = buildFontFamily(kTextEmojiFont, "ja-JP");
1566 auto colorEmojiFamily = buildFontFamily(kColorEmojiFont, "und-Zsye");
1567
1568 std::vector<std::shared_ptr<FontFamily>> families = {dummyFamily, textEmojiFamily,
1569 colorEmojiFamily};
1570 auto collection = std::make_shared<FontCollection>(families);
1571 // Both textEmojiFamily and colorEmojiFamily supports U+203C and U+23E9.
1572 // U+203C is text default emoji, and U+23E9 is color default emoji.
1573 auto runs = itemize(collection, "U+203C", "en-US,en-Zsym");
1574 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1575 runs = itemize(collection, "U+23E9", "en-US,en-Zsym");
1576 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1577
1578 runs = itemize(collection, "U+203C", "en-US,en-Zsye");
1579 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1580 runs = itemize(collection, "U+23E9", "en-US,en-Zsye");
1581 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1582
1583 runs = itemize(collection, "U+203C", "ja-Zsym-JP");
1584 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1585 runs = itemize(collection, "U+23E9", "ja-Zsym-JP");
1586 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1587
1588 runs = itemize(collection, "U+203C", "ja-Zsye-JP");
1589 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1590 runs = itemize(collection, "U+23E9", "ja-Zsye-JP");
1591 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1592
1593 runs = itemize(collection, "U+203C", "ja-JP-u-em-text");
1594 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1595 runs = itemize(collection, "U+23E9", "ja-JP-u-em-text");
1596 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1597
1598 runs = itemize(collection, "U+203C", "ja-JP-u-em-emoji");
1599 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1600 runs = itemize(collection, "U+23E9", "ja-JP-u-em-emoji");
1601 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1602
1603 runs = itemize(collection, "U+203C", "ja-JP,und-Zsym");
1604 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1605 runs = itemize(collection, "U+23E9", "ja-JP,und-Zsym");
1606 EXPECT_EQ(textEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1607
1608 runs = itemize(collection, "U+203C", "ja-JP,und-Zsye");
1609 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1610 runs = itemize(collection, "U+23E9", "ja-JP,und-Zsye");
1611 EXPECT_EQ(colorEmojiFamily->getFont(0), runs[0].fakedFont.font.get());
1612 }
1613
TEST(FontCollectionItemizeTest,customFallbackTest)1614 TEST(FontCollectionItemizeTest, customFallbackTest) {
1615 auto firstFamily = buildFontFamily(kNoGlyphFont);
1616 auto customFallbackFamily = buildFontFamily(kAsciiFont, "", true /* isCustomFallback */);
1617 auto languageFamily = buildFontFamily(kAsciiFont, "ja-JP");
1618
1619 std::vector<std::shared_ptr<FontFamily>> families = {firstFamily, customFallbackFamily,
1620 languageFamily};
1621
1622 auto collection = std::make_shared<FontCollection>(families);
1623
1624 auto runs = itemize(collection, "'a'", "");
1625 EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
1626 runs = itemize(collection, "'a'", "en-US");
1627 EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
1628 runs = itemize(collection, "'a'", "ja-JP");
1629 EXPECT_EQ(customFallbackFamily->getFont(0), runs[0].fakedFont.font.get());
1630 }
1631
itemizeEmojiAndFontPostScriptName(const std::string & txt)1632 std::string itemizeEmojiAndFontPostScriptName(const std::string& txt) {
1633 auto firstFamily = buildFontFamily(kAsciiFont);
1634 auto OverrideEmojiFamily = buildFontFamily("OverrideEmoji.ttf", "und-Zsye");
1635 auto emojiBaseFamily = buildFontFamily("EmojiBase.ttf", "und-Zsye");
1636
1637 std::vector<std::shared_ptr<FontFamily>> families = {firstFamily, OverrideEmojiFamily,
1638 emojiBaseFamily};
1639
1640 auto collection = std::make_shared<FontCollection>(families);
1641 auto runs = itemize(collection, txt.c_str());
1642
1643 EXPECT_EQ(1u, runs.size());
1644 return FontFileParser(runs[0].fakedFont.font->baseFont()).getPostScriptName().value();
1645 }
1646
TEST(FontCollectionItemizeTest,emojiFallback)1647 TEST(FontCollectionItemizeTest, emojiFallback) {
1648 // OverrideEmojiFont supports U+1F9B0, U+E0000, U+1F3FB and U+1F9B0 U+1F3FB sequence.
1649 // Use Override font.
1650 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0"));
1651 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+E0000"));
1652 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0 U+1F3FB"));
1653 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B0 U+FE0F U+1F3FB"));
1654
1655 // OverrideEmojiFont doesn't suppot U+1F9B6 U+E0001 and U+1F3FC.
1656 EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6"));
1657 EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+E0001"));
1658 EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6 U+1F3FC"));
1659 EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B6 U+FE0F U+1F3FC"));
1660
1661 // OverrideEmojiFont support U+1F9B1, U+1F3FB but doesn't support the sequence U+1F9B1 U+1F3FB.
1662 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B1"));
1663 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F3FB"));
1664 EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B1 U+1F3FB"));
1665 EXPECT_EQ("EmojiBaseFont", itemizeEmojiAndFontPostScriptName("U+1F9B1 U+FE0F U+1F3FB"));
1666
1667 // Find the longest sequence if two sequences are supported.
1668 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F9B2 U+200D U+1F9B3"));
1669 EXPECT_EQ("EmojiBaseFont",
1670 itemizeEmojiAndFontPostScriptName("U+1F9B2 U+200D U+1F9B3 U+200D U+1F9B4"));
1671 }
1672
TEST(FontCollectionItemizeTest,emojiFlagFallback)1673 TEST(FontCollectionItemizeTest, emojiFlagFallback) {
1674 // If the OverrideEmojiFont supports U+1F1E6 U+1F1E6, use that font.
1675 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F1E6 U+1F1E6"));
1676
1677 // Even if the OverrideEmojiFont directs to .notdef (i.e. Tofu glyph) for the sequence, use it.
1678 EXPECT_EQ("OverrideEmojiFont", itemizeEmojiAndFontPostScriptName("U+1F1E6 U+1F1E7"));
1679 }
1680
1681 } // namespace minikin
1682