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