Home | History | Annotate | Download | only in graphics
      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 
     17 package android.graphics;
     18 
     19 import android.graphics.fonts.FontVariationAxis;
     20 import android.text.FontConfig;
     21 import android.util.Xml;
     22 
     23 import org.xmlpull.v1.XmlPullParser;
     24 import org.xmlpull.v1.XmlPullParserException;
     25 
     26 import java.io.IOException;
     27 import java.io.InputStream;
     28 import java.util.ArrayList;
     29 import java.util.List;
     30 import java.util.regex.Pattern;
     31 
     32 /**
     33  * Parser for font config files.
     34  *
     35  * @hide
     36  */
     37 public class FontListParser {
     38 
     39     /* Parse fallback list (no names) */
     40     public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
     41         try {
     42             XmlPullParser parser = Xml.newPullParser();
     43             parser.setInput(in, null);
     44             parser.nextTag();
     45             return readFamilies(parser);
     46         } finally {
     47             in.close();
     48         }
     49     }
     50 
     51     private static FontConfig readFamilies(XmlPullParser parser)
     52             throws XmlPullParserException, IOException {
     53         List<FontConfig.Family> families = new ArrayList<>();
     54         List<FontConfig.Alias> aliases = new ArrayList<>();
     55 
     56         parser.require(XmlPullParser.START_TAG, null, "familyset");
     57         while (parser.next() != XmlPullParser.END_TAG) {
     58             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
     59             String tag = parser.getName();
     60             if (tag.equals("family")) {
     61                 families.add(readFamily(parser));
     62             } else if (tag.equals("alias")) {
     63                 aliases.add(readAlias(parser));
     64             } else {
     65                 skip(parser);
     66             }
     67         }
     68         return new FontConfig(families.toArray(new FontConfig.Family[families.size()]),
     69                 aliases.toArray(new FontConfig.Alias[aliases.size()]));
     70     }
     71 
     72     private static FontConfig.Family readFamily(XmlPullParser parser)
     73             throws XmlPullParserException, IOException {
     74         final String name = parser.getAttributeValue(null, "name");
     75         final String lang = parser.getAttributeValue(null, "lang");
     76         final String[] langs = lang == null ? null : lang.split("\\s+");
     77         final String variant = parser.getAttributeValue(null, "variant");
     78         final List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
     79         while (parser.next() != XmlPullParser.END_TAG) {
     80             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
     81             final String tag = parser.getName();
     82             if (tag.equals("font")) {
     83                 fonts.add(readFont(parser));
     84             } else {
     85                 skip(parser);
     86             }
     87         }
     88         int intVariant = FontConfig.Family.VARIANT_DEFAULT;
     89         if (variant != null) {
     90             if (variant.equals("compact")) {
     91                 intVariant = FontConfig.Family.VARIANT_COMPACT;
     92             } else if (variant.equals("elegant")) {
     93                 intVariant = FontConfig.Family.VARIANT_ELEGANT;
     94             }
     95         }
     96         return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), langs,
     97                 intVariant);
     98     }
     99 
    100     /** Matches leading and trailing XML whitespace. */
    101     private static final Pattern FILENAME_WHITESPACE_PATTERN =
    102             Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
    103 
    104     private static FontConfig.Font readFont(XmlPullParser parser)
    105             throws XmlPullParserException, IOException {
    106         String indexStr = parser.getAttributeValue(null, "index");
    107         int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
    108         List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
    109         String weightStr = parser.getAttributeValue(null, "weight");
    110         int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
    111         boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
    112         String fallbackFor = parser.getAttributeValue(null, "fallbackFor");
    113         StringBuilder filename = new StringBuilder();
    114         while (parser.next() != XmlPullParser.END_TAG) {
    115             if (parser.getEventType() == XmlPullParser.TEXT) {
    116                 filename.append(parser.getText());
    117             }
    118             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
    119             String tag = parser.getName();
    120             if (tag.equals("axis")) {
    121                 axes.add(readAxis(parser));
    122             } else {
    123                 skip(parser);
    124             }
    125         }
    126         String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
    127         return new FontConfig.Font(sanitizedName, index,
    128                 axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
    129     }
    130 
    131     private static FontVariationAxis readAxis(XmlPullParser parser)
    132             throws XmlPullParserException, IOException {
    133         String tagStr = parser.getAttributeValue(null, "tag");
    134         String styleValueStr = parser.getAttributeValue(null, "stylevalue");
    135         skip(parser);  // axis tag is empty, ignore any contents and consume end tag
    136         return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr));
    137     }
    138 
    139     private static FontConfig.Alias readAlias(XmlPullParser parser)
    140             throws XmlPullParserException, IOException {
    141         String name = parser.getAttributeValue(null, "name");
    142         String toName = parser.getAttributeValue(null, "to");
    143         String weightStr = parser.getAttributeValue(null, "weight");
    144         int weight;
    145         if (weightStr == null) {
    146             weight = 400;
    147         } else {
    148             weight = Integer.parseInt(weightStr);
    149         }
    150         skip(parser);  // alias tag is empty, ignore any contents and consume end tag
    151         return new FontConfig.Alias(name, toName, weight);
    152     }
    153 
    154     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
    155         int depth = 1;
    156         while (depth > 0) {
    157             switch (parser.next()) {
    158             case XmlPullParser.START_TAG:
    159                 depth++;
    160                 break;
    161             case XmlPullParser.END_TAG:
    162                 depth--;
    163                 break;
    164             }
    165         }
    166     }
    167 }
    168