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