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