/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.graphics;

import android.graphics.fonts.FontVariationAxis;
import android.text.FontConfig;
import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

Parser for font config files.
@hide
/** * Parser for font config files. * * @hide */
public class FontListParser { /* Parse fallback list (no names) */ public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException { try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, null); parser.nextTag(); return readFamilies(parser); } finally { in.close(); } } private static FontConfig readFamilies(XmlPullParser parser) throws XmlPullParserException, IOException { List<FontConfig.Family> families = new ArrayList<>(); List<FontConfig.Alias> aliases = new ArrayList<>(); parser.require(XmlPullParser.START_TAG, null, "familyset"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) continue; String tag = parser.getName(); if (tag.equals("family")) { families.add(readFamily(parser)); } else if (tag.equals("alias")) { aliases.add(readAlias(parser)); } else { skip(parser); } } return new FontConfig(families.toArray(new FontConfig.Family[families.size()]), aliases.toArray(new FontConfig.Alias[aliases.size()])); } private static FontConfig.Family readFamily(XmlPullParser parser) throws XmlPullParserException, IOException { final String name = parser.getAttributeValue(null, "name"); final String lang = parser.getAttributeValue(null, "lang"); final String[] langs = lang == null ? null : lang.split("\\s+"); final String variant = parser.getAttributeValue(null, "variant"); final List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>(); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) continue; final String tag = parser.getName(); if (tag.equals("font")) { fonts.add(readFont(parser)); } else { skip(parser); } } int intVariant = FontConfig.Family.VARIANT_DEFAULT; if (variant != null) { if (variant.equals("compact")) { intVariant = FontConfig.Family.VARIANT_COMPACT; } else if (variant.equals("elegant")) { intVariant = FontConfig.Family.VARIANT_ELEGANT; } } return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), langs, intVariant); }
Matches leading and trailing XML whitespace.
/** Matches leading and trailing XML whitespace. */
private static final Pattern FILENAME_WHITESPACE_PATTERN = Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$"); private static FontConfig.Font readFont(XmlPullParser parser) throws XmlPullParserException, IOException { String indexStr = parser.getAttributeValue(null, "index"); int index = indexStr == null ? 0 : Integer.parseInt(indexStr); List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>(); String weightStr = parser.getAttributeValue(null, "weight"); int weight = weightStr == null ? 400 : Integer.parseInt(weightStr); boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style")); String fallbackFor = parser.getAttributeValue(null, "fallbackFor"); StringBuilder filename = new StringBuilder(); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() == XmlPullParser.TEXT) { filename.append(parser.getText()); } if (parser.getEventType() != XmlPullParser.START_TAG) continue; String tag = parser.getName(); if (tag.equals("axis")) { axes.add(readAxis(parser)); } else { skip(parser); } } String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); return new FontConfig.Font(sanitizedName, index, axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor); } private static FontVariationAxis readAxis(XmlPullParser parser) throws XmlPullParserException, IOException { String tagStr = parser.getAttributeValue(null, "tag"); String styleValueStr = parser.getAttributeValue(null, "stylevalue"); skip(parser); // axis tag is empty, ignore any contents and consume end tag return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr)); } private static FontConfig.Alias readAlias(XmlPullParser parser) throws XmlPullParserException, IOException { String name = parser.getAttributeValue(null, "name"); String toName = parser.getAttributeValue(null, "to"); String weightStr = parser.getAttributeValue(null, "weight"); int weight; if (weightStr == null) { weight = 400; } else { weight = Integer.parseInt(weightStr); } skip(parser); // alias tag is empty, ignore any contents and consume end tag return new FontConfig.Alias(name, toName, weight); } private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException { int depth = 1; while (depth > 0) { switch (parser.next()) { case XmlPullParser.START_TAG: depth++; break; case XmlPullParser.END_TAG: depth--; break; } } } }