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