6378099: RFE: Use libfontconfig to create/synthesise a fontconfig.properties
authorprr
Thu, 12 Jun 2008 13:17:33 -0700
changeset 883 c3e81f0acd3d
parent 882 79d8619aab0b
child 884 4d6082745d10
6378099: RFE: Use libfontconfig to create/synthesise a fontconfig.properties Reviewed-by: tdv, igor
jdk/make/sun/headless/mapfile-vers
jdk/make/sun/xawt/mapfile-vers
jdk/src/share/classes/sun/awt/FontConfiguration.java
jdk/src/share/classes/sun/font/FontManager.java
jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java
jdk/src/solaris/classes/sun/font/FcFontConfiguration.java
jdk/src/solaris/native/sun/awt/fontconfig.h
jdk/src/solaris/native/sun/awt/fontpath.c
jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java
--- a/jdk/make/sun/headless/mapfile-vers	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/make/sun/headless/mapfile-vers	Thu Jun 12 13:17:33 2008 -0700
@@ -60,6 +60,7 @@
 		X11SurfaceData_GetOps;
 		Java_java_awt_Font_initIDs;
                 Java_sun_font_FontManager_getFontConfig;
+                Java_sun_font_FontManager_getFontConfigVersion;
                 Java_sun_font_FontManager_getFontConfigAASettings;
 		Java_sun_font_FontManager_getFontPath;
 		Java_sun_font_FontManager_setNativeFontPath;
--- a/jdk/make/sun/xawt/mapfile-vers	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/make/sun/xawt/mapfile-vers	Thu Jun 12 13:17:33 2008 -0700
@@ -177,6 +177,7 @@
         Java_java_awt_TextField_initIDs;
         Java_java_awt_TrayIcon_initIDs;
         Java_sun_font_FontManager_getFontConfig;
+        Java_sun_font_FontManager_getFontConfigVersion;
         Java_sun_font_FontManager_getFontConfigAASettings;
 	Java_sun_font_FontManager_getFontPath;
 	Java_sun_font_FontManager_setNativeFontPath;
--- a/jdk/src/share/classes/sun/awt/FontConfiguration.java	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/share/classes/sun/awt/FontConfiguration.java	Thu Jun 12 13:17:33 2008 -0700
@@ -72,6 +72,11 @@
     protected boolean preferLocaleFonts;
     protected boolean preferPropFonts;
 
+    private File fontConfigFile;
+    private boolean foundOsSpecificFile;
+    private boolean inited;
+    private String javaLib;
+
     /* A default FontConfiguration must be created before an alternate
      * one to ensure proper static initialisation takes place.
      */
@@ -80,14 +85,25 @@
             logger = Logger.getLogger("sun.awt.FontConfiguration");
         }
         this.environment = environment;
-        this.preferLocaleFonts = false;
-        this.preferPropFonts = false;
         setOsNameAndVersion();  /* static initialization */
         setEncoding();          /* static initialization */
-        fontConfig = this;      /* static initialization */
+        /* Separating out the file location from the rest of the
+         * initialisation, so the caller has the option of doing
+         * something else if a suitable file isn't found.
+         */
+        findFontConfigFile();
+    }
 
-        readFontConfigFile();
-        initFontConfig();
+    public synchronized boolean init() {
+        if (!inited) {
+            this.preferLocaleFonts = false;
+            this.preferPropFonts = false;
+            fontConfig = this;      /* static initialization */
+            readFontConfigFile(fontConfigFile);
+            initFontConfig();
+            inited = true;
+        }
+        return true;
     }
 
     public FontConfiguration(SunGraphicsEnvironment environment,
@@ -121,21 +137,51 @@
     /////////////////////////////////////////////////////////////////////
     // methods for loading the FontConfig file                         //
     /////////////////////////////////////////////////////////////////////
-    private void readFontConfigFile() {
-        // Find fontconfig file
-        File f = null;
+
+    public boolean foundOsSpecificFile() {
+        return foundOsSpecificFile;
+    }
+
+    /* Smoke test to see if we can trust this configuration by testing if
+     * the first slot of a composite font maps to an installed file.
+     */
+    public boolean fontFilesArePresent() {
+        init();
+        short fontNameID = compFontNameIDs[0][0][0];
+        short fileNameID = getComponentFileID(fontNameID);
+        final String fileName = mapFileName(getComponentFileName(fileNameID));
+        Boolean exists = (Boolean)java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction() {
+                 public Object run() {
+                     try {
+                         File f = new File(fileName);
+                         return Boolean.valueOf(f.exists());
+                     }
+                     catch (Exception e) {
+                         return false;
+                     }
+                 }
+                });
+        return exists.booleanValue();
+    }
+
+    private void findFontConfigFile() {
+
+        foundOsSpecificFile = true; // default assumption.
         String javaHome = System.getProperty("java.home");
         if (javaHome == null) {
             throw new Error("java.home property not set");
         }
-        String javaLib = javaHome + File.separator + "lib";
+        javaLib = javaHome + File.separator + "lib";
         String userConfigFile = System.getProperty("sun.awt.fontconfig");
         if (userConfigFile != null) {
-            f = new File(userConfigFile);
+            fontConfigFile = new File(userConfigFile);
         } else {
-            f = findFontConfigFile(javaLib);
+            fontConfigFile = findFontConfigFile(javaLib);
         }
+    }
 
+    private void readFontConfigFile(File f) {
         /* This is invoked here as readFontConfigFile is only invoked
          * once per VM, and always in a privileged context, thus the
          * directory containing installed fall back fonts is accessed
@@ -167,7 +213,7 @@
         }
     }
 
-    private void getInstalledFallbackFonts(String javaLib) {
+    protected void getInstalledFallbackFonts(String javaLib) {
         String fallbackDirName = javaLib + File.separator +
             "fonts" + File.separator + "fallback";
 
@@ -229,6 +275,8 @@
                 return configFile;
             }
         }
+        foundOsSpecificFile = false;
+
         configFile = findImpl(baseName);
         if (configFile != null) {
             return configFile;
@@ -506,12 +554,12 @@
     /////////////////////////////////////////////////////////////////////
     protected static final int NUM_FONTS = 5;
     protected static final int NUM_STYLES = 4;
-    private static final String[] fontNames
+    protected static final String[] fontNames
             = {"serif", "sansserif", "monospaced", "dialog", "dialoginput"};
-    private static final String[] publicFontNames
+    protected static final String[] publicFontNames
             = {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, Font.DIALOG,
                Font.DIALOG_INPUT};
-    private static final String[] styleNames
+    protected static final String[] styleNames
             = {"plain", "bold", "italic", "bolditalic"};
 
     /**
@@ -656,7 +704,7 @@
         return null;
     }
 
-    private static String[] installedFallbackFontFiles = null;
+    protected static String[] installedFallbackFontFiles = null;
 
     /**
      * Maps a file name given in the font configuration file
--- a/jdk/src/share/classes/sun/font/FontManager.java	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/share/classes/sun/font/FontManager.java	Thu Jun 12 13:17:33 2008 -0700
@@ -148,6 +148,7 @@
     static HashSet<String> jreLucidaFontFiles;
     static String[] jreOtherFontFiles;
     static boolean noOtherJREFontFiles = false; // initial assumption.
+    static boolean fontConfigFailed = false;
 
     /* Used to indicate required return type from toArray(..); */
     private static String[] STR_ARRAY = new String[0];
@@ -3100,19 +3101,30 @@
         "monospace:bold:italic",
     };
 
-    /* This class is just a data structure.
+    /* These next three classes are just data structures.
      */
-    private static class FontConfigInfo {
+    static class FontConfigFont {
+        String familyName;        // eg Bitstream Vera Sans
+        String styleStr;          // eg Bold
+        String fullName;          // eg Bitstream Vera Sans Bold
+        String fontFile;          // eg /usr/X11/lib/fonts/foo.ttf
+    }
+
+    static class FcCompFont {
         String fcName;            // eg sans
         String fcFamily;          // eg sans
         String jdkName;           // eg sansserif
         int style;                // eg 0=PLAIN
-        String familyName;        // eg Bitstream Vera Sans
-        String fontFile;          // eg /usr/X11/lib/fonts/foo.ttf
+        FontConfigFont firstFont;
+        FontConfigFont[] allFonts;
         //boolean preferBitmaps;    // if embedded bitmaps preferred over AA
         CompositeFont compFont;   // null if not yet created/known.
     }
 
+    static class FontConfigInfo {
+        int fcVersion;
+        String[] cacheDirs = new String[4];
+    }
 
     private static String getFCLocaleStr() {
         Locale l = SunToolkit.getStartupLocale();
@@ -3124,6 +3136,12 @@
         return localeStr;
     }
 
+    /* This does cause the native libfontconfig to be loaded and unloaded,
+     * but it does not incur the overhead of initialisation of its
+     * data structures, so shouldn't have a measurable impact.
+     */
+    public static native int getFontConfigVersion();
+
     private static native int
         getFontConfigAASettings(String locale, String fcFamily);
 
@@ -3157,17 +3175,35 @@
         return getFontConfigAAHint("sans");
     }
 
+    /* This is populated by native */
+    private static final FontConfigInfo fcInfo = new FontConfigInfo();
+
     /* This array has the array elements created in Java code and is
      * passed down to native to be filled in.
      */
-    private static FontConfigInfo[] fontConfigFonts;
-
-    /* Return an array of FontConfigInfo structs describing the primary
+    private static FcCompFont[] fontConfigFonts;
+
+    /* Return an array of FcCompFont structs describing the primary
      * font located for each of fontconfig/GTK/Pango's logical font names.
      */
     private static native void getFontConfig(String locale,
-                                             FontConfigInfo[] fonts);
-
+                                             FontConfigInfo fcInfo,
+                                             FcCompFont[] fonts,
+                                             boolean includeFallbacks);
+
+    static void populateFontConfig(FcCompFont[] fcInfo) {
+        fontConfigFonts = fcInfo;
+    }
+
+    static FcCompFont[] loadFontConfig() {
+        initFontConfigFonts(true);
+        return fontConfigFonts;
+    }
+
+    static FontConfigInfo getFontConfigInfo() {
+        initFontConfigFonts(true);
+        return fcInfo;
+    }
 
     /* This can be made public if it's needed to force a re-read
      * rather than using the cached values. The re-read would be needed
@@ -3175,54 +3211,80 @@
      * In that event this method would need to return directly the array
      * to be used by the caller in case it subsequently changed.
      */
-    private static void initFontConfigFonts() {
+    private static synchronized void
+        initFontConfigFonts(boolean includeFallbacks) {
 
         if (fontConfigFonts != null) {
-            return;
+            if (!includeFallbacks || (fontConfigFonts[0].allFonts != null)) {
+                return;
+            }
         }
 
-        if (isWindows) {
+        if (isWindows || fontConfigFailed) {
             return;
         }
 
         long t0 = 0;
         if (logging) {
-            t0 = System.currentTimeMillis();
+            t0 = System.nanoTime();
         }
 
-        FontConfigInfo[] fontArr = new FontConfigInfo[fontConfigNames.length];
+        FcCompFont[] fontArr = new FcCompFont[fontConfigNames.length];
         for (int i = 0; i< fontArr.length; i++) {
-            fontArr[i] = new FontConfigInfo();
+            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].jdkName = mapFcName(fontArr[i].fcFamily);
             fontArr[i].style = i % 4; // depends on array order.
         }
-        getFontConfig(getFCLocaleStr(), fontArr);
+        getFontConfig(getFCLocaleStr(), fcInfo, fontArr, includeFallbacks);
+        /* 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 (logging) {
+                    logger.info("Fontconfig returned no fonts.");
+                }
+                fontConfigFailed = true;
+                return;
+            }
+        }
         fontConfigFonts = fontArr;
 
         if (logging) {
-            long t1 = System.currentTimeMillis();
-            logger.info("Time spent accessing fontconfig="+(t1-t0)+"ms.");
+            long t1 = System.nanoTime();
+            logger.info("Time spent accessing fontconfig="+
+                        (t1-t0)/1000000+"ms.");
 
             for (int i = 0; i< fontConfigFonts.length; i++) {
-                FontConfigInfo fci = fontConfigFonts[i];
+                FcCompFont fci = fontConfigFonts[i];
                 logger.info("FC font " + fci.fcName+" maps to family " +
-                            fci.familyName + " in file " + fci.fontFile);
+                            fci.firstFont.familyName +
+                            " in file " + fci.firstFont.fontFile);
+                if (fci.allFonts != null) {
+                    for (int f=0;f<fci.allFonts.length;f++) {
+                        FontConfigFont fcf = fci.allFonts[f];
+                        logger.info("Family=" + fcf.familyName +
+                                    " Style="+ fcf.styleStr +
+                                    " Fullname="+fcf.fullName +
+                                    " File="+fcf.fontFile);
+                    }
+                }
             }
         }
     }
 
-    private static PhysicalFont registerFromFcInfo(FontConfigInfo fcInfo) {
+    private static PhysicalFont registerFromFcInfo(FcCompFont fcInfo) {
 
         /* If it's a TTC file we need to know that as we will need to
          * make sure we return the right font */
-        int offset = fcInfo.fontFile.length()-4;
+        String fontFile = fcInfo.firstFont.fontFile;
+        int offset = fontFile.length()-4;
         if (offset <= 0) {
             return null;
         }
-        String ext = fcInfo.fontFile.substring(offset).toLowerCase();
+        String ext = fontFile.substring(offset).toLowerCase();
         boolean isTTC = ext.equals(".ttc");
 
         /* If this file is already registered, can just return its font.
@@ -3230,10 +3292,10 @@
          * a specific font, so rather than directly returning it, let
          * findFont2D resolve that.
          */
-        PhysicalFont physFont = registeredFontFiles.get(fcInfo.fontFile);
+        PhysicalFont physFont = registeredFontFiles.get(fontFile);
         if (physFont != null) {
             if (isTTC) {
-                Font2D f2d = findFont2D(fcInfo.familyName,
+                Font2D f2d = findFont2D(fcInfo.firstFont.familyName,
                                         fcInfo.style, NO_FALLBACK);
                 if (f2d instanceof PhysicalFont) { /* paranoia */
                     return (PhysicalFont)f2d;
@@ -3249,18 +3311,20 @@
          * Lucida Sans), we want to use the JRE version, so make it
          * point to the JRE font.
          */
-        physFont = findJREDeferredFont(fcInfo.familyName, fcInfo.style);
+        physFont = findJREDeferredFont(fcInfo.firstFont.familyName,
+                                       fcInfo.style);
 
         /* It is also possible the font file is on the "deferred" list,
          * in which case we can just initialise it now.
          */
         if (physFont == null &&
-            deferredFontFiles.get(fcInfo.fontFile) != null) {
-            physFont = initialiseDeferredFont(fcInfo.fontFile);
+            deferredFontFiles.get(fontFile) != null)
+        {
+            physFont = initialiseDeferredFont(fcInfo.firstFont.fontFile);
             /* use findFont2D to get the right font from TTC's */
             if (physFont != null) {
                 if (isTTC) {
-                    Font2D f2d = findFont2D(fcInfo.familyName,
+                    Font2D f2d = findFont2D(fcInfo.firstFont.familyName,
                                             fcInfo.style, NO_FALLBACK);
                     if (f2d instanceof PhysicalFont) { /* paranoia */
                         return (PhysicalFont)f2d;
@@ -3287,7 +3351,7 @@
                 fontFormat = FONTFORMAT_TYPE1;
                 fontRank = Font2D.TYPE1_RANK;
             }
-            physFont = registerFontFile(fcInfo.fontFile, null,
+            physFont = registerFontFile(fcInfo.firstFont.fontFile, null,
                                       fontFormat, true, fontRank);
         }
         return physFont;
@@ -3345,12 +3409,12 @@
             }
             info[1] = info[1] + File.separator + "arial.ttf";
         } else {
-            initFontConfigFonts();
+            initFontConfigFonts(false);
             for (int i=0; i<fontConfigFonts.length; i++) {
                 if ("sans".equals(fontConfigFonts[i].fcFamily) &&
                     0 == fontConfigFonts[i].style) {
-                    info[0] = fontConfigFonts[i].familyName;
-                    info[1] = fontConfigFonts[i].fontFile;
+                    info[0] = fontConfigFonts[i].firstFont.familyName;
+                    info[1] = fontConfigFonts[i].firstFont.fontFile;
                     break;
                 }
             }
@@ -3360,9 +3424,9 @@
              */
             if (info[0] == null) {
                  if (fontConfigFonts.length > 0 &&
-                     fontConfigFonts[0].fontFile != null) {
-                     info[0] = fontConfigFonts[0].familyName;
-                     info[1] = fontConfigFonts[0].fontFile;
+                     fontConfigFonts[0].firstFont.fontFile != null) {
+                     info[0] = fontConfigFonts[0].firstFont.familyName;
+                     info[1] = fontConfigFonts[0].firstFont.fontFile;
                  } else {
                      info[0] = "Dialog";
                      info[1] = "/dialog.ttf";
@@ -3373,8 +3437,8 @@
         return defaultPlatformFont;
     }
 
-    private FontConfigInfo getFontConfigInfo() {
-         initFontConfigFonts();
+    private FcCompFont getFcCompFont() {
+         initFontConfigFonts(false);
          for (int i=0; i<fontConfigFonts.length; i++) {
              if ("sans".equals(fontConfigFonts[i].fcFamily) &&
                  0 == fontConfigFonts[i].style) {
@@ -3391,9 +3455,9 @@
 
         name = name.toLowerCase();
 
-        initFontConfigFonts();
-
-        FontConfigInfo fcInfo = null;
+        initFontConfigFonts(false);
+
+        FcCompFont fcInfo = null;
         for (int i=0; i<fontConfigFonts.length; i++) {
             if (name.equals(fontConfigFonts[i].fcFamily) &&
                 style == fontConfigFonts[i].style) {
@@ -3407,7 +3471,8 @@
 
         if (logging) {
             logger.info("FC name=" + name + " style=" + style + " uses " +
-                        fcInfo.familyName + " in file: " + fcInfo.fontFile);
+                        fcInfo.firstFont.familyName +
+                        " in file: " + fcInfo.firstFont.fontFile);
         }
 
         if (fcInfo.compFont != null) {
@@ -3420,7 +3485,8 @@
         CompositeFont jdkFont = (CompositeFont)
             findFont2D(fcInfo.jdkName, style, LOGICAL_FALLBACK);
 
-        if (fcInfo.familyName == null || fcInfo.fontFile == null) {
+        if (fcInfo.firstFont.familyName == null ||
+            fcInfo.firstFont.fontFile == null) {
             return (fcInfo.compFont = jdkFont);
         }
 
@@ -3432,7 +3498,7 @@
          * will fall through this code, but the regisration code will
          * find that file already registered and return its font.
          */
-        FontFamily family = FontFamily.getFamily(fcInfo.familyName);
+        FontFamily family = FontFamily.getFamily(fcInfo.firstFont.familyName);
         PhysicalFont physFont = null;
         if (family != null) {
             Font2D f2D = family.getFontWithExactStyleMatch(fcInfo.style);
@@ -3441,7 +3507,8 @@
             }
         }
 
-        if (physFont == null || !fcInfo.fontFile.equals(physFont.platName)) {
+        if (physFont == null ||
+            !fcInfo.firstFont.fontFile.equals(physFont.platName)) {
             physFont = registerFromFcInfo(fcInfo);
             if (physFont == null) {
                 return (fcInfo.compFont = jdkFont);
@@ -3459,10 +3526,10 @@
          * together to prevent synthetic styling.
          */
         for (int i=0; i<fontConfigFonts.length; i++) {
-            FontConfigInfo fc = fontConfigFonts[i];
+            FcCompFont fc = fontConfigFonts[i];
             if (fc != fcInfo &&
-                physFont.getFamilyName(null).equals(fc.familyName) &&
-                !fc.fontFile.equals(physFont.platName) &&
+                physFont.getFamilyName(null).equals(fc.firstFont.familyName) &&
+                !fc.firstFont.fontFile.equals(physFont.platName) &&
                 family.getFontWithExactStyleMatch(fc.style) == null) {
 
                 registerFromFcInfo(fontConfigFonts[i]);
--- a/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/share/classes/sun/java2d/SunGraphicsEnvironment.java	Thu Jun 12 13:17:33 2008 -0700
@@ -78,6 +78,7 @@
 
     public static boolean isLinux;
     public static boolean isSolaris;
+    public static boolean isOpenSolaris;
     public static boolean isWindows;
     public static boolean noType1Font;
     private static Font defaultFont;
@@ -167,6 +168,23 @@
                     isLinux = true;
                 } else if ("SunOS".equals(osName)) {
                     isSolaris = true;
+                    String version = System.getProperty("os.version", "0.0");
+                    try {
+                        float ver = Float.parseFloat(version);
+                        if (ver > 5.10f) {
+                            File f = new File("/etc/release");
+                            FileInputStream fis = new FileInputStream(f);
+                            InputStreamReader isr
+                                = new InputStreamReader(fis, "ISO-8859-1");
+                            BufferedReader br = new BufferedReader(isr);
+                            String line = br.readLine();
+                            if (line.indexOf("OpenSolaris") >= 0) {
+                                isOpenSolaris = true;
+                            }
+                            fis.close();
+                        }
+                    } catch (Exception e) {
+                    }
                 } else if ("Windows".equals(osName)) {
                     isWindows = true;
                 }
@@ -174,11 +192,7 @@
                 noType1Font = "true".
                     equals(System.getProperty("sun.java2d.noType1Font"));
 
-                if (isOpenJDK()) {
-                    String[] fontInfo = FontManager.getDefaultPlatformFont();
-                    defaultFontName = fontInfo[0];
-                    defaultFontFileName = fontInfo[1];
-                } else {
+                if (!isOpenJDK()) {
                     defaultFontName = lucidaFontName;
                     if (useAbsoluteFontFileNames()) {
                         defaultFontFileName =
@@ -244,6 +258,11 @@
                  * that might be specified.
                  */
                 fontConfig = createFontConfiguration();
+                if (isOpenJDK()) {
+                    String[] fontInfo = FontManager.getDefaultPlatformFont();
+                    defaultFontName = fontInfo[0];
+                    defaultFontFileName = fontInfo[1];
+                }
                 getPlatformFontPathFromFontConfig();
 
                 String extraFontPath = fontConfig.getExtraFontPath();
@@ -1069,7 +1088,7 @@
             String fontFileName =
                 getFileNameFromPlatformName(platformFontName);
             String[] nativeNames = null;
-            if (fontFileName == null) {
+            if (fontFileName == null || fontFileName.equals(platformFontName)){
                 /* No file located, so register using the platform name,
                  * i.e. as a native font.
                  */
--- a/jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java	Thu Jun 12 13:17:33 2008 -0700
@@ -44,6 +44,7 @@
 import java.util.logging.*;
 
 import sun.awt.motif.MFontConfiguration;
+import sun.font.FcFontConfiguration;
 import sun.font.Font2D;
 import sun.font.FontManager;
 import sun.font.NativeFont;
@@ -350,6 +351,14 @@
      * only to get called for these fonts.
      */
     public String getFileNameFromPlatformName(String platName) {
+
+        /* If the FontConfig file doesn't use xlfds, or its
+         * FcFontConfiguration, this may be already a file name.
+         */
+        if (platName.startsWith("/")) {
+            return platName;
+        }
+
         String fileName = null;
         String fontID = specificFontIDForName(platName);
 
@@ -905,12 +914,50 @@
 
     // Implements SunGraphicsEnvironment.createFontConfiguration.
     protected FontConfiguration createFontConfiguration() {
-        return new MFontConfiguration(this);
+
+        /* The logic here decides whether to use a preconfigured
+         * fontconfig.properties file, or synthesise one using platform APIs.
+         * On Solaris (as opposed to OpenSolaris) we try to use the
+         * pre-configured ones, but if the files it specifies are missing
+         * we fail-safe to synthesising one. This might happen if Solaris
+         * changes its fonts.
+         * For OpenSolaris I don't expect us to ever create fontconfig files,
+         * so it will always synthesise. Note that if we misidentify
+         * OpenSolaris as Solaris, then the test for the presence of
+         * Solaris-only font files will correct this.
+         * For Linux we require an exact match of distro and version to
+         * use the preconfigured file, and also that it points to
+         * existent fonts.
+         * If synthesising fails, we fall back to any preconfigured file
+         * and do the best we can. For the commercial JDK this will be
+         * fine as it includes the Lucida fonts. OpenJDK should not hit
+         * this as the synthesis should always work on its platforms.
+         */
+        FontConfiguration mFontConfig = new MFontConfiguration(this);
+        if (isOpenSolaris ||
+            (isLinux &&
+             (!mFontConfig.foundOsSpecificFile() ||
+              !mFontConfig.fontFilesArePresent()) ||
+             (isSolaris && !mFontConfig.fontFilesArePresent()))) {
+            FcFontConfiguration fcFontConfig =
+                new FcFontConfiguration(this);
+            if (fcFontConfig.init()) {
+                return fcFontConfig;
+            }
+        }
+        mFontConfig.init();
+        return mFontConfig;
     }
     public FontConfiguration
         createFontConfiguration(boolean preferLocaleFonts,
                                 boolean preferPropFonts) {
 
+        FontConfiguration config = getFontConfiguration();
+        if (config instanceof FcFontConfiguration) {
+            // Doesn't need to implement the alternate support.
+            return config;
+        }
+
         return new MFontConfiguration(this,
                                       preferLocaleFonts, preferPropFonts);
     }
@@ -921,6 +968,7 @@
      * for this platform.
      */
     public String getDefaultFontFaceName() {
+
         return null;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java	Thu Jun 12 13:17:33 2008 -0700
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.font;
+
+import java.awt.Font;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.logging.Logger;
+import java.util.Properties;
+import java.util.Scanner;
+import sun.awt.FontConfiguration;
+import sun.awt.FontDescriptor;
+import sun.awt.SunToolkit;
+import sun.font.CompositeFontDescriptor;
+import sun.font.FontManager;
+import sun.font.FontManager.FontConfigInfo;
+import sun.font.FontManager.FcCompFont;
+import sun.font.FontManager.FontConfigFont;
+import sun.java2d.SunGraphicsEnvironment;
+
+public class FcFontConfiguration extends FontConfiguration {
+
+    /** Version of the cache file format understood by this code.
+     * Its part of the file name so that we can rev this at
+     * any time, even in a minor JDK update.
+     * It is stored as the value of the "version" property.
+     * This is distinct from the version of "libfontconfig" that generated
+     * the cached results, and which is the "fcversion" property in the file.
+     * {@code FontConfiguration.getVersion()} also returns a version string,
+     * and has meant the version of the fontconfiguration.properties file
+     * that was read. Since this class doesn't use such files, then what
+     * that really means is whether the methods on this class return
+     * values that are compatible with the classes that do directly read
+     * from such files. It is a compatible subset of version "1".
+     */
+    private static final String fileVersion = "1";
+    private String fcInfoFileName = null;
+
+    private FcCompFont[] fcCompFonts = null;
+
+    public FcFontConfiguration(SunGraphicsEnvironment environment) {
+        super(environment);
+        init();
+    }
+
+    /* This isn't called but is needed to satisfy super-class contract. */
+    public FcFontConfiguration(SunGraphicsEnvironment environment,
+                               boolean preferLocaleFonts,
+                               boolean preferPropFonts) {
+        super(environment, preferLocaleFonts, preferPropFonts);
+        init();
+    }
+
+    @Override
+    public synchronized boolean init() {
+        if (fcCompFonts != null) {
+            return true;
+        }
+
+        readFcInfo();
+        if (fcCompFonts == null) {
+            fcCompFonts = FontManager.loadFontConfig();
+            if (fcCompFonts != null) {
+                try {
+                    writeFcInfo();
+                } catch (Exception e) {
+                    if (SunGraphicsEnvironment.debugFonts) {
+                        Logger logger =
+                            Logger.getLogger("sun.awt.FontConfiguration");
+                        logger.warning("Exception writing fcInfo " + e);
+                    }
+                }
+            } else if (SunGraphicsEnvironment.debugFonts) {
+                Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
+                logger.warning("Failed to get info from libfontconfig");
+            }
+        } else {
+            FontManager.populateFontConfig(fcCompFonts);
+        }
+
+        if (fcCompFonts == null) {
+            return false; // couldn't load fontconfig.
+        }
+
+        // NB already in a privileged block from SGE
+        String javaHome = System.getProperty("java.home");
+        if (javaHome == null) {
+            throw new Error("java.home property not set");
+        }
+        String javaLib = javaHome + File.separator + "lib";
+        getInstalledFallbackFonts(javaLib);
+
+        return true;
+    }
+
+    @Override
+    public String getFallbackFamilyName(String fontName,
+                                        String defaultFallback) {
+        // maintain compatibility with old font.properties files, which either
+        // had aliases for TimesRoman & Co. or defined mappings for them.
+        String compatibilityName = getCompatibilityFamilyName(fontName);
+        if (compatibilityName != null) {
+            return compatibilityName;
+        }
+        return defaultFallback;
+    }
+
+    @Override
+    protected String
+        getFaceNameFromComponentFontName(String componentFontName) {
+        return null;
+    }
+
+    @Override
+    protected String
+        getFileNameFromComponentFontName(String componentFontName) {
+        return null;
+    }
+
+    @Override
+    public String getFileNameFromPlatformName(String platformName) {
+        /* Platform name is the file name, but rather than returning
+         * the arg, return null*/
+        return null;
+    }
+
+    @Override
+    protected Charset getDefaultFontCharset(String fontName) {
+        return Charset.forName("ISO8859_1");
+    }
+
+    @Override
+    protected String getEncoding(String awtFontName,
+                                 String characterSubsetName) {
+        return "default";
+    }
+
+    @Override
+    protected void initReorderMap() {
+        reorderMap = new HashMap();
+    }
+
+    @Override
+    public FontDescriptor[] getFontDescriptors(String fontName, int style) {
+        throw new InternalError("Not implemented");
+    }
+
+    @Override
+    public int getNumberCoreFonts() {
+        return 1;
+    }
+
+    @Override
+    public String[] getPlatformFontNames() {
+        HashSet<String> nameSet = new HashSet<String>();
+        FcCompFont[] fcCompFonts = FontManager.loadFontConfig();
+        for (int i=0; i<fcCompFonts.length; i++) {
+            for (int j=0; j<fcCompFonts[i].allFonts.length; j++) {
+                nameSet.add(fcCompFonts[i].allFonts[j].fontFile);
+            }
+        }
+        return nameSet.toArray(new String[0]);
+    }
+
+    @Override
+    public String getExtraFontPath() {
+        return null;
+    }
+
+    @Override
+    public boolean needToSearchForFile(String fileName) {
+        return false;
+    }
+
+    private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
+                                           String fontname, int style) {
+
+        if (fontname.equals("dialog")) {
+            fontname = "sansserif";
+        } else if (fontname.equals("dialoginput")) {
+            fontname = "monospaced";
+        }
+        for (int i=0; i<fcFonts.length; i++) {
+            if (fontname.equals(fcFonts[i].jdkName) &&
+                style == fcFonts[i].style) {
+                return fcFonts[i].allFonts;
+            }
+        }
+        return fcFonts[0].allFonts;
+    }
+
+    @Override
+    public CompositeFontDescriptor[] get2DCompositeFontInfo() {
+
+        FcCompFont[] fcCompFonts = FontManager.loadFontConfig();
+
+        CompositeFontDescriptor[] result =
+                new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
+
+        for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
+            String fontName = publicFontNames[fontIndex];
+
+            for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
+
+                String faceName = fontName + "." + styleNames[styleIndex];
+                FontConfigFont[] fcFonts =
+                    getFcFontList(fcCompFonts,
+                                  fontNames[fontIndex], styleIndex);
+
+                int numFonts = fcFonts.length;
+                // fall back fonts listed in the lib/fonts/fallback directory
+                if (installedFallbackFontFiles != null) {
+                    numFonts += installedFallbackFontFiles.length;
+                }
+
+                String[] fileNames = new String[numFonts];
+
+                int index;
+                for (index = 0; index < fcFonts.length; index++) {
+                    fileNames[index] = fcFonts[index].fontFile;
+                }
+
+                if (installedFallbackFontFiles != null) {
+                    System.arraycopy(fileNames, index,
+                                     installedFallbackFontFiles,
+                                     0, installedFallbackFontFiles.length);
+                }
+
+                result[fontIndex * NUM_STYLES + styleIndex]
+                        = new CompositeFontDescriptor(
+                            faceName,
+                            1,
+                            null,
+                            fileNames,
+                            null, null);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Gets the OS version string from a Linux release-specific file.
+     */
+    private String getVersionString(File f){
+        try {
+            Scanner sc  = new Scanner(f);
+            return sc.findInLine("(\\d)+((\\.)(\\d)+)*");
+        }
+        catch (Exception e){
+        }
+        return null;
+    }
+
+    /**
+     * Sets the OS name and version from environment information.
+     */
+    @Override
+    protected void setOsNameAndVersion() {
+
+        super.setOsNameAndVersion();
+
+        if (!osName.equals("Linux")) {
+            return;
+        }
+        try {
+            File f;
+            if ((f = new File("/etc/lsb-release")).canRead()) {
+                    /* Ubuntu and (perhaps others) use only lsb-release.
+                     * Syntax and encoding is compatible with java properties.
+                     * For Ubuntu the ID is "Ubuntu".
+                     */
+                    Properties props = new Properties();
+                    props.load(new FileInputStream(f));
+                    osName = props.getProperty("DISTRIB_ID");
+                    osVersion =  props.getProperty("DISTRIB_RELEASE");
+            } else if ((f = new File("/etc/redhat-release")).canRead()) {
+                osName = "RedHat";
+                osVersion = getVersionString(f);
+            } else if ((f = new File("/etc/SuSE-release")).canRead()) {
+                osName = "SuSE";
+                osVersion = getVersionString(f);
+            } else if ((f = new File("/etc/turbolinux-release")).canRead()) {
+                osName = "Turbo";
+                osVersion = getVersionString(f);
+            } else if ((f = new File("/etc/fedora-release")).canRead()) {
+                osName = "Fedora";
+                osVersion = getVersionString(f);
+            } else if ((f = new File("/etc/sun-release")).canRead()) {
+                osName = "Sun";
+                osVersion = getVersionString(f);
+            }
+        } catch (Exception e) {
+            if (SunGraphicsEnvironment.debugFonts) {
+                Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
+                logger.warning("Exception identifying Linux distro.");
+            }
+        }
+    }
+
+    private File getFcInfoFile() {
+        if (fcInfoFileName == null) {
+            // NB need security permissions to get true IP address, and
+            // we should have those as the whole initialisation is in a
+            // doPrivileged block. But in this case no exception is thrown,
+            // and it returns the loop back address, and so we end up with
+            // "localhost"
+            String hostname;
+            try {
+                hostname = InetAddress.getLocalHost().getHostName();
+            } catch (UnknownHostException e) {
+                hostname = "localhost";
+            }
+            String userDir = System.getProperty("user.home");
+            String version = System.getProperty("java.version");
+            String fs = File.separator;
+            String dir = userDir+fs+".java"+fs+"fonts"+fs+version;
+            String lang = SunToolkit.getStartupLocale().getLanguage();
+            String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+
+                osName+"-"+osVersion+"-"+lang+".properties";
+            fcInfoFileName = dir+fs+name;
+        }
+        return new File(fcInfoFileName);
+    }
+
+    private void writeFcInfo() {
+        Properties props = new Properties();
+        props.setProperty("version", fileVersion);
+        FontConfigInfo fcInfo = FontManager.getFontConfigInfo();
+        props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
+        if (fcInfo.cacheDirs != null) {
+            for (int i=0;i<fcInfo.cacheDirs.length;i++) {
+                if (fcInfo.cacheDirs[i] != null) {
+                   props.setProperty("cachedir."+i,  fcInfo.cacheDirs[i]);
+                }
+            }
+        }
+        for (int i=0; i<fcCompFonts.length; i++) {
+            FcCompFont fci = fcCompFonts[i];
+            String styleKey = fci.jdkName+"."+fci.style;
+            props.setProperty(styleKey+".length",
+                              Integer.toString(fci.allFonts.length));
+            for (int j=0; j<fci.allFonts.length; j++) {
+                props.setProperty(styleKey+"."+j+".family",
+                                  fci.allFonts[j].familyName);
+                props.setProperty(styleKey+"."+j+".file",
+                                  fci.allFonts[j].fontFile);
+            }
+        }
+        try {
+            /* This writes into a temp file then renames when done.
+             * Since the rename is an atomic action within the same
+             * directory no client will ever see a partially written file.
+             */
+            File fcInfoFile = getFcInfoFile();
+            File dir = fcInfoFile.getParentFile();
+            dir.mkdirs();
+            File tempFile = File.createTempFile("fcinfo", null, dir);
+            FileOutputStream fos = new FileOutputStream(tempFile);
+            props.store(fos,
+                      "JDK Font Configuration Generated File: *Do Not Edit*");
+            fos.close();
+            boolean renamed = tempFile.renameTo(fcInfoFile);
+            if (!renamed && SunGraphicsEnvironment.debugFonts) {
+                System.out.println("rename failed");
+                Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
+                logger.warning("Failed renaming file to "+ getFcInfoFile());
+            }
+        } catch (Exception e) {
+            if (SunGraphicsEnvironment.debugFonts) {
+                Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
+                logger.warning("IOException writing to "+ getFcInfoFile());
+            }
+        }
+    }
+
+    /* We want to be able to use this cache instead of invoking
+     * fontconfig except when we can detect the system cache has changed.
+     * But there doesn't seem to be a way to find the location of
+     * the system cache.
+     */
+    private void readFcInfo() {
+        File fcFile = getFcInfoFile();
+        if (!fcFile.exists()) {
+            return;
+        }
+        Properties props = new Properties();
+        try {
+            FileInputStream fis = new FileInputStream(fcFile);
+            props.load(fis);
+            fis.close();
+        } catch (IOException e) {
+            if (SunGraphicsEnvironment.debugFonts) {
+                Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
+                logger.warning("IOException reading from "+fcFile.toString());
+            }
+            return;
+        }
+        String version = (String)props.get("version");
+        if (version == null || !version.equals(fileVersion)) {
+            return;
+        }
+
+        // If there's a new, different fontconfig installed on the
+        // system, we invalidate our fontconfig file.
+        String fcVersionStr = (String)props.get("fcversion");
+        if (fcVersionStr != null) {
+            int fcVersion;
+            try {
+                fcVersion = Integer.parseInt(fcVersionStr);
+                if (fcVersion != 0 &&
+                    fcVersion != FontManager.getFontConfigVersion()) {
+                    return;
+                }
+            } catch (Exception e) {
+                if (SunGraphicsEnvironment.debugFonts) {
+                    Logger logger =
+                        Logger.getLogger("sun.awt.FontConfiguration");
+                    logger.warning("Exception parsing version " +
+                                   fcVersionStr);
+                }
+                return;
+            }
+        }
+
+        // If we can locate the fontconfig cache dirs, then compare the
+        // time stamp of those with our properties file. If we are out
+        // of date then re-generate.
+        long lastModified = fcFile.lastModified();
+        int cacheDirIndex = 0;
+        while (cacheDirIndex<4) { // should never be more than 2 anyway.
+            String dir = (String)props.get("cachedir."+cacheDirIndex);
+            if (dir == null) {
+                break;
+            }
+            File dirFile = new File(dir);
+            if (dirFile.exists() && dirFile.lastModified() > lastModified) {
+                return;
+            }
+            cacheDirIndex++;
+        }
+
+        String[] names = { "sansserif", "serif", "monospaced" };
+        String[] fcnames = { "sans", "serif", "monospace" };
+        int namesLen = names.length;
+        int numStyles = 4;
+        FcCompFont[] fci = new FcCompFont[namesLen*numStyles];
+
+        try {
+            for (int i=0; i<namesLen; i++) {
+                for (int s=0; s<numStyles; s++) {
+                    int index = i*numStyles+s;
+                    fci[index] = new FcCompFont();
+                    String key = names[i]+"."+s;
+                    fci[index].jdkName = names[i];
+                    fci[index].fcFamily = fcnames[i];
+                    fci[index].style = s;
+                    String lenStr = (String)props.get(key+".length");
+                    int nfonts = Integer.parseInt(lenStr);
+                    if (nfonts <= 0) {
+                        return; // bad file
+                    }
+                    fci[index].allFonts = new FontConfigFont[nfonts];
+                    for (int f=0; f<nfonts; f++) {
+                        fci[index].allFonts[f] = new FontConfigFont();
+                        String fkey = key+"."+f+".family";
+                        String family = (String)props.get(fkey);
+                        fci[index].allFonts[f].familyName = family;
+                        fkey = key+"."+f+".file";
+                        String file = (String)props.get(fkey);
+                        if (file == null) {
+                            return; // bad file
+                        }
+                        fci[index].allFonts[f].fontFile = file;
+                    }
+                    fci[index].firstFont =  fci[index].allFonts[0];
+
+                }
+            }
+            fcCompFonts = fci;
+        } catch (Throwable t) {
+            if (SunGraphicsEnvironment.debugFonts) {
+                Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
+                logger.warning(t.toString());
+            }
+        }
+    }
+}
--- a/jdk/src/solaris/native/sun/awt/fontconfig.h	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/solaris/native/sun/awt/fontconfig.h	Thu Jun 12 13:17:33 2008 -0700
@@ -1,11 +1,7 @@
-/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
- */
 /*
  * $RCSId: xc/lib/fontconfig/fontconfig/fontconfig.h,v 1.30 2002/09/26 00:17:27 keithp Exp $
  *
- * Copyright © 2001 Keith Packard
+ * Copyright © 2001 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -29,8 +25,21 @@
 #ifndef _FONTCONFIG_H_
 #define _FONTCONFIG_H_
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <stdarg.h>
 
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define FC_ATTRIBUTE_SENTINEL(x) __attribute__((__sentinel__(0)))
+#else
+#define FC_ATTRIBUTE_SENTINEL(x)
+#endif
+
+#ifndef FcPublic
+#define FcPublic
+#endif
+
 typedef unsigned char   FcChar8;
 typedef unsigned short  FcChar16;
 typedef unsigned int    FcChar32;
@@ -43,7 +52,7 @@
  */
 
 #define FC_MAJOR        2
-#define FC_MINOR        2
+#define FC_MINOR        5
 #define FC_REVISION     0
 
 #define FC_VERSION      ((FC_MAJOR * 10000) + (FC_MINOR * 100) + (FC_REVISION))
@@ -58,7 +67,7 @@
  * it means multiple copies of the font information.
  */
 
-#define FC_CACHE_VERSION    "1"
+#define FC_CACHE_VERSION    "2"
 
 #define FcTrue          1
 #define FcFalse         0
@@ -74,6 +83,7 @@
 #define FC_FOUNDRY          "foundry"           /* String */
 #define FC_ANTIALIAS        "antialias"         /* Bool (depends) */
 #define FC_HINTING          "hinting"           /* Bool (true) */
+#define FC_HINT_STYLE       "hintstyle"         /* Int */
 #define FC_VERTICAL_LAYOUT  "verticallayout"    /* Bool (false) */
 #define FC_AUTOHINT         "autohint"          /* Bool (false) */
 #define FC_GLOBAL_ADVANCE   "globaladvance"     /* Bool (true) */
@@ -88,11 +98,21 @@
 #define FC_DPI              "dpi"               /* double */
 #define FC_RGBA             "rgba"              /* Int */
 #define FC_MINSPACE         "minspace"          /* Bool use minimum line spacing */
-#define FC_SOURCE           "source"            /* String (X11, freetype) */
+#define FC_SOURCE           "source"            /* String (deprecated) */
 #define FC_CHARSET          "charset"           /* CharSet */
 #define FC_LANG             "lang"              /* String RFC 3066 langs */
 #define FC_FONTVERSION      "fontversion"       /* Int from 'head' table */
+#define FC_FULLNAME         "fullname"          /* String */
+#define FC_FAMILYLANG       "familylang"        /* String RFC 3066 langs */
+#define FC_STYLELANG        "stylelang"         /* String RFC 3066 langs */
+#define FC_FULLNAMELANG     "fullnamelang"      /* String RFC 3066 langs */
+#define FC_CAPABILITY       "capability"        /* String */
+#define FC_FONTFORMAT       "fontformat"        /* String */
+#define FC_EMBOLDEN         "embolden"          /* Bool - true if emboldening needed*/
+#define FC_EMBEDDED_BITMAP  "embeddedbitmap"    /* Bool - true to enable embedded bitmaps */
+#define FC_DECORATIVE       "decorative"        /* Bool - true if style is a decorative variant */
 
+#define FC_CACHE_SUFFIX             ".cache-"FC_CACHE_VERSION
 #define FC_DIR_CACHE_FILE           "fonts.cache-"FC_CACHE_VERSION
 #define FC_USER_CACHE_FILE          ".fonts.cache-"FC_CACHE_VERSION
 
@@ -105,6 +125,7 @@
 #define FC_WEIGHT_EXTRALIGHT        40
 #define FC_WEIGHT_ULTRALIGHT        FC_WEIGHT_EXTRALIGHT
 #define FC_WEIGHT_LIGHT             50
+#define FC_WEIGHT_BOOK              75
 #define FC_WEIGHT_REGULAR           80
 #define FC_WEIGHT_NORMAL            FC_WEIGHT_REGULAR
 #define FC_WEIGHT_MEDIUM            100
@@ -115,6 +136,8 @@
 #define FC_WEIGHT_ULTRABOLD         FC_WEIGHT_EXTRABOLD
 #define FC_WEIGHT_BLACK             210
 #define FC_WEIGHT_HEAVY             FC_WEIGHT_BLACK
+#define FC_WEIGHT_EXTRABLACK        215
+#define FC_WEIGHT_ULTRABLACK        FC_WEIGHT_EXTRABLACK
 
 #define FC_SLANT_ROMAN              0
 #define FC_SLANT_ITALIC             100
@@ -131,6 +154,7 @@
 #define FC_WIDTH_ULTRAEXPANDED      200
 
 #define FC_PROPORTIONAL             0
+#define FC_DUAL                     90
 #define FC_MONO                     100
 #define FC_CHARCELL                 110
 
@@ -142,6 +166,12 @@
 #define FC_RGBA_VBGR        4
 #define FC_RGBA_NONE        5
 
+/* hinting style */
+#define FC_HINT_NONE        0
+#define FC_HINT_SLIGHT      1
+#define FC_HINT_MEDIUM      2
+#define FC_HINT_FULL        3
+
 typedef enum _FcType {
     FcTypeVoid,
     FcTypeInteger,
@@ -180,7 +210,8 @@
 } FcConstant;
 
 typedef enum _FcResult {
-    FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId
+    FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId,
+    FcResultOutOfMemory
 } FcResult;
 
 typedef struct _FcPattern   FcPattern;
@@ -197,7 +228,6 @@
         const FcMatrix  *m;
         const FcCharSet *c;
         void            *f;
-        const FcPattern *p;
         const FcLangSet *l;
     } u;
 } FcValue;
@@ -215,11 +245,14 @@
 } FcObjectSet;
 
 typedef enum _FcMatchKind {
-    FcMatchPattern, FcMatchFont
+    FcMatchPattern, FcMatchFont, FcMatchScan
 } FcMatchKind;
 
 typedef enum _FcLangResult {
-    FcLangEqual, FcLangDifferentCountry, FcLangDifferentLang
+    FcLangEqual = 0,
+    FcLangDifferentCountry = 1,
+    FcLangDifferentTerritory = 1,
+    FcLangDifferentLang = 2
 } FcLangResult;
 
 typedef enum _FcSetName {
@@ -249,169 +282,207 @@
 
 typedef struct _FcStrSet    FcStrSet;
 
-_FCFUNCPROTOBEGIN
+typedef struct _FcCache     FcCache;
 
-FcBool
-FcDirCacheValid (const FcChar8 *cache_file);
+_FCFUNCPROTOBEGIN
 
 /* fcblanks.c */
-FcBlanks *
+FcPublic FcBlanks *
 FcBlanksCreate (void);
 
-void
+FcPublic void
 FcBlanksDestroy (FcBlanks *b);
 
-FcBool
+FcPublic FcBool
 FcBlanksAdd (FcBlanks *b, FcChar32 ucs4);
 
-FcBool
+FcPublic FcBool
 FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4);
 
+/* fccache.c */
+
+FcPublic const FcChar8 *
+FcCacheDir(const FcCache *c);
+
+FcPublic FcFontSet *
+FcCacheCopySet(const FcCache *c);
+
+FcPublic const FcChar8 *
+FcCacheSubdir (const FcCache *c, int i);
+
+FcPublic int
+FcCacheNumSubdir (const FcCache *c);
+
+FcPublic int
+FcCacheNumFont (const FcCache *c);
+
+FcPublic FcBool
+FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config);
+
+FcPublic FcBool
+FcDirCacheValid (const FcChar8 *cache_file);
+
 /* fccfg.c */
-FcChar8 *
+FcPublic FcChar8 *
 FcConfigHome (void);
 
-FcBool
+FcPublic FcBool
 FcConfigEnableHome (FcBool enable);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcConfigFilename (const FcChar8 *url);
 
-FcConfig *
+FcPublic FcConfig *
 FcConfigCreate (void);
 
-void
+FcPublic void
 FcConfigDestroy (FcConfig *config);
 
-FcBool
+FcPublic FcBool
 FcConfigSetCurrent (FcConfig *config);
 
-FcConfig *
+FcPublic FcConfig *
 FcConfigGetCurrent (void);
 
-FcBool
+FcPublic FcBool
 FcConfigUptoDate (FcConfig *config);
 
-FcBool
+FcPublic FcBool
 FcConfigBuildFonts (FcConfig *config);
 
-FcStrList *
+FcPublic FcStrList *
 FcConfigGetFontDirs (FcConfig   *config);
 
-FcStrList *
+FcPublic FcStrList *
 FcConfigGetConfigDirs (FcConfig   *config);
 
-FcStrList *
+FcPublic FcStrList *
 FcConfigGetConfigFiles (FcConfig    *config);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcConfigGetCache (FcConfig  *config);
 
-FcBlanks *
+FcPublic FcBlanks *
 FcConfigGetBlanks (FcConfig *config);
 
-int
-FcConfigGetRescanInverval (FcConfig *config);
+FcPublic FcStrList *
+FcConfigGetCacheDirs (FcConfig  *config);
 
-FcBool
-FcConfigSetRescanInverval (FcConfig *config, int rescanInterval);
+FcPublic int
+FcConfigGetRescanInterval (FcConfig *config);
 
-FcFontSet *
+FcPublic FcBool
+FcConfigSetRescanInterval (FcConfig *config, int rescanInterval);
+
+FcPublic FcFontSet *
 FcConfigGetFonts (FcConfig      *config,
                   FcSetName     set);
 
-FcBool
+FcPublic FcBool
 FcConfigAppFontAddFile (FcConfig    *config,
                         const FcChar8  *file);
 
-FcBool
+FcPublic FcBool
 FcConfigAppFontAddDir (FcConfig     *config,
                        const FcChar8   *dir);
 
-void
+FcPublic void
 FcConfigAppFontClear (FcConfig      *config);
 
-FcBool
+FcPublic FcBool
 FcConfigSubstituteWithPat (FcConfig     *config,
                            FcPattern    *p,
                            FcPattern    *p_pat,
                            FcMatchKind  kind);
 
-FcBool
+FcPublic FcBool
 FcConfigSubstitute (FcConfig    *config,
                     FcPattern   *p,
                     FcMatchKind kind);
 
 /* fccharset.c */
-FcCharSet *
+FcPublic FcCharSet*
 FcCharSetCreate (void);
 
-void
+/* deprecated alias for FcCharSetCreate */
+FcPublic FcCharSet *
+FcCharSetNew (void);
+
+FcPublic void
 FcCharSetDestroy (FcCharSet *fcs);
 
-FcBool
+FcPublic FcBool
 FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4);
 
-FcCharSet *
+FcPublic FcCharSet*
 FcCharSetCopy (FcCharSet *src);
 
-FcBool
+FcPublic FcBool
 FcCharSetEqual (const FcCharSet *a, const FcCharSet *b);
 
-FcCharSet *
+FcPublic FcCharSet*
 FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b);
 
-FcCharSet *
+FcPublic FcCharSet*
 FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
 
-FcCharSet *
+FcPublic FcCharSet*
 FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b);
 
-FcBool
+FcPublic FcBool
 FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4);
 
-FcChar32
+FcPublic FcChar32
 FcCharSetCount (const FcCharSet *a);
 
-FcChar32
+FcPublic FcChar32
 FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b);
 
-FcChar32
+FcPublic FcChar32
 FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b);
 
-FcBool
+FcPublic FcBool
 FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b);
 
 #define FC_CHARSET_MAP_SIZE (256/32)
 #define FC_CHARSET_DONE ((FcChar32) -1)
 
-FcChar32
+FcPublic FcChar32
 FcCharSetFirstPage (const FcCharSet *a,
                     FcChar32        map[FC_CHARSET_MAP_SIZE],
                     FcChar32        *next);
 
-FcChar32
+FcPublic FcChar32
 FcCharSetNextPage (const FcCharSet  *a,
                    FcChar32         map[FC_CHARSET_MAP_SIZE],
                    FcChar32         *next);
 
+/*
+ * old coverage API, rather hard to use correctly
+ */
+
+FcPublic FcChar32
+FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result);
 
 /* fcdbg.c */
-void
+FcPublic void
 FcValuePrint (const FcValue v);
 
-void
+FcPublic void
 FcPatternPrint (const FcPattern *p);
 
-void
+FcPublic void
 FcFontSetPrint (const FcFontSet *s);
 
 /* fcdefault.c */
-void
+FcPublic void
 FcDefaultSubstitute (FcPattern *pattern);
 
 /* fcdir.c */
-FcBool
+FcPublic FcBool
+FcFileIsDir (const FcChar8 *file);
+
+FcPublic FcBool
 FcFileScan (FcFontSet       *set,
             FcStrSet        *dirs,
             FcFileCache     *cache,
@@ -419,7 +490,7 @@
             const FcChar8   *file,
             FcBool          force);
 
-FcBool
+FcPublic FcBool
 FcDirScan (FcFontSet        *set,
            FcStrSet         *dirs,
            FcFileCache      *cache,
@@ -427,144 +498,165 @@
            const FcChar8    *dir,
            FcBool           force);
 
-FcBool
+FcPublic FcBool
 FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir);
 
+FcPublic FcCache *
+FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file);
+
+FcPublic FcCache *
+FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config);
+
+FcPublic FcCache *
+FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat);
+
+FcPublic void
+FcDirCacheUnload (FcCache *cache);
+
 /* fcfreetype.c */
-FcPattern *
+FcPublic FcPattern *
 FcFreeTypeQuery (const FcChar8 *file, int id, FcBlanks *blanks, int *count);
 
 /* fcfs.c */
 
-FcFontSet *
+FcPublic FcFontSet *
 FcFontSetCreate (void);
 
-void
+FcPublic void
 FcFontSetDestroy (FcFontSet *s);
 
-FcBool
+FcPublic FcBool
 FcFontSetAdd (FcFontSet *s, FcPattern *font);
 
 /* fcinit.c */
-FcConfig *
+FcPublic FcConfig *
 FcInitLoadConfig (void);
 
-FcConfig *
+FcPublic FcConfig *
 FcInitLoadConfigAndFonts (void);
 
-FcBool
+FcPublic FcBool
 FcInit (void);
 
-int
+FcPublic void
+FcFini (void);
+
+FcPublic int
 FcGetVersion (void);
 
-FcBool
+FcPublic FcBool
 FcInitReinitialize (void);
 
-FcBool
+FcPublic FcBool
 FcInitBringUptoDate (void);
 
 /* fclang.c */
-FcLangSet *
+FcPublic FcStrSet *
+FcGetLangs (void);
+
+FcPublic const FcCharSet *
+FcLangGetCharSet (const FcChar8 *lang);
+
+FcPublic FcLangSet*
 FcLangSetCreate (void);
 
-void
+FcPublic void
 FcLangSetDestroy (FcLangSet *ls);
 
-FcLangSet *
+FcPublic FcLangSet*
 FcLangSetCopy (const FcLangSet *ls);
 
-FcBool
+FcPublic FcBool
 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang);
 
-FcLangResult
+FcPublic FcLangResult
 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang);
 
-FcLangResult
+FcPublic FcLangResult
 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb);
 
-FcBool
+FcPublic FcBool
 FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb);
 
-FcBool
+FcPublic FcBool
 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb);
 
-FcChar32
+FcPublic FcChar32
 FcLangSetHash (const FcLangSet *ls);
 
 /* fclist.c */
-FcObjectSet *
+FcPublic FcObjectSet *
 FcObjectSetCreate (void);
 
-FcBool
+FcPublic FcBool
 FcObjectSetAdd (FcObjectSet *os, const char *object);
 
-void
+FcPublic void
 FcObjectSetDestroy (FcObjectSet *os);
 
-FcObjectSet *
+FcPublic FcObjectSet *
 FcObjectSetVaBuild (const char *first, va_list va);
 
-FcObjectSet *
-FcObjectSetBuild (const char *first, ...);
+FcPublic FcObjectSet *
+FcObjectSetBuild (const char *first, ...) FC_ATTRIBUTE_SENTINEL(0);
 
-FcFontSet *
+FcPublic FcFontSet *
 FcFontSetList (FcConfig     *config,
                FcFontSet    **sets,
                int          nsets,
                FcPattern    *p,
                FcObjectSet  *os);
 
-FcFontSet *
+FcPublic FcFontSet *
 FcFontList (FcConfig    *config,
             FcPattern   *p,
             FcObjectSet *os);
 
 /* fcatomic.c */
 
-FcAtomic *
+FcPublic FcAtomic *
 FcAtomicCreate (const FcChar8   *file);
 
-FcBool
+FcPublic FcBool
 FcAtomicLock (FcAtomic *atomic);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcAtomicNewFile (FcAtomic *atomic);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcAtomicOrigFile (FcAtomic *atomic);
 
-FcBool
+FcPublic FcBool
 FcAtomicReplaceOrig (FcAtomic *atomic);
 
-void
+FcPublic void
 FcAtomicDeleteNew (FcAtomic *atomic);
 
-void
+FcPublic void
 FcAtomicUnlock (FcAtomic *atomic);
 
-void
+FcPublic void
 FcAtomicDestroy (FcAtomic *atomic);
 
 /* fcmatch.c */
-FcPattern *
+FcPublic FcPattern *
 FcFontSetMatch (FcConfig    *config,
                 FcFontSet   **sets,
                 int         nsets,
                 FcPattern   *p,
                 FcResult    *result);
 
-FcPattern *
+FcPublic FcPattern *
 FcFontMatch (FcConfig   *config,
              FcPattern  *p,
              FcResult   *result);
 
-FcPattern *
+FcPublic FcPattern *
 FcFontRenderPrepare (FcConfig       *config,
                      FcPattern      *pat,
                      FcPattern      *font);
 
-FcFontSet *
+FcPublic FcFontSet *
 FcFontSetSort (FcConfig     *config,
                FcFontSet    **sets,
                int          nsets,
@@ -573,179 +665,198 @@
                FcCharSet    **csp,
                FcResult     *result);
 
-FcFontSet *
+FcPublic FcFontSet *
 FcFontSort (FcConfig     *config,
             FcPattern    *p,
             FcBool       trim,
             FcCharSet    **csp,
             FcResult     *result);
 
-void
+FcPublic void
 FcFontSetSortDestroy (FcFontSet *fs);
 
 /* fcmatrix.c */
-FcMatrix *
+FcPublic FcMatrix *
 FcMatrixCopy (const FcMatrix *mat);
 
-FcBool
+FcPublic FcBool
 FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2);
 
-void
+FcPublic void
 FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b);
 
-void
+FcPublic void
 FcMatrixRotate (FcMatrix *m, double c, double s);
 
-void
+FcPublic void
 FcMatrixScale (FcMatrix *m, double sx, double sy);
 
-void
+FcPublic void
 FcMatrixShear (FcMatrix *m, double sh, double sv);
 
 /* fcname.c */
 
-FcBool
+FcPublic FcBool
 FcNameRegisterObjectTypes (const FcObjectType *types, int ntype);
 
-FcBool
+FcPublic FcBool
 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntype);
 
-const FcObjectType *
+FcPublic const FcObjectType *
 FcNameGetObjectType (const char *object);
 
-FcBool
+FcPublic FcBool
 FcNameRegisterConstants (const FcConstant *consts, int nconsts);
 
-FcBool
+FcPublic FcBool
 FcNameUnregisterConstants (const FcConstant *consts, int nconsts);
 
-const FcConstant *
+FcPublic const FcConstant *
 FcNameGetConstant (FcChar8 *string);
 
-FcBool
+FcPublic FcBool
 FcNameConstant (FcChar8 *string, int *result);
 
-FcPattern *
+FcPublic FcPattern *
 FcNameParse (const FcChar8 *name);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcNameUnparse (FcPattern *pat);
 
 /* fcpat.c */
-FcPattern *
+FcPublic FcPattern *
 FcPatternCreate (void);
 
-FcPattern *
+FcPublic FcPattern *
 FcPatternDuplicate (const FcPattern *p);
 
-void
+FcPublic void
 FcPatternReference (FcPattern *p);
 
-void
+FcPublic void
 FcValueDestroy (FcValue v);
 
-FcBool
+FcPublic FcBool
 FcValueEqual (FcValue va, FcValue vb);
 
-FcValue
+FcPublic FcValue
 FcValueSave (FcValue v);
 
-void
+FcPublic void
 FcPatternDestroy (FcPattern *p);
 
-FcBool
+FcPublic FcBool
 FcPatternEqual (const FcPattern *pa, const FcPattern *pb);
 
-FcBool
+FcPublic FcBool
 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os);
 
-FcChar32
+FcPublic FcChar32
 FcPatternHash (const FcPattern *p);
 
-FcBool
+FcPublic FcBool
 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append);
 
-FcBool
+FcPublic FcBool
 FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append);
 
-FcResult
+FcPublic FcResult
 FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v);
 
-FcBool
+FcPublic FcBool
 FcPatternDel (FcPattern *p, const char *object);
 
-FcBool
+FcPublic FcBool
+FcPatternRemove (FcPattern *p, const char *object, int id);
+
+FcPublic FcBool
 FcPatternAddInteger (FcPattern *p, const char *object, int i);
 
-FcBool
+FcPublic FcBool
 FcPatternAddDouble (FcPattern *p, const char *object, double d);
 
-FcBool
+FcPublic FcBool
 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s);
 
-FcBool
+FcPublic FcBool
 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s);
 
-FcBool
+FcPublic FcBool
 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c);
 
-FcBool
+FcPublic FcBool
 FcPatternAddBool (FcPattern *p, const char *object, FcBool b);
 
-FcBool
+FcPublic FcBool
 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls);
 
-FcResult
+FcPublic FcResult
 FcPatternGetInteger (const FcPattern *p, const char *object, int n, int *i);
 
-FcResult
+FcPublic FcResult
 FcPatternGetDouble (const FcPattern *p, const char *object, int n, double *d);
 
-FcResult
+FcPublic FcResult
 FcPatternGetString (const FcPattern *p, const char *object, int n, FcChar8 ** s);
 
-FcResult
+FcPublic FcResult
 FcPatternGetMatrix (const FcPattern *p, const char *object, int n, FcMatrix **s);
 
-FcResult
+FcPublic FcResult
 FcPatternGetCharSet (const FcPattern *p, const char *object, int n, FcCharSet **c);
 
-FcResult
+FcPublic FcResult
 FcPatternGetBool (const FcPattern *p, const char *object, int n, FcBool *b);
 
-FcResult
+FcPublic FcResult
 FcPatternGetLangSet (const FcPattern *p, const char *object, int n, FcLangSet **ls);
 
-FcPattern *
+FcPublic FcPattern *
 FcPatternVaBuild (FcPattern *orig, va_list va);
 
-FcPattern *
-FcPatternBuild (FcPattern *orig, ...);
+FcPublic FcPattern *
+FcPatternBuild (FcPattern *orig, ...) FC_ATTRIBUTE_SENTINEL(0);
 
 /* fcstr.c */
 
-FcChar8 *
+FcPublic FcChar8 *
 FcStrCopy (const FcChar8 *s);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcStrCopyFilename (const FcChar8 *s);
 
-#define FcIsUpper(c)    (('A' <= (c) && (c) <= 'Z'))
-#define FcIsLower(c)    (('a' <= (c) && (c) <= 'z'))
-#define FcToLower(c)    (FcIsUpper(c) ? (c) - 'A' + 'a' : (c))
+FcPublic FcChar8 *
+FcStrPlus (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic void
+FcStrFree (FcChar8 *s);
 
-int
+/* These are ASCII only, suitable only for pattern element names */
+#define FcIsUpper(c)    ((0101 <= (c) && (c) <= 0132))
+#define FcIsLower(c)    ((0141 <= (c) && (c) <= 0172))
+#define FcToLower(c)    (FcIsUpper(c) ? (c) - 0101 + 0141 : (c))
+
+FcPublic FcChar8 *
+FcStrDowncase (const FcChar8 *s);
+
+FcPublic int
 FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2);
 
-int
+FcPublic int
 FcStrCmp (const FcChar8 *s1, const FcChar8 *s2);
 
-int
+FcPublic const FcChar8 *
+FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic const FcChar8 *
+FcStrStr (const FcChar8 *s1, const FcChar8 *s2);
+
+FcPublic int
 FcUtf8ToUcs4 (const FcChar8 *src_orig,
               FcChar32      *dst,
               int           len);
 
-FcBool
+FcPublic FcBool
 FcUtf8Len (const FcChar8    *string,
            int              len,
            int              *nchar,
@@ -753,63 +864,78 @@
 
 #define FC_UTF8_MAX_LEN 6
 
-int
+FcPublic int
 FcUcs4ToUtf8 (FcChar32  ucs4,
               FcChar8   dest[FC_UTF8_MAX_LEN]);
 
-int
+FcPublic int
 FcUtf16ToUcs4 (const FcChar8    *src_orig,
                FcEndian         endian,
                FcChar32         *dst,
                int              len);       /* in bytes */
 
-FcBool
+FcPublic FcBool
 FcUtf16Len (const FcChar8   *string,
             FcEndian        endian,
             int             len,            /* in bytes */
             int             *nchar,
             int             *wchar);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcStrDirname (const FcChar8 *file);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcStrBasename (const FcChar8 *file);
 
-FcStrSet *
+FcPublic FcStrSet *
 FcStrSetCreate (void);
 
-FcBool
+FcPublic FcBool
 FcStrSetMember (FcStrSet *set, const FcChar8 *s);
 
-FcBool
+FcPublic FcBool
 FcStrSetEqual (FcStrSet *sa, FcStrSet *sb);
 
-FcBool
+FcPublic FcBool
 FcStrSetAdd (FcStrSet *set, const FcChar8 *s);
 
-FcBool
+FcPublic FcBool
 FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s);
 
-FcBool
+FcPublic FcBool
 FcStrSetDel (FcStrSet *set, const FcChar8 *s);
 
-void
+FcPublic void
 FcStrSetDestroy (FcStrSet *set);
 
-FcStrList *
+FcPublic FcStrList *
 FcStrListCreate (FcStrSet *set);
 
-FcChar8 *
+FcPublic FcChar8 *
 FcStrListNext (FcStrList *list);
 
-void
+FcPublic void
 FcStrListDone (FcStrList *list);
 
 /* fcxml.c */
-FcBool
+FcPublic FcBool
 FcConfigParseAndLoad (FcConfig *config, const FcChar8 *file, FcBool complain);
 
 _FCFUNCPROTOEND
 
+#undef FC_ATTRIBUTE_SENTINEL
+
+
+#ifndef _FCINT_H_
+
+/*
+ * Deprecated functions are placed here to help users fix their code without
+ * digging through documentation
+ */
+
+#define FcConfigGetRescanInverval   FcConfigGetRescanInverval_REPLACE_BY_FcConfigGetRescanInterval
+#define FcConfigSetRescanInverval   FcConfigSetRescanInverval_REPLACE_BY_FcConfigSetRescanInterval
+
+#endif
+
 #endif /* _FONTCONFIG_H_ */
--- a/jdk/src/solaris/native/sun/awt/fontpath.c	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/solaris/native/sun/awt/fontpath.c	Thu Jun 12 13:17:33 2008 -0700
@@ -735,6 +735,25 @@
 typedef FcFontSet* (*FcFontSetCreateFuncType)();
 typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);
 
+typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p,
+                                                const char *object,
+                                                int n,
+                                                FcCharSet **c);
+typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config,
+                                         FcPattern *p,
+                                         FcBool trim,
+                                         FcCharSet **csp,
+                                         FcResult *result);
+typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a,
+                                             const FcCharSet *b);
+typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a,
+                                                   const FcCharSet *b);
+
+typedef int (*FcGetVersionFuncType)();
+
+typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);
+typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);
+typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);
 
 static char **getFontConfigLocations() {
 
@@ -955,10 +974,35 @@
     }
 }
 
+JNIEXPORT jint JNICALL
+Java_sun_font_FontManager_getFontConfigVersion
+    (JNIEnv *env, jclass obj) {
+
+    void* libfontconfig;
+    FcGetVersionFuncType FcGetVersion;
+    int version = 0;
+
+    if ((libfontconfig = openFontConfig()) == NULL) {
+        return 0;
+    }
+
+    FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");
+
+    if (FcGetVersion == NULL) {
+        closeFontConfig(libfontconfig, JNI_FALSE);
+        return 0;
+    }
+    version = (*FcGetVersion)();
+    closeFontConfig(libfontconfig, JNI_FALSE);
+
+    return version;
+}
+
 
 JNIEXPORT void JNICALL
 Java_sun_font_FontManager_getFontConfig
-(JNIEnv *env, jclass obj, jstring localeStr, jobjectArray fontInfoArray) {
+(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,
+ jobjectArray fcCompFontArray,  jboolean includeFallbacks) {
 
     FcNameParseFuncType FcNameParse;
     FcPatternAddStringFuncType FcPatternAddString;
@@ -967,33 +1011,70 @@
     FcFontMatchFuncType FcFontMatch;
     FcPatternGetStringFuncType FcPatternGetString;
     FcPatternDestroyFuncType FcPatternDestroy;
+    FcPatternGetCharSetFuncType FcPatternGetCharSet;
+    FcFontSortFuncType FcFontSort;
+    FcFontSetDestroyFuncType FcFontSetDestroy;
+    FcCharSetUnionFuncType FcCharSetUnion;
+    FcCharSetSubtractCountFuncType FcCharSetSubtractCount;
+    FcGetVersionFuncType FcGetVersion;
+    FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs;
+    FcStrListNextFuncType FcStrListNext;
+    FcStrListDoneFuncType FcStrListDone;
 
     int i, arrlen;
-    jobject fontInfoObj;
+    jobject fcCompFontObj;
     jstring fcNameStr, jstr;
     const char *locale, *fcName;
-    FcPattern *pattern, *matchPattern;
+    FcPattern *pattern;
     FcResult result;
     void* libfontconfig;
-    jfieldID fcNameID, familyNameID, fontFileID;
+    jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;
+    jfieldID familyNameID, styleNameID, fullNameID, fontFileID;
+    jmethodID fcFontCons;
+    char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");
 
-    jclass fontInfoArrayClass =
-        (*env)->FindClass(env, "[Lsun/font/FontManager$FontConfigInfo;");
-    jclass fontInfoClass =
+    jclass fcInfoClass =
         (*env)->FindClass(env, "sun/font/FontManager$FontConfigInfo");
+    jclass fcCompFontClass =
+        (*env)->FindClass(env, "sun/font/FontManager$FcCompFont");
+    jclass fcFontClass =
+         (*env)->FindClass(env, "sun/font/FontManager$FontConfigFont");
 
-    if (fontInfoArray == NULL || fontInfoClass == NULL) {
+    if (fcInfoObj == NULL || fcCompFontArray == NULL || fcInfoClass == NULL ||
+        fcCompFontClass == NULL || fcFontClass == NULL) {
         return;
     }
 
-    fcNameID = (*env)->GetFieldID(env, fontInfoClass,
+    fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I");
+
+    fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs",
+                                       "[Ljava/lang/String;");
+
+    fcNameID = (*env)->GetFieldID(env, fcCompFontClass,
                                   "fcName", "Ljava/lang/String;");
-    familyNameID = (*env)->GetFieldID(env, fontInfoClass,
+    fcFirstFontID =
+        (*env)->GetFieldID(env, fcCompFontClass, "firstFont",
+                           "Lsun/font/FontManager$FontConfigFont;");
+
+    fcAllFontsID =
+        (*env)->GetFieldID(env, fcCompFontClass, "allFonts",
+                           "[Lsun/font/FontManager$FontConfigFont;");
+
+    fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V");
+
+    familyNameID = (*env)->GetFieldID(env, fcFontClass,
                                       "familyName", "Ljava/lang/String;");
-    fontFileID = (*env)->GetFieldID(env, fontInfoClass,
+    styleNameID = (*env)->GetFieldID(env, fcFontClass,
+                                    "styleStr", "Ljava/lang/String;");
+    fullNameID = (*env)->GetFieldID(env, fcFontClass,
+                                    "fullName", "Ljava/lang/String;");
+    fontFileID = (*env)->GetFieldID(env, fcFontClass,
                                     "fontFile", "Ljava/lang/String;");
 
-    if (fcNameID == NULL || familyNameID == NULL || fontFileID == NULL) {
+    if (fcVersionID == NULL || fcCacheDirsID == NULL || fcNameID == NULL ||
+        fcFirstFontID == NULL || fcAllFontsID == NULL || fcFontCons == NULL ||
+        familyNameID == NULL || styleNameID == NULL || fullNameID == NULL ||
+        fontFileID == NULL) {
         return;
     }
 
@@ -1013,6 +1094,19 @@
         (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
     FcPatternDestroy =
         (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
+    FcPatternGetCharSet =
+        (FcPatternGetCharSetFuncType)dlsym(libfontconfig,
+                                           "FcPatternGetCharSet");
+    FcFontSort =
+        (FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");
+    FcFontSetDestroy =
+        (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");
+    FcCharSetUnion =
+        (FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");
+    FcCharSetSubtractCount =
+        (FcCharSetSubtractCountFuncType)dlsym(libfontconfig,
+                                              "FcCharSetSubtractCount");
+    FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");
 
     if (FcNameParse          == NULL ||
         FcPatternAddString   == NULL ||
@@ -1020,23 +1114,77 @@
         FcDefaultSubstitute  == NULL ||
         FcFontMatch          == NULL ||
         FcPatternGetString   == NULL ||
-        FcPatternDestroy     == NULL) { /* problem with the library: return. */
+        FcPatternDestroy     == NULL ||
+        FcPatternGetCharSet  == NULL ||
+        FcFontSetDestroy     == NULL ||
+        FcCharSetUnion       == NULL ||
+        FcGetVersion         == NULL ||
+        FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/
         closeFontConfig(libfontconfig, JNI_FALSE);
         return;
     }
 
+    (*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)());
+
+    /* Optionally get the cache dir locations. This isn't
+     * available until v 2.4.x, but this is OK since on those later versions
+     * we can check the time stamps on the cache dirs to see if we
+     * are out of date. There are a couple of assumptions here. First
+     * that the time stamp on the directory changes when the contents are
+     * updated. Secondly that the locations don't change. The latter is
+     * most likely if a new version of fontconfig is installed, but we also
+     * invalidate the cache if we detect that. Arguably even that is "rare",
+     * and most likely is tied to an OS upgrade which gets a new file anyway.
+     */
+    FcConfigGetCacheDirs =
+        (FcConfigGetCacheDirsFuncType)dlsym(libfontconfig,
+                                            "FcConfigGetCacheDirs");
+    FcStrListNext =
+        (FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");
+    FcStrListDone =
+        (FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");
+    if (FcStrListNext != NULL && FcStrListDone != NULL &&
+        FcConfigGetCacheDirs != NULL) {
+
+        FcStrList* cacheDirs;
+        FcChar8* cacheDir;
+        int cnt = 0;
+        jobject cacheDirArray =
+            (*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);
+        int max = (*env)->GetArrayLength(env, cacheDirArray);
+
+        cacheDirs = (*FcConfigGetCacheDirs)(NULL);
+        if (cacheDirs != NULL) {
+            while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) {
+                jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);
+                (*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);
+            }
+            (*FcStrListDone)(cacheDirs);
+        }
+    }
+
     locale = (*env)->GetStringUTFChars(env, localeStr, 0);
 
-    arrlen = (*env)->GetArrayLength(env, fontInfoArray);
+    arrlen = (*env)->GetArrayLength(env, fcCompFontArray);
     for (i=0; i<arrlen; i++) {
-        fontInfoObj = (*env)->GetObjectArrayElement(env, fontInfoArray, i);
+        FcFontSet* fontset;
+        int fn, j, fontCount, nfonts, minGlyphs;
+        FcChar8 **family, **styleStr, **fullname, **file;
+        jarray fcFontArr;
+
+        fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);
         fcNameStr =
-            (jstring)((*env)->GetObjectField(env, fontInfoObj, fcNameID));
+            (jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));
         fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
         if (fcName == NULL) {
             continue;
         }
         pattern = (*FcNameParse)((FcChar8 *)fcName);
+        if (pattern == NULL) {
+            closeFontConfig(libfontconfig, JNI_FALSE);
+            return;
+        }
+
         /* locale may not usually be necessary as fontconfig appears to apply
          * this anyway based on the user's environment. However we want
          * to use the value of the JDK startup locale so this should take
@@ -1047,25 +1195,134 @@
         }
         (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
         (*FcDefaultSubstitute)(pattern);
-        matchPattern = (*FcFontMatch)(NULL, pattern, &result);
-        if (matchPattern) {
-            FcChar8 *file, *family;
+        fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result);
+        if (fontset == NULL) {
+            closeFontConfig(libfontconfig, JNI_FALSE);
+            return;
+        }
 
-            (*FcPatternGetString)(matchPattern, FC_FILE, 0, &file);
-            (*FcPatternGetString)(matchPattern, FC_FAMILY, 0, &family);
+        /* fontconfig returned us "nfonts". If we are just getting the
+         * first font, we set nfont to zero. Otherwise we use "nfonts".
+         * Next create separate C arrrays of length nfonts for family file etc.
+         * Inspect the returned fonts and the ones we like (adds enough glyphs)
+         * are added to the arrays and we increment 'fontCount'.
+         */
+        if (includeFallbacks) {
+            nfonts = fontset->nfont;
+        } else {
+            nfonts = 1;
+        }
+        family   = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
+        styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
+        fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
+        file     = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
+        if (family == NULL || styleStr == NULL ||
+            fullname == NULL || file == NULL) {
+            closeFontConfig(libfontconfig, JNI_FALSE);
+            return;
+        }
+        fontCount = 0;
+        minGlyphs = 20;
+        if (debugMinGlyphsStr != NULL) {
+            int val = minGlyphs;
+            sscanf(debugMinGlyphsStr, "%5d", &val);
+            if (val >= 0 && val <= 65536) {
+                minGlyphs = val;
+            }
+        }
+        for (j=0; j<nfonts; j++) {
+            FcPattern *fontPattern = fontset->fonts[j];
+            FcChar8 *fontformat;
+            FcCharSet *unionCharset, *charset;
+
+            fontformat = NULL;
+            (*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);
+            if (fontformat != NULL && strcmp((char*)fontformat, "TrueType")
+                != 0) {
+                continue;
+            }
+            result = (*FcPatternGetCharSet)(fontPattern,
+                                            FC_CHARSET, 0, &charset);
+            if (result != FcResultMatch) {
+                closeFontConfig(libfontconfig, JNI_FALSE);
+                return;
+            }
 
-            if (file != NULL) {
-                jstr = (*env)->NewStringUTF(env, (const char*)file);
-                ((*env)->SetObjectField(env, fontInfoObj, fontFileID, jstr));
+            /* We don't want 20 or 30 fonts, so once we hit 10 fonts,
+             * then require that they really be adding value. Too many
+             * adversely affects load time for minimal value-add.
+             * This is still likely far more than we've had in the past.
+             */
+            if (nfonts==10) {
+                minGlyphs = 50;
+            }
+            if (j == 0) {
+                unionCharset = charset;
+            } else {
+                if ((*FcCharSetSubtractCount)(charset, unionCharset)
+                    > minGlyphs) {
+                    unionCharset = (* FcCharSetUnion)(unionCharset, charset);
+                } else {
+                    continue;
+                }
             }
-            if (family != NULL) {
-                jstr = (*env)->NewStringUTF(env, (const char*)family);
-                ((*env)->SetObjectField(env, fontInfoObj, familyNameID, jstr));
+
+            fontCount++; // found a font we will use.
+            (*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);
+            (*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);
+            (*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);
+            (*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);
+        }
+
+        /* Once we get here 'fontCount' is the number of returned fonts
+         * we actually want to use, so we create 'fcFontArr' of that length.
+         * The non-null entries of "family[]" etc are those fonts.
+         * Then loop again over all nfonts adding just those non-null ones
+         * to 'fcFontArr'. If its null (we didn't want the font)
+         * then we don't enter the main body.
+         * So we should never get more than 'fontCount' entries.
+         */
+        if (includeFallbacks) {
+            fcFontArr =
+                (*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);
+            (*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
+        }
+        fn=0;
+
+        for (j=0;j<nfonts;j++) {
+            if (family[j] != NULL) {
+                jobject fcFont =
+                    (*env)->NewObject(env, fcFontClass, fcFontCons);
+                jstr = (*env)->NewStringUTF(env, (const char*)family[j]);
+                (*env)->SetObjectField(env, fcFont, familyNameID, jstr);
+                if (file[j] != NULL) {
+                    jstr = (*env)->NewStringUTF(env, (const char*)file[j]);
+                    (*env)->SetObjectField(env, fcFont, fontFileID, jstr);
+                }
+                if (styleStr[j] != NULL) {
+                    jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);
+                    (*env)->SetObjectField(env, fcFont, styleNameID, jstr);
+                }
+                if (fullname[j] != NULL) {
+                    jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);
+                    (*env)->SetObjectField(env, fcFont, fullNameID, jstr);
+                }
+                if (fn==0) {
+                    (*env)->SetObjectField(env, fcCompFontObj,
+                                           fcFirstFontID, fcFont);
+                }
+                if (includeFallbacks) {
+                    (*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);
+                }
             }
-            (*FcPatternDestroy)(matchPattern);
         }
         (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
+        (*FcFontSetDestroy)(fontset);
         (*FcPatternDestroy)(pattern);
+        free(family);
+        free(styleStr);
+        free(fullname);
+        free(file);
     }
 
     /* release resources and close the ".so" */
--- a/jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java	Thu Jun 05 14:18:37 2008 -0700
+++ b/jdk/src/windows/classes/sun/awt/Win32GraphicsEnvironment.java	Thu Jun 12 13:17:33 2008 -0700
@@ -338,7 +338,9 @@
 
     // Implements SunGraphicsEnvironment.createFontConfiguration.
     protected FontConfiguration createFontConfiguration() {
-        return new WFontConfiguration(this);
+       FontConfiguration fc = new WFontConfiguration(this);
+       fc.init();
+       return fc;
     }
 
     public FontConfiguration createFontConfiguration(boolean preferLocaleFonts,