Basic scaffolding for handling a language list.

The behavior hasn't changed much yet: all languages are ignored for
rendering text, except the very first supported language.

Change-Id: I1695fb985927ae5e28e4f59c1b531e4993af8688
This commit is contained in:
Roozbeh Pournader 2015-10-19 22:16:08 -07:00
parent 0eb96541f6
commit 9a4c3535be
3 changed files with 104 additions and 0 deletions

View File

@ -35,6 +35,7 @@ class MinikinFont;
// font rendering.
class FontLanguage {
friend class FontStyle;
friend class FontLanguages;
public:
FontLanguage() : mBits(0) { }
@ -46,6 +47,8 @@ public:
}
operator bool() const { return mBits != 0; }
bool isUnsupported() const { return mBits == kUnsupportedLanguage; }
std::string getString() const;
// 0 = no match, 1 = language matches, 2 = language and script match
@ -64,6 +67,23 @@ private:
uint32_t mBits;
};
// A list of zero or more instances of FontLanguage, in the order of
// preference. Used for further resolution of rendering results.
class FontLanguages {
public:
FontLanguages() { mLangs.clear(); }
// Parse from string, which is a comma-separated list of languages
FontLanguages(const char* buf, size_t size);
const FontLanguage& operator[](size_t index) const { return mLangs.at(index); }
size_t size() const { return mLangs.size(); }
private:
std::vector<FontLanguage> mLangs;
};
// FontStyle represents all style information needed to select an actual font
// from a collection. The implementation is packed into a single 32-bit word
// so it can be efficiently copied, embedded in other objects, etc.
@ -76,6 +96,9 @@ public:
bits = (weight & kWeightMask) | (italic ? kItalicMask : 0)
| (variant << kVariantShift) | (lang.bits() << kLangShift);
}
FontStyle(FontLanguages langs, int variant = 0, int weight = 4, bool italic = false) :
// TODO: Use all the languages in langs
FontStyle(langs[0], variant, weight, italic) { }
int getWeight() const { return bits & kWeightMask; }
bool getItalic() const { return (bits & kItalicMask) != 0; }
int getVariant() const { return (bits >> kVariantShift) & kVariantMask; }

View File

@ -16,9 +16,12 @@
#define LOG_TAG "Minikin"
#include <unordered_set>
#include <cutils/log.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <hb.h>
#include <hb-ot.h>
@ -115,6 +118,36 @@ int FontLanguage::match(const FontLanguage other) const {
return result;
}
FontLanguages::FontLanguages(const char* buf, size_t size) {
std::unordered_set<uint32_t> seen;
mLangs.clear();
const char* bufEnd = buf + size;
const char* lastStart = buf;
bool isLastLang = false;
while (true) {
const char* commaLoc = static_cast<const char*>(
memchr(lastStart, ',', bufEnd - lastStart));
if (commaLoc == NULL) {
commaLoc = bufEnd;
isLastLang = true;
}
FontLanguage lang(lastStart, commaLoc - lastStart);
if (isLastLang && mLangs.size() == 0) {
// Make sure the list has at least one member
mLangs.push_back(lang);
return;
}
uint32_t bits = lang.bits();
if (bits != FontLanguage::kUnsupportedLanguage && seen.count(bits) == 0) {
mLangs.push_back(lang);
if (isLastLang) return;
seen.insert(bits);
}
if (isLastLang) return;
lastStart = commaLoc + 1;
}
}
FontFamily::~FontFamily() {
for (size_t i = 0; i < mFonts.size(); i++) {
mFonts[i].typeface->UnrefLocked();

View File

@ -22,6 +22,54 @@
namespace android {
TEST(FontLanguagesTest, basicTests) {
FontLanguages emptyLangs;
EXPECT_EQ(0u, emptyLangs.size());
FontLanguage english("en", 2);
FontLanguages singletonLangs("en", 2);
EXPECT_EQ(1u, singletonLangs.size());
EXPECT_EQ(english, singletonLangs[0]);
FontLanguage french("fr", 2);
FontLanguages twoLangs("en,fr", 5);
EXPECT_EQ(2u, twoLangs.size());
EXPECT_EQ(english, twoLangs[0]);
EXPECT_EQ(french, twoLangs[1]);
}
TEST(FontLanguagesTest, unsupportedLanguageTests) {
FontLanguage unsupportedLang("x-example", 9);
ASSERT_TRUE(unsupportedLang.isUnsupported());
FontLanguages oneUnsupported("x-example", 9);
EXPECT_EQ(1u, oneUnsupported.size());
EXPECT_TRUE(oneUnsupported[0].isUnsupported());
FontLanguages twoUnsupporteds("x-example,x-example", 19);
EXPECT_EQ(1u, twoUnsupporteds.size());
EXPECT_TRUE(twoUnsupporteds[0].isUnsupported());
FontLanguage english("en", 2);
FontLanguages firstUnsupported("x-example,en", 12);
EXPECT_EQ(1u, firstUnsupported.size());
EXPECT_EQ(english, firstUnsupported[0]);
FontLanguages lastUnsupported("en,x-example", 12);
EXPECT_EQ(1u, lastUnsupported.size());
EXPECT_EQ(english, lastUnsupported[0]);
}
TEST(FontLanguagesTest, repeatedLanguageTests) {
FontLanguage english("en", 2);
FontLanguage englishInLatn("en-Latn", 2);
ASSERT_TRUE(english == englishInLatn);
FontLanguages langs("en,en-Latn", 10);
EXPECT_EQ(1u, langs.size());
EXPECT_EQ(english, langs[0]);
}
// The test font has following glyphs.
// U+82A6
// U+82A6 U+FE00 (VS1)