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