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