FontFamilyTest.cpp revision d3376522332e1e016e59fabb22c24025092c724d
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 <minikin/FontFamily.h> 20 21#include <cutils/log.h> 22 23#include "FontLanguageListCache.h" 24#include "ICUTestBase.h" 25#include "MinikinFontForTest.h" 26#include "MinikinInternal.h" 27 28namespace android { 29 30typedef ICUTestBase FontLanguagesTest; 31typedef ICUTestBase FontLanguageTest; 32 33static FontLanguages createFontLanguages(const std::string& input) { 34 uint32_t langId = FontLanguageListCache::getId(input); 35 return FontLanguageListCache::getById(langId); 36} 37 38static FontLanguage createFontLanguage(const std::string& input) { 39 uint32_t langId = FontLanguageListCache::getId(input); 40 return FontLanguageListCache::getById(langId)[0]; 41} 42 43TEST_F(FontLanguageTest, basicTests) { 44 FontLanguage defaultLang; 45 FontLanguage emptyLang("", 0); 46 FontLanguage english = createFontLanguage("en"); 47 FontLanguage french = createFontLanguage("fr"); 48 FontLanguage und = createFontLanguage("und"); 49 FontLanguage undZsye = createFontLanguage("und-Zsye"); 50 51 EXPECT_EQ(english, english); 52 EXPECT_EQ(french, french); 53 54 EXPECT_TRUE(defaultLang != defaultLang); 55 EXPECT_TRUE(emptyLang != emptyLang); 56 EXPECT_TRUE(defaultLang != emptyLang); 57 EXPECT_TRUE(defaultLang != und); 58 EXPECT_TRUE(emptyLang != und); 59 EXPECT_TRUE(english != defaultLang); 60 EXPECT_TRUE(english != emptyLang); 61 EXPECT_TRUE(english != french); 62 EXPECT_TRUE(english != undZsye); 63 EXPECT_TRUE(und != undZsye); 64 EXPECT_TRUE(english != und); 65 66 EXPECT_TRUE(defaultLang.isUnsupported()); 67 EXPECT_TRUE(emptyLang.isUnsupported()); 68 69 EXPECT_FALSE(english.isUnsupported()); 70 EXPECT_FALSE(french.isUnsupported()); 71 EXPECT_FALSE(und.isUnsupported()); 72 EXPECT_FALSE(undZsye.isUnsupported()); 73} 74 75TEST_F(FontLanguageTest, getStringTest) { 76 EXPECT_EQ("en-Latn", createFontLanguage("en").getString()); 77 EXPECT_EQ("en-Latn", createFontLanguage("en-Latn").getString()); 78 79 // Capitalized language code or lowercased script should be normalized. 80 EXPECT_EQ("en-Latn", createFontLanguage("EN-LATN").getString()); 81 EXPECT_EQ("en-Latn", createFontLanguage("EN-latn").getString()); 82 EXPECT_EQ("en-Latn", createFontLanguage("en-latn").getString()); 83 84 // Invalid script should be kept. 85 EXPECT_EQ("en-Xyzt", createFontLanguage("en-xyzt").getString()); 86 87 EXPECT_EQ("en-Latn", createFontLanguage("en-Latn-US").getString()); 88 EXPECT_EQ("ja-Jpan", createFontLanguage("ja").getString()); 89 EXPECT_EQ("und", createFontLanguage("und").getString()); 90 EXPECT_EQ("und", createFontLanguage("UND").getString()); 91 EXPECT_EQ("und", createFontLanguage("Und").getString()); 92 EXPECT_EQ("und-Zsye", createFontLanguage("und-Zsye").getString()); 93 EXPECT_EQ("und-Zsye", createFontLanguage("Und-ZSYE").getString()); 94 EXPECT_EQ("und-Zsye", createFontLanguage("Und-zsye").getString()); 95 96 EXPECT_EQ("de-Latn", createFontLanguage("de-1901").getString()); 97 98 // This is not a necessary desired behavior, just known behavior. 99 EXPECT_EQ("en-Latn", createFontLanguage("und-Abcdefgh").getString()); 100} 101 102TEST_F(FontLanguageTest, ScriptEqualTest) { 103 EXPECT_TRUE(createFontLanguage("en").isEqualScript(createFontLanguage("en"))); 104 EXPECT_TRUE(createFontLanguage("en-Latn").isEqualScript(createFontLanguage("en"))); 105 EXPECT_TRUE(createFontLanguage("jp-Latn").isEqualScript(createFontLanguage("en-Latn"))); 106 EXPECT_TRUE(createFontLanguage("en-Jpan").isEqualScript(createFontLanguage("en-Jpan"))); 107 108 EXPECT_FALSE(createFontLanguage("en-Jpan").isEqualScript(createFontLanguage("en-Hira"))); 109 EXPECT_FALSE(createFontLanguage("en-Jpan").isEqualScript(createFontLanguage("en-Hani"))); 110} 111 112TEST_F(FontLanguageTest, ScriptMatchTest) { 113 const bool SUPPORTED = true; 114 const bool NOT_SUPPORTED = false; 115 116 struct TestCase { 117 const std::string baseScript; 118 const std::string requestedScript; 119 bool isSupported; 120 } testCases[] = { 121 // Same scripts 122 { "en-Latn", "Latn", SUPPORTED }, 123 { "ja-Jpan", "Jpan", SUPPORTED }, 124 { "ja-Hira", "Hira", SUPPORTED }, 125 { "ja-Kana", "Kana", SUPPORTED }, 126 { "ja-Hrkt", "Hrkt", SUPPORTED }, 127 { "zh-Hans", "Hans", SUPPORTED }, 128 { "zh-Hant", "Hant", SUPPORTED }, 129 { "zh-Hani", "Hani", SUPPORTED }, 130 { "ko-Kore", "Kore", SUPPORTED }, 131 { "ko-Hang", "Hang", SUPPORTED }, 132 133 // Japanese supports Hiragana, Katakanara, etc. 134 { "ja-Jpan", "Hira", SUPPORTED }, 135 { "ja-Jpan", "Kana", SUPPORTED }, 136 { "ja-Jpan", "Hrkt", SUPPORTED }, 137 { "ja-Hrkt", "Hira", SUPPORTED }, 138 { "ja-Hrkt", "Kana", SUPPORTED }, 139 140 // Chinese supports Han. 141 { "zh-Hans", "Hani", SUPPORTED }, 142 { "zh-Hant", "Hani", SUPPORTED }, 143 144 // Korean supports Hangul. 145 { "ko-Kore", "Hang", SUPPORTED }, 146 147 // Different scripts 148 { "ja-Jpan", "Latn", NOT_SUPPORTED }, 149 { "en-Latn", "Jpan", NOT_SUPPORTED }, 150 { "ja-Jpan", "Hant", NOT_SUPPORTED }, 151 { "zh-Hant", "Jpan", NOT_SUPPORTED }, 152 { "ja-Jpan", "Hans", NOT_SUPPORTED }, 153 { "zh-Hans", "Jpan", NOT_SUPPORTED }, 154 { "ja-Jpan", "Kore", NOT_SUPPORTED }, 155 { "ko-Kore", "Jpan", NOT_SUPPORTED }, 156 { "zh-Hans", "Hant", NOT_SUPPORTED }, 157 { "zh-Hant", "Hans", NOT_SUPPORTED }, 158 { "zh-Hans", "Kore", NOT_SUPPORTED }, 159 { "ko-Kore", "Hans", NOT_SUPPORTED }, 160 { "zh-Hant", "Kore", NOT_SUPPORTED }, 161 { "ko-Kore", "Hant", NOT_SUPPORTED }, 162 163 // Hiragana doesn't support Japanese, etc. 164 { "ja-Hira", "Jpan", NOT_SUPPORTED }, 165 { "ja-Kana", "Jpan", NOT_SUPPORTED }, 166 { "ja-Hrkt", "Jpan", NOT_SUPPORTED }, 167 { "ja-Hani", "Jpan", NOT_SUPPORTED }, 168 { "ja-Hira", "Hrkt", NOT_SUPPORTED }, 169 { "ja-Kana", "Hrkt", NOT_SUPPORTED }, 170 { "ja-Hani", "Hrkt", NOT_SUPPORTED }, 171 { "ja-Hani", "Hira", NOT_SUPPORTED }, 172 { "ja-Hani", "Kana", NOT_SUPPORTED }, 173 174 // Kanji doesn't support Chinese, etc. 175 { "zh-Hani", "Hant", NOT_SUPPORTED }, 176 { "zh-Hani", "Hans", NOT_SUPPORTED }, 177 178 // Hangul doesn't support Korean, etc. 179 { "ko-Hang", "Kore", NOT_SUPPORTED }, 180 { "ko-Hani", "Kore", NOT_SUPPORTED }, 181 { "ko-Hani", "Hang", NOT_SUPPORTED }, 182 { "ko-Hang", "Hani", NOT_SUPPORTED }, 183 }; 184 185 for (auto testCase : testCases) { 186 hb_script_t script = hb_script_from_iso15924_tag( 187 HB_TAG(testCase.requestedScript[0], testCase.requestedScript[1], 188 testCase.requestedScript[2], testCase.requestedScript[3])); 189 if (testCase.isSupported) { 190 EXPECT_TRUE( 191 createFontLanguage(testCase.baseScript).supportsHbScript(script)) 192 << testCase.baseScript << " should support " << testCase.requestedScript; 193 } else { 194 EXPECT_FALSE( 195 createFontLanguage(testCase.baseScript).supportsHbScript(script)) 196 << testCase.baseScript << " shouldn't support " << testCase.requestedScript; 197 } 198 } 199} 200 201TEST_F(FontLanguagesTest, basicTests) { 202 FontLanguages emptyLangs; 203 EXPECT_EQ(0u, emptyLangs.size()); 204 205 FontLanguage english = createFontLanguage("en"); 206 FontLanguages singletonLangs = createFontLanguages("en"); 207 EXPECT_EQ(1u, singletonLangs.size()); 208 EXPECT_EQ(english, singletonLangs[0]); 209 210 FontLanguage french = createFontLanguage("fr"); 211 FontLanguages twoLangs = createFontLanguages("en,fr"); 212 EXPECT_EQ(2u, twoLangs.size()); 213 EXPECT_EQ(english, twoLangs[0]); 214 EXPECT_EQ(french, twoLangs[1]); 215} 216 217TEST_F(FontLanguagesTest, unsupportedLanguageTests) { 218 FontLanguage unsupportedLang = createFontLanguage("abcd"); 219 ASSERT_TRUE(unsupportedLang.isUnsupported()); 220 221 FontLanguages oneUnsupported = createFontLanguages("abcd-example"); 222 EXPECT_EQ(1u, oneUnsupported.size()); 223 EXPECT_TRUE(oneUnsupported[0].isUnsupported()); 224 225 FontLanguages twoUnsupporteds = createFontLanguages("abcd-example,abcd-example"); 226 EXPECT_EQ(1u, twoUnsupporteds.size()); 227 EXPECT_TRUE(twoUnsupporteds[0].isUnsupported()); 228 229 FontLanguage english = createFontLanguage("en"); 230 FontLanguages firstUnsupported = createFontLanguages("abcd-example,en"); 231 EXPECT_EQ(1u, firstUnsupported.size()); 232 EXPECT_EQ(english, firstUnsupported[0]); 233 234 FontLanguages lastUnsupported = createFontLanguages("en,abcd-example"); 235 EXPECT_EQ(1u, lastUnsupported.size()); 236 EXPECT_EQ(english, lastUnsupported[0]); 237} 238 239TEST_F(FontLanguagesTest, repeatedLanguageTests) { 240 FontLanguage english = createFontLanguage("en"); 241 FontLanguage french = createFontLanguage("fr"); 242 FontLanguage englishInLatn = createFontLanguage("en-Latn"); 243 ASSERT_TRUE(english == englishInLatn); 244 245 FontLanguages langs = createFontLanguages("en,en-Latn"); 246 EXPECT_EQ(1u, langs.size()); 247 EXPECT_EQ(english, langs[0]); 248 249 // Country codes are ignored. 250 FontLanguages fr = createFontLanguages("fr,fr-CA,fr-FR"); 251 EXPECT_EQ(1u, fr.size()); 252 EXPECT_EQ(french, fr[0]); 253 254 // The order should be kept. 255 langs = createFontLanguages("en,fr,en-Latn"); 256 EXPECT_EQ(2u, langs.size()); 257 EXPECT_EQ(english, langs[0]); 258 EXPECT_EQ(french, langs[1]); 259} 260 261TEST_F(FontLanguagesTest, undEmojiTests) { 262 FontLanguage emoji = createFontLanguage("und-Zsye"); 263 EXPECT_TRUE(emoji.hasEmojiFlag()); 264 265 FontLanguage und = createFontLanguage("und"); 266 EXPECT_FALSE(und.hasEmojiFlag()); 267 EXPECT_FALSE(emoji == und); 268 269 FontLanguage undExample = createFontLanguage("und-example"); 270 EXPECT_FALSE(undExample.hasEmojiFlag()); 271 EXPECT_FALSE(emoji == undExample); 272} 273 274TEST_F(FontLanguagesTest, registerLanguageListTest) { 275 EXPECT_EQ(0UL, FontStyle::registerLanguageList("")); 276 EXPECT_NE(0UL, FontStyle::registerLanguageList("en")); 277 EXPECT_NE(0UL, FontStyle::registerLanguageList("jp")); 278 EXPECT_NE(0UL, FontStyle::registerLanguageList("en,zh-Hans")); 279 280 EXPECT_EQ(FontStyle::registerLanguageList("en"), FontStyle::registerLanguageList("en")); 281 EXPECT_NE(FontStyle::registerLanguageList("en"), FontStyle::registerLanguageList("jp")); 282 283 EXPECT_EQ(FontStyle::registerLanguageList("en,zh-Hans"), 284 FontStyle::registerLanguageList("en,zh-Hans")); 285 EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), 286 FontStyle::registerLanguageList("zh-Hans,en")); 287 EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), 288 FontStyle::registerLanguageList("jp")); 289 EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), 290 FontStyle::registerLanguageList("en")); 291 EXPECT_NE(FontStyle::registerLanguageList("en,zh-Hans"), 292 FontStyle::registerLanguageList("en,zh-Hant")); 293} 294 295// The test font has following glyphs. 296// U+82A6 297// U+82A6 U+FE00 (VS1) 298// U+82A6 U+E0100 (VS17) 299// U+82A6 U+E0101 (VS18) 300// U+82A6 U+E0102 (VS19) 301// U+845B 302// U+845B U+FE00 (VS2) 303// U+845B U+E0101 (VS18) 304// U+845B U+E0102 (VS19) 305// U+845B U+E0103 (VS20) 306// U+537F 307// U+717D U+FE02 (VS3) 308// U+717D U+E0102 (VS19) 309// U+717D U+E0103 (VS20) 310const char kVsTestFont[] = kTestFontDir "VarioationSelectorTest-Regular.ttf"; 311 312class FontFamilyTest : public ICUTestBase { 313public: 314 virtual void SetUp() override { 315 ICUTestBase::SetUp(); 316 if (access(kVsTestFont, R_OK) != 0) { 317 FAIL() << "Unable to read " << kVsTestFont << ". " 318 << "Please prepare the test data directory. " 319 << "For more details, please see how_to_run.txt."; 320 } 321 } 322}; 323 324// Asserts that the font family has glyphs for and only for specified codepoint 325// and variationSelector pairs. 326void expectVSGlyphs(FontFamily* family, uint32_t codepoint, const std::set<uint32_t>& vs) { 327 for (uint32_t i = 0xFE00; i <= 0xE01EF; ++i) { 328 // Move to variation selectors supplements after variation selectors. 329 if (i == 0xFF00) { 330 i = 0xE0100; 331 } 332 if (vs.find(i) == vs.end()) { 333 EXPECT_FALSE(family->hasVariationSelector(codepoint, i)) 334 << "Glyph for U+" << std::hex << codepoint << " U+" << i; 335 } else { 336 EXPECT_TRUE(family->hasVariationSelector(codepoint, i)) 337 << "Glyph for U+" << std::hex << codepoint << " U+" << i; 338 } 339 340 } 341} 342 343TEST_F(FontFamilyTest, hasVariationSelectorTest) { 344 MinikinFontForTest minikinFont(kVsTestFont); 345 FontFamily family; 346 family.addFont(&minikinFont); 347 348 AutoMutex _l(gMinikinLock); 349 350 const uint32_t kVS1 = 0xFE00; 351 const uint32_t kVS2 = 0xFE01; 352 const uint32_t kVS3 = 0xFE02; 353 const uint32_t kVS17 = 0xE0100; 354 const uint32_t kVS18 = 0xE0101; 355 const uint32_t kVS19 = 0xE0102; 356 const uint32_t kVS20 = 0xE0103; 357 358 const uint32_t kSupportedChar1 = 0x82A6; 359 EXPECT_TRUE(family.getCoverage()->get(kSupportedChar1)); 360 expectVSGlyphs(&family, kSupportedChar1, std::set<uint32_t>({kVS1, kVS17, kVS18, kVS19})); 361 362 const uint32_t kSupportedChar2 = 0x845B; 363 EXPECT_TRUE(family.getCoverage()->get(kSupportedChar2)); 364 expectVSGlyphs(&family, kSupportedChar2, std::set<uint32_t>({kVS2, kVS18, kVS19, kVS20})); 365 366 const uint32_t kNoVsSupportedChar = 0x537F; 367 EXPECT_TRUE(family.getCoverage()->get(kNoVsSupportedChar)); 368 expectVSGlyphs(&family, kNoVsSupportedChar, std::set<uint32_t>()); 369 370 const uint32_t kVsOnlySupportedChar = 0x717D; 371 EXPECT_FALSE(family.getCoverage()->get(kVsOnlySupportedChar)); 372 expectVSGlyphs(&family, kVsOnlySupportedChar, std::set<uint32_t>({kVS3, kVS19, kVS20})); 373 374 const uint32_t kNotSupportedChar = 0x845C; 375 EXPECT_FALSE(family.getCoverage()->get(kNotSupportedChar)); 376 expectVSGlyphs(&family, kNotSupportedChar, std::set<uint32_t>()); 377} 378 379TEST_F(FontFamilyTest, hasVariationSelectorWorksAfterpurgeHbFontCache) { 380 MinikinFontForTest minikinFont(kVsTestFont); 381 FontFamily family; 382 family.addFont(&minikinFont); 383 384 const uint32_t kVS1 = 0xFE00; 385 const uint32_t kSupportedChar1 = 0x82A6; 386 387 AutoMutex _l(gMinikinLock); 388 EXPECT_TRUE(family.hasVariationSelector(kSupportedChar1, kVS1)); 389 390 family.purgeHbFontCache(); 391 EXPECT_TRUE(family.hasVariationSelector(kSupportedChar1, kVS1)); 392} 393} // namespace android 394