1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package android.graphics;
18
19import android.util.Xml;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
24import java.io.IOException;
25import java.io.InputStream;
26import java.util.ArrayList;
27import java.util.List;
28
29/**
30 * Parser for font config files.
31 *
32 * @hide
33 */
34public class FontListParser {
35
36    public static class Config {
37        Config() {
38            families = new ArrayList<Family>();
39            aliases = new ArrayList<Alias>();
40        }
41        public List<Family> families;
42        public List<Alias> aliases;
43    }
44
45    public static class Font {
46        Font(String fontName, int weight, boolean isItalic) {
47            this.fontName = fontName;
48            this.weight = weight;
49            this.isItalic = isItalic;
50        }
51        public String fontName;
52        public int weight;
53        public boolean isItalic;
54    }
55
56    public static class Alias {
57        public String name;
58        public String toName;
59        public int weight;
60    }
61
62    public static class Family {
63        public Family(String name, List<Font> fonts, String lang, String variant) {
64            this.name = name;
65            this.fonts = fonts;
66            this.lang = lang;
67            this.variant = variant;
68        }
69
70        public String name;
71        public List<Font> fonts;
72        public String lang;
73        public String variant;
74    }
75
76    /* Parse fallback list (no names) */
77    public static Config parse(InputStream in) throws XmlPullParserException, IOException {
78        try {
79            XmlPullParser parser = Xml.newPullParser();
80            parser.setInput(in, null);
81            parser.nextTag();
82            return readFamilies(parser);
83        } finally {
84            in.close();
85        }
86    }
87
88    private static Config readFamilies(XmlPullParser parser)
89            throws XmlPullParserException, IOException {
90        Config config = new Config();
91        parser.require(XmlPullParser.START_TAG, null, "familyset");
92        while (parser.next() != XmlPullParser.END_TAG) {
93            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
94            if (parser.getName().equals("family")) {
95                config.families.add(readFamily(parser));
96            } else if (parser.getName().equals("alias")) {
97                config.aliases.add(readAlias(parser));
98            } else {
99                skip(parser);
100            }
101        }
102        return config;
103    }
104
105    private static Family readFamily(XmlPullParser parser)
106            throws XmlPullParserException, IOException {
107        String name = parser.getAttributeValue(null, "name");
108        String lang = parser.getAttributeValue(null, "lang");
109        String variant = parser.getAttributeValue(null, "variant");
110        List<Font> fonts = new ArrayList<Font>();
111        while (parser.next() != XmlPullParser.END_TAG) {
112            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
113            String tag = parser.getName();
114            if (tag.equals("font")) {
115                String weightStr = parser.getAttributeValue(null, "weight");
116                int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
117                boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
118                String filename = parser.nextText();
119                String fullFilename = "/system/fonts/" + filename;
120                fonts.add(new Font(fullFilename, weight, isItalic));
121            } else {
122                skip(parser);
123            }
124        }
125        return new Family(name, fonts, lang, variant);
126    }
127
128    private static Alias readAlias(XmlPullParser parser)
129            throws XmlPullParserException, IOException {
130        Alias alias = new Alias();
131        alias.name = parser.getAttributeValue(null, "name");
132        alias.toName = parser.getAttributeValue(null, "to");
133        String weightStr = parser.getAttributeValue(null, "weight");
134        if (weightStr == null) {
135            alias.weight = 400;
136        } else {
137            alias.weight = Integer.parseInt(weightStr);
138        }
139        skip(parser);  // alias tag is empty, ignore any contents and consume end tag
140        return alias;
141    }
142
143    private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
144        int depth = 1;
145        while (depth > 0) {
146            switch (parser.next()) {
147            case XmlPullParser.START_TAG:
148                depth++;
149                break;
150            case XmlPullParser.END_TAG:
151                depth--;
152                break;
153            }
154        }
155    }
156}
157