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