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

Commit a644359b authored by d34d's avatar d34d Committed by Clark Scheff
Browse files

Themes: Ensure themed fonts always have fallbacks

We need to ensure that if fonts are being used from a theme that
we include any families from the system that the theme did not
include.  We also need to add the Roboto fonts as fallback.

The system sans-serif fonts (Roboto) are added as fallback fonts.
This ensures we have a fallback for glyphs that are not in the
themed fonts.

Change-Id: Iebb634ef4d01fedd132858410a5d392e74800acf
parent 044bdde5
Loading
Loading
Loading
Loading
+94 −13
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ public class Typeface {

    static final String FONTS_CONFIG = "fonts.xml";

    static final String SANS_SERIF_FAMILY_NAME = "sans-serif";

    /**
     * @hide
     */
@@ -269,6 +271,73 @@ public class Typeface {
        return fontFamily;
    }

    /**
     * Adds the family from src with the name familyName as a fallback font in dst
     * @param src Source font config
     * @param dst Destination font config
     * @param familyName Name of family to add as a fallback
     */
    private static void addFallbackFontsForFamilyName(FontListParser.Config src,
            FontListParser.Config dst, String familyName) {
        for (Family srcFamily : src.families) {
            if (familyName.equals(srcFamily.name)) {
                // set the name to null so that it will be added as a fallback
                srcFamily.name = null;
                dst.families.add(srcFamily);
                return;
            }
        }
    }

    /**
     * Adds any font families in src that do not exist in dst
     * @param src Source font config
     * @param dst Destination font config
     */
    private static void addMissingFontFamilies(FontListParser.Config src,
            FontListParser.Config dst) {
        final int N = dst.families.size();
        // add missing families
        for (Family srcFamily : src.families) {
            boolean addFamily = true;
            for (int i = 0; i < N && addFamily; i++) {
                final Family dstFamily = dst.families.get(i);
                final String dstFamilyName = dstFamily.name;
                if (dstFamilyName != null && dstFamilyName.equals(srcFamily.name)) {
                    addFamily = false;
                    break;
                }
            }
            if (addFamily) {
                dst.families.add(srcFamily);
            }
        }
    }

    /**
     * Adds any aliases in src that do not exist in dst
     * @param src Source font config
     * @param dst Destination font config
     */
    private static void addMissingFontAliases(FontListParser.Config src,
            FontListParser.Config dst) {
        final int N = dst.aliases.size();
        // add missing aliases
        for (FontListParser.Alias alias : src.aliases) {
            boolean addAlias = true;
            for (int i = 0; i < N && addAlias; i++) {
                final String dstAliasName = dst.aliases.get(i).name;
                if (dstAliasName != null && dstAliasName.equals(alias.name)) {
                    addAlias = false;
                    break;
                }
            }
            if (addAlias) {
                dst.aliases.add(alias);
            }
        }
    }

    /*
     * (non-Javadoc)
     *
@@ -279,22 +348,33 @@ public class Typeface {
        File systemFontConfigLocation = getSystemFontConfigLocation();
        File themeFontConfigLocation = getThemeFontConfigLocation();

        File systemConfigFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
        File themeConfigFilename = new File(themeFontConfigLocation, FONTS_CONFIG);
        File configFilename = null;
        File systemConfigFile = new File(systemFontConfigLocation, FONTS_CONFIG);
        File themeConfigFile = new File(themeFontConfigLocation, FONTS_CONFIG);
        File configFile = null;
        File fontDir;


        if (themeConfigFilename.exists()) {
            configFilename = themeConfigFilename;
            fontDir = getThemeFontConfigLocation();
        if (themeConfigFile.exists()) {
            configFile = themeConfigFile;
            fontDir = getThemeFontDirLocation();
        } else {
            configFilename = systemConfigFilename;
            configFile = systemConfigFile;
            fontDir = getSystemFontDirLocation();
        }

        try {
            FontListParser.Config fontConfig = FontListParser.parse(configFilename, fontDir);
            FontListParser.Config fontConfig = FontListParser.parse(configFile, fontDir);
            FontListParser.Config systemFontConfig = null;

            // If the fonts are coming from a theme, we will need to make sure that we include
            // any font families from the system fonts that the theme did not include.
            // NOTE: All the system font families without names ALWAYS get added.
            if (configFile == themeConfigFile) {
                systemFontConfig = FontListParser.parse(systemConfigFile,
                        getSystemFontDirLocation());
                addMissingFontFamilies(systemFontConfig, fontConfig);
                addMissingFontAliases(systemFontConfig, fontConfig);
                addFallbackFontsForFamilyName(systemFontConfig, fontConfig, SANS_SERIF_FAMILY_NAME);
            }

            List<FontFamily> familyList = new ArrayList<FontFamily>();
            // Note that the default typeface is always present in the fallback list;
@@ -305,6 +385,7 @@ public class Typeface {
                    familyList.add(makeFamilyFromParsed(f));
                }
            }

            sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
            setDefault(Typeface.createFromFamilies(sFallbackFonts));

@@ -340,11 +421,11 @@ public class Typeface {
            Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
            // TODO: normal in non-Minikin case, remove or make error when Minikin-only
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Error opening " + configFilename);
            Log.e(TAG, "Error opening " + configFile);
        } catch (IOException e) {
            Log.e(TAG, "Error reading " + configFilename);
            Log.e(TAG, "Error reading " + configFile);
        } catch (XmlPullParserException e) {
            Log.e(TAG, "XML parse exception for " + configFilename);
            Log.e(TAG, "XML parse exception for " + configFile);
        }
    }

@@ -405,7 +486,7 @@ public class Typeface {
        return new File("/data/system/theme/fonts/");
    }

    private static File getThemeFontDir() {
    private static File getThemeFontDirLocation() {
        return new File("/data/system/theme/fonts/");
    }