2 * Copyright (C) 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.graphics;
19 import android.text.FontConfig;
20 import android.graphics.fonts.FontVariationAxis;
21 import android.util.Xml;
23 import org.xmlpull.v1.XmlPullParser;
24 import org.xmlpull.v1.XmlPullParserException;
26 import android.annotation.Nullable;
27 import com.android.internal.annotations.VisibleForTesting;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.regex.Pattern;
36 * Parser for font config files.
40 public class FontListParser {
42 /* Parse fallback list (no names) */
43 public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
45 XmlPullParser parser = Xml.newPullParser();
46 parser.setInput(in, null);
48 return readFamilies(parser);
54 private static FontConfig readFamilies(XmlPullParser parser)
55 throws XmlPullParserException, IOException {
56 List<FontConfig.Family> families = new ArrayList<>();
57 List<FontConfig.Alias> aliases = new ArrayList<>();
59 parser.require(XmlPullParser.START_TAG, null, "familyset");
60 while (parser.next() != XmlPullParser.END_TAG) {
61 if (parser.getEventType() != XmlPullParser.START_TAG) continue;
62 String tag = parser.getName();
63 if (tag.equals("family")) {
64 families.add(readFamily(parser));
65 } else if (tag.equals("alias")) {
66 aliases.add(readAlias(parser));
71 return new FontConfig(families.toArray(new FontConfig.Family[families.size()]),
72 aliases.toArray(new FontConfig.Alias[aliases.size()]));
75 private static FontConfig.Family readFamily(XmlPullParser parser)
76 throws XmlPullParserException, IOException {
77 String name = parser.getAttributeValue(null, "name");
78 String lang = parser.getAttributeValue(null, "lang");
79 String variant = parser.getAttributeValue(null, "variant");
80 List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
81 while (parser.next() != XmlPullParser.END_TAG) {
82 if (parser.getEventType() != XmlPullParser.START_TAG) continue;
83 String tag = parser.getName();
84 if (tag.equals("font")) {
85 fonts.add(readFont(parser));
90 int intVariant = FontConfig.Family.VARIANT_DEFAULT;
91 if (variant != null) {
92 if (variant.equals("compact")) {
93 intVariant = FontConfig.Family.VARIANT_COMPACT;
94 } else if (variant.equals("elegant")) {
95 intVariant = FontConfig.Family.VARIANT_ELEGANT;
98 return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), lang,
102 /** Matches leading and trailing XML whitespace. */
103 private static final Pattern FILENAME_WHITESPACE_PATTERN =
104 Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
106 private static FontConfig.Font readFont(XmlPullParser parser)
107 throws XmlPullParserException, IOException {
108 String indexStr = parser.getAttributeValue(null, "index");
109 int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
110 List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
111 String weightStr = parser.getAttributeValue(null, "weight");
112 int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
113 boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
114 StringBuilder filename = new StringBuilder();
115 while (parser.next() != XmlPullParser.END_TAG) {
116 if (parser.getEventType() == XmlPullParser.TEXT) {
117 filename.append(parser.getText());
119 if (parser.getEventType() != XmlPullParser.START_TAG) continue;
120 String tag = parser.getName();
121 if (tag.equals("axis")) {
122 axes.add(readAxis(parser));
127 String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
128 return new FontConfig.Font(sanitizedName, index,
129 axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic);
132 private static FontVariationAxis readAxis(XmlPullParser parser)
133 throws XmlPullParserException, IOException {
134 String tagStr = parser.getAttributeValue(null, "tag");
135 String styleValueStr = parser.getAttributeValue(null, "stylevalue");
136 skip(parser); // axis tag is empty, ignore any contents and consume end tag
137 return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr));
140 private static FontConfig.Alias readAlias(XmlPullParser parser)
141 throws XmlPullParserException, IOException {
142 String name = parser.getAttributeValue(null, "name");
143 String toName = parser.getAttributeValue(null, "to");
144 String weightStr = parser.getAttributeValue(null, "weight");
146 if (weightStr == null) {
149 weight = Integer.parseInt(weightStr);
151 skip(parser); // alias tag is empty, ignore any contents and consume end tag
152 return new FontConfig.Alias(name, toName, weight);
155 private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
158 switch (parser.next()) {
159 case XmlPullParser.START_TAG:
162 case XmlPullParser.END_TAG: