src/solaris/classes/sun/font/FcFontConfiguration.java

Print this page
rev 1379 : [mq]: fontmanager.patch


  24  */
  25 
  26 package sun.font;
  27 
  28 import java.awt.Font;
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.FileOutputStream;
  32 import java.io.IOException;
  33 import java.net.InetAddress;
  34 import java.net.UnknownHostException;
  35 import java.nio.charset.Charset;
  36 import java.util.HashMap;
  37 import java.util.HashSet;
  38 import java.util.logging.Logger;
  39 import java.util.Properties;
  40 import java.util.Scanner;
  41 import sun.awt.FontConfiguration;
  42 import sun.awt.FontDescriptor;
  43 import sun.awt.SunToolkit;

  44 import sun.font.CompositeFontDescriptor;
  45 import sun.font.FontManager;
  46 import sun.font.FontManager.FontConfigInfo;
  47 import sun.font.FontManager.FcCompFont;
  48 import sun.font.FontManager.FontConfigFont;
  49 import sun.java2d.SunGraphicsEnvironment;
  50 
  51 public class FcFontConfiguration extends FontConfiguration {
  52 
  53     /** Version of the cache file format understood by this code.
  54      * Its part of the file name so that we can rev this at
  55      * any time, even in a minor JDK update.
  56      * It is stored as the value of the "version" property.
  57      * This is distinct from the version of "libfontconfig" that generated
  58      * the cached results, and which is the "fcversion" property in the file.
  59      * {@code FontConfiguration.getVersion()} also returns a version string,
  60      * and has meant the version of the fontconfiguration.properties file
  61      * that was read. Since this class doesn't use such files, then what
  62      * that really means is whether the methods on this class return
  63      * values that are compatible with the classes that do directly read
  64      * from such files. It is a compatible subset of version "1".
  65      */
  66     private static final String fileVersion = "1";
  67     private String fcInfoFileName = null;
  68 
  69     private FcCompFont[] fcCompFonts = null;
  70 
  71     public FcFontConfiguration(SunGraphicsEnvironment environment) {
  72         super(environment);
  73         init();
  74     }
  75 
  76     /* This isn't called but is needed to satisfy super-class contract. */
  77     public FcFontConfiguration(SunGraphicsEnvironment environment,
  78                                boolean preferLocaleFonts,
  79                                boolean preferPropFonts) {
  80         super(environment, preferLocaleFonts, preferPropFonts);
  81         init();
  82     }
  83 
  84     @Override
  85     public synchronized boolean init() {
  86         if (fcCompFonts != null) {
  87             return true;
  88         }
  89 
  90         setFontConfiguration();
  91         readFcInfo();


  92         if (fcCompFonts == null) {
  93             fcCompFonts = FontManager.loadFontConfig();
  94             if (fcCompFonts != null) {
  95                 try {
  96                     writeFcInfo();
  97                 } catch (Exception e) {
  98                     if (SunGraphicsEnvironment.debugFonts) {
  99                         Logger logger =
 100                             Logger.getLogger("sun.awt.FontConfiguration");
 101                         logger.warning("Exception writing fcInfo " + e);
 102                     }
 103                 }
 104             } else if (SunGraphicsEnvironment.debugFonts) {
 105                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 106                 logger.warning("Failed to get info from libfontconfig");
 107             }
 108         } else {
 109             FontManager.populateFontConfig(fcCompFonts);
 110         }
 111 
 112         if (fcCompFonts == null) {
 113             return false; // couldn't load fontconfig.
 114         }
 115 
 116         // NB already in a privileged block from SGE
 117         String javaHome = System.getProperty("java.home");
 118         if (javaHome == null) {
 119             throw new Error("java.home property not set");
 120         }
 121         String javaLib = javaHome + File.separator + "lib";
 122         getInstalledFallbackFonts(javaLib);
 123 
 124         return true;
 125     }
 126 
 127     @Override
 128     public String getFallbackFamilyName(String fontName,
 129                                         String defaultFallback) {


 167     }
 168 
 169     @Override
 170     protected void initReorderMap() {
 171         reorderMap = new HashMap();
 172     }
 173 
 174     @Override
 175     public FontDescriptor[] getFontDescriptors(String fontName, int style) {
 176         return new FontDescriptor[0];
 177     }
 178 
 179     @Override
 180     public int getNumberCoreFonts() {
 181         return 1;
 182     }
 183 
 184     @Override
 185     public String[] getPlatformFontNames() {
 186         HashSet<String> nameSet = new HashSet<String>();
 187         FcCompFont[] fcCompFonts = FontManager.loadFontConfig();


 188         for (int i=0; i<fcCompFonts.length; i++) {
 189             for (int j=0; j<fcCompFonts[i].allFonts.length; j++) {
 190                 nameSet.add(fcCompFonts[i].allFonts[j].fontFile);
 191             }
 192         }
 193         return nameSet.toArray(new String[0]);
 194     }
 195 
 196     @Override
 197     public String getExtraFontPath() {
 198         return null;
 199     }
 200 
 201     @Override
 202     public boolean needToSearchForFile(String fileName) {
 203         return false;
 204     }
 205 
 206     private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
 207                                            String fontname, int style) {
 208 
 209         if (fontname.equals("dialog")) {
 210             fontname = "sansserif";
 211         } else if (fontname.equals("dialoginput")) {
 212             fontname = "monospaced";
 213         }
 214         for (int i=0; i<fcFonts.length; i++) {
 215             if (fontname.equals(fcFonts[i].jdkName) &&
 216                 style == fcFonts[i].style) {
 217                 return fcFonts[i].allFonts;
 218             }
 219         }
 220         return fcFonts[0].allFonts;
 221     }
 222 
 223     @Override
 224     public CompositeFontDescriptor[] get2DCompositeFontInfo() {
 225 
 226         FcCompFont[] fcCompFonts = FontManager.loadFontConfig();


 227 
 228         CompositeFontDescriptor[] result =
 229                 new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
 230 
 231         for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
 232             String fontName = publicFontNames[fontIndex];
 233 
 234             for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
 235 
 236                 String faceName = fontName + "." + styleNames[styleIndex];
 237                 FontConfigFont[] fcFonts =
 238                     getFcFontList(fcCompFonts,
 239                                   fontNames[fontIndex], styleIndex);
 240 
 241                 int numFonts = fcFonts.length;
 242                 // fall back fonts listed in the lib/fonts/fallback directory
 243                 if (installedFallbackFontFiles != null) {
 244                     numFonts += installedFallbackFontFiles.length;
 245                 }
 246 


 304                     props.load(new FileInputStream(f));
 305                     osName = props.getProperty("DISTRIB_ID");
 306                     osVersion =  props.getProperty("DISTRIB_RELEASE");
 307             } else if ((f = new File("/etc/redhat-release")).canRead()) {
 308                 osName = "RedHat";
 309                 osVersion = getVersionString(f);
 310             } else if ((f = new File("/etc/SuSE-release")).canRead()) {
 311                 osName = "SuSE";
 312                 osVersion = getVersionString(f);
 313             } else if ((f = new File("/etc/turbolinux-release")).canRead()) {
 314                 osName = "Turbo";
 315                 osVersion = getVersionString(f);
 316             } else if ((f = new File("/etc/fedora-release")).canRead()) {
 317                 osName = "Fedora";
 318                 osVersion = getVersionString(f);
 319             } else if ((f = new File("/etc/sun-release")).canRead()) {
 320                 osName = "Sun";
 321                 osVersion = getVersionString(f);
 322             }
 323         } catch (Exception e) {
 324             if (SunGraphicsEnvironment.debugFonts) {
 325                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 326                 logger.warning("Exception identifying Linux distro.");
 327             }
 328         }
 329     }
 330 
 331     private File getFcInfoFile() {
 332         if (fcInfoFileName == null) {
 333             // NB need security permissions to get true IP address, and
 334             // we should have those as the whole initialisation is in a
 335             // doPrivileged block. But in this case no exception is thrown,
 336             // and it returns the loop back address, and so we end up with
 337             // "localhost"
 338             String hostname;
 339             try {
 340                 hostname = InetAddress.getLocalHost().getHostName();
 341             } catch (UnknownHostException e) {
 342                 hostname = "localhost";
 343             }
 344             String userDir = System.getProperty("user.home");
 345             String version = System.getProperty("java.version");
 346             String fs = File.separator;
 347             String dir = userDir+fs+".java"+fs+"fonts"+fs+version;
 348             String lang = SunToolkit.getStartupLocale().getLanguage();
 349             String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+
 350                 osName+"-"+osVersion+"-"+lang+".properties";
 351             fcInfoFileName = dir+fs+name;
 352         }
 353         return new File(fcInfoFileName);
 354     }
 355 
 356     private void writeFcInfo() {
 357         Properties props = new Properties();
 358         props.setProperty("version", fileVersion);
 359         FontConfigInfo fcInfo = FontManager.getFontConfigInfo();


 360         props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
 361         if (fcInfo.cacheDirs != null) {
 362             for (int i=0;i<fcInfo.cacheDirs.length;i++) {
 363                 if (fcInfo.cacheDirs[i] != null) {
 364                    props.setProperty("cachedir."+i,  fcInfo.cacheDirs[i]);
 365                 }
 366             }
 367         }
 368         for (int i=0; i<fcCompFonts.length; i++) {
 369             FcCompFont fci = fcCompFonts[i];
 370             String styleKey = fci.jdkName+"."+fci.style;
 371             props.setProperty(styleKey+".length",
 372                               Integer.toString(fci.allFonts.length));
 373             for (int j=0; j<fci.allFonts.length; j++) {
 374                 props.setProperty(styleKey+"."+j+".family",
 375                                   fci.allFonts[j].familyName);
 376                 props.setProperty(styleKey+"."+j+".file",
 377                                   fci.allFonts[j].fontFile);
 378             }
 379         }
 380         try {
 381             /* This writes into a temp file then renames when done.
 382              * Since the rename is an atomic action within the same
 383              * directory no client will ever see a partially written file.
 384              */
 385             File fcInfoFile = getFcInfoFile();
 386             File dir = fcInfoFile.getParentFile();
 387             dir.mkdirs();
 388             File tempFile = File.createTempFile("fcinfo", null, dir);
 389             FileOutputStream fos = new FileOutputStream(tempFile);
 390             props.store(fos,
 391                       "JDK Font Configuration Generated File: *Do Not Edit*");
 392             fos.close();
 393             boolean renamed = tempFile.renameTo(fcInfoFile);
 394             if (!renamed && SunGraphicsEnvironment.debugFonts) {
 395                 System.out.println("rename failed");
 396                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 397                 logger.warning("Failed renaming file to "+ getFcInfoFile());
 398             }
 399         } catch (Exception e) {
 400             if (SunGraphicsEnvironment.debugFonts) {
 401                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 402                 logger.warning("IOException writing to "+ getFcInfoFile());
 403             }
 404         }
 405     }
 406 
 407     /* We want to be able to use this cache instead of invoking
 408      * fontconfig except when we can detect the system cache has changed.
 409      * But there doesn't seem to be a way to find the location of
 410      * the system cache.
 411      */
 412     private void readFcInfo() {
 413         File fcFile = getFcInfoFile();
 414         if (!fcFile.exists()) {
 415             return;
 416         }
 417         Properties props = new Properties();


 418         try {
 419             FileInputStream fis = new FileInputStream(fcFile);
 420             props.load(fis);
 421             fis.close();
 422         } catch (IOException e) {
 423             if (SunGraphicsEnvironment.debugFonts) {
 424                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 425                 logger.warning("IOException reading from "+fcFile.toString());
 426             }
 427             return;
 428         }
 429         String version = (String)props.get("version");
 430         if (version == null || !version.equals(fileVersion)) {
 431             return;
 432         }
 433 
 434         // If there's a new, different fontconfig installed on the
 435         // system, we invalidate our fontconfig file.
 436         String fcVersionStr = (String)props.get("fcversion");
 437         if (fcVersionStr != null) {
 438             int fcVersion;
 439             try {
 440                 fcVersion = Integer.parseInt(fcVersionStr);
 441                 if (fcVersion != 0 &&
 442                     fcVersion != FontManager.getFontConfigVersion()) {
 443                     return;
 444                 }
 445             } catch (Exception e) {
 446                 if (SunGraphicsEnvironment.debugFonts) {
 447                     Logger logger =
 448                         Logger.getLogger("sun.awt.FontConfiguration");
 449                     logger.warning("Exception parsing version " +
 450                                    fcVersionStr);
 451                 }
 452                 return;
 453             }
 454         }
 455 
 456         // If we can locate the fontconfig cache dirs, then compare the
 457         // time stamp of those with our properties file. If we are out
 458         // of date then re-generate.
 459         long lastModified = fcFile.lastModified();
 460         int cacheDirIndex = 0;
 461         while (cacheDirIndex<4) { // should never be more than 2 anyway.
 462             String dir = (String)props.get("cachedir."+cacheDirIndex);
 463             if (dir == null) {
 464                 break;
 465             }
 466             File dirFile = new File(dir);


 492                     }
 493                     fci[index].allFonts = new FontConfigFont[nfonts];
 494                     for (int f=0; f<nfonts; f++) {
 495                         fci[index].allFonts[f] = new FontConfigFont();
 496                         String fkey = key+"."+f+".family";
 497                         String family = (String)props.get(fkey);
 498                         fci[index].allFonts[f].familyName = family;
 499                         fkey = key+"."+f+".file";
 500                         String file = (String)props.get(fkey);
 501                         if (file == null) {
 502                             return; // bad file
 503                         }
 504                         fci[index].allFonts[f].fontFile = file;
 505                     }
 506                     fci[index].firstFont =  fci[index].allFonts[0];
 507 
 508                 }
 509             }
 510             fcCompFonts = fci;
 511         } catch (Throwable t) {
 512             if (SunGraphicsEnvironment.debugFonts) {
 513                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 514                 logger.warning(t.toString());
 515             }
 516         }
 517     }
 518 }


  24  */
  25 
  26 package sun.font;
  27 
  28 import java.awt.Font;
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.FileOutputStream;
  32 import java.io.IOException;
  33 import java.net.InetAddress;
  34 import java.net.UnknownHostException;
  35 import java.nio.charset.Charset;
  36 import java.util.HashMap;
  37 import java.util.HashSet;
  38 import java.util.logging.Logger;
  39 import java.util.Properties;
  40 import java.util.Scanner;
  41 import sun.awt.FontConfiguration;
  42 import sun.awt.FontDescriptor;
  43 import sun.awt.SunToolkit;
  44 import sun.awt.X11FontManager;
  45 import sun.font.CompositeFontDescriptor;
  46 import sun.font.FontManager;
  47 import sun.font.FontConfigManager.FontConfigInfo;
  48 import sun.font.FontConfigManager.FcCompFont;
  49 import sun.font.FontConfigManager.FontConfigFont;
  50 import sun.java2d.SunGraphicsEnvironment;
  51 
  52 public class FcFontConfiguration extends FontConfiguration {
  53 
  54     /** Version of the cache file format understood by this code.
  55      * Its part of the file name so that we can rev this at
  56      * any time, even in a minor JDK update.
  57      * It is stored as the value of the "version" property.
  58      * This is distinct from the version of "libfontconfig" that generated
  59      * the cached results, and which is the "fcversion" property in the file.
  60      * {@code FontConfiguration.getVersion()} also returns a version string,
  61      * and has meant the version of the fontconfiguration.properties file
  62      * that was read. Since this class doesn't use such files, then what
  63      * that really means is whether the methods on this class return
  64      * values that are compatible with the classes that do directly read
  65      * from such files. It is a compatible subset of version "1".
  66      */
  67     private static final String fileVersion = "1";
  68     private String fcInfoFileName = null;
  69 
  70     private FcCompFont[] fcCompFonts = null;
  71 
  72     public FcFontConfiguration(SunFontManager fm) {
  73         super(fm);
  74         init();
  75     }
  76 
  77     /* This isn't called but is needed to satisfy super-class contract. */
  78     public FcFontConfiguration(SunFontManager fm,
  79                                boolean preferLocaleFonts,
  80                                boolean preferPropFonts) {
  81         super(fm, preferLocaleFonts, preferPropFonts);
  82         init();
  83     }
  84 
  85     @Override
  86     public synchronized boolean init() {
  87         if (fcCompFonts != null) {
  88             return true;
  89         }
  90 
  91         setFontConfiguration();
  92         readFcInfo();
  93         X11FontManager fm = X11FontManager.getInstance();
  94         FontConfigManager fcm = fm.getFontConfigManager();
  95         if (fcCompFonts == null) {
  96             fcCompFonts = fcm.loadFontConfig();
  97             if (fcCompFonts != null) {
  98                 try {
  99                     writeFcInfo();
 100                 } catch (Exception e) {
 101                     if (FontUtilities.debugFonts()) {
 102                         Logger logger =
 103                             Logger.getLogger("sun.awt.FontConfiguration");
 104                         logger.warning("Exception writing fcInfo " + e);
 105                     }
 106                 }
 107             } else if (FontUtilities.debugFonts()) {
 108                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 109                 logger.warning("Failed to get info from libfontconfig");
 110             }
 111         } else {
 112             fcm.populateFontConfig(fcCompFonts);
 113         }
 114 
 115         if (fcCompFonts == null) {
 116             return false; // couldn't load fontconfig.
 117         }
 118 
 119         // NB already in a privileged block from SGE
 120         String javaHome = System.getProperty("java.home");
 121         if (javaHome == null) {
 122             throw new Error("java.home property not set");
 123         }
 124         String javaLib = javaHome + File.separator + "lib";
 125         getInstalledFallbackFonts(javaLib);
 126 
 127         return true;
 128     }
 129 
 130     @Override
 131     public String getFallbackFamilyName(String fontName,
 132                                         String defaultFallback) {


 170     }
 171 
 172     @Override
 173     protected void initReorderMap() {
 174         reorderMap = new HashMap();
 175     }
 176 
 177     @Override
 178     public FontDescriptor[] getFontDescriptors(String fontName, int style) {
 179         return new FontDescriptor[0];
 180     }
 181 
 182     @Override
 183     public int getNumberCoreFonts() {
 184         return 1;
 185     }
 186 
 187     @Override
 188     public String[] getPlatformFontNames() {
 189         HashSet<String> nameSet = new HashSet<String>();
 190         X11FontManager fm = X11FontManager.getInstance();
 191         FontConfigManager fcm = fm.getFontConfigManager();
 192         FcCompFont[] fcCompFonts = fcm.loadFontConfig();
 193         for (int i=0; i<fcCompFonts.length; i++) {
 194             for (int j=0; j<fcCompFonts[i].allFonts.length; j++) {
 195                 nameSet.add(fcCompFonts[i].allFonts[j].fontFile);
 196             }
 197         }
 198         return nameSet.toArray(new String[0]);
 199     }
 200 
 201     @Override
 202     public String getExtraFontPath() {
 203         return null;
 204     }
 205 
 206     @Override
 207     public boolean needToSearchForFile(String fileName) {
 208         return false;
 209     }
 210 
 211     private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
 212                                            String fontname, int style) {
 213 
 214         if (fontname.equals("dialog")) {
 215             fontname = "sansserif";
 216         } else if (fontname.equals("dialoginput")) {
 217             fontname = "monospaced";
 218         }
 219         for (int i=0; i<fcFonts.length; i++) {
 220             if (fontname.equals(fcFonts[i].jdkName) &&
 221                 style == fcFonts[i].style) {
 222                 return fcFonts[i].allFonts;
 223             }
 224         }
 225         return fcFonts[0].allFonts;
 226     }
 227 
 228     @Override
 229     public CompositeFontDescriptor[] get2DCompositeFontInfo() {
 230 
 231         X11FontManager fm = X11FontManager.getInstance();
 232         FontConfigManager fcm = fm.getFontConfigManager();
 233         FcCompFont[] fcCompFonts = fcm.loadFontConfig();
 234 
 235         CompositeFontDescriptor[] result =
 236                 new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
 237 
 238         for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
 239             String fontName = publicFontNames[fontIndex];
 240 
 241             for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
 242 
 243                 String faceName = fontName + "." + styleNames[styleIndex];
 244                 FontConfigFont[] fcFonts =
 245                     getFcFontList(fcCompFonts,
 246                                   fontNames[fontIndex], styleIndex);
 247 
 248                 int numFonts = fcFonts.length;
 249                 // fall back fonts listed in the lib/fonts/fallback directory
 250                 if (installedFallbackFontFiles != null) {
 251                     numFonts += installedFallbackFontFiles.length;
 252                 }
 253 


 311                     props.load(new FileInputStream(f));
 312                     osName = props.getProperty("DISTRIB_ID");
 313                     osVersion =  props.getProperty("DISTRIB_RELEASE");
 314             } else if ((f = new File("/etc/redhat-release")).canRead()) {
 315                 osName = "RedHat";
 316                 osVersion = getVersionString(f);
 317             } else if ((f = new File("/etc/SuSE-release")).canRead()) {
 318                 osName = "SuSE";
 319                 osVersion = getVersionString(f);
 320             } else if ((f = new File("/etc/turbolinux-release")).canRead()) {
 321                 osName = "Turbo";
 322                 osVersion = getVersionString(f);
 323             } else if ((f = new File("/etc/fedora-release")).canRead()) {
 324                 osName = "Fedora";
 325                 osVersion = getVersionString(f);
 326             } else if ((f = new File("/etc/sun-release")).canRead()) {
 327                 osName = "Sun";
 328                 osVersion = getVersionString(f);
 329             }
 330         } catch (Exception e) {
 331             if (FontUtilities.debugFonts()) {
 332                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 333                 logger.warning("Exception identifying Linux distro.");
 334             }
 335         }
 336     }
 337 
 338     private File getFcInfoFile() {
 339         if (fcInfoFileName == null) {
 340             // NB need security permissions to get true IP address, and
 341             // we should have those as the whole initialisation is in a
 342             // doPrivileged block. But in this case no exception is thrown,
 343             // and it returns the loop back address, and so we end up with
 344             // "localhost"
 345             String hostname;
 346             try {
 347                 hostname = InetAddress.getLocalHost().getHostName();
 348             } catch (UnknownHostException e) {
 349                 hostname = "localhost";
 350             }
 351             String userDir = System.getProperty("user.home");
 352             String version = System.getProperty("java.version");
 353             String fs = File.separator;
 354             String dir = userDir+fs+".java"+fs+"fonts"+fs+version;
 355             String lang = SunToolkit.getStartupLocale().getLanguage();
 356             String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+
 357                 osName+"-"+osVersion+"-"+lang+".properties";
 358             fcInfoFileName = dir+fs+name;
 359         }
 360         return new File(fcInfoFileName);
 361     }
 362 
 363     private void writeFcInfo() {
 364         Properties props = new Properties();
 365         props.setProperty("version", fileVersion);
 366         X11FontManager fm = X11FontManager.getInstance();
 367         FontConfigManager fcm = fm.getFontConfigManager();
 368         FontConfigInfo fcInfo = fcm.getFontConfigInfo();
 369         props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
 370         if (fcInfo.cacheDirs != null) {
 371             for (int i=0;i<fcInfo.cacheDirs.length;i++) {
 372                 if (fcInfo.cacheDirs[i] != null) {
 373                    props.setProperty("cachedir."+i,  fcInfo.cacheDirs[i]);
 374                 }
 375             }
 376         }
 377         for (int i=0; i<fcCompFonts.length; i++) {
 378             FcCompFont fci = fcCompFonts[i];
 379             String styleKey = fci.jdkName+"."+fci.style;
 380             props.setProperty(styleKey+".length",
 381                               Integer.toString(fci.allFonts.length));
 382             for (int j=0; j<fci.allFonts.length; j++) {
 383                 props.setProperty(styleKey+"."+j+".family",
 384                                   fci.allFonts[j].familyName);
 385                 props.setProperty(styleKey+"."+j+".file",
 386                                   fci.allFonts[j].fontFile);
 387             }
 388         }
 389         try {
 390             /* This writes into a temp file then renames when done.
 391              * Since the rename is an atomic action within the same
 392              * directory no client will ever see a partially written file.
 393              */
 394             File fcInfoFile = getFcInfoFile();
 395             File dir = fcInfoFile.getParentFile();
 396             dir.mkdirs();
 397             File tempFile = File.createTempFile("fcinfo", null, dir);
 398             FileOutputStream fos = new FileOutputStream(tempFile);
 399             props.store(fos,
 400                       "JDK Font Configuration Generated File: *Do Not Edit*");
 401             fos.close();
 402             boolean renamed = tempFile.renameTo(fcInfoFile);
 403             if (!renamed && FontUtilities.debugFonts()) {
 404                 System.out.println("rename failed");
 405                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 406                 logger.warning("Failed renaming file to "+ getFcInfoFile());
 407             }
 408         } catch (Exception e) {
 409             if (FontUtilities.debugFonts()) {
 410                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 411                 logger.warning("IOException writing to "+ getFcInfoFile());
 412             }
 413         }
 414     }
 415 
 416     /* We want to be able to use this cache instead of invoking
 417      * fontconfig except when we can detect the system cache has changed.
 418      * But there doesn't seem to be a way to find the location of
 419      * the system cache.
 420      */
 421     private void readFcInfo() {
 422         File fcFile = getFcInfoFile();
 423         if (!fcFile.exists()) {
 424             return;
 425         }
 426         Properties props = new Properties();
 427         X11FontManager fm = X11FontManager.getInstance();
 428         FontConfigManager fcm = fm.getFontConfigManager();
 429         try {
 430             FileInputStream fis = new FileInputStream(fcFile);
 431             props.load(fis);
 432             fis.close();
 433         } catch (IOException e) {
 434             if (FontUtilities.debugFonts()) {
 435                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 436                 logger.warning("IOException reading from "+fcFile.toString());
 437             }
 438             return;
 439         }
 440         String version = (String)props.get("version");
 441         if (version == null || !version.equals(fileVersion)) {
 442             return;
 443         }
 444 
 445         // If there's a new, different fontconfig installed on the
 446         // system, we invalidate our fontconfig file.
 447         String fcVersionStr = (String)props.get("fcversion");
 448         if (fcVersionStr != null) {
 449             int fcVersion;
 450             try {
 451                 fcVersion = Integer.parseInt(fcVersionStr);
 452                 if (fcVersion != 0 &&
 453                     fcVersion != fcm.getFontConfigVersion()) {
 454                     return;
 455                 }
 456             } catch (Exception e) {
 457                 if (FontUtilities.debugFonts()) {
 458                     Logger logger =
 459                         Logger.getLogger("sun.awt.FontConfiguration");
 460                     logger.warning("Exception parsing version " +
 461                                    fcVersionStr);
 462                 }
 463                 return;
 464             }
 465         }
 466 
 467         // If we can locate the fontconfig cache dirs, then compare the
 468         // time stamp of those with our properties file. If we are out
 469         // of date then re-generate.
 470         long lastModified = fcFile.lastModified();
 471         int cacheDirIndex = 0;
 472         while (cacheDirIndex<4) { // should never be more than 2 anyway.
 473             String dir = (String)props.get("cachedir."+cacheDirIndex);
 474             if (dir == null) {
 475                 break;
 476             }
 477             File dirFile = new File(dir);


 503                     }
 504                     fci[index].allFonts = new FontConfigFont[nfonts];
 505                     for (int f=0; f<nfonts; f++) {
 506                         fci[index].allFonts[f] = new FontConfigFont();
 507                         String fkey = key+"."+f+".family";
 508                         String family = (String)props.get(fkey);
 509                         fci[index].allFonts[f].familyName = family;
 510                         fkey = key+"."+f+".file";
 511                         String file = (String)props.get(fkey);
 512                         if (file == null) {
 513                             return; // bad file
 514                         }
 515                         fci[index].allFonts[f].fontFile = file;
 516                     }
 517                     fci[index].firstFont =  fci[index].allFonts[0];
 518 
 519                 }
 520             }
 521             fcCompFonts = fci;
 522         } catch (Throwable t) {
 523             if (FontUtilities.debugFonts()) {
 524                 Logger logger = Logger.getLogger("sun.awt.FontConfiguration");
 525                 logger.warning(t.toString());
 526             }
 527         }
 528     }
 529 }