All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.javafx.font.FontConfigManager Maven / Gradle / Ivy

/*
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.javafx.font;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;

class FontConfigManager {

    static boolean debugFonts = false;
    static boolean fontConfigFailed = false;
    static boolean useEmbeddedFontSupport = false;

    static {
        AccessController.doPrivileged(
            new PrivilegedAction() {
                public Void run() {
                    String dbg = System.getProperty("prism.debugfonts", "");
                    debugFonts = "true".equals(dbg);
                    String emb = System.getProperty("prism.embeddedfonts", "");
                    useEmbeddedFontSupport = "true".equals(emb);
                    return null;
                }
            }
        );
    }

    /* These next three classes are just data structures.
     */
    public static class FontConfigFont {
        public String familyName;        // eg Bitstream Vera Sans
        public String styleStr;          // eg Bold
        public String fullName;          // eg Bitstream Vera Sans Bold
        public String fontFile;          // eg /usr/X11/lib/fonts/foo.ttf
    }

    public static class FcCompFont {
        public String fcName;            // eg sans
        public String fcFamily;          // eg sans
        //public String fxName;           // eg sans serif
        public int style;                // eg 0=PLAIN
        public FontConfigFont firstFont;
        public FontConfigFont[] allFonts;
        //public CompositeFont compFont;   // null if not yet created/known.
    }

    /* fontconfig recognises slants roman, italic, as well as oblique,
     * and a slew of weights, where the ones that matter here are
     * regular and bold.
     * To fully qualify what we want, we can for example ask for (eg)
     * Font.PLAIN             : "serif:regular:roman"
     * Font.BOLD              : "serif:bold:roman"
     * Font.ITALIC            : "serif:regular:italic"
     * Font.BOLD|Font.ITALIC  : "serif:bold:italic"
     */
    private static final String[] fontConfigNames = {
        "sans:regular:roman",
        "sans:bold:roman",
        "sans:regular:italic",
        "sans:bold:italic",

        "serif:regular:roman",
        "serif:bold:roman",
        "serif:regular:italic",
        "serif:bold:italic",

        "monospace:regular:roman",
        "monospace:bold:roman",
        "monospace:regular:italic",
        "monospace:bold:italic",
    };

    /* This array has the array elements created in Java code and is
     * passed down to native to be filled in.
     */
    private static FcCompFont[] fontConfigFonts;

    private FontConfigManager() {
    }

    private static String[] getFontConfigNames() {
        return fontConfigNames;
    }

    private static String getFCLocaleStr() {
        Locale l = Locale.getDefault();
        String localeStr = l.getLanguage();
        String country = l.getCountry();
        if (!country.equals("")) {
            localeStr = localeStr + "-" + country;
        }
        return localeStr;
    }

    /* Return an array of FcCompFont structs describing the primary
     * font located for each of fontconfig/GTK/Pango's logical font names.
     */
    private static native boolean getFontConfig(String locale,
                                                FcCompFont[] fonts,
                                                boolean includeFallbacks);

    private static synchronized void initFontConfigLogFonts() {

        if (fontConfigFonts != null || fontConfigFailed) {
            return;
        }

        long t0 = 0;
        if (debugFonts) {
            t0 = System.nanoTime();
        }

        String[] fontConfigNames = FontConfigManager.getFontConfigNames();
        FcCompFont[] fontArr = new FcCompFont[fontConfigNames.length];

        for (int i = 0; i< fontArr.length; i++) {
            fontArr[i] = new FcCompFont();
            fontArr[i].fcName = fontConfigNames[i];
            int colonPos = fontArr[i].fcName.indexOf(':');
            fontArr[i].fcFamily = fontArr[i].fcName.substring(0, colonPos);
            fontArr[i].style = i % 4; // depends on array order.
        }
        if (useEmbeddedFontSupport ||
            !getFontConfig(getFCLocaleStr(), fontArr, true))
        {
            EmbeddedFontSupport.initLogicalFonts(fontArr);
        }
        FontConfigFont anyFont = null;
        /* If don't find anything (eg no libfontconfig), then just return */
        for (int i = 0; i< fontArr.length; i++) {
            FcCompFont fci = fontArr[i];
            if (fci.firstFont == null) {
                if (debugFonts) {
                    System.err.println("Fontconfig returned no font for " +
                                fontArr[i].fcName);
                }
                fontConfigFailed = true;
            } else if (anyFont == null) {
                anyFont = fci.firstFont;
                defaultFontFile = anyFont.fontFile;
            }
        }

        if (anyFont == null) {
            if (debugFonts) {
                System.err.println("Fontconfig returned no fonts at all.");
            }
            fontConfigFailed = true;
            return;
        } else if (fontConfigFailed) {
            for (int i = 0; i< fontArr.length; i++) {
                if (fontArr[i].firstFont == null) {
                    fontArr[i].firstFont = anyFont;
                }
            }
        }

        fontConfigFonts = fontArr;

        if (debugFonts) {

            long t1 = System.nanoTime();
            System.err.println("Time spent accessing fontconfig="
                               + ((t1 - t0) / 1000000) + "ms.");

            for (int i = 0; i
        getFileNames(FcCompFont font, boolean fallBacksOnly) {

        ArrayList fileList = new ArrayList();

        if (font.allFonts != null) {
            int start = (fallBacksOnly) ? 1 : 0;
            for (int i=start; i
        getFontNames(FcCompFont font, boolean fallBacksOnly) {

        ArrayList fontList = new ArrayList();

        if (font.allFonts != null) {
            int start = (fallBacksOnly) ? 1 : 0;
            for (int i=start; i() {
                    public Void run() {
                        initEmbeddedFonts();
                    return null;
                    }
                }
            );
        }

        private static void initEmbeddedFonts() {
            fontDirProp = System.getProperty("prism.fontdir");
            if (fontDirProp != null) {
                fontDir = fontDirProp;
            } else {
                try {
                    // In a jar, the URL string for a class looks like
                    // jar:file:/home/user/rt/lib/ext/jfxrt.jar!/com/pkg/FCM.class
                    // Strip this down to get the "lib" directory URL.
                    Class c = FontConfigManager.class;
                    String name = "FontConfigManager.class";
                    String urlStr = c.getResource(name).toString();
                    if (debugFonts) {
                        System.err.println("Class URL is " + urlStr);
                    }
                    if (urlStr == null) {
                        return;
                    }
                    int ei =  urlStr.indexOf("!");
                    if (urlStr.startsWith("jar:file:") || ei != -1) {
                        urlStr = urlStr.substring(9, ei);
                        int lsi = Math.max(urlStr.lastIndexOf("/"),
                                           urlStr.lastIndexOf("\\"));
                        urlStr = urlStr.substring(0, lsi);
                    }
                    File fontDirectory = new File(urlStr, "fonts");
                    fontDir = fontDirectory.getPath();
                    if (debugFonts) {
                        System.err.println("Font Dir is " + fontDirectory +
                                           " exists = " +
                                           fontDirectory.exists());
                    }
                } catch (Exception e) {
                    if (debugFonts) {
                        e.printStackTrace();
                    }
                    fontDir = "/";
                }
            }
        }

        private static String getStyleStr(int style) {
            switch (style) {
                case 0 : return "regular";
                case 1 : return "bold";
                case 2 : return "italic";
                case 3 : return "bolditalic";
            default : return "regular";
            }
        }


        private static boolean exists(final File f) {
            return AccessController.doPrivileged(
                new PrivilegedAction() {
                    public Boolean run() {
                        return f.exists();
                    }
                }
            );
        }

        /**
         * Logical Font Support for FX on embedded platforms
         *
         * Reads a simple properties file which defines the 3
         * font families "sans", "serif", "monospace". This uses
         * fontconfig names because the interface to access this
         * goes via internal APIs which communicate with FontConfig.
         * The format using sans as an example, looks like
         * sans.regular.0.font=Arial
         * sans.regular.0.file=Arial.ttf
         * sans.bold.0.font=Arial Bold
         * sans.bold.0.file=Arial-Bold.ttf
         * sans.italic.0.font=Arial Italic
         * sans.italic.0.file=Arial-Italic.ttf
         * sans.bolditalic.0.font=Arial Bold Italic
         * sans.bolditalic.0.file=Arial-BoldItalic.ttf
         *
         * Additional fonts for each style would be indexed 1, 2, etc ..
         * The fonts must be made visible to the embedded FX - see
         * populateMaps()
         */
        static void initLogicalFonts(FcCompFont[] fonts) {

            Properties props = new Properties();
            try {
                String lFile = fontDir+"/logicalfonts.properties";
                FileInputStream fis = new FileInputStream(lFile);
                props.load(fis);
                fis.close();
            } catch (IOException ioe) {
                if (debugFonts) {
                    System.err.println(ioe);
                    return;
                }
            }
            for (int f=0; f allFonts =
                      new ArrayList();
                int i=0;
                while (true) {
                    String file = props.getProperty(key+i+".file");
                    String font = props.getProperty(key+i+".font");
                    i++;
                    if (file == null) {
                        break;
                    }
                    File ff = new File(fontDir, file);
                    if (!exists(ff)) {
                        continue;
                    }
                    FontConfigFont fcFont = new FontConfigFont();
                    fcFont.fontFile = ff.getPath(); // required.
                    fcFont.fullName = font; // optional.
                    fcFont.familyName = null; // not used.
                    fcFont.styleStr = null; // not used.
                    if (fonts[f].firstFont == null) {
                        fonts[f].firstFont = fcFont;
                    }
                    allFonts.add(fcFont);
                }
                if (allFonts.size() > 0) {
                    fonts[f].allFonts = new FontConfigFont[allFonts.size()];
                    allFonts.toArray(fonts[f].allFonts);
                }
            }
        }

        /*
         * To speed lookup of fonts, check for a file called
         * allfonts.properties. Only fonts in that file will be enumerated.
         * If this file isn't present we'll open all the files.
         * The file name must be a simple basename, and is mandatory.
         * But you are encouraged to name the font and family too.
         * If this file doesn't say the name or family of a font,
         * we'll still open the file. The names must be the actual
         * font names. No promises to fix it if you spell it wrongly.
         * We look for "maxFont" and if that's a valid property
         * we'll look from 0 .. maxFont, else we stop at the first
         * index for which no file exists. Eg file :
         * maxFont=1
         * family.0=Arial
         * font.0=Arial Regular
         * file.0=arial.ttf
         * family.1=Times New Roman
         * font.1=Times New Roman Regular
         * file.1=times.ttf
         *
         * NOTE: if you are testing embedded on desktop, and are using
         * the 2D pipeline, you will want to use /home//.fonts as
         * the font directory, else Java 2D won't know where to find
         * the fonts. If this turns out to be a major impediment, we
         * can arrange to register them with Java 2D.
         */
        static void populateMaps
            (HashMap fontToFileMap,
             HashMap fontToFamilyNameMap,
             HashMap> familyToFontListMap,
             Locale locale)
        {
            final Properties props = new Properties();
            AccessController.doPrivileged(
              new PrivilegedAction() {
                public Void run() {
                    try {
                        String lFile = fontDir+"/allfonts.properties";
                        FileInputStream fis = new FileInputStream(lFile);
                        props.load(fis);
                        fis.close();
                    } catch (IOException ioe) {
                        props.clear();
                        if (debugFonts) {
                            System.err.println(ioe);
                            System.err.println("Fall back to opening the files");
                        }
                    }
                    return null;
                }
            });

            if (!props.isEmpty()) {
                int maxFont = Integer.MAX_VALUE;
                try {
                    maxFont = Integer.parseInt(props.getProperty("maxFont",""));
                } catch (NumberFormatException e) {
                }
                if (maxFont <= 0) {
                    maxFont = Integer.MAX_VALUE;
                }
                for (int f=0; f familyArr =
                        familyToFontListMap.get(familyLC);
                    if (familyArr == null) {
                        familyArr = new ArrayList(4);
                        familyToFontListMap.put(familyLC, familyArr);
                    }
                    familyArr.add(font);
                }
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy