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