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