Index: src/java/org/apache/fop/fonts/FontCache.java
===================================================================
--- src/java/org/apache/fop/fonts/FontCache.java	(revision 724434)
+++ src/java/org/apache/fop/fonts/FontCache.java	(working copy)
@@ -68,7 +68,7 @@
 
     /** master mapping of font url -> font info.  This needs to be
      *  a list, since a TTC file may contain more than 1 font. */
-    private Map/*<String, CachedFontFile>*/ fontfileMap = null;
+    private volatile Map/*<String, CachedFontFile>*/ fontfileMap = null;
 
     /** mapping of font url -> file modified date (for all fonts that have failed to load) */
     private Map failedFontMap/*<String, Long>*/ = null;
@@ -278,74 +278,107 @@
     public void addFont(EmbedFontInfo fontInfo) {
         String cacheKey = getCacheKey(fontInfo);
         synchronized (changeLock) {
-            CachedFontFile cachedFontFile;
-            if (containsFont(cacheKey)) {
-                cachedFontFile = (CachedFontFile)getFontFileMap().get(cacheKey);
-                if (!cachedFontFile.containsFont(fontInfo)) {
-                    cachedFontFile.put(fontInfo);
+            CachedFontFile cff = (CachedFontFile)getFontFileMap().get(cacheKey);
+            if (cff != null) {
+                if (!cff.containsFont(fontInfo)) {
+                    cff.put(fontInfo);
                 }
             } else {
                 // try and determine modified date
                 File fontFile = getFileFromUrls(new String[]
                                      {fontInfo.getEmbedFile(), fontInfo.getMetricsFile()});
                 long lastModified = (fontFile != null ? fontFile.lastModified() : -1);
-                cachedFontFile = new CachedFontFile(lastModified);
+                cff = new CachedFontFile(lastModified);
                 if (log.isTraceEnabled()) {
                     log.trace("Font added to cache: " + cacheKey);
                 }
-                cachedFontFile.put(fontInfo);
-                getFontFileMap().put(cacheKey, cachedFontFile);
+                cff.put(fontInfo);
+                getFontFileMap().put(cacheKey, cff);
                 changed = true;
+                changeLock.notifyAll();
             }
         }
     }
 
     /**
-     * Returns a font from the cache.
-     * @param embedUrl font info
+     * Returns a font file from the cache, or <code>null</code> if
+     * there is no mapping for the given URL.
+     *
+     * @param embedUrl URL to the font-file
      * @return CachedFontFile object
      */
     public CachedFontFile getFontFile(String embedUrl) {
-        return containsFont(embedUrl) ? (CachedFontFile) getFontFileMap().get(embedUrl) : null;
+        return (CachedFontFile) getFontFileMap().get(embedUrl);
     }
 
     /**
-     * Returns the EmbedFontInfo instances belonging to a font file. If the font file was
-     * modified since it was cached the entry is removed and null is returned.
+     * Returns the {@link EmbedFontInfo} instances belonging to a font file.
+     * If the font file was modified since it was cached, the entry is removed,
+     * and null is returned
+     *
      * @param embedUrl the font URL
-     * @param lastModified the last modified date/time of the font file
-     * @return the EmbedFontInfo instances or null if there's no cached entry or if it is outdated
+     * @param lastModified last-modified timestamp of the file
+     * @return the EmbedFontInfo instances, if any
      */
     public EmbedFontInfo[] getFontInfos(String embedUrl, long lastModified) {
+
         CachedFontFile cff = getFontFile(embedUrl);
-        if (cff.lastModified() == lastModified) {
-            return cff.getEmbedFontInfos();
-        } else {
-            removeFont(embedUrl);
-            return null;
-        }
-    }
+        if (cff != null) {
+            if (cff.lastModified >= lastModified) {
+                /* easiest case */
+                return cff.getEmbedFontInfos();
+            }
 
-    /**
-     * removes font from cache
-     * @param embedUrl embed url
-     */
-    public void removeFont(String embedUrl) {
-        synchronized (changeLock) {
-            if (containsFont(embedUrl)) {
-                if (log.isTraceEnabled()) {
-                    log.trace("Font removed from cache: " + embedUrl);
+            /* a newer version of the file is available
+             * re-check synchronized, to see if the
+             * change has already been detected by
+             * another thread
+             */
+            synchronized (changeLock) {
+                cff = getFontFile(embedUrl);
+                if (cff != null) {
+                    if (cff.lastModified < lastModified) {
+                        /* still the outdated version, so we're
+                         * the first.
+                         * remove the entry, so other threads
+                         * will be forced to retry synchronized
+                         */
+                        getFontFileMap().remove(embedUrl);
+                        if (log.isTraceEnabled()) {
+                            log.trace("Font removed: " + embedUrl);
+                        }
+                        changed = true;
+                        return null;
+                    } else {
+                        /* more recent version already added */
+                        return cff.getEmbedFontInfos();
+                    }
+                } else {
+                    /* another thread removed the entry
+                     * wait for notification...
+                     */
+                    try {
+                        changeLock.wait();
+                    } catch (InterruptedException ie) {
+                        cff = getFontFile(embedUrl);
+                        if (cff != null) {
+                            /* for simplicity, assume that the entry
+                             * that was added in the meantime, will do
+                             */
+                            return cff.getEmbedFontInfos();
+                        }
+                    }
                 }
-                getFontFileMap().remove(embedUrl);
-                changed = true;
             }
         }
+
+        return null;
     }
 
     /**
      * has this font previously failed to load?
      * @param embedUrl embed url
-     * @param lastModified last modified
+     * @param lastModified last modified timestamp of the file
      * @return whether this is a failed font
      */
     public boolean isFailedFont(String embedUrl, long lastModified) {
@@ -375,6 +408,7 @@
             if (!getFailedFontMap().containsKey(embedUrl)) {
                 getFailedFontMap().put(embedUrl, new Long(lastModified));
                 changed = true;
+                changeLock.notifyAll();
             }
         }
     }
@@ -425,7 +459,7 @@
         private static final long serialVersionUID = 4524237324330578883L;
 
         /** file modify date (if available) */
-        private long lastModified = -1;
+        private volatile long lastModified = -1;
 
         private Map/*<String, EmbedFontInfo>*/ filefontsMap = null;
 
