1 /*
2  * Copyright (C) 2018 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.fonts;
18 
19 import android.annotation.NonNull;
20 import android.graphics.FontListParser;
21 import android.text.FontConfig;
22 import android.util.Xml;
23 
24 import org.xmlpull.v1.XmlPullParser;
25 import org.xmlpull.v1.XmlPullParserException;
26 
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.util.ArrayList;
30 import java.util.HashSet;
31 
32 /**
33  * Parser for font customization
34  *
35  * @hide
36  */
37 public class FontCustomizationParser {
38     /**
39      * Represents a customization XML
40      */
41     public static class Result {
42         ArrayList<FontConfig.Family> mAdditionalNamedFamilies = new ArrayList<>();
43         ArrayList<FontConfig.Alias> mAdditionalAliases = new ArrayList<>();
44     }
45 
46     /**
47      * Parses the customization XML
48      *
49      * Caller must close the input stream
50      */
parse(@onNull InputStream in, @NonNull String fontDir)51     public static Result parse(@NonNull InputStream in, @NonNull String fontDir)
52             throws XmlPullParserException, IOException {
53         XmlPullParser parser = Xml.newPullParser();
54         parser.setInput(in, null);
55         parser.nextTag();
56         return readFamilies(parser, fontDir);
57     }
58 
validate(Result result)59     private static void validate(Result result) {
60         HashSet<String> familyNames = new HashSet<>();
61         for (int i = 0; i < result.mAdditionalNamedFamilies.size(); ++i) {
62             final FontConfig.Family family = result.mAdditionalNamedFamilies.get(i);
63             final String name = family.getName();
64             if (name == null) {
65                 throw new IllegalArgumentException("new-named-family requires name attribute");
66             }
67             if (!familyNames.add(name)) {
68                 throw new IllegalArgumentException(
69                         "new-named-family requires unique name attribute");
70             }
71         }
72     }
73 
readFamilies(XmlPullParser parser, String fontDir)74     private static Result readFamilies(XmlPullParser parser, String fontDir)
75             throws XmlPullParserException, IOException {
76         Result out = new Result();
77         parser.require(XmlPullParser.START_TAG, null, "fonts-modification");
78         while (parser.next() != XmlPullParser.END_TAG) {
79             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
80             String tag = parser.getName();
81             if (tag.equals("family")) {
82                 readFamily(parser, fontDir, out);
83             } else if (tag.equals("alias")) {
84                 out.mAdditionalAliases.add(FontListParser.readAlias(parser));
85             } else {
86                 FontListParser.skip(parser);
87             }
88         }
89         validate(out);
90         return out;
91     }
92 
readFamily(XmlPullParser parser, String fontDir, Result out)93     private static void readFamily(XmlPullParser parser, String fontDir, Result out)
94             throws XmlPullParserException, IOException {
95         final String customizationType = parser.getAttributeValue(null, "customizationType");
96         if (customizationType == null) {
97             throw new IllegalArgumentException("customizationType must be specified");
98         }
99         if (customizationType.equals("new-named-family")) {
100             out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir));
101         } else {
102             throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
103         }
104     }
105 }
106