Support multiple locales for font language settings.
am: dbcbe1f
* commit 'dbcbe1f426b17242f2c548fb3df5e2b6a659ac50':
Support multiple locales for font language settings.
Change-Id: Iad60bf1c01f309e70c3b1ad22e28b22afe44b33f
This commit is contained in:
@@ -177,9 +177,15 @@ uint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs, FontFamily*
|
||||
}
|
||||
|
||||
if (vs == 0xFE0F || vs == 0xFE0E) {
|
||||
// TODO use all language in the list.
|
||||
const FontLanguage lang = FontLanguageListCache::getById(fontFamily->langId())[0];
|
||||
const bool hasEmojiFlag = lang.hasEmojiFlag();
|
||||
const FontLanguages& langs = FontLanguageListCache::getById(fontFamily->langId());
|
||||
bool hasEmojiFlag = false;
|
||||
for (size_t i = 0; i < langs.size(); ++i) {
|
||||
if (langs[i].hasEmojiFlag()) {
|
||||
hasEmojiFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vs == 0xFE0F) {
|
||||
return hasEmojiFlag ? 2 : 1;
|
||||
} else { // vs == 0xFE0E
|
||||
@@ -208,13 +214,12 @@ uint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs, FontFamily*
|
||||
uint32_t FontCollection::calcLanguageMatchingScore(
|
||||
uint32_t userLangListId, const FontFamily& fontFamily) {
|
||||
const FontLanguages& langList = FontLanguageListCache::getById(userLangListId);
|
||||
// TODO use all language in the list.
|
||||
FontLanguage fontLanguage = FontLanguageListCache::getById(fontFamily.langId())[0];
|
||||
const FontLanguages& fontLanguages = FontLanguageListCache::getById(fontFamily.langId());
|
||||
|
||||
const size_t maxCompareNum = std::min(langList.size(), FONT_LANGUAGES_LIMIT);
|
||||
uint32_t score = fontLanguage.getScoreFor(langList[0]); // maxCompareNum can't be zero.
|
||||
for (size_t i = 1; i < maxCompareNum; ++i) {
|
||||
score = score * 3u + fontLanguage.getScoreFor(langList[i]);
|
||||
uint32_t score = 0;
|
||||
for (size_t i = 0; i < maxCompareNum; ++i) {
|
||||
score = score * 3u + langList[i].calcScoreFor(fontLanguages);
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
@@ -126,24 +126,59 @@ bool FontLanguage::isEqualScript(const FontLanguage& other) const {
|
||||
return other.mScript == mScript;
|
||||
}
|
||||
|
||||
bool FontLanguage::supportsScript(uint8_t requestedBits) const {
|
||||
return requestedBits != 0 && (mSubScriptBits & requestedBits) == requestedBits;
|
||||
// static
|
||||
bool FontLanguage::supportsScript(uint8_t providedBits, uint8_t requestedBits) {
|
||||
return requestedBits != 0 && (providedBits & requestedBits) == requestedBits;
|
||||
}
|
||||
|
||||
bool FontLanguage::supportsHbScript(hb_script_t script) const {
|
||||
static_assert(SCRIPT_TAG('J', 'p', 'a', 'n') == HB_TAG('J', 'p', 'a', 'n'),
|
||||
"The Minikin script and HarfBuzz hb_script_t have different encodings.");
|
||||
if (script == mScript) return true;
|
||||
return supportsScript(scriptToSubScriptBits(script));
|
||||
return supportsScript(mSubScriptBits, scriptToSubScriptBits(script));
|
||||
}
|
||||
|
||||
int FontLanguage::getScoreFor(const FontLanguage other) const {
|
||||
if (isUnsupported() || other.isUnsupported()) {
|
||||
return 0;
|
||||
} else if (isEqualScript(other) || supportsScript(other.mSubScriptBits)) {
|
||||
return mLanguage == other.mLanguage ? 2 : 1;
|
||||
} else {
|
||||
return 0;
|
||||
int FontLanguage::calcScoreFor(const FontLanguages& supported) const {
|
||||
int score = 0;
|
||||
for (size_t i = 0; i < supported.size(); ++i) {
|
||||
if (isEqualScript(supported[i]) ||
|
||||
supportsScript(supported[i].mSubScriptBits, mSubScriptBits)) {
|
||||
if (mLanguage == supported[i].mLanguage) {
|
||||
return 2;
|
||||
} else {
|
||||
score = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (score == 1) {
|
||||
return score;
|
||||
}
|
||||
|
||||
if (supportsScript(supported.getUnionOfSubScriptBits(), mSubScriptBits)) {
|
||||
// Gives score of 2 only if the language matches all of the font languages except for the
|
||||
// exact match case handled above.
|
||||
return (mLanguage == supported[0].mLanguage && supported.isAllTheSameLanguage()) ? 2 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FontLanguages::FontLanguages(std::vector<FontLanguage>&& languages)
|
||||
: mLanguages(std::move(languages)) {
|
||||
if (mLanguages.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FontLanguage& lang = mLanguages[0];
|
||||
|
||||
mIsAllTheSameLanguage = true;
|
||||
mUnionOfSubScriptBits = lang.mSubScriptBits;
|
||||
for (size_t i = 1; i < mLanguages.size(); ++i) {
|
||||
mUnionOfSubScriptBits |= mLanguages[i].mSubScriptBits;
|
||||
if (mIsAllTheSameLanguage && lang.mLanguage != mLanguages[i].mLanguage) {
|
||||
mIsAllTheSameLanguage = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
// Due to the limits in font fallback score calculation, we can't use anything more than 17
|
||||
// languages.
|
||||
const size_t FONT_LANGUAGES_LIMIT = 17;
|
||||
class FontLanguages;
|
||||
|
||||
// FontLanguage is a compact representation of a BCP 47 language tag. It
|
||||
// does not capture all possible information, only what directly affects
|
||||
// font rendering.
|
||||
@@ -54,12 +59,16 @@ public:
|
||||
|
||||
std::string getString() const;
|
||||
|
||||
// Calculates a matching score. This score represents how well the input languages cover this
|
||||
// language. The maximum score in the language list is returned.
|
||||
// 0 = no match, 1 = script match, 2 = script and primary language match.
|
||||
int getScoreFor(const FontLanguage other) const;
|
||||
int calcScoreFor(const FontLanguages& supported) const;
|
||||
|
||||
uint64_t getIdentifier() const { return (uint64_t)mScript << 32 | (uint64_t)mLanguage; }
|
||||
|
||||
private:
|
||||
friend class FontLanguages; // for FontLanguages constructor
|
||||
|
||||
// ISO 15924 compliant script code. The 4 chars script code are packed into a 32 bit integer.
|
||||
uint32_t mScript;
|
||||
|
||||
@@ -80,12 +89,37 @@ private:
|
||||
uint8_t mSubScriptBits;
|
||||
|
||||
static uint8_t scriptToSubScriptBits(uint32_t script);
|
||||
bool supportsScript(uint8_t requestedBits) const;
|
||||
|
||||
// Returns true if the provide subscript bits has the requested subscript bits.
|
||||
// Note that this function returns false if the requested subscript bits are empty.
|
||||
static bool supportsScript(uint8_t providedBits, uint8_t requestedBits);
|
||||
};
|
||||
|
||||
// Due to the limit of font fallback cost calculation, we can't use anything more than 17 languages.
|
||||
const size_t FONT_LANGUAGES_LIMIT = 17;
|
||||
typedef std::vector<FontLanguage> FontLanguages;
|
||||
// An immutable list of languages.
|
||||
class FontLanguages {
|
||||
public:
|
||||
FontLanguages(std::vector<FontLanguage>&& languages);
|
||||
FontLanguages() : mUnionOfSubScriptBits(0), mIsAllTheSameLanguage(false) {}
|
||||
FontLanguages(FontLanguages&&) = default;
|
||||
|
||||
size_t size() const { return mLanguages.size(); }
|
||||
bool empty() const { return mLanguages.empty(); }
|
||||
const FontLanguage& operator[] (size_t n) const { return mLanguages[n]; }
|
||||
|
||||
private:
|
||||
friend struct FontLanguage; // for calcScoreFor
|
||||
|
||||
std::vector<FontLanguage> mLanguages;
|
||||
uint8_t mUnionOfSubScriptBits;
|
||||
bool mIsAllTheSameLanguage;
|
||||
|
||||
uint8_t getUnionOfSubScriptBits() const { return mUnionOfSubScriptBits; }
|
||||
bool isAllTheSameLanguage() const { return mIsAllTheSameLanguage; }
|
||||
|
||||
// Do not copy and assign.
|
||||
FontLanguages(const FontLanguages&) = delete;
|
||||
void operator=(const FontLanguages&) = delete;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
|
||||
@@ -76,8 +76,8 @@ static size_t toLanguageTag(char* output, size_t outSize, const std::string& loc
|
||||
return outLength;
|
||||
}
|
||||
|
||||
static FontLanguages constructFontLanguages(const std::string& input) {
|
||||
FontLanguages result;
|
||||
static std::vector<FontLanguage> parseLanguageList(const std::string& input) {
|
||||
std::vector<FontLanguage> result;
|
||||
size_t currentIdx = 0;
|
||||
size_t commaLoc = 0;
|
||||
char langTag[ULOC_FULLNAME_CAPACITY];
|
||||
@@ -121,11 +121,11 @@ uint32_t FontLanguageListCache::getId(const std::string& languages) {
|
||||
|
||||
// Given language list is not in cache. Insert it and return newly assigned ID.
|
||||
const uint32_t nextId = inst->mLanguageLists.size();
|
||||
FontLanguages fontLanguages = constructFontLanguages(languages);
|
||||
FontLanguages fontLanguages(parseLanguageList(languages));
|
||||
if (fontLanguages.empty()) {
|
||||
return kEmptyListId;
|
||||
}
|
||||
inst->mLanguageLists.push_back(fontLanguages);
|
||||
inst->mLanguageLists.push_back(std::move(fontLanguages));
|
||||
inst->mLanguageListLookupTable.insert(std::make_pair(languages, nextId));
|
||||
return nextId;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ FontLanguageListCache* FontLanguageListCache::getInstance() {
|
||||
|
||||
// Insert an empty language list for mapping default language list to kEmptyListId.
|
||||
// The default language list has only one FontLanguage and it is the unsupported language.
|
||||
instance->mLanguageLists.push_back(FontLanguages({FontLanguage()}));
|
||||
instance->mLanguageLists.push_back(FontLanguages());
|
||||
instance->mLanguageListLookupTable.insert(std::make_pair("", kEmptyListId));
|
||||
}
|
||||
return instance;
|
||||
|
||||
@@ -698,72 +698,104 @@ TEST_F(FontCollectionItemizeTest, itemize_vs_sequence_but_no_base_char) {
|
||||
TEST_F(FontCollectionItemizeTest, itemize_LanguageScore) {
|
||||
struct TestCase {
|
||||
std::string userPreferredLanguages;
|
||||
std::string fontLanguages;
|
||||
std::vector<std::string> fontLanguages;
|
||||
int selectedFontIndex;
|
||||
} testCases[] = {
|
||||
// Font can specify empty language.
|
||||
{ "und", { "", "" }, 0 },
|
||||
{ "und", { "", "en-Latn" }, 0 },
|
||||
{ "en-Latn", { "", "" }, 0 },
|
||||
{ "en-Latn", { "", "en-Latn" }, 1 },
|
||||
|
||||
// Single user preferred language.
|
||||
// Exact match case
|
||||
{ "en-Latn", "en-Latn,ja-Jpan", 0 },
|
||||
{ "ja-Jpan", "en-Latn,ja-Jpan", 1 },
|
||||
{ "en-Latn", "en-Latn,nl-Latn,es-Latn", 0 },
|
||||
{ "nl-Latn", "en-Latn,nl-Latn,es-Latn", 1 },
|
||||
{ "es-Latn", "en-Latn,nl-Latn,es-Latn", 2 },
|
||||
{ "es-Latn", "en-Latn,en-Latn,nl-Latn", 0 },
|
||||
{ "en-Latn", { "en-Latn", "ja-Jpan" }, 0 },
|
||||
{ "ja-Jpan", { "en-Latn", "ja-Jpan" }, 1 },
|
||||
{ "en-Latn", { "en-Latn", "nl-Latn", "es-Latn" }, 0 },
|
||||
{ "nl-Latn", { "en-Latn", "nl-Latn", "es-Latn" }, 1 },
|
||||
{ "es-Latn", { "en-Latn", "nl-Latn", "es-Latn" }, 2 },
|
||||
{ "es-Latn", { "en-Latn", "en-Latn", "nl-Latn" }, 0 },
|
||||
|
||||
// Exact script match case
|
||||
{ "en-Latn", "nl-Latn,be-Latn", 0 },
|
||||
{ "en-Arab", "nl-Latn,ar-Arab", 1 },
|
||||
{ "en-Latn", "be-Latn,ar-Arab,bd-Beng", 0 },
|
||||
{ "en-Arab", "be-Latn,ar-Arab,bd-Beng", 1 },
|
||||
{ "en-Beng", "be-Latn,ar-Arab,bd-Beng", 2 },
|
||||
{ "en-Beng", "be-Latn,ar-Beng,bd-Beng", 1 },
|
||||
{ "zh-Hant", "zh-Hant,zh-Hans", 0 },
|
||||
{ "zh-Hans", "zh-Hant,zh-Hans", 1 },
|
||||
{ "en-Latn", { "nl-Latn", "e-Latn" }, 0 },
|
||||
{ "en-Arab", { "nl-Latn", "ar-Arab" }, 1 },
|
||||
{ "en-Latn", { "be-Latn", "ar-Arab", "d-Beng" }, 0 },
|
||||
{ "en-Arab", { "be-Latn", "ar-Arab", "d-Beng" }, 1 },
|
||||
{ "en-Beng", { "be-Latn", "ar-Arab", "d-Beng" }, 2 },
|
||||
{ "en-Beng", { "be-Latn", "ar-Beng", "d-Beng" }, 1 },
|
||||
{ "zh-Hant", { "zh-Hant", "zh-Hans" }, 0 },
|
||||
{ "zh-Hans", { "zh-Hant", "zh-Hans" }, 1 },
|
||||
|
||||
// Subscript match case, e.g. Jpan supports Hira.
|
||||
{ "en-Hira", "ja-Jpan", 0 },
|
||||
{ "zh-Hani", "zh-Hans,zh-Hant", 0 },
|
||||
{ "zh-Hani", "zh-Hant,zh-Hans", 0 },
|
||||
{ "en-Hira", "zh-Hant,ja-Jpan,ja-Jpan", 1 },
|
||||
{ "en-Hira", { "ja-Jpan" }, 0 },
|
||||
{ "zh-Hani", { "zh-Hans", "zh-Hant" }, 0 },
|
||||
{ "zh-Hani", { "zh-Hant", "zh-Hans" }, 0 },
|
||||
{ "en-Hira", { "zh-Hant", "ja-Jpan", "ja-Jpan" }, 1 },
|
||||
|
||||
// Language match case
|
||||
{ "ja-Latn", "zh-Latn,ja-Latn", 1 },
|
||||
{ "zh-Latn", "zh-Latn,ja-Latn", 0 },
|
||||
{ "ja-Latn", "zh-Latn,ja-Latn", 1 },
|
||||
{ "ja-Latn", "zh-Latn,ja-Latn,ja-Latn", 1 },
|
||||
{ "ja-Latn", { "zh-Latn", "ja-Latn" }, 1 },
|
||||
{ "zh-Latn", { "zh-Latn", "ja-Latn" }, 0 },
|
||||
{ "ja-Latn", { "zh-Latn", "ja-Latn" }, 1 },
|
||||
{ "ja-Latn", { "zh-Latn", "ja-Latn", "ja-Latn" }, 1 },
|
||||
|
||||
// Mixed case
|
||||
// Script/subscript match is strongest.
|
||||
{ "ja-Jpan", "en-Latn,ja-Latn,en-Jpan", 2 },
|
||||
{ "ja-Hira", "en-Latn,ja-Latn,en-Jpan", 2 },
|
||||
{ "ja-Hira", "en-Latn,ja-Latn,en-Jpan,en-Jpan", 2 },
|
||||
{ "ja-Jpan", { "en-Latn", "ja-Latn", "en-Jpan" }, 2 },
|
||||
{ "ja-Hira", { "en-Latn", "ja-Latn", "en-Jpan" }, 2 },
|
||||
{ "ja-Hira", { "en-Latn", "ja-Latn", "en-Jpan", "en-Jpan" }, 2 },
|
||||
|
||||
// Language match only happens if the script matches.
|
||||
{ "ja-Hira", "en-Latn,ja-Latn", 0 },
|
||||
{ "ja-Hira", "en-Jpan,ja-Jpan", 1 },
|
||||
{ "ja-Hira", { "en-Latn", "ja-Latn" }, 0 },
|
||||
{ "ja-Hira", { "en-Jpan", "ja-Jpan" }, 1 },
|
||||
|
||||
// Multiple languages.
|
||||
// Even if all fonts have the same score, use the 2nd language for better selection.
|
||||
{ "en-Latn,ja-Jpan", "zh-Hant,zh-Hans,ja-Jpan", 2 },
|
||||
{ "en-Latn,nl-Latn", "es-Latn,be-Latn,nl-Latn", 2 },
|
||||
{ "en-Latn,br-Latn,nl-Latn", "es-Latn,be-Latn,nl-Latn", 2 },
|
||||
{ "en-Latn,br-Latn,nl-Latn", "es-Latn,be-Latn,nl-Latn,nl-Latn", 2 },
|
||||
{ "en-Latn,ja-Jpan", { "zh-Hant", "zh-Hans", "ja-Jpan" }, 2 },
|
||||
{ "en-Latn,nl-Latn", { "es-Latn", "be-Latn", "nl-Latn" }, 2 },
|
||||
{ "en-Latn,br-Latn,nl-Latn", { "es-Latn", "be-Latn", "nl-Latn" }, 2 },
|
||||
{ "en-Latn,br-Latn,nl-Latn", { "es-Latn", "be-Latn", "nl-Latn", "nl-Latn" }, 2 },
|
||||
|
||||
// Script score.
|
||||
{ "en-Latn,ja-Jpan", "en-Arab,en-Jpan", 1 },
|
||||
{ "en-Latn,ja-Jpan", "en-Arab,en-Jpan,en-Jpan", 1 },
|
||||
{ "en-Latn,ja-Jpan", { "en-Arab", "en-Jpan" }, 1 },
|
||||
{ "en-Latn,ja-Jpan", { "en-Arab", "en-Jpan", "en-Jpan" }, 1 },
|
||||
|
||||
// Language match case
|
||||
{ "en-Latn,ja-Latn", "bd-Latn,ja-Latn", 1 },
|
||||
{ "en-Latn,ja-Latn", "bd-Latn,ja-Latn,ja-Latn", 1 },
|
||||
{ "en-Latn,ja-Latn", { "bd-Latn", "ja-Latn" }, 1 },
|
||||
{ "en-Latn,ja-Latn", { "bd-Latn", "ja-Latn", "ja-Latn" }, 1 },
|
||||
|
||||
// Language match only happens if the script matches.
|
||||
{ "en-Latn,ar-Arab", "en-Beng,ar-Arab", 1 },
|
||||
{ "en-Latn,ar-Arab", { "en-Beng", "ar-Arab" }, 1 },
|
||||
|
||||
// Multiple languages in the font settings.
|
||||
{ "ko-Jamo", { "ja-Jpan", "ko-Kore", "ko-Kore,ko-Jamo"}, 2 },
|
||||
{ "en-Latn", { "ja-Jpan", "en-Latn,ja-Jpan"}, 1 },
|
||||
{ "en-Latn", { "ja-Jpan", "ja-Jpan,en-Latn"}, 1 },
|
||||
{ "en-Latn", { "ja-Jpan,zh-Hant", "en-Latn,ja-Jpan", "en-Latn"}, 1 },
|
||||
{ "en-Latn", { "zh-Hant,ja-Jpan", "ja-Jpan,en-Latn", "en-Latn"}, 1 },
|
||||
|
||||
// Kore = Hang + Hani, etc.
|
||||
{ "ko-Kore", { "ko-Hang", "ko-Jamo,ko-Hani", "ko-Hang,ko-Hani"}, 2 },
|
||||
{ "ja-Hrkt", { "ja-Hira", "ja-Kana", "ja-Hira,ja-Kana"}, 2 },
|
||||
{ "ja-Jpan", { "ja-Hira", "ja-Kana", "ja-Hani", "ja-Hira,ja-Kana,ja-Hani"}, 3 },
|
||||
{ "zh-Hanb", { "zh-Hant", "zh-Bopo", "zh-Hant,zh-Bopo"}, 2 },
|
||||
{ "zh-Hanb", { "ja-Hanb", "zh-Hant,zh-Bopo"}, 1 },
|
||||
|
||||
// Language match with unified subscript bits.
|
||||
{ "zh-Hanb", { "zh-Hant", "zh-Bopo", "ja-Hant,ja-Bopo", "zh-Hant,zh-Bopo"}, 3 },
|
||||
{ "zh-Hanb", { "zh-Hant", "zh-Bopo", "ja-Hant,zh-Bopo", "zh-Hant,zh-Bopo"}, 3 },
|
||||
};
|
||||
|
||||
for (auto testCase : testCases) {
|
||||
std::string fontLanguagesStr = "{";
|
||||
for (size_t i = 0; i < testCase.fontLanguages.size(); ++i) {
|
||||
if (i != 0) {
|
||||
fontLanguagesStr += ", ";
|
||||
}
|
||||
fontLanguagesStr += "\"" + testCase.fontLanguages[i] + "\"";
|
||||
}
|
||||
fontLanguagesStr += "}";
|
||||
SCOPED_TRACE("Test of user preferred languages: \"" + testCase.userPreferredLanguages +
|
||||
"\" with font languages: " + testCase.fontLanguages);
|
||||
"\" with font languages: " + fontLanguagesStr);
|
||||
|
||||
std::vector<FontFamily*> families;
|
||||
|
||||
@@ -778,12 +810,10 @@ TEST_F(FontCollectionItemizeTest, itemize_LanguageScore) {
|
||||
// Each font family is associated with a specified language. All font families except for
|
||||
// the first font support U+9AA8.
|
||||
std::unordered_map<MinikinFont*, int> fontLangIdxMap;
|
||||
const FontLanguages& fontLanguages = registerAndGetFontLanguages(testCase.fontLanguages);
|
||||
|
||||
for (size_t i = 0; i < fontLanguages.size(); ++i) {
|
||||
const FontLanguage& fontLanguage = fontLanguages[i];
|
||||
for (size_t i = 0; i < testCase.fontLanguages.size(); ++i) {
|
||||
FontFamily* family = new FontFamily(
|
||||
FontStyle::registerLanguageList(fontLanguage.getString()), 0 /* variant */);
|
||||
FontStyle::registerLanguageList(testCase.fontLanguages[i]), 0 /* variant */);
|
||||
MinikinFont* minikin_font = new MinikinFontForTest(kJAFont);
|
||||
family->addFont(minikin_font);
|
||||
families.push_back(family);
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace android {
|
||||
typedef ICUTestBase FontLanguagesTest;
|
||||
typedef ICUTestBase FontLanguageTest;
|
||||
|
||||
static FontLanguages createFontLanguages(const std::string& input) {
|
||||
static const FontLanguages& createFontLanguages(const std::string& input) {
|
||||
AutoMutex _l(gMinikinLock);
|
||||
uint32_t langId = FontLanguageListCache::getId(input);
|
||||
return FontLanguageListCache::getById(langId);
|
||||
@@ -217,35 +217,30 @@ TEST_F(FontLanguagesTest, basicTests) {
|
||||
EXPECT_EQ(0u, emptyLangs.size());
|
||||
|
||||
FontLanguage english = createFontLanguage("en");
|
||||
FontLanguages singletonLangs = createFontLanguages("en");
|
||||
const FontLanguages& singletonLangs = createFontLanguages("en");
|
||||
EXPECT_EQ(1u, singletonLangs.size());
|
||||
EXPECT_EQ(english, singletonLangs[0]);
|
||||
|
||||
FontLanguage french = createFontLanguage("fr");
|
||||
FontLanguages twoLangs = createFontLanguages("en,fr");
|
||||
const FontLanguages& twoLangs = createFontLanguages("en,fr");
|
||||
EXPECT_EQ(2u, twoLangs.size());
|
||||
EXPECT_EQ(english, twoLangs[0]);
|
||||
EXPECT_EQ(french, twoLangs[1]);
|
||||
}
|
||||
|
||||
TEST_F(FontLanguagesTest, unsupportedLanguageTests) {
|
||||
FontLanguage unsupportedLang = createFontLanguage("abcd");
|
||||
ASSERT_TRUE(unsupportedLang.isUnsupported());
|
||||
const FontLanguages& oneUnsupported = createFontLanguages("abcd-example");
|
||||
EXPECT_TRUE(oneUnsupported.empty());
|
||||
|
||||
FontLanguages oneUnsupported = createFontLanguages("abcd-example");
|
||||
EXPECT_EQ(1u, oneUnsupported.size());
|
||||
EXPECT_TRUE(oneUnsupported[0].isUnsupported());
|
||||
|
||||
FontLanguages twoUnsupporteds = createFontLanguages("abcd-example,abcd-example");
|
||||
EXPECT_EQ(1u, twoUnsupporteds.size());
|
||||
EXPECT_TRUE(twoUnsupporteds[0].isUnsupported());
|
||||
const FontLanguages& twoUnsupporteds = createFontLanguages("abcd-example,abcd-example");
|
||||
EXPECT_TRUE(twoUnsupporteds.empty());
|
||||
|
||||
FontLanguage english = createFontLanguage("en");
|
||||
FontLanguages firstUnsupported = createFontLanguages("abcd-example,en");
|
||||
const FontLanguages& firstUnsupported = createFontLanguages("abcd-example,en");
|
||||
EXPECT_EQ(1u, firstUnsupported.size());
|
||||
EXPECT_EQ(english, firstUnsupported[0]);
|
||||
|
||||
FontLanguages lastUnsupported = createFontLanguages("en,abcd-example");
|
||||
const FontLanguages& lastUnsupported = createFontLanguages("en,abcd-example");
|
||||
EXPECT_EQ(1u, lastUnsupported.size());
|
||||
EXPECT_EQ(english, lastUnsupported[0]);
|
||||
}
|
||||
@@ -256,20 +251,20 @@ TEST_F(FontLanguagesTest, repeatedLanguageTests) {
|
||||
FontLanguage englishInLatn = createFontLanguage("en-Latn");
|
||||
ASSERT_TRUE(english == englishInLatn);
|
||||
|
||||
FontLanguages langs = createFontLanguages("en,en-Latn");
|
||||
const FontLanguages& langs = createFontLanguages("en,en-Latn");
|
||||
EXPECT_EQ(1u, langs.size());
|
||||
EXPECT_EQ(english, langs[0]);
|
||||
|
||||
// Country codes are ignored.
|
||||
FontLanguages fr = createFontLanguages("fr,fr-CA,fr-FR");
|
||||
const FontLanguages& fr = createFontLanguages("fr,fr-CA,fr-FR");
|
||||
EXPECT_EQ(1u, fr.size());
|
||||
EXPECT_EQ(french, fr[0]);
|
||||
|
||||
// The order should be kept.
|
||||
langs = createFontLanguages("en,fr,en-Latn");
|
||||
EXPECT_EQ(2u, langs.size());
|
||||
EXPECT_EQ(english, langs[0]);
|
||||
EXPECT_EQ(french, langs[1]);
|
||||
const FontLanguages& langs2 = createFontLanguages("en,fr,en-Latn");
|
||||
EXPECT_EQ(2u, langs2.size());
|
||||
EXPECT_EQ(english, langs2[0]);
|
||||
EXPECT_EQ(french, langs2[1]);
|
||||
}
|
||||
|
||||
TEST_F(FontLanguagesTest, undEmojiTests) {
|
||||
|
||||
@@ -56,18 +56,18 @@ TEST_F(FontLanguageListCacheTest, getById) {
|
||||
FontLanguage english = FontLanguageListCache::getById(enLangId)[0];
|
||||
FontLanguage japanese = FontLanguageListCache::getById(jpLangId)[0];
|
||||
|
||||
FontLanguages defLangs = FontLanguageListCache::getById(0);
|
||||
EXPECT_EQ(1UL, defLangs.size());
|
||||
EXPECT_TRUE(defLangs[0].isUnsupported());
|
||||
const FontLanguages& defLangs = FontLanguageListCache::getById(0);
|
||||
EXPECT_TRUE(defLangs.empty());
|
||||
|
||||
FontLanguages langs = FontLanguageListCache::getById(FontLanguageListCache::getId("en"));
|
||||
const FontLanguages& langs = FontLanguageListCache::getById(FontLanguageListCache::getId("en"));
|
||||
ASSERT_EQ(1UL, langs.size());
|
||||
EXPECT_EQ(english, langs[0]);
|
||||
|
||||
langs = FontLanguageListCache::getById(FontLanguageListCache::getId("en,jp"));
|
||||
ASSERT_EQ(2UL, langs.size());
|
||||
EXPECT_EQ(english, langs[0]);
|
||||
EXPECT_EQ(japanese, langs[1]);
|
||||
const FontLanguages& langs2 =
|
||||
FontLanguageListCache::getById(FontLanguageListCache::getId("en,jp"));
|
||||
ASSERT_EQ(2UL, langs2.size());
|
||||
EXPECT_EQ(english, langs2[0]);
|
||||
EXPECT_EQ(japanese, langs2[1]);
|
||||
}
|
||||
|
||||
} // android
|
||||
|
||||
Reference in New Issue
Block a user