summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/android/graphics/FontListConverter.java220
-rw-r--r--graphics/java/android/graphics/FontListParser.java53
-rw-r--r--graphics/java/android/graphics/LegacyFontListParser.java186
-rw-r--r--graphics/java/android/graphics/Typeface.java65
-rw-r--r--graphics/tests/localtests/Android.mk18
-rw-r--r--graphics/tests/localtests/src/android/graphics/FontListConverterTest.java280
-rw-r--r--graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java27
7 files changed, 838 insertions, 11 deletions
diff --git a/graphics/java/android/graphics/FontListConverter.java b/graphics/java/android/graphics/FontListConverter.java
new file mode 100644
index 0000000..c675c88
--- /dev/null
+++ b/graphics/java/android/graphics/FontListConverter.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics;
+
+import android.graphics.FontListParser;
+import android.graphics.FontListParser.Alias;
+import android.graphics.FontListParser.Font;
+import android.graphics.LegacyFontListParser.Family;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * Converts a list of Family to FontListParser.Config
+ * {@hide}
+ */
+public class FontListConverter {
+ // These array values were determined by the order
+ // of fonts in a fileset. The order is:
+ // "Normal, Bold, Italic, BoldItalic"
+ // Additionally the weight values in L's fonts.xml
+ // are used to determine a generic weight value for each type
+ // e.g The 2nd entry in a fileset is the bold font.
+ protected static final int[] WEIGHTS = { 400, 700, 400, 700 };
+ protected static boolean[] ITALICS = { false, false, true, true };
+ protected static final int DEFAULT_WEIGHT = WEIGHTS[0];
+
+ // Arbitrarily chosen list based on L's fonts.xml.
+ // There could be more out there, but we can't use a generic pattern of "fontName-styleName"
+ // as "sans-serif" would be translated as a font called "sans" with the style "serif".
+ public static final String[] STYLES = {
+ "thin",
+ "light",
+ "medium",
+ "black"
+ };
+
+ // Maps a "normal" family to a list of similar families differing by style
+ // Example: "sans-serif" -> { sans-serif-thin, sans-serif-light, sans-serif-medium }
+ private HashMap<Family, List<Family>> mFamilyVariants = new HashMap<Family, List<Family>>();
+ private List<Family> mFamilies =
+ new ArrayList<Family >();
+ private String mFontDir;
+
+
+ public FontListConverter(List<Family> families, String fontDir) {
+ mFamilies.addAll(families);
+ mFontDir = fontDir;
+ findFamilyVariants();
+ }
+
+ public FontListConverter(Family family, String fontDir) {
+ mFamilies.add(family);
+ mFontDir = fontDir;
+ findFamilyVariants();
+ }
+
+ private void findFamilyVariants() {
+ for(Family family : mFamilies) {
+ if (isNormalStyle(family)) {
+ List<Family> variants = findVariants(family, mFamilies);
+ mFamilyVariants.put(family, variants);
+ }
+ }
+ }
+
+ private List<Family> findVariants(Family normalFamily, List<Family> legacyFamilies) {
+ List<Family> variants = new ArrayList<Family>();
+
+ String normalFamilyName = normalFamily.getName();
+
+ for(Family family : legacyFamilies) {
+ String name = family.getName();
+
+ if (name.startsWith(normalFamilyName) && !isNormalStyle(family)) {
+ variants.add(family);
+ }
+ }
+ return variants;
+ }
+
+ public FontListParser.Config convert() {
+ FontListParser.Config config = new FontListParser.Config();
+ config.families.addAll(convertFamilies());
+ config.aliases.addAll(createAliases());
+ return config;
+ }
+
+ /**
+ * A "normal" style is just standard font,
+ * eg Roboto is normal. Roboto-Thin is styled.
+ */
+ protected boolean isNormalStyle(Family family) {
+ String name = family.getName();
+ if (name == null) return false;
+
+ for(String style : STYLES) {
+ if (name.endsWith('-' + style)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected List<FontListParser.Family> convertFamilies() {
+ List<FontListParser.Family> convertedFamilies = new ArrayList<FontListParser.Family>();
+
+ // Only convert normal families. Each normal family will add in its variants
+ for(Family family : mFamilyVariants.keySet()) {
+ convertedFamilies.add(convertFamily(family));
+ }
+
+ return convertedFamilies;
+ }
+
+ protected FontListParser.Family convertFamily(Family legacyFamily) {
+ List<String> nameset = legacyFamily.nameset;
+ List<String> fileset = legacyFamily.fileset;
+
+ // Arbitrarily choose the first entry in the nameset to be the name
+ String name = nameset.isEmpty() ? null : nameset.get(0);
+
+ List<Font> fonts = convertFonts(fileset);
+
+ // Add fonts from other variants
+ for(Family variantFamily : mFamilyVariants.get(legacyFamily)) {
+ fonts.addAll(convertFonts(variantFamily.fileset));
+ }
+
+ return new FontListParser.Family(name, fonts, null, null);
+ }
+
+ protected List<FontListParser.Font> convertFonts(List<String> fileset) {
+ List<Font> fonts = new ArrayList<Font>();
+
+ for(int i=0; i < fileset.size(); i++) {
+ String fullpath = mFontDir + File.separatorChar + fileset.get(i);
+ // fileset should only be 4 entries, but if
+ // its more we can just assign a default.
+ int weight = i < WEIGHTS.length ? WEIGHTS[i] : DEFAULT_WEIGHT;
+ boolean isItalic = i < ITALICS.length ? ITALICS[i] : false;
+
+ Font font = new Font(fullpath, weight, isItalic);
+ fonts.add(font);
+ }
+
+ return fonts;
+ }
+
+ protected List<Alias> createAliases() {
+ List<Alias> aliases = new ArrayList<Alias>();
+
+ for(Family family : mFamilyVariants.keySet()) {
+ // Get any aliases that might be from a normal family's nameset.
+ // eg sans-serif, arial, helvetica, tahoma etc.
+ if (isNormalStyle(family)) {
+ aliases.addAll(adaptNamesetAliases(family.nameset));
+ }
+ }
+
+ aliases.addAll(getAliasesForRelatedFamilies());
+
+ return aliases;
+ }
+
+ private List<Alias> getAliasesForRelatedFamilies() {
+ List<Alias> aliases = new ArrayList<Alias>();
+
+ for(Entry<Family, List<Family>> entry : mFamilyVariants.entrySet()) {
+ String toName = entry.getKey().nameset.get(0);
+ List<Family> relatedFamilies = entry.getValue();
+ for(Family relatedFamily : relatedFamilies) {
+ aliases.addAll(adaptNamesetAliases(relatedFamily.nameset, toName));
+ }
+ }
+ return aliases;
+ }
+
+ private List<Alias> adaptNamesetAliases(List<String> nameset, String toName) {
+ List<Alias> aliases = new ArrayList<Alias>();
+ for(String name : nameset) {
+ Alias alias = new Alias();
+ alias.name = name;
+ alias.toName = toName;
+ aliases.add(alias);
+ }
+ return aliases;
+ }
+
+ private List<Alias> adaptNamesetAliases(List<String> nameset) {
+ List<Alias> aliases = new ArrayList<Alias>();
+ if (nameset.size() < 2) return aliases; // An alias requires a name and toName
+
+ String toName = nameset.get(0);
+ for(int i = 1; i < nameset.size(); i++) {
+ Alias alias = new Alias();
+ alias.name = nameset.get(i);
+ alias.toName = toName;
+ aliases.add(alias);
+ }
+
+ return aliases;
+ }
+}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 97081f9..1ca464d 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -21,6 +21,8 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -74,25 +76,64 @@ public class FontListParser {
}
/* Parse fallback list (no names) */
- public static Config parse(InputStream in) throws XmlPullParserException, IOException {
+ public static Config parse(File configFilename, File fontDir)
+ throws XmlPullParserException, IOException {
+ FileInputStream in = new FileInputStream(configFilename);
+ if (isLegacyFormat(configFilename)) {
+ return parseLegacyFormat(in, fontDir.getAbsolutePath());
+ } else {
+ return parseNormalFormat(in, fontDir.getAbsolutePath());
+ }
+ }
+
+ private static boolean isLegacyFormat(File configFilename)
+ throws XmlPullParserException, IOException {
+ FileInputStream in = new FileInputStream(configFilename);
+ boolean isLegacy = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ parser.require(XmlPullParser.START_TAG, null, "familyset");
+ String version = parser.getAttributeValue(null, "version");
+ isLegacy = version == null;
+ } finally {
+ in.close();
+ }
+ return isLegacy;
+ }
+
+ public static Config parseLegacyFormat(InputStream in, String dirName)
+ throws XmlPullParserException, IOException {
+ try {
+ List<LegacyFontListParser.Family> legacyFamilies = LegacyFontListParser.parse(in);
+ FontListConverter converter = new FontListConverter(legacyFamilies, dirName);
+ return converter.convert();
+ } finally {
+ in.close();
+ }
+ }
+
+ public static Config parseNormalFormat(InputStream in, String dirName)
+ throws XmlPullParserException, IOException {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
parser.nextTag();
- return readFamilies(parser);
+ return readFamilies(parser, dirName);
} finally {
in.close();
}
}
- private static Config readFamilies(XmlPullParser parser)
+ private static Config readFamilies(XmlPullParser parser, String dirPath)
throws XmlPullParserException, IOException {
Config config = new Config();
parser.require(XmlPullParser.START_TAG, null, "familyset");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
if (parser.getName().equals("family")) {
- config.families.add(readFamily(parser));
+ config.families.add(readFamily(parser, dirPath));
} else if (parser.getName().equals("alias")) {
config.aliases.add(readAlias(parser));
} else {
@@ -102,7 +143,7 @@ public class FontListParser {
return config;
}
- private static Family readFamily(XmlPullParser parser)
+ private static Family readFamily(XmlPullParser parser, String dirPath)
throws XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, "name");
String lang = parser.getAttributeValue(null, "lang");
@@ -116,7 +157,7 @@ public class FontListParser {
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
String filename = parser.nextText();
- String fullFilename = "/system/fonts/" + filename;
+ String fullFilename = dirPath + File.separatorChar + filename;
fonts.add(new Font(fullFilename, weight, isItalic));
} else {
skip(parser);
diff --git a/graphics/java/android/graphics/LegacyFontListParser.java b/graphics/java/android/graphics/LegacyFontListParser.java
new file mode 100644
index 0000000..adb37a3
--- /dev/null
+++ b/graphics/java/android/graphics/LegacyFontListParser.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics;
+
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parses an XML font config. Example:
+ *
+ *<familyset>
+ *
+ * <family>
+ * <nameset>
+ * <name>sans-serif</name>
+ * <name>arial</name>
+ * </nameset>
+ * <fileset>
+ * <file>Roboto-Regular.ttf</file>
+ * <file>Roboto-Bold.ttf</file>
+ * <file>Roboto-Italic.ttf</file>
+ * <file>Roboto-BoldItalic.ttf</file>
+ * </fileset>
+ * </family>
+ * <family>
+ * ...
+ * </family>
+ *</familyset>
+ */
+public class LegacyFontListParser {
+ public static class Family {
+ public List<String> nameset = new ArrayList<String>();
+ public List<String> fileset = new ArrayList<String>();
+
+ public String getName() {
+ if (nameset != null && !nameset.isEmpty()) {
+ return nameset.get(0);
+ }
+ return null;
+ }
+ }
+
+ public static List<Family> parse(InputStream in)
+ throws XmlPullParserException, IOException {
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readFamilySet(parser);
+ } finally {
+ in.close();
+ }
+ }
+
+ private static List<Family> readFamilySet(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<Family> families = new ArrayList<Family>();
+ parser.require(XmlPullParser.START_TAG, null, "familyset");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+
+ // Starts by looking for the entry tag
+ if (name.equals("family")) {
+ Family family = readFamily(parser);
+ families.add(family);
+ }
+ }
+ return families;
+ }
+
+ private static Family readFamily(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ Family family = new Family();
+ parser.require(XmlPullParser.START_TAG, null, "family");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ if (name.equals("nameset")) {
+ List<String> nameset = readNameset(parser);
+ family.nameset = nameset;
+ } else if (name.equals("fileset")) {
+ List<String> fileset = readFileset(parser);
+ family.fileset = fileset;
+ } else {
+ skip(parser);
+ }
+ }
+ return family;
+ }
+
+ private static List<String> readNameset(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<String> names = new ArrayList<String>();
+ parser.require(XmlPullParser.START_TAG, null, "nameset");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String tagname = parser.getName();
+ if (tagname.equals("name")) {
+ String name = readText(parser);
+ names.add(name);
+ } else {
+ skip(parser);
+ }
+ }
+ return names;
+ }
+
+ private static List<String> readFileset(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<String> files = new ArrayList<String>();
+ parser.require(XmlPullParser.START_TAG, null, "fileset");
+
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ if (name.equals("file")) {
+ String file = readText(parser);
+ files.add(file);
+ } else {
+ skip(parser);
+ }
+ }
+ return files;
+ }
+
+ // For the tags title and summary, extracts their text values.
+ private static String readText(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String result = "";
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+ return result;
+ }
+
+ private static void skip(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index db42314..5c62a86 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -25,7 +25,6 @@ import android.util.SparseArray;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
@@ -228,7 +227,10 @@ public class Typeface {
for (int i = 0; i < families.length; i++) {
ptrArray[i] = families[i].mNativePtr;
}
- return new Typeface(nativeCreateFromArray(ptrArray));
+
+
+ Typeface typeface = new Typeface(nativeCreateFromArray(ptrArray));
+ return typeface;
}
/**
@@ -275,10 +277,24 @@ public class Typeface {
private static void init() {
// Load font config and initialize Minikin state
File systemFontConfigLocation = getSystemFontConfigLocation();
- File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
+ File themeFontConfigLocation = getThemeFontConfigLocation();
+
+ File systemConfigFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
+ File themeConfigFilename = new File(themeFontConfigLocation, FONTS_CONFIG);
+ File configFilename = null;
+ File fontDir;
+
+
+ if (themeConfigFilename.exists()) {
+ configFilename = themeConfigFilename;
+ fontDir = getThemeFontConfigLocation();
+ } else {
+ configFilename = systemConfigFilename;
+ fontDir = getSystemFontDirLocation();
+ }
+
try {
- FileInputStream fontsIn = new FileInputStream(configFilename);
- FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
+ FontListParser.Config fontConfig = FontListParser.parse(configFilename, fontDir);
List<FontFamily> familyList = new ArrayList<FontFamily>();
// Note that the default typeface is always present in the fallback list;
@@ -332,6 +348,33 @@ public class Typeface {
}
}
+ /**
+ * Clears caches in java and skia.
+ * Skia will then reparse font config
+ * @hide
+ */
+ public static void recreateDefaults() {
+ sTypefaceCache.clear();
+ sSystemFontMap.clear();
+ init();
+
+ long newDefault = create((String) null, 0).native_instance;
+ long newDefaultBold = create((String) null, Typeface.BOLD).native_instance;
+ long newSansSerif = create("sans-serif", 0).native_instance;
+ long newSerif = create("serif", 0).native_instance;
+ long newMonoSpace = create("monospace", 0).native_instance;
+ long newItalic = create((String) null, Typeface.ITALIC).native_instance;
+ long newBoldItalic = create((String) null, Typeface.BOLD_ITALIC).native_instance;
+
+ DEFAULT.native_instance = newDefault;
+ DEFAULT_BOLD.native_instance = newDefaultBold;
+ SANS_SERIF.native_instance = newSansSerif;
+ SERIF.native_instance = newSerif;
+ MONOSPACE.native_instance = newMonoSpace;
+ sDefaults[2].native_instance = newItalic;
+ sDefaults[3].native_instance = newBoldItalic;
+ }
+
static {
init();
// Set up defaults and typefaces exposed in public API
@@ -354,6 +397,18 @@ public class Typeface {
return new File("/system/etc/");
}
+ private static File getSystemFontDirLocation() {
+ return new File("/system/fonts/");
+ }
+
+ private static File getThemeFontConfigLocation() {
+ return new File("/data/system/theme/fonts/");
+ }
+
+ private static File getThemeFontDir() {
+ return new File("/data/system/theme/fonts/");
+ }
+
@Override
protected void finalize() throws Throwable {
try {
diff --git a/graphics/tests/localtests/Android.mk b/graphics/tests/localtests/Android.mk
new file mode 100644
index 0000000..0b95ecd
--- /dev/null
+++ b/graphics/tests/localtests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := FrameworksGraphicsHostTests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+#LOCAL_PACKAGE_NAME := FrameworksGraphicsTests
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#####################################
+
+
diff --git a/graphics/tests/localtests/src/android/graphics/FontListConverterTest.java b/graphics/tests/localtests/src/android/graphics/FontListConverterTest.java
new file mode 100644
index 0000000..60c9053
--- /dev/null
+++ b/graphics/tests/localtests/src/android/graphics/FontListConverterTest.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics;
+
+import android.graphics.FontListParser.Alias;
+import android.graphics.LegacyFontListParser.Family;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class FontListConverterTest extends TestCase {
+ // VALID nameset includes the default name first and
+ // and some other 'aliases' with it.
+ private static final String[] VALID_NAMESET = {
+ "sans-serif",
+ "arial",
+ "helvetica",
+ "tahoma",
+ "verdana"
+ };
+
+ // The correct fileset will have 4 files in
+ // order by type (regular, bold, italic, bolditalic)
+ private static final String[] VALID_FILESET = {
+ "Roboto-Regular.ttf",
+ "Roboto-Bold.ttf",
+ "Roboto-Italic.ttf",
+ "Roboto-BoldItalic.ttf"
+ };
+
+ // The legacy fontlist format considered thin, light, and black styles
+ // each as part of their own familysets. The new format does not, so we need
+ // to provide a test case to adapt this. Note: "condensed" is still considered
+ // to be its own familyset. So we must be careful
+ private static final String[] VALID_ADDITIONAL_STYLE_NAMESET = {
+ "sans-serif-thin"
+ };
+
+ private static final String[] VALID_ADDITIONAL_STYLE_FILESET = {
+ "Roboto-Thin.ttf",
+ "Roboto-ThinItalic.ttf"
+ };
+
+ // thin, light, and black styles are part of the same family but a Roboto "condensed"
+ // or Roboto "slab" would be considered part of a different family. Since the legacy
+ // format would already consider these as a different family, we just have to make sure
+ // they don't get brought back into a common family like thin/light/black
+ private static final String[] VALID_RELATED_FAMILY_NAMESET = {
+ "sans-serif-condensed"
+ };
+
+ private static final String[] VALID_RELATED_FAMILY_FILESET = {
+ "RobotoCondensed-Regular.ttf",
+ "RobotoCondensed-Bold.ttf",
+ "RobotoCondensed-Italic.ttf",
+ "RobotoCondensed-BoldItalic.ttf"
+ };
+
+ // Some typefaces will only have one style.
+ private static final String[] VALID_SINGLE_STYLE_FAMIlY_NAMESET = {
+ "monospace"
+ };
+ private static final String[] VALID_SINGLE_STYLE_FAMIlY_FILESET = {
+ "DroidSansMono.ttf"
+ };
+
+ final String VALID_PATH = "/valid/path/";
+
+ private Family sValidFamily; // eg "sans-serif"
+ private Family sValidAdditionalStyleFamily; // eg "sans-serif-light"
+ private Family sValidRelatedFamily; // eg "sans-serif-condensed"
+ private Family mValidSingleStyleFamily; // eg "monospace" which only uses DroidSansMono.ttf
+
+ protected void setUp() {
+ sValidFamily = new Family();
+ sValidFamily.nameset = new ArrayList<String>(Arrays.asList(VALID_NAMESET));
+ sValidFamily.fileset = new ArrayList<String>(Arrays.asList(VALID_FILESET));
+
+ sValidAdditionalStyleFamily = new Family();
+ sValidAdditionalStyleFamily.nameset =
+ new ArrayList<String>(Arrays.asList(VALID_ADDITIONAL_STYLE_NAMESET));
+ sValidAdditionalStyleFamily.fileset =
+ new ArrayList<String>(Arrays.asList(VALID_ADDITIONAL_STYLE_FILESET));
+
+ sValidRelatedFamily = new Family();
+ sValidRelatedFamily.nameset =
+ new ArrayList<String>(Arrays.asList(VALID_RELATED_FAMILY_NAMESET));
+ sValidRelatedFamily.fileset =
+ new ArrayList<String>(Arrays.asList(VALID_RELATED_FAMILY_FILESET));
+
+ mValidSingleStyleFamily = new Family();
+ }
+
+ @SmallTest
+ public void testValidAdaptedFamilyShouldHaveNameOfNamesetsFirstElement() {
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ FontListParser.Family convertedFamily = adapter.convertFamily(sValidFamily);
+ assertEquals(VALID_NAMESET[0], convertedFamily.name);
+ }
+
+ @SmallTest
+ public void testValidAdaptedFamilyShouldHaveFonts() {
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ FontListParser.Family convertedFamily = adapter.convertFamily(sValidFamily);
+ List<FontListParser.Font> fonts = convertedFamily.fonts;
+ assertEquals(VALID_FILESET.length, fonts.size());
+ }
+
+ @SmallTest
+ public void testValidAdaptedFontsShouldHaveCorrectProperties() {
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ List<FontListParser.Font> fonts = adapter.convertFonts(Arrays.asList(VALID_FILESET));
+
+ assertEquals(VALID_FILESET.length, fonts.size());
+ for(int i=0; i < fonts.size(); i++) {
+ FontListParser.Font font = fonts.get(i);
+ assertEquals(VALID_PATH + VALID_FILESET[i], font.fontName);
+ assertEquals("shouldBeItalic", shouldBeItalic(i), font.isItalic);
+ assertEquals(FontListConverter.WEIGHTS[i], font.weight);
+ }
+ }
+
+ @SmallTest
+ public void testExtraNamesetsShouldConvertToAliases() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily);
+
+ FontListConverter adapter = new FontListConverter(sValidFamily, VALID_PATH);
+ List<FontListParser.Alias> aliases = adapter.createAliases();
+
+ // Be sure the aliases point to the first name in the nameset
+ for(int i = 0; i < aliases.size(); i++) {
+ FontListParser.Alias alias = aliases.get(i);
+ assertEquals(VALID_NAMESET[0], alias.toName);
+ }
+
+ // Be sure the extra namesets are in the alias list
+ for(int i = 1; i < VALID_NAMESET.length; i++) {
+ assertTrue("hasAliasWithName", hasAliasWithName(aliases, VALID_NAMESET[i]));
+ }
+ }
+
+ /**
+ * The legacy format treats thin, light, and black fonts to be different families
+ * The new format treats these as all part of the original
+ * eg sans-serif and sans-serif-thin become one family
+ */
+ @SmallTest
+ public void testAdditionalStylesShouldConvertToSameFamily() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily); //eg "sans-serif"
+ families.add(sValidAdditionalStyleFamily); //eg "sans-serif-light"
+
+ FontListConverter adapter = new FontListConverter(families, VALID_PATH);
+ List<FontListParser.Family> convertedFamilies = adapter.convertFamilies();
+
+ // We started with two similiar families, and now should have one
+ assertEquals(1, convertedFamilies.size());
+
+ // The name of the family should be the base name, no style modifiers
+ // ie "sans-serif" not "sans-serif-light"
+ FontListParser.Family convertedFamily = convertedFamilies.get(0);
+ assertEquals(sValidFamily.nameset.get(0), convertedFamily.name);
+
+ // Verify all the fonts from both families exist now in the converted Family
+ List<String> combinedFileSet = new ArrayList<String>();
+ combinedFileSet.addAll(sValidFamily.fileset);
+ combinedFileSet.addAll(sValidAdditionalStyleFamily.fileset);
+ for(String filename : combinedFileSet) {
+ String fontName = VALID_PATH + filename;
+ assertTrue("hasFontWithName", hasFontWithName(convertedFamily, fontName));
+ }
+ }
+
+ /**
+ * When two families combine, the "varied" family (ie light, light, black) should
+ * have their namesets converted to aliases.
+ * IE sans-serif-light should point to sans-serif because the light family
+ * gets merged to sans-serif
+ */
+ @SmallTest
+ public void testAdditionalStylesNamesShouldBecomeAliases() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily); //eg "sans-serif"
+ families.add(sValidAdditionalStyleFamily); //eg "sans-serif-light"
+
+ FontListConverter adapter = new FontListConverter(families, VALID_PATH);
+ List<Alias> aliases = adapter.createAliases();
+
+ // Subtract 1 from the total length since VALID_NAMESET[0] will be the family name
+ int expectedSize = VALID_NAMESET.length + VALID_ADDITIONAL_STYLE_NAMESET.length - 1;
+ assertEquals(expectedSize, aliases.size());
+
+ // All aliases should point at the base family
+ for(Alias alias : aliases) {
+ assertEquals(VALID_NAMESET[0], alias.toName);
+ }
+
+ // There should be an alias for every name in the merged in family
+ for(String name : VALID_ADDITIONAL_STYLE_NAMESET) {
+ assertTrue("hasAliasWithName", hasAliasWithName(aliases, name));
+ }
+ }
+
+ /**
+ * sans-serif-condensed should not get merged in with sans-serif
+ */
+ @SmallTest
+ public void testSimiliarFontsShouldKeepSameFamily() {
+ List<Family> families = new ArrayList<Family>();
+ families.add(sValidFamily); //eg "sans-serif"
+ families.add(sValidRelatedFamily); //eg "sans-serif-condensed"
+
+ FontListConverter adapter = new FontListConverter(families, VALID_PATH);
+ List<FontListParser.Family> convertedFamilies = adapter.convertFamilies();
+ FontListParser.Family convertedValidFamily =
+ getFontListFamilyWithName(convertedFamilies, VALID_NAMESET[0]);
+ FontListParser.Family convertedRelatedFamily =
+ getFontListFamilyWithName(convertedFamilies, VALID_RELATED_FAMILY_NAMESET[0]);
+
+
+ // Valid family should only have its own fonts. Will fail if these were merged
+ for(String filename : sValidFamily.fileset) {
+ String fontName = VALID_PATH + filename;
+ assertTrue("hasFontWithName", hasFontWithName(convertedValidFamily, fontName));
+ assertFalse("hasFontWIthName", hasFontWithName(convertedRelatedFamily, fontName));
+ }
+
+ // Related family should also only have have its own fonts. Will fail if these were merged
+ for(String filename : sValidRelatedFamily.fileset) {
+ String fontName = VALID_PATH + filename;
+ assertTrue("hasFontWithName", hasFontWithName(convertedRelatedFamily, fontName));
+ assertFalse("hasFontWIthName", hasFontWithName(convertedValidFamily, fontName));
+ }
+ }
+
+ private static boolean hasAliasWithName(List<Alias> aliases, String name) {
+ for (Alias alias : aliases) if (name.equals(alias.name)) return true;
+ return false;
+ }
+
+ private static boolean hasFontWithName(FontListParser.Family family, String name) {
+ for (FontListParser.Font font : family.fonts) {
+ if(font.fontName != null && font.fontName.equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static FontListParser.Family getFontListFamilyWithName(
+ List<FontListParser.Family> families, String name) {
+ for(FontListParser.Family family : families) {
+ if (name.equals(family.name)) return family;
+ }
+ return null;
+ }
+
+ private boolean shouldBeItalic(int index) {
+ // Since the fileset format is regular, bold, italic, bolditalic, anything >= 2 is italic
+ return index >= 2;
+ }
+}
diff --git a/graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java b/graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java
new file mode 100644
index 0000000..9ef8421
--- /dev/null
+++ b/graphics/tests/localtests/src/android/graphics/TypefaceTestSuite.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import junit.framework.TestSuite;
+
+public class TypefaceTestSuite {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(TypefaceTestSuite.class.getName());
+ suite.addTestSuite(FontListConverterTest.class);
+ return suite;
+ }
+}