mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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:
parent
0eb96541f6
commit
9a4c3535be
@ -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; }
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user