Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 178006a0 authored by Xavier Ducrohet's avatar Xavier Ducrohet
Browse files

Layoutlib now parses system_fonts.xml instead of its own.

Also parse fallback_fonts.
This lets layoutlib automatically use the same fonts as the base
platforms, for instance it now uses the new ICS fonts.

Change-Id: Id6e778dc0e3f2a9112601e0eaf8499a9713ec433
parent 3c1951c4
Loading
Loading
Loading
Loading

data/fonts/fonts.xml

deleted100644 → 0
+0 −48
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<!--
	This is only used by the layoutlib to display
	layouts in ADT.
-->
<fonts>
    <font ttf="DroidSans">
        <name>sans-serif</name>
        <name>arial</name>
        <name>helvetica</name>
        <name>tahoma</name>
        <name>verdana</name>
    </font>
   <font ttf="DroidSerif">
        <name>serif</name>
        <name>times</name>
        <name>times new roman</name>
        <name>palatino</name>
        <name>georgia</name>
        <name>baskerville</name>
        <name>goudy</name>
        <name>fantasy</name>
        <name>cursive</name>
        <name>ITC Stone Serif</name>
    </font>
    <font ttf="DroidSansMono">
        <name>monospace</name>
        <name>courier</name>
        <name>courier new</name>
        <name>monaco</name>
    </font>
    <fallback ttf="DroidSansFallback" />
    <fallback ttf="MTLmr3m" />
</fonts>
+1 −11
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.content.res.AssetManager;

import java.awt.Font;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
@@ -50,7 +49,6 @@ public final class Typeface_Delegate {

    // ---- delegate helper data ----
    private static final String DEFAULT_FAMILY = "sans-serif";
    private static final int[] STYLE_BUFFER = new int[1];

    private static FontLoader sFontLoader;
    private static final List<Typeface_Delegate> sPostInitDelegate =
@@ -178,14 +176,6 @@ public final class Typeface_Delegate {
    }

    private void init() {
        STYLE_BUFFER[0] = mStyle;
        Font font = sFontLoader.getFont(mFamily, STYLE_BUFFER);
        if (font != null) {
            List<Font> list = new ArrayList<Font>();
            list.add(font);
            list.addAll(sFontLoader.getFallBackFonts());
            mFonts = Collections.unmodifiableList(list);
            mStyle = STYLE_BUFFER[0];
        }
        mFonts = sFontLoader.getFont(mFamily, mStyle);
    }
}
+134 −168
Original line number Diff line number Diff line
@@ -23,17 +23,13 @@ import org.xml.sax.helpers.DefaultHandler;
import android.graphics.Typeface;

import java.awt.Font;
import java.awt.FontFormatException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;
@@ -47,49 +43,53 @@ import javax.xml.parsers.SAXParserFactory;
 * fonts.xml file located alongside the ttf files.
 */
public final class FontLoader {
    private static final String FONTS_DEFINITIONS = "fonts.xml";
    private static final String FONTS_SYSTEM = "system_fonts.xml";
    private static final String FONTS_VENDOR = "vendor_fonts.xml";
    private static final String FONTS_FALLBACK = "fallback_fonts.xml";

    private static final String NODE_FONTS = "fonts";
    private static final String NODE_FONT = "font";
    private static final String NODE_FAMILYSET = "familyset";
    private static final String NODE_FAMILY = "family";
    private static final String NODE_NAME = "name";
    private static final String NODE_FALLBACK = "fallback";

    private static final String ATTR_TTF = "ttf";

    private static final String FONT_EXT = ".ttf";

    private static final String[] FONT_STYLE_DEFAULT = { "", "-Regular" };
    private static final String[] FONT_STYLE_BOLD = { "-Bold" };
    private static final String[] FONT_STYLE_ITALIC = { "-Italic" };
    private static final String[] FONT_STYLE_BOLDITALIC = { "-BoldItalic" };

    // list of font style, in the order matching the Typeface Font style
    private static final String[][] FONT_STYLES = {
        FONT_STYLE_DEFAULT,
        FONT_STYLE_BOLD,
        FONT_STYLE_ITALIC,
        FONT_STYLE_BOLDITALIC
    private static final String NODE_FILE = "file";

    private static final String FONT_SUFFIX_NONE = ".ttf";
    private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf";
    private static final String FONT_SUFFIX_BOLD = "-Bold.ttf";
    private static final String FONT_SUFFIX_ITALIC = "-Italic.ttf";
    private static final String FONT_SUFFIX_BOLDITALIC = "-BoldItalic.ttf";

    // This must match the values of Typeface styles so that we can use them for indices in this
    // array.
    private static final int[] AWT_STYLES = new int[] {
        Font.PLAIN,
        Font.BOLD,
        Font.ITALIC,
        Font.BOLD | Font.ITALIC
    };
    private static int[] DERIVE_BOLD_ITALIC = new int[] {
        Typeface.ITALIC, Typeface.BOLD, Typeface.NORMAL
    };
    private static int[] DERIVE_ITALIC = new int[] { Typeface.NORMAL };
    private static int[] DERIVE_BOLD = new int[] { Typeface.NORMAL };

    private final Map<String, String> mFamilyToTtf = new HashMap<String, String>();
    private final Map<String, Map<Integer, Font>> mTtfToFontMap =
        new HashMap<String, Map<Integer, Font>>();

    private List<Font> mFallBackFonts = null;
    private static final List<FontInfo> mMainFonts = new ArrayList<FontInfo>();
    private static final List<FontInfo> mFallbackFonts = new ArrayList<FontInfo>();

    public static FontLoader create(String fontOsLocation) {
        try {
            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
                parserFactory.setNamespaceAware(true);

            SAXParser parser = parserFactory.newSAXParser();
            File f = new File(fontOsLocation + File.separator + FONTS_DEFINITIONS);
            // parse the system fonts
            FontHandler handler = parseFontFile(parserFactory, fontOsLocation, FONTS_SYSTEM);
            List<FontInfo> systemFonts = handler.getFontList();

            FontDefinitionParser definitionParser = new FontDefinitionParser(
                    fontOsLocation + File.separator);
            parser.parse(new FileInputStream(f), definitionParser);

            return definitionParser.getFontLoader();
            // parse the fallback fonts
            handler = parseFontFile(parserFactory, fontOsLocation, FONTS_FALLBACK);
            List<FontInfo> fallbackFonts = handler.getFontList();

            return new FontLoader(systemFonts, fallbackFonts);
        } catch (ParserConfigurationException e) {
            // return null below
        } catch (SAXException e) {
@@ -103,35 +103,22 @@ public final class FontLoader {
        return null;
    }

    private FontLoader(List<FontInfo> fontList, List<String> fallBackList) {
        for (FontInfo info : fontList) {
            for (String family : info.families) {
                mFamilyToTtf.put(family, info.ttf);
            }
        }
    private static FontHandler parseFontFile(SAXParserFactory parserFactory,
            String fontOsLocation, String fontFileName)
            throws ParserConfigurationException, SAXException, IOException, FileNotFoundException {

        ArrayList<Font> list = new ArrayList<Font>();
        for (String path : fallBackList) {
            File f = new File(path + FONT_EXT);
            if (f.isFile()) {
                try {
                    Font font = Font.createFont(Font.TRUETYPE_FONT, f);
                    if (font != null) {
                        list.add(font);
                    }
                } catch (FontFormatException e) {
                    // skip this font name
                } catch (IOException e) {
                    // skip this font name
                }
            }
        }
        SAXParser parser = parserFactory.newSAXParser();
        File f = new File(fontOsLocation, fontFileName);

        mFallBackFonts = Collections.unmodifiableList(list);
        FontHandler definitionParser = new FontHandler(
                fontOsLocation + File.separator);
        parser.parse(new FileInputStream(f), definitionParser);
        return definitionParser;
    }

    public List<Font> getFallBackFonts() {
        return mFallBackFonts;
    private FontLoader(List<FontInfo> fontList, List<FontInfo> fallBackList) {
        mMainFonts.addAll(fontList);
        mFallbackFonts.addAll(fallBackList);
    }

    /**
@@ -143,96 +130,32 @@ public final class FontLoader {
     *              the method returns.
     * @return the font object or null if no match could be found.
     */
    public synchronized Font getFont(String family, int[] style) {
        if (family == null) {
            return null;
        }
    public synchronized List<Font> getFont(String family, int style) {
        List<Font> result = new ArrayList<Font>();

        // get the ttf name from the family
        String ttf = mFamilyToTtf.get(family);

        if (ttf == null) {
            return null;
        }

        // get the font from the ttf
        Map<Integer, Font> styleMap = mTtfToFontMap.get(ttf);

        if (styleMap == null) {
            styleMap = new HashMap<Integer, Font>();
            mTtfToFontMap.put(ttf, styleMap);
        if (family == null) {
            return result;
        }

        Font f = styleMap.get(style[0]);

        if (f != null) {
            return f;
        }

        // if it doesn't exist, we create it, and we can't, we try with a simpler style
        switch (style[0]) {
            case Typeface.NORMAL:
                f = getFont(ttf, FONT_STYLES[Typeface.NORMAL]);
        // get the font objects from the main list based on family.
        for (FontInfo info : mMainFonts) {
            if (info.families.contains(family)) {
                result.add(info.font[style]);
                break;
            case Typeface.BOLD:
            case Typeface.ITALIC:
                f = getFont(ttf, FONT_STYLES[style[0]]);
                if (f == null) {
                    f = getFont(ttf, FONT_STYLES[Typeface.NORMAL]);
                    style[0] = Typeface.NORMAL;
                }
                break;
            case Typeface.BOLD_ITALIC:
                f = getFont(ttf, FONT_STYLES[style[0]]);
                if (f == null) {
                    f = getFont(ttf, FONT_STYLES[Typeface.BOLD]);
                    if (f != null) {
                        style[0] = Typeface.BOLD;
                    } else {
                        f = getFont(ttf, FONT_STYLES[Typeface.ITALIC]);
                        if (f != null) {
                            style[0] = Typeface.ITALIC;
                        } else {
                            f = getFont(ttf, FONT_STYLES[Typeface.NORMAL]);
                            style[0] = Typeface.NORMAL;
                        }
            }
        }
                break;
        }

        if (f != null) {
            styleMap.put(style[0], f);
            return f;
        // add all the fallback fonts
        for (FontInfo info : mFallbackFonts) {
            result.add(info.font[style]);
        }

        return null;
    }

    private Font getFont(String ttf, String[] fontFileSuffix) {
        for (String suffix : fontFileSuffix) {
            String name = ttf + suffix + FONT_EXT;

            File f = new File(name);
            if (f.isFile()) {
                try {
                    Font font = Font.createFont(Font.TRUETYPE_FONT, f);
                    if (font != null) {
                        return font;
                    }
                } catch (FontFormatException e) {
                    // skip this font name
                } catch (IOException e) {
                    // skip this font name
                }
            }
        }

        return null;
        return result;
    }

    private final static class FontInfo {
        String ttf;
        final Font[] font = new Font[4]; // Matches the 4 type-face styles.
        final Set<String> families;

        FontInfo() {
@@ -240,21 +163,20 @@ public final class FontLoader {
        }
    }

    private final static class FontDefinitionParser extends DefaultHandler {
    private final static class FontHandler extends DefaultHandler {
        private final String mOsFontsLocation;

        private FontInfo mFontInfo = null;
        private final StringBuilder mBuilder = new StringBuilder();
        private List<FontInfo> mFontList;
        private List<String> mFallBackList;
        private List<FontInfo> mFontList = new ArrayList<FontInfo>();

        private FontDefinitionParser(String osFontsLocation) {
        private FontHandler(String osFontsLocation) {
            super();
            mOsFontsLocation = osFontsLocation;
        }

        FontLoader getFontLoader() {
            return new FontLoader(mFontList, mFallBackList);
        public List<FontInfo> getFontList() {
            return mFontList;
        }

        /* (non-Javadoc)
@@ -263,26 +185,11 @@ public final class FontLoader {
        @Override
        public void startElement(String uri, String localName, String name, Attributes attributes)
                throws SAXException {
            if (NODE_FONTS.equals(localName)) {
            if (NODE_FAMILYSET.equals(localName)) {
                mFontList = new ArrayList<FontInfo>();
                mFallBackList = new ArrayList<String>();
            } else if (NODE_FONT.equals(localName)) {
            } else if (NODE_FAMILY.equals(localName)) {
                if (mFontList != null) {
                    String ttf = attributes.getValue(ATTR_TTF);
                    if (ttf != null) {
                    mFontInfo = new FontInfo();
                        mFontInfo.ttf = mOsFontsLocation + ttf;
                        mFontList.add(mFontInfo);
                    }
                }
            } else if (NODE_NAME.equals(localName)) {
                // do nothing, we'll handle the name in the endElement
            } else if (NODE_FALLBACK.equals(localName)) {
                if (mFallBackList != null) {
                    String ttf = attributes.getValue(ATTR_TTF);
                    if (ttf != null) {
                        mFallBackList.add(mOsFontsLocation + ttf);
                    }
                }
            }

@@ -304,20 +211,79 @@ public final class FontLoader {
         */
        @Override
        public void endElement(String uri, String localName, String name) throws SAXException {
            if (NODE_FONTS.equals(localName)) {
                // top level, do nothing
            } else if (NODE_FONT.equals(localName)) {
            if (NODE_FAMILY.equals(localName)) {
                if (mFontInfo != null) {
                    // if has a normal font file, add to the list
                    if (mFontInfo.font[Typeface.NORMAL] != null) {
                        mFontList.add(mFontInfo);

                        // create missing font styles, order is important.
                        if (mFontInfo.font[Typeface.BOLD_ITALIC] == null) {
                            computeDerivedFont(Typeface.BOLD_ITALIC, DERIVE_BOLD_ITALIC);
                        }
                        if (mFontInfo.font[Typeface.ITALIC] == null) {
                            computeDerivedFont(Typeface.ITALIC, DERIVE_ITALIC);
                        }
                        if (mFontInfo.font[Typeface.BOLD] == null) {
                            computeDerivedFont(Typeface.BOLD, DERIVE_BOLD);
                        }
                    }

                    mFontInfo = null;
                }
            } else if (NODE_NAME.equals(localName)) {
                // handle a new name for an existing Font Info
                if (mFontInfo != null) {
                    String family = trimXmlWhitespaces(mBuilder.toString());
                    mFontInfo.families.add(family);
                }
            } else if (NODE_FALLBACK.equals(localName)) {
                // nothing to do here.
            } else if (NODE_FILE.equals(localName)) {
                // handle a new file for an existing Font Info
                if (mFontInfo != null) {
                    String fileName = trimXmlWhitespaces(mBuilder.toString());
                    Font font = getFont(fileName);
                    if (font != null) {
                        if (fileName.endsWith(FONT_SUFFIX_REGULAR)) {
                            mFontInfo.font[Typeface.NORMAL] = font;
                        } else if (fileName.endsWith(FONT_SUFFIX_BOLD)) {
                            mFontInfo.font[Typeface.BOLD] = font;
                        } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) {
                            mFontInfo.font[Typeface.ITALIC] = font;
                        } else if (fileName.endsWith(FONT_SUFFIX_BOLDITALIC)) {
                            mFontInfo.font[Typeface.BOLD_ITALIC] = font;
                        } else if (fileName.endsWith(FONT_SUFFIX_NONE)) {
                            mFontInfo.font[Typeface.NORMAL] = font;
                        }
                    }
                }
            }
        }

        private Font getFont(String fileName) {
            try {
                File file = new File(mOsFontsLocation, fileName);
                if (file.exists()) {
                    return Font.createFont(Font.TRUETYPE_FONT, file);
                }
            } catch (Exception e) {

            }

            return null;
        }

        private void computeDerivedFont( int toCompute, int[] basedOnList) {
            for (int basedOn : basedOnList) {
                if (mFontInfo.font[basedOn] != null) {
                    mFontInfo.font[toCompute] =
                        mFontInfo.font[basedOn].deriveFont(AWT_STYLES[toCompute]);
                    return;
                }
            }

            // we really shouldn't stop there. This means we don't have a NORMAL font...
            assert false;
        }

        private String trimXmlWhitespaces(String value) {
            if (value == null) {