• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.text.FontConfig.Alias;
20 import static android.text.FontConfig.FontFamily;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.graphics.FontListParser;
25 import android.util.Xml;
26 
27 import org.xmlpull.v1.XmlPullParser;
28 import org.xmlpull.v1.XmlPullParserException;
29 
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 
39 /**
40  * Parser for font customization
41  *
42  * @hide
43  */
44 public class FontCustomizationParser {
45     /**
46      * Represents a customization XML
47      */
48     public static class Result {
49         private final Map<String, FontFamily> mAdditionalNamedFamilies;
50         private final List<Alias> mAdditionalAliases;
51 
Result()52         public Result() {
53             mAdditionalNamedFamilies = Collections.emptyMap();
54             mAdditionalAliases = Collections.emptyList();
55         }
56 
Result(Map<String, FontFamily> additionalNamedFamilies, List<Alias> additionalAliases)57         public Result(Map<String, FontFamily> additionalNamedFamilies,
58                 List<Alias> additionalAliases) {
59             mAdditionalNamedFamilies = additionalNamedFamilies;
60             mAdditionalAliases = additionalAliases;
61         }
62 
getAdditionalNamedFamilies()63         public Map<String, FontFamily> getAdditionalNamedFamilies() {
64             return mAdditionalNamedFamilies;
65         }
66 
getAdditionalAliases()67         public List<Alias> getAdditionalAliases() {
68             return mAdditionalAliases;
69         }
70     }
71 
72     /**
73      * Parses the customization XML
74      *
75      * Caller must close the input stream
76      */
parse( @onNull InputStream in, @NonNull String fontDir, @Nullable Map<String, File> updatableFontMap )77     public static Result parse(
78             @NonNull InputStream in,
79             @NonNull String fontDir,
80             @Nullable Map<String, File> updatableFontMap
81     ) throws XmlPullParserException, IOException {
82         XmlPullParser parser = Xml.newPullParser();
83         parser.setInput(in, null);
84         parser.nextTag();
85         return readFamilies(parser, fontDir, updatableFontMap);
86     }
87 
validateAndTransformToMap(List<FontFamily> families)88     private static Map<String, FontFamily> validateAndTransformToMap(List<FontFamily> families) {
89         HashMap<String, FontFamily> namedFamily = new HashMap<>();
90         for (int i = 0; i < families.size(); ++i) {
91             final FontFamily family = families.get(i);
92             final String name = family.getName();
93             if (name == null) {
94                 throw new IllegalArgumentException("new-named-family requires name attribute");
95             }
96             if (namedFamily.put(name, family) != null) {
97                 throw new IllegalArgumentException(
98                         "new-named-family requires unique name attribute");
99             }
100         }
101         return namedFamily;
102     }
103 
readFamilies( @onNull XmlPullParser parser, @NonNull String fontDir, @Nullable Map<String, File> updatableFontMap )104     private static Result readFamilies(
105             @NonNull XmlPullParser parser,
106             @NonNull String fontDir,
107             @Nullable Map<String, File> updatableFontMap
108     ) throws XmlPullParserException, IOException {
109         List<FontFamily> families = new ArrayList<>();
110         List<Alias> aliases = new ArrayList<>();
111         parser.require(XmlPullParser.START_TAG, null, "fonts-modification");
112         while (parser.next() != XmlPullParser.END_TAG) {
113             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
114             String tag = parser.getName();
115             if (tag.equals("family")) {
116                 readFamily(parser, fontDir, families, updatableFontMap);
117             } else if (tag.equals("alias")) {
118                 aliases.add(FontListParser.readAlias(parser));
119             } else {
120                 FontListParser.skip(parser);
121             }
122         }
123         return new Result(validateAndTransformToMap(families), aliases);
124     }
125 
readFamily( @onNull XmlPullParser parser, @NonNull String fontDir, @NonNull List<FontFamily> out, @Nullable Map<String, File> updatableFontMap)126     private static void readFamily(
127             @NonNull XmlPullParser parser,
128             @NonNull String fontDir,
129             @NonNull List<FontFamily> out,
130             @Nullable Map<String, File> updatableFontMap)
131             throws XmlPullParserException, IOException {
132         final String customizationType = parser.getAttributeValue(null, "customizationType");
133         if (customizationType == null) {
134             throw new IllegalArgumentException("customizationType must be specified");
135         }
136         if (customizationType.equals("new-named-family")) {
137             FontFamily fontFamily = FontListParser.readFamily(
138                     parser, fontDir, updatableFontMap, false);
139             if (fontFamily != null) {
140                 out.add(fontFamily);
141             }
142         } else {
143             throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
144         }
145     }
146 }
147