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