< prev index next >

modules/graphics/src/main/java/com/sun/javafx/font/PrismFontFactory.java

Print this page




 228         }
 229         return theFontFactory;
 230     }
 231 
 232     private static synchronized PrismFontFactory getFontFactory(String factoryClass) {
 233         try {
 234             Class<?> clazz = Class.forName(factoryClass);
 235             Method mid = clazz.getMethod("getFactory", (Class[])null);
 236             return (PrismFontFactory)mid.invoke(null);
 237         } catch (Throwable t) {
 238             if (debugFonts) {
 239                 System.err.println("Loading font factory failed "+ factoryClass);
 240             }
 241         }
 242         return null;
 243     }
 244 
 245     private HashMap<String, PrismFontFile>
 246         fileNameToFontResourceMap = new HashMap<String, PrismFontFile>();
 247 
 248     protected abstract PrismFontFile createFontFile(String name, String filename,

 249                                                     int fIndex, boolean register,
 250                                                     boolean embedded,
 251                                                     boolean copy, boolean tracked)
 252                                                     throws Exception;
 253 
 254     public abstract GlyphLayout createGlyphLayout();
 255 
 256     // For an caller who has recognised a TTC file and wants to create
 257     // the instances one at a time so as to have visibility into the
 258     // contents of the TTC. Onus is on caller to enumerate all the fonts.
 259     private PrismFontFile createFontResource(String filename, int index) {
 260         return createFontResource(filename, index, true, false, false, false);

 261     }
 262 
 263     private PrismFontFile createFontResource(String filename, int index,

 264                                              boolean register, boolean embedded,
 265                                              boolean copy, boolean tracked) {
 266         String key = (filename+index).toLowerCase();
 267         PrismFontFile fr = fileNameToFontResourceMap.get(key);
 268         if (fr != null) {
 269             return fr;
 270         }
 271 
 272         try {
 273             fr = createFontFile(null, filename, index, register,
 274                                 embedded, copy, tracked);
 275             if (register) {
 276                 storeInMap(fr.getFullName(), fr);
 277                 fileNameToFontResourceMap.put(key, fr);
 278             }
 279             return fr;
 280         } catch (Exception e) {
 281             if (PrismFontFactory.debugFonts) {
 282                 e.printStackTrace();
 283             }
 284             return null;
 285         }
 286     }
 287 
 288     private PrismFontFile createFontResource(String name, String filename) {
 289         return createFontResource(name, filename, true, false, false, false);







 290     }
 291 
 292     private PrismFontFile createFontResource(String name, String filename,
 293                                              boolean register,
 294                                              boolean embedded,
 295                                              boolean copy,
 296                                              boolean tracked) {



 297         if (filename == null) {
 298             return null;
 299         } else {
 300             String lcFN = filename.toLowerCase();
 301             if (lcFN.endsWith(".ttc")) {
 302                 int index = 0;
 303                 PrismFontFile fr, namedFR = null;












 304                 do {
 305                     String key = (filename+index).toLowerCase();
 306                     try {
 307                         fr = fileNameToFontResourceMap.get(key);
 308                         if (fr != null) {
 309                             if (name.equals(fr.getFullName())) {
 310                                 return fr; // already mapped etc.
 311                             } else {
 312                                 // Already loaded this TTC component, but
 313                                 // its not the one we are looking for.
 314                                 continue;
 315                             }
 316                         } else {
 317                             fr = createFontFile(name, filename, index,
 318                                                 register, embedded,
 319                                                 copy, tracked);
 320                         }
 321                     } catch (Exception e) {
 322                         if (PrismFontFactory.debugFonts) {
 323                             e.printStackTrace();
 324                         }
 325                         return null;
 326                     }
 327 



 328                     String fontname = fr.getFullName();
 329                     if (register) {
 330                         storeInMap(fontname, fr);
 331                         fileNameToFontResourceMap.put(key, fr);
 332                     }
 333                     if (index == 0 || name.equals(fontname)) {
 334                         namedFR = fr;
 335                     }
 336                 } while (++index < fr.getFontCount());
 337                 return namedFR;
 338             } else {
 339                 return createFontResource(filename, 0, register,
 340                                           embedded, copy, tracked);
 341             }

 342         }



 343     }
 344 
 345     private String dotStyleStr(boolean bold, boolean italic) {
 346         if (!bold) {
 347             if (!italic) {
 348                 return "";
 349             }
 350             else {
 351                 return ".italic";
 352             }
 353         } else {
 354             if (!italic) {
 355                 return ".bold";
 356             }
 357             else {
 358                 return ".bolditalic";
 359             }
 360         }
 361     }
 362 


 367         if (resource instanceof PrismCompositeFontResource) {
 368             System.err.println(name + " is a composite " +
 369                                             resource);
 370             Thread.dumpStack();
 371             return;
 372         }
 373         fontResourceMap.put(name.toLowerCase(), resource);
 374     }
 375 
 376     private ArrayList<WeakReference<PrismFontFile>> tmpFonts;
 377     synchronized void addDecodedFont(PrismFontFile fr) {
 378         fr.setIsDecoded(true);
 379         addTmpFont(fr);
 380     }
 381 
 382     private synchronized void addTmpFont(PrismFontFile fr) {
 383         if (tmpFonts == null) {
 384             tmpFonts = new ArrayList<WeakReference<PrismFontFile>>();
 385         }
 386         WeakReference<PrismFontFile> ref;






 387         if (fr.isRegistered()) {
 388             ref = new WeakReference<PrismFontFile>(fr);
 389         } else {
 390             ref = fr.createFileDisposer(this);
 391         }
 392         tmpFonts.add(ref);
 393         addFileCloserHook();
 394     }
 395 
 396     synchronized void removeTmpFont(WeakReference<PrismFontFile> ref) {
 397         if (tmpFonts != null) {
 398             tmpFonts.remove(ref);
 399         }
 400     }
 401 
 402     /* familyName is expected to be a physical font family name.
 403      */
 404     public synchronized FontResource getFontResource(String familyName,
 405                                                      boolean bold,
 406                                                      boolean italic,
 407                                                      boolean wantComp) {
 408 
 409         if (familyName == null || familyName.isEmpty()) {
 410             return null;


1417             java.security.AccessController.doPrivileged(
1418                     (PrivilegedAction<Object>) () -> {
1419                         /* The thread must be a member of a thread group
1420                          * which will not get GCed before VM exit.
1421                          * Make its parent the top-level thread group.
1422                          */
1423                         ThreadGroup tg = Thread.currentThread().getThreadGroup();
1424                         for (ThreadGroup tgn = tg;
1425                              tgn != null; tg = tgn, tgn = tg.getParent());
1426                         fileCloser = new Thread(tg, fileCloserRunnable);
1427                         fileCloser.setContextClassLoader(null);
1428                         Runtime.getRuntime().addShutdownHook(fileCloser);
1429                         return null;
1430                     }
1431             );
1432         }
1433     }
1434 
1435     private HashMap<String, PrismFontFile> embeddedFonts;
1436 
1437     public PGFont loadEmbeddedFont(String name, InputStream fontStream,
1438                                    float size, boolean register) {


1439         if (!hasPermission()) {
1440             return createFont(DEFAULT_FULLNAME, size);
1441         }
1442         if (FontFileWriter.hasTempPermission()) {
1443             return loadEmbeddedFont0(name, fontStream, size, register);
1444         }
1445 
1446         // Otherwise, be extra conscious of pending temp file creation and
1447         // resourcefully handle the temp file resources, among other things.
1448         FontFileWriter.FontTracker tracker =
1449             FontFileWriter.FontTracker.getTracker();
1450         boolean acquired = false;
1451         try {
1452             acquired = tracker.acquirePermit();
1453             if (!acquired) {
1454                 // Timed out waiting for resources.
1455                 return null;
1456             }
1457             return loadEmbeddedFont0(name, fontStream, size, register);
1458         } catch (InterruptedException e) {
1459             // Interrupted while waiting to acquire a permit.
1460             return null;
1461         } finally {
1462             if (acquired) {
1463                 tracker.releasePermit();
1464             }
1465         }
1466     }
1467 
1468     private PGFont loadEmbeddedFont0(String name, InputStream fontStream,
1469                                      float size, boolean register) {
1470         PrismFontFile fr = null;


1471         FontFileWriter fontWriter = new FontFileWriter();
1472         try {
1473             // We use a shutdown hook to close all open tmp files
1474             // created via this API and delete them.
1475             final File tFile = fontWriter.openFile();
1476             byte[] buf = new byte[8192];
1477             for (;;) {
1478                 int bytesRead = fontStream.read(buf);
1479                 if (bytesRead < 0) {
1480                     break;
1481                 }
1482                 fontWriter.writeBytes(buf, 0, bytesRead);
1483             }
1484             fontWriter.closeFile();
1485 
1486             fr = loadEmbeddedFont(name, tFile.getPath(), register, true,
1487                                   fontWriter.isTracking());
1488 
1489             if (fr != null) {
1490                 /* Delete the file downloaded if it was decoded
1491                  * to another file */
1492                 if (fr.isDecoded()) {
1493                     fontWriter.deleteFile();
1494                 }
1495             }
1496 
1497             /* We don't want to leave the temp files around after exit.
1498              * Also in a shared applet-type context, after all references to
1499              * the applet and therefore the font are dropped, the file
1500              * should be removed. This isn't so much an issue so long as
1501              * the VM exists to serve a single FX app, but will be
1502              * important in an app-context model.
1503              * But also fonts that are over-written by new versions
1504              * need to be cleaned up and that applies even in the single
1505              * context.
1506              * We also need to decrement the byte count by the size
1507              * of the file.
1508              */
1509             addFileCloserHook();
1510         } catch (Exception e) {
1511             fontWriter.deleteFile();
1512         } finally {
1513             /* If the data isn't a valid font, so that registering it
1514              * returns null, or we didn't get so far as copying the data,
1515              * delete the tmp file and decrement the byte count
1516              * in the tracker object before returning.
1517              */
1518             if (fr == null) {
1519                 fontWriter.deleteFile();
1520             }
1521         }
1522         if (fr != null) {
1523             if (size <= 0) size = getSystemFontSize();
1524             return new PrismFont(fr, fr.getFullName(), size);





1525         }
1526         return null;
1527     }
1528 
1529     /**
1530      * registerEmbeddedFont(String name, String path) is a small subset of
1531      * registerEmbeddedFont(String name, InputStream fontStream)
1532      * It does not attempt to create a temporary file and has different
1533      * parameters.
1534      *
1535      * @param name font name
1536      * @param path Path name to system file
1537      * @param size font size
1538      * @param register whether the font should be registered.

1539      * @return font name extracted from font file
1540      */
1541     public PGFont loadEmbeddedFont(String name, String path,
1542                                    float size, boolean register) {


1543         if (!hasPermission()) {
1544             return createFont(DEFAULT_FULLNAME, size);
1545         }
1546         addFileCloserHook();
1547         FontResource fr = loadEmbeddedFont(name, path, register, false, false);
1548         if (fr != null) {

1549             if (size <= 0) size = getSystemFontSize();
1550             return new PrismFont(fr, fr.getFullName(), size);






1551         }
1552         return null;
1553     }
1554 
1555     /* This should make the embedded font eligible for reclaimation
1556      * and subsequently, disposal of native resources, once any existing
1557      * strong refs by the application are released.
1558      */
1559     private void removeEmbeddedFont(String name) {
1560         PrismFontFile font = embeddedFonts.get(name);
1561         if (font == null) {
1562             return;
1563         }
1564         embeddedFonts.remove(name);
1565         String lcName = name.toLowerCase();
1566         fontResourceMap.remove(lcName);
1567         compResourceMap.remove(lcName);
1568         // The following looks tedious, but if the compMap could have
1569         // the font referenced via some lookup name that applies a style
1570         // or used the family name, we need to find it and remove all
1571         // references to it, so it can be collected.
1572         Iterator<CompositeFontResource> fi = compResourceMap.values().iterator();
1573             while (fi.hasNext()) {
1574             CompositeFontResource compFont = fi.next();
1575             if (compFont.getSlotResource(0) == font) {
1576                 fi.remove();
1577             }
1578         }
1579     }
1580 
1581     protected boolean registerEmbeddedFont(String path) {
1582         return true;
1583     }
1584 
1585     // Used for testing
1586     private int numEmbeddedFonts = 0;
1587     public int test_getNumEmbeddedFonts() {
1588         return numEmbeddedFonts;
1589     }
1590 
1591     private synchronized PrismFontFile loadEmbeddedFont(String name, String path,

1592                                                         boolean register, boolean copy,
1593                                                         boolean tracked) {
1594 
1595         ++numEmbeddedFonts;
1596 
1597         /*
1598          * Fonts that aren't platform installed include those in the
1599          * application jar, WOFF fonts that are downloaded, and fonts
1600          * created via Font.loadFont. If copy==true, we can infer its
1601          * one of these, but its also possible for a font to be file-system
1602          * installed as part of the application but not known to the
1603          * platform. In this case copy==false, but we still need to flag
1604          * to the system its not a platform font so that other pipelines
1605          * know to reference the file directly.
1606          */
1607         PrismFontFile fr = createFontResource(name, path, register,
1608                                               true, copy, tracked);
1609         if (fr == null) {

1610             return null; // yes, this means the caller needs to handle null.
1611         }
1612 











1613         String family = fr.getFamilyName();
1614         if (family == null || family.length() == 0) return null;
1615         String fullname = fr.getFullName();
1616         if (fullname == null || fullname.length() == 0) return null;
1617         String psname = fr.getPSName();
1618         if (psname == null || psname.length() == 0) return null;
1619 
1620         boolean registerEmbedded = true;
1621         if (embeddedFonts != null) {
1622             FontResource resource = embeddedFonts.get(fullname);
1623             if (resource != null && fr.equals(resource)) {
1624                 /* Do not register the same font twice in the OS */
1625                 registerEmbedded = false;
1626             }
1627         }
1628 
1629         if (registerEmbedded) {
1630             /* Use filename from the resource so woff fonts are handled */
1631             if (!registerEmbeddedFont(fr.getFileName())) {
1632                 /* This font file can't be used by the underlying rasterizer */
1633                 return null;
1634             }
1635         }
1636 
1637         if (!register) {
1638             /* If a temporary font is a copy but it is not decoded then it
1639              * will not be anywhere the shutdown hook can see.
1640              * That means if the font is keep for the entire life of the VM
1641              * its file will not be deleted.
1642              * The fix is to add this font to the list of temporary fonts.
1643              */
1644             if (copy && !fr.isDecoded()) {
1645                 addTmpFont(fr);
1646             }
1647             return fr;
1648         }
1649 
1650         if (embeddedFonts == null) {
1651             embeddedFonts = new HashMap<String, PrismFontFile>();
1652         }
1653 
1654         /* If a font name is provided then we will also store that in the
1655          * map as an alias, otherwise should use the only the real name,
1656          * REMIND: its possible that either name may hide some installed
1657          * version of the font, possibly one we haven't seen yet. But
1658          * without loading all the platform fonts (expensive) this is
1659          * difficult to ascertain. A contains() check here is therefore
1660          * probably mostly futile.
1661          */
1662         if (name != null && !name.isEmpty()) {
1663             embeddedFonts.put(name, fr);
1664             storeInMap(name, fr);
1665         }
1666 




1667         removeEmbeddedFont(fullname);
1668         embeddedFonts.put(fullname, fr);
1669         storeInMap(fullname, fr);
1670         family = family + dotStyleStr(fr.isBold(), fr.isItalic());
1671         storeInMap(family, fr);
1672         /* The remove call is to assist the case where we have
1673          * previously mapped into the composite map a different style
1674          * in this family as a partial match for the application request.
1675          * This can occur when an application requested a bold font before
1676          * it called Font.loadFont to register the bold font. It won't
1677          * fix the cases that already happened, but will fix the future ones.
1678          */
1679         compResourceMap.remove(family.toLowerCase());
1680         return fr;

1681     }
1682 
1683     private void
1684         logFontInfo(String message,
1685                     HashMap<String,String> fontToFileMap,
1686                     HashMap<String,String> fontToFamilyNameMap,
1687                     HashMap<String,ArrayList<String>> familyToFontListMap) {
1688 
1689         System.err.println(message);
1690         for (String keyName : fontToFileMap.keySet()) {
1691             System.err.println("font="+keyName+" file="+
1692                                fontToFileMap.get(keyName));
1693         }
1694         for (String keyName : fontToFamilyNameMap.keySet()) {
1695             System.err.println("font="+keyName+" family="+
1696                                fontToFamilyNameMap.get(keyName));
1697         }
1698         for (String keyName : familyToFontListMap.keySet()) {
1699             System.err.println("family="+keyName+ " fonts="+
1700                                familyToFontListMap.get(keyName));




 228         }
 229         return theFontFactory;
 230     }
 231 
 232     private static synchronized PrismFontFactory getFontFactory(String factoryClass) {
 233         try {
 234             Class<?> clazz = Class.forName(factoryClass);
 235             Method mid = clazz.getMethod("getFactory", (Class[])null);
 236             return (PrismFontFactory)mid.invoke(null);
 237         } catch (Throwable t) {
 238             if (debugFonts) {
 239                 System.err.println("Loading font factory failed "+ factoryClass);
 240             }
 241         }
 242         return null;
 243     }
 244 
 245     private HashMap<String, PrismFontFile>
 246         fileNameToFontResourceMap = new HashMap<String, PrismFontFile>();
 247 
 248     protected abstract PrismFontFile
 249           createFontFile(String name, String filename,
 250                          int fIndex, boolean register,
 251                          boolean embedded,
 252                          boolean copy, boolean tracked)
 253                          throws Exception;
 254 
 255     public abstract GlyphLayout createGlyphLayout();
 256 
 257     // For an caller who has recognised a TTC file and wants to create
 258     // the instances one at a time so as to have visibility into the
 259     // contents of the TTC. Onus is on caller to enumerate all the fonts.
 260     private PrismFontFile createFontResource(String filename, int index) {
 261         return createFontResource(null, filename, index,
 262                                   true, false, false, false);
 263     }
 264 
 265     private PrismFontFile createFontResource(String name,
 266                                              String filename, int index,
 267                                              boolean register, boolean embedded,
 268                                              boolean copy, boolean tracked) {
 269         String key = (filename+index).toLowerCase();
 270         PrismFontFile fr = fileNameToFontResourceMap.get(key);
 271         if (fr != null) {
 272             return fr;
 273         }
 274 
 275         try {
 276             fr = createFontFile(name, filename, index, register,
 277                                 embedded, copy, tracked);
 278             if (register) {
 279                 storeInMap(fr.getFullName(), fr);
 280                 fileNameToFontResourceMap.put(key, fr);
 281             }
 282             return fr;
 283         } catch (Exception e) {
 284             if (PrismFontFactory.debugFonts) {
 285                 e.printStackTrace();
 286             }
 287             return null;
 288         }
 289     }
 290 
 291     private PrismFontFile createFontResource(String name, String filename) {
 292         PrismFontFile[] pffArr =
 293             createFontResources(name, filename,
 294                                 true, false, false, false, false);
 295         if (pffArr == null || pffArr.length == 0) {
 296            return null;
 297         } else {
 298            return pffArr[0];
 299         }
 300     }
 301 
 302     private PrismFontFile[] createFontResources(String name, String filename,
 303                                                 boolean register,
 304                                                 boolean embedded,
 305                                                 boolean copy,
 306                                                 boolean tracked,
 307                                                 boolean loadAll) {
 308 
 309         PrismFontFile[] fArr = null;
 310         if (filename == null) {
 311             return null;
 312         }
 313         PrismFontFile fr = createFontResource(name, filename, 0, register,
 314                                              embedded, copy, tracked);
 315         if (fr == null) {
 316             return null;
 317         }
 318         int cnt = (!loadAll) ? 1 : fr.getFontCount();
 319         fArr = new PrismFontFile[cnt];
 320         fArr[0] = fr;
 321         if (cnt == 1) { // Not a TTC, or only requesting one font.
 322             return fArr;
 323         }
 324         PrismFontFile.FileRefCounter rc = null;
 325         if (copy) {
 326             rc = fr.createFileRefCounter();
 327         }
 328         int index = 1;
 329         do {
 330             String key = (filename+index).toLowerCase();
 331             try {
 332                 fr = fileNameToFontResourceMap.get(key);
 333                 if (fr != null) {
 334                     fArr[index] = fr;




 335                     continue;

 336                 } else {
 337                     fr = createFontFile(null, filename, index,
 338                                         register, embedded,
 339                                         copy, tracked);
 340                     if (fr == null) {




 341                         return null;
 342                     }
 343                     if (rc != null) {
 344                         fr.setAndIncFileRefCounter(rc);
 345                     }
 346                     fArr[index] = fr;
 347                     String fontname = fr.getFullName();
 348                     if (register) {
 349                         storeInMap(fontname, fr);
 350                         fileNameToFontResourceMap.put(key, fr);
 351                     }


 352                 }
 353             } catch (Exception e) {
 354                 if (PrismFontFactory.debugFonts) {
 355                     e.printStackTrace();


 356                 }
 357                 return null;
 358             }
 359 
 360         } while (++index < cnt);
 361         return fArr;
 362     }
 363 
 364     private String dotStyleStr(boolean bold, boolean italic) {
 365         if (!bold) {
 366             if (!italic) {
 367                 return "";
 368             }
 369             else {
 370                 return ".italic";
 371             }
 372         } else {
 373             if (!italic) {
 374                 return ".bold";
 375             }
 376             else {
 377                 return ".bolditalic";
 378             }
 379         }
 380     }
 381 


 386         if (resource instanceof PrismCompositeFontResource) {
 387             System.err.println(name + " is a composite " +
 388                                             resource);
 389             Thread.dumpStack();
 390             return;
 391         }
 392         fontResourceMap.put(name.toLowerCase(), resource);
 393     }
 394 
 395     private ArrayList<WeakReference<PrismFontFile>> tmpFonts;
 396     synchronized void addDecodedFont(PrismFontFile fr) {
 397         fr.setIsDecoded(true);
 398         addTmpFont(fr);
 399     }
 400 
 401     private synchronized void addTmpFont(PrismFontFile fr) {
 402         if (tmpFonts == null) {
 403             tmpFonts = new ArrayList<WeakReference<PrismFontFile>>();
 404         }
 405         WeakReference<PrismFontFile> ref;
 406         /* Registered fonts are enumerable by the application and are
 407          * expected to persist until VM shutdown.
 408          * Other fonts - notably ones temporarily loaded in a web page via
 409          * webview - should be eligible to be collected and have their
 410          * temp files deleted at any time.
 411          */
 412         if (fr.isRegistered()) {
 413             ref = new WeakReference<PrismFontFile>(fr);
 414         } else {
 415             ref = fr.createFileDisposer(this, fr.getFileRefCounter());
 416         }
 417         tmpFonts.add(ref);
 418         addFileCloserHook();
 419     }
 420 
 421     synchronized void removeTmpFont(WeakReference<PrismFontFile> ref) {
 422         if (tmpFonts != null) {
 423             tmpFonts.remove(ref);
 424         }
 425     }
 426 
 427     /* familyName is expected to be a physical font family name.
 428      */
 429     public synchronized FontResource getFontResource(String familyName,
 430                                                      boolean bold,
 431                                                      boolean italic,
 432                                                      boolean wantComp) {
 433 
 434         if (familyName == null || familyName.isEmpty()) {
 435             return null;


1442             java.security.AccessController.doPrivileged(
1443                     (PrivilegedAction<Object>) () -> {
1444                         /* The thread must be a member of a thread group
1445                          * which will not get GCed before VM exit.
1446                          * Make its parent the top-level thread group.
1447                          */
1448                         ThreadGroup tg = Thread.currentThread().getThreadGroup();
1449                         for (ThreadGroup tgn = tg;
1450                              tgn != null; tg = tgn, tgn = tg.getParent());
1451                         fileCloser = new Thread(tg, fileCloserRunnable);
1452                         fileCloser.setContextClassLoader(null);
1453                         Runtime.getRuntime().addShutdownHook(fileCloser);
1454                         return null;
1455                     }
1456             );
1457         }
1458     }
1459 
1460     private HashMap<String, PrismFontFile> embeddedFonts;
1461 
1462     public PGFont[] loadEmbeddedFont(String name, InputStream fontStream,
1463                                      float size,
1464                                      boolean register,
1465                                      boolean loadAll) {
1466         if (!hasPermission()) {
1467             return new PGFont[] { createFont(DEFAULT_FULLNAME, size) } ;
1468         }
1469         if (FontFileWriter.hasTempPermission()) {
1470             return loadEmbeddedFont0(name, fontStream, size, register, loadAll);
1471         }
1472 
1473         // Otherwise, be extra conscious of pending temp file creation and
1474         // resourcefully handle the temp file resources, among other things.
1475         FontFileWriter.FontTracker tracker =
1476             FontFileWriter.FontTracker.getTracker();
1477         boolean acquired = false;
1478         try {
1479             acquired = tracker.acquirePermit();
1480             if (!acquired) {
1481                 // Timed out waiting for resources.
1482                 return null;
1483             }
1484             return loadEmbeddedFont0(name, fontStream, size, register, loadAll);
1485         } catch (InterruptedException e) {
1486             // Interrupted while waiting to acquire a permit.
1487             return null;
1488         } finally {
1489             if (acquired) {
1490                 tracker.releasePermit();
1491             }
1492         }
1493     }
1494 
1495     private PGFont[] loadEmbeddedFont0(String name, InputStream fontStream,
1496                                        float size,
1497                                        boolean register,
1498                                        boolean loadAll) {
1499         PrismFontFile[] fr = null;
1500         FontFileWriter fontWriter = new FontFileWriter();
1501         try {
1502             // We use a shutdown hook to close all open tmp files
1503             // created via this API and delete them.
1504             final File tFile = fontWriter.openFile();
1505             byte[] buf = new byte[8192];
1506             for (;;) {
1507                 int bytesRead = fontStream.read(buf);
1508                 if (bytesRead < 0) {
1509                     break;
1510                 }
1511                 fontWriter.writeBytes(buf, 0, bytesRead);
1512             }
1513             fontWriter.closeFile();
1514 
1515             fr = loadEmbeddedFont1(name, tFile.getPath(), register, true,
1516                                    fontWriter.isTracking(), loadAll);
1517 
1518             if (fr != null && fr.length > 0) {
1519                 /* Delete the file downloaded if it was decoded
1520                  * to another file */
1521                 if (fr[0].isDecoded()) {
1522                     fontWriter.deleteFile();
1523                 }
1524             }
1525 
1526             /* We don't want to leave the temp files around after exit.
1527              * Also in a shared applet-type context, after all references to
1528              * the applet and therefore the font are dropped, the file
1529              * should be removed. This isn't so much an issue so long as
1530              * the VM exists to serve a single FX app, but will be
1531              * important in an app-context model.
1532              * But also fonts that are over-written by new versions
1533              * need to be cleaned up and that applies even in the single
1534              * context.
1535              * We also need to decrement the byte count by the size
1536              * of the file.
1537              */
1538             addFileCloserHook();
1539         } catch (Exception e) {
1540             fontWriter.deleteFile();
1541         } finally {
1542             /* If the data isn't a valid font, so that registering it
1543              * returns null, or we didn't get so far as copying the data,
1544              * delete the tmp file and decrement the byte count
1545              * in the tracker object before returning.
1546              */
1547             if (fr == null) {
1548                 fontWriter.deleteFile();
1549             }
1550         }
1551         if (fr != null && fr.length > 0) {
1552             if (size <= 0) size = getSystemFontSize();
1553             int num = fr.length;
1554             PrismFont[] pFonts = new PrismFont[num];
1555             for (int i=0; i<num; i++) {
1556                 pFonts[i] = new PrismFont(fr[i], fr[i].getFullName(), size);
1557             }
1558             return pFonts;
1559         }
1560         return null;
1561     }
1562 
1563     /**
1564      * registerEmbeddedFont(String name, String path) is a small subset of
1565      * registerEmbeddedFont(String name, InputStream fontStream)
1566      * It does not attempt to create a temporary file and has different
1567      * parameters.
1568      *
1569      * @param name font name
1570      * @param path Path name to system file
1571      * @param size font size
1572      * @param register whether the font should be registered.
1573      * @param loadAll whether to load all fonts if it is a TTC
1574      * @return font name extracted from font file
1575      */
1576     public PGFont[] loadEmbeddedFont(String name, String path,
1577                                      float size,
1578                                      boolean register,
1579                                      boolean loadAll) {
1580         if (!hasPermission()) {
1581             return new PGFont[] { createFont(DEFAULT_FULLNAME, size) };
1582         }
1583         addFileCloserHook();
1584         FontResource[] frArr =
1585           loadEmbeddedFont1(name, path, register, false, false, loadAll);
1586         if (frArr != null && frArr.length > 0) {
1587             if (size <= 0) size = getSystemFontSize();
1588             int num = frArr.length;
1589             PGFont[] pgFonts = new PGFont[num];
1590             for (int i=0; i<num; i++) {
1591                 pgFonts[i] =
1592                     new PrismFont(frArr[i], frArr[i].getFullName(), size);
1593             }
1594             return pgFonts;
1595         }
1596         return null;
1597     }
1598 
1599     /* This should make the embedded font eligible for reclaimation
1600      * and subsequently, disposal of native resources, once any existing
1601      * strong refs by the application are released.
1602      */
1603     private void removeEmbeddedFont(String name) {
1604         PrismFontFile font = embeddedFonts.get(name);
1605         if (font == null) {
1606             return;
1607         }
1608         embeddedFonts.remove(name);
1609         String lcName = name.toLowerCase();
1610         fontResourceMap.remove(lcName);
1611         compResourceMap.remove(lcName);
1612         // The following looks tedious, but if the compMap could have
1613         // the font referenced via some lookup name that applies a style
1614         // or used the family name, we need to find it and remove all
1615         // references to it, so it can be collected.
1616         Iterator<CompositeFontResource> fi = compResourceMap.values().iterator();
1617             while (fi.hasNext()) {
1618             CompositeFontResource compFont = fi.next();
1619             if (compFont.getSlotResource(0) == font) {
1620                 fi.remove();
1621             }
1622         }
1623     }
1624 
1625     protected boolean registerEmbeddedFont(String path) {
1626         return true;
1627     }
1628 
1629     // Used for testing
1630     private int numEmbeddedFonts = 0;
1631     public int test_getNumEmbeddedFonts() {
1632         return numEmbeddedFonts;
1633     }
1634 
1635     private synchronized
1636         PrismFontFile[] loadEmbeddedFont1(String name, String path,
1637                                           boolean register, boolean copy,
1638                                           boolean tracked, boolean loadAll) {
1639 
1640         ++numEmbeddedFonts;

1641         /*
1642          * Fonts that aren't platform installed include those in the
1643          * application jar, WOFF fonts that are downloaded, and fonts
1644          * created via Font.loadFont. If copy==true, we can infer its
1645          * one of these, but its also possible for a font to be file-system
1646          * installed as part of the application but not known to the
1647          * platform. In this case copy==false, but we still need to flag
1648          * to the system its not a platform font so that other pipelines
1649          * know to reference the file directly.
1650          */
1651         PrismFontFile[] frArr = createFontResources(name, path, register,
1652                                                     true, copy, tracked,
1653                                                     loadAll);
1654         if (frArr == null || frArr.length == 0) {
1655             return null; // yes, this means the caller needs to handle null.
1656         }
1657 
1658         /* Before we return or register, make sure names are present
1659          * check whether any of the fonts duplicate an OS font.
1660          */
1661 
1662         if (embeddedFonts == null) {
1663             embeddedFonts = new HashMap<String, PrismFontFile>();
1664         }
1665 
1666         boolean registerEmbedded = true;
1667         for (int i=0; i<frArr.length; i++) {
1668             PrismFontFile fr = frArr[i];
1669             String family = fr.getFamilyName();
1670             if (family == null || family.length() == 0) return null;
1671             String fullname = fr.getFullName();
1672             if (fullname == null || fullname.length() == 0) return null;
1673             String psname = fr.getPSName();
1674             if (psname == null || psname.length() == 0) return null;
1675 


1676             FontResource resource = embeddedFonts.get(fullname);
1677             if (resource != null && fr.equals(resource)) {
1678                 /* Do not register the same font twice in the OS */
1679                 registerEmbedded = false;
1680             }
1681         }
1682 
1683         if (registerEmbedded) {
1684             /* Use filename from the resource so woff fonts are handled */
1685             if (!registerEmbeddedFont(frArr[0].getFileName())) {
1686                 /* This font file can't be used by the underlying rasterizer */
1687                 return null;
1688             }
1689         }
1690 

1691         /* If a temporary font is a copy but it is not decoded then it
1692          * will not be anywhere the shutdown hook can see.
1693          * That means if the font is keep for the entire life of the VM
1694          * its file will not be deleted.
1695          * The fix is to add this font to the list of temporary fonts.
1696          */
1697         if (copy && !frArr[0].isDecoded()) {
1698             addTmpFont(frArr[0]);


1699         }
1700 
1701         if (!register) {
1702             return frArr;
1703         }
1704 
1705         /* If a font name is provided then we will also store that in the
1706          * map as an alias, otherwise should use the only the real name,
1707          * REMIND: its possible that either name may hide some installed
1708          * version of the font, possibly one we haven't seen yet. But
1709          * without loading all the platform fonts (expensive) this is
1710          * difficult to ascertain. A contains() check here is therefore
1711          * probably mostly futile.
1712          */
1713         if (name != null && !name.isEmpty()) {
1714             embeddedFonts.put(name, frArr[0]);
1715             storeInMap(name, frArr[0]);
1716         }
1717 
1718         for (int i=0; i<frArr.length; i++) {
1719             PrismFontFile fr = frArr[i];
1720             String family = fr.getFamilyName();
1721             String fullname = fr.getFullName();
1722             removeEmbeddedFont(fullname);
1723             embeddedFonts.put(fullname, fr);
1724             storeInMap(fullname, fr);
1725             family = family + dotStyleStr(fr.isBold(), fr.isItalic());
1726             storeInMap(family, fr);
1727             /* The remove call is to assist the case where we have
1728              * previously mapped into the composite map a different style
1729              * in this family as a partial match for the application request.
1730              * This can occur when an application requested a bold font before
1731              * it called Font.loadFont to register the bold font. It won't
1732              * fix the cases that already happened, but will fix the future ones.
1733              */
1734             compResourceMap.remove(family.toLowerCase());
1735         }
1736         return frArr;
1737     }
1738 
1739     private void
1740         logFontInfo(String message,
1741                     HashMap<String,String> fontToFileMap,
1742                     HashMap<String,String> fontToFamilyNameMap,
1743                     HashMap<String,ArrayList<String>> familyToFontListMap) {
1744 
1745         System.err.println(message);
1746         for (String keyName : fontToFileMap.keySet()) {
1747             System.err.println("font="+keyName+" file="+
1748                                fontToFileMap.get(keyName));
1749         }
1750         for (String keyName : fontToFamilyNameMap.keySet()) {
1751             System.err.println("font="+keyName+" family="+
1752                                fontToFamilyNameMap.get(keyName));
1753         }
1754         for (String keyName : familyToFontListMap.keySet()) {
1755             System.err.println("family="+keyName+ " fonts="+
1756                                familyToFontListMap.get(keyName));


< prev index next >