Merge "Support multiple languages per font in fonts.xml"
This commit is contained in:
committed by
Android (Google) Code Review
commit
c9c6ee667f
@@ -175,7 +175,7 @@ public final class FontConfig {
|
||||
public static final class Family {
|
||||
private final @NonNull String mName;
|
||||
private final @NonNull Font[] mFonts;
|
||||
private final @NonNull String mLanguage;
|
||||
private final @NonNull String[] mLanguages;
|
||||
|
||||
/** @hide */
|
||||
@Retention(SOURCE)
|
||||
@@ -209,11 +209,11 @@ public final class FontConfig {
|
||||
// See frameworks/minikin/include/minikin/FontFamily.h
|
||||
private final @Variant int mVariant;
|
||||
|
||||
public Family(@NonNull String name, @NonNull Font[] fonts, @NonNull String language,
|
||||
public Family(@NonNull String name, @NonNull Font[] fonts, @NonNull String[] languages,
|
||||
@Variant int variant) {
|
||||
mName = name;
|
||||
mFonts = fonts;
|
||||
mLanguage = language;
|
||||
mLanguages = languages;
|
||||
mVariant = variant;
|
||||
}
|
||||
|
||||
@@ -232,10 +232,10 @@ public final class FontConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language for this family. May be null.
|
||||
* Returns the languages for this family. May be null.
|
||||
*/
|
||||
public @Nullable String getLanguage() {
|
||||
return mLanguage;
|
||||
public @Nullable String[] getLanguages() {
|
||||
return mLanguages;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,10 +51,10 @@ struct NativeFamilyBuilder {
|
||||
std::vector<minikin::FontVariation> axes;
|
||||
};
|
||||
|
||||
static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
|
||||
static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring langs, jint variant) {
|
||||
NativeFamilyBuilder* builder;
|
||||
if (lang != nullptr) {
|
||||
ScopedUtfChars str(env, lang);
|
||||
if (langs != nullptr) {
|
||||
ScopedUtfChars str(env, langs);
|
||||
builder = new NativeFamilyBuilder(
|
||||
minikin::FontStyle::registerLanguageList(str.c_str()), variant);
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,7 @@ import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Locale;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -128,7 +129,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_NonExistentFontShouldBeIgnored() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " <font weight='400' style='normal'>NoSuchFont.ttf</font>"
|
||||
@@ -154,7 +155,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_NamedFamily() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -200,7 +201,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_defaultFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -239,7 +240,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_namedFallbackFamily() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -291,7 +292,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_namedFallbackFamily2() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -341,7 +342,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_ImplicitSansSerifFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -380,7 +381,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_ElegantFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -418,7 +419,7 @@ public class TypefaceSystemFallbackTest {
|
||||
@Test
|
||||
public void testBuildSystemFallback_ElegantFallback_customFallback() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset version='22'>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
@@ -466,4 +467,42 @@ public class TypefaceSystemFallbackTest {
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_multiLingualFamilies() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family lang='de'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family lang='it fr'>"
|
||||
+ " <font weight='400' style='normal'>b3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
|
||||
buildSystemFallback(xml, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
paint.setTypeface(fontMap.get("sans-serif"));
|
||||
|
||||
paint.setTextLocale(Locale.GERMANY);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
paint.setTextLocale(Locale.ITALY);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
|
||||
paint.setTextLocale(Locale.FRANCE);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
effectively add 300 to the weight, this ensures that 900 is the bold
|
||||
paired with the 500 weight, ensuring adequate contrast.
|
||||
-->
|
||||
<familyset version="22">
|
||||
<familyset version="23">
|
||||
<!-- first font is default -->
|
||||
<family name="sans-serif">
|
||||
<font weight="100" style="normal">Roboto-Thin.ttf</font>
|
||||
@@ -128,8 +128,7 @@
|
||||
<font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
|
||||
<font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
|
||||
</family>
|
||||
<!-- TODO: add Geok -->
|
||||
<family lang="und-Geor">
|
||||
<family lang="und-Geor und-Geok">
|
||||
<font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
|
||||
<font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
|
||||
</family>
|
||||
@@ -474,8 +473,7 @@
|
||||
<family lang="zh-Hans">
|
||||
<font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
|
||||
</family>
|
||||
<!-- TODO: Add Bopo -->
|
||||
<family lang="zh-Hant">
|
||||
<family lang="zh-Hant zh-Bopo">
|
||||
<font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
|
||||
</family>
|
||||
<family lang="ja">
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package android.graphics;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.fonts.FontVariationAxis;
|
||||
import android.text.FontConfig;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
|
||||
@@ -48,8 +50,16 @@ public class FontFamily {
|
||||
mBuilderPtr = nInitBuilder(null, 0);
|
||||
}
|
||||
|
||||
public FontFamily(String lang, int variant) {
|
||||
mBuilderPtr = nInitBuilder(lang, variant);
|
||||
public FontFamily(@Nullable String[] langs, int variant) {
|
||||
final String langsString;
|
||||
if (langs == null || langs.length == 0) {
|
||||
langsString = null;
|
||||
} else if (langs.length == 1) {
|
||||
langsString = langs[0];
|
||||
} else {
|
||||
langsString = TextUtils.join(",", langs);
|
||||
}
|
||||
mBuilderPtr = nInitBuilder(langsString, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,7 +184,7 @@ public class FontFamily {
|
||||
return nAddFont(builderPtr, font, ttcIndex, -1, -1);
|
||||
}
|
||||
|
||||
private static native long nInitBuilder(String lang, int variant);
|
||||
private static native long nInitBuilder(String langs, int variant);
|
||||
|
||||
@CriticalNative
|
||||
private static native long nCreateFamily(long mBuilderPtr);
|
||||
|
||||
@@ -74,13 +74,14 @@ public class FontListParser {
|
||||
|
||||
private static FontConfig.Family readFamily(XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
String name = parser.getAttributeValue(null, "name");
|
||||
String lang = parser.getAttributeValue(null, "lang");
|
||||
String variant = parser.getAttributeValue(null, "variant");
|
||||
List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
|
||||
final String name = parser.getAttributeValue(null, "name");
|
||||
final String lang = parser.getAttributeValue(null, "lang");
|
||||
final String[] langs = lang == null ? null : lang.split("\\s+");
|
||||
final String variant = parser.getAttributeValue(null, "variant");
|
||||
final List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
|
||||
while (parser.next() != XmlPullParser.END_TAG) {
|
||||
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
||||
String tag = parser.getName();
|
||||
final String tag = parser.getName();
|
||||
if (tag.equals("font")) {
|
||||
fonts.add(readFont(parser));
|
||||
} else {
|
||||
@@ -95,7 +96,7 @@ public class FontListParser {
|
||||
intVariant = FontConfig.Family.VARIANT_ELEGANT;
|
||||
}
|
||||
}
|
||||
return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), lang,
|
||||
return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), langs,
|
||||
intVariant);
|
||||
}
|
||||
|
||||
|
||||
@@ -929,9 +929,9 @@ public class Typeface {
|
||||
}
|
||||
|
||||
private static @Nullable FontFamily createFontFamily(
|
||||
String familyName, List<FontConfig.Font> fonts, String languageTag, int variant,
|
||||
String familyName, List<FontConfig.Font> fonts, String[] languageTags, int variant,
|
||||
Map<String, ByteBuffer> cache, String fontDir) {
|
||||
final FontFamily family = new FontFamily(languageTag, variant);
|
||||
final FontFamily family = new FontFamily(languageTags, variant);
|
||||
for (int i = 0; i < fonts.size(); i++) {
|
||||
final FontConfig.Font font = fonts.get(i);
|
||||
final String fullPath = fontDir + font.getFontName();
|
||||
@@ -952,7 +952,8 @@ public class Typeface {
|
||||
}
|
||||
}
|
||||
if (!family.freeze()) {
|
||||
Log.e(TAG, "Unable to load Family: " + familyName + " : " + languageTag);
|
||||
Log.e(TAG, "Unable to load Family: " + familyName + " : "
|
||||
+ Arrays.toString(languageTags));
|
||||
return null;
|
||||
}
|
||||
return family;
|
||||
@@ -963,7 +964,7 @@ public class Typeface {
|
||||
Map<String, ByteBuffer> cache,
|
||||
String fontDir) {
|
||||
|
||||
final String languageTag = xmlFamily.getLanguage();
|
||||
final String[] languageTags = xmlFamily.getLanguages();
|
||||
final int variant = xmlFamily.getVariant();
|
||||
|
||||
final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>();
|
||||
@@ -985,7 +986,7 @@ public class Typeface {
|
||||
}
|
||||
|
||||
final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
|
||||
xmlFamily.getName(), defaultFonts, languageTag, variant, cache, fontDir);
|
||||
xmlFamily.getName(), defaultFonts, languageTags, variant, cache, fontDir);
|
||||
|
||||
// Insert family into fallback map.
|
||||
for (int i = 0; i < fallbackMap.size(); i++) {
|
||||
@@ -997,7 +998,7 @@ public class Typeface {
|
||||
}
|
||||
} else {
|
||||
final FontFamily family = createFontFamily(
|
||||
xmlFamily.getName(), fallback, languageTag, variant, cache, fontDir);
|
||||
xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir);
|
||||
if (family != null) {
|
||||
fallbackMap.valueAt(i).add(family);
|
||||
}
|
||||
@@ -1034,7 +1035,7 @@ public class Typeface {
|
||||
}
|
||||
final FontFamily family = createFontFamily(
|
||||
xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()),
|
||||
xmlFamily.getLanguage(), xmlFamily.getVariant(), bufferCache, fontDir);
|
||||
xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir);
|
||||
if (family == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user