]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-3220: Add option to lazy load fonts for PNG/TIFF/PCL output main
authorSimon Steiner <ssteiner@apache.org>
Tue, 19 Nov 2024 10:52:59 +0000 (10:52 +0000)
committerSimon Steiner <ssteiner@apache.org>
Tue, 19 Nov 2024 10:52:59 +0000 (10:52 +0000)
fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java
fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java
fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java
fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java
fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
fop-core/src/main/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java
fop-core/src/test/java/org/apache/fop/render/java2d/ConfiguredFontCollectionTestCase.java

index 2b67dbd2e0b85a63131c7d22e1353cdc9fae6568..39ebc49f5661292b9e6766ac3eb1657d1bed7c85 100644 (file)
@@ -38,7 +38,7 @@ import org.apache.fop.util.LogUtil;
  */
 public final class DefaultFontConfig implements FontConfig {
 
-    private static final Log log = LogFactory.getLog(DefaultFontConfig.class);
+    private static final Log LOG = LogFactory.getLog(DefaultFontConfig.class);
 
     private final List<Directory> directories = new ArrayList<Directory>();
 
@@ -116,24 +116,27 @@ public final class DefaultFontConfig implements FontConfig {
         }
 
         private void parseFonts() throws FOPException {
+            boolean lazyLoad = fontInfoCfg.getAttributeAsBoolean("lazy-load", false);
             for (Configuration fontCfg : fontInfoCfg.getChildren("font")) {
                 String embed = fontCfg.getAttribute("embed-url", null);
                 if (embed == null) {
-                    LogUtil.handleError(log, "Font configuration without embed-url attribute",
+                    LogUtil.handleError(LOG, "Font configuration without embed-url attribute",
                             strict);
                     continue;
                 }
+                String subFont = fontCfg.getAttribute("sub-font", null);
                 Font font = new Font(fontCfg.getAttribute("metrics-url", null), embed,
                         fontCfg.getAttribute("embed-url-afm", null),
                         fontCfg.getAttribute("embed-url-pfm", null),
-                        fontCfg.getAttribute("sub-font", null),
+                        subFont,
                         fontCfg.getAttributeAsBoolean("kerning", true),
                         fontCfg.getAttributeAsBoolean("advanced", true),
                         fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()),
                         fontCfg.getAttribute("embedding-mode", EncodingMode.AUTO.getName()),
                         fontCfg.getAttributeAsBoolean("simulate-style", false),
                         fontCfg.getAttributeAsBoolean("embed-as-type1", false),
-                        fontCfg.getAttributeAsBoolean("svg", true));
+                        fontCfg.getAttributeAsBoolean("svg", true),
+                        lazyLoad);
                 instance.fonts.add(font);
                 boolean hasTriplets = false;
                 for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) {
@@ -143,7 +146,7 @@ public final class DefaultFontConfig implements FontConfig {
                 }
                 // no font triplet info
                 if (!hasTriplets) {
-                    LogUtil.handleError(log, "font without font-triplet", strict);
+                    LogUtil.handleError(LOG, "font without font-triplet", strict);
                 }
                 try {
                     if (eventAdapter != null && font.getSimulateStyle()
@@ -155,7 +158,7 @@ public final class DefaultFontConfig implements FontConfig {
                         throw new FOPException("The embed-as-type1 attribute is only supported in postscript");
                     }
                 } catch (ConfigurationException ex) {
-                    LogUtil.handleException(log, ex, true);
+                    LogUtil.handleException(LOG, ex, true);
                 }
             }
         }
@@ -167,7 +170,7 @@ public final class DefaultFontConfig implements FontConfig {
                     try {
                         instance.referencedFontFamilies.add(match.getAttribute("font-family"));
                     } catch (ConfigurationException ce) {
-                        LogUtil.handleException(log, ce, strict);
+                        LogUtil.handleException(LOG, ce, strict);
                         continue;
                     }
                 }
@@ -181,11 +184,11 @@ public final class DefaultFontConfig implements FontConfig {
                 try {
                     directory = directoriesCfg.getValue();
                 } catch (ConfigurationException e) {
-                    LogUtil.handleException(log, e, strict);
+                    LogUtil.handleException(LOG, e, strict);
                     continue;
                 }
                 if (directory == null) {
-                    LogUtil.handleException(log,
+                    LogUtil.handleException(LOG,
                             new FOPException("directory defined without value"), strict);
                     continue;
                 }
@@ -205,25 +208,25 @@ public final class DefaultFontConfig implements FontConfig {
             try {
                 String name = tripletCfg.getAttribute("name");
                 if (name == null) {
-                    LogUtil.handleError(log, "font-triplet without name", strict);
+                    LogUtil.handleError(LOG, "font-triplet without name", strict);
                     return null;
                 }
                 String weightStr = tripletCfg.getAttribute("weight");
                 if (weightStr == null) {
-                    LogUtil.handleError(log, "font-triplet without weight", strict);
+                    LogUtil.handleError(LOG, "font-triplet without weight", strict);
                     return null;
                 }
                 int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr));
                 String style = tripletCfg.getAttribute("style");
                 if (style == null) {
-                    LogUtil.handleError(log, "font-triplet without style", strict);
+                    LogUtil.handleError(LOG, "font-triplet without style", strict);
                     return null;
                 } else {
                     style = FontUtil.stripWhiteSpace(style);
                 }
                 return FontInfo.createFontKey(name, style, weight);
             } catch (ConfigurationException e) {
-                LogUtil.handleException(log, e, strict);
+                LogUtil.handleException(LOG, e, strict);
             }
             return null;
         }
@@ -316,14 +319,12 @@ public final class DefaultFontConfig implements FontConfig {
 
         private final String embeddingMode;
 
-        public String getEncodingMode() {
-            return encodingMode;
-        }
+        private final boolean simulateStyle;
 
         private final boolean embedAsType1;
-        private final boolean simulateStyle;
 
         private final boolean useSVG;
+        private final boolean lazyLoad;
 
         private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>();
 
@@ -333,7 +334,7 @@ public final class DefaultFontConfig implements FontConfig {
 
         private Font(String metrics, String embed, String afm, String pfm, String subFont, boolean kerning,
                      boolean advanced, String encodingMode, String embeddingMode, boolean simulateStyle,
-                     boolean embedAsType1, boolean useSVG) {
+                     boolean embedAsType1, boolean useSVG, boolean lazyLoad) {
             this.metrics = metrics;
             this.embedUri = embed;
             this.afm = afm;
@@ -346,6 +347,7 @@ public final class DefaultFontConfig implements FontConfig {
             this.simulateStyle = simulateStyle;
             this.embedAsType1 = embedAsType1;
             this.useSVG = useSVG;
+            this.lazyLoad = lazyLoad;
         }
 
         /**
@@ -384,6 +386,10 @@ public final class DefaultFontConfig implements FontConfig {
             return subFont;
         }
 
+        public String getEncodingMode() {
+            return encodingMode;
+        }
+
         public String getEmbeddingMode() {
             return embeddingMode;
         }
@@ -407,5 +413,9 @@ public final class DefaultFontConfig implements FontConfig {
         public boolean getUseSVG() {
             return useSVG;
         }
+
+        public boolean isLazyLoad() {
+            return lazyLoad;
+        }
     }
 }
index 6e8c493cd93d8fdfc185ec27ac7db16d3b70193f..9181937e4a9954df5af1041c2c3a52801bd0a59e 100644 (file)
@@ -168,7 +168,7 @@ public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo>
         EmbeddingMode embeddingMode = EmbeddingMode.getValue(font.getEmbeddingMode());
         EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, font.isKerning(),
                 font.isAdvanced(), tripletList, subFont, encodingMode, embeddingMode,
-                font.getSimulateStyle(), font.getEmbedAsType1(), font.getUseSVG());
+                font.getSimulateStyle(), font.getEmbedAsType1(), font.getUseSVG(), font.isLazyLoad());
         if (fontCache != null) {
             if (!fontCache.containsFont(embedFontInfo)) {
                 fontCache.addFont(embedFontInfo, resourceResolver);
index 27a0a4db28c778232455488ce682f48ac226388c..269356a6ddf61ce45bb09fac4eba528db99eea9a 100644 (file)
@@ -46,6 +46,7 @@ public class EmbedFontInfo implements Serializable {
     private final boolean simulateStyle;
     private final boolean embedAsType1;
     private final boolean useSVG;
+    private final boolean lazyLoad;
 
     /** the PostScript name of the font */
     protected String postScriptName;
@@ -68,9 +69,9 @@ public class EmbedFontInfo implements Serializable {
      * @param subFontName the sub-fontname used for TrueType Collections (null otherwise)
      * @param encodingMode the encoding mode to use for this font
      */
-    public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced,
-            List<FontTriplet> fontTriplets, String subFontName, EncodingMode encodingMode,
-            EmbeddingMode embeddingMode, boolean simulateStyle, boolean embedAsType1, boolean useSVG) {
+    public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced, List<FontTriplet> fontTriplets,
+                         String subFontName, EncodingMode encodingMode, EmbeddingMode embeddingMode,
+                         boolean simulateStyle, boolean embedAsType1, boolean useSVG, boolean lazyLoad) {
         this.kerning = kerning;
         this.advanced = advanced;
         this.fontTriplets = fontTriplets;
@@ -81,6 +82,7 @@ public class EmbedFontInfo implements Serializable {
         this.simulateStyle = simulateStyle;
         this.embedAsType1 = embedAsType1;
         this.useSVG = useSVG;
+        this.lazyLoad = lazyLoad;
     }
 
     /**
@@ -93,7 +95,7 @@ public class EmbedFontInfo implements Serializable {
     public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced,
             List<FontTriplet> fontTriplets, String subFontName) {
         this(fontUris, kerning, advanced, fontTriplets, subFontName, EncodingMode.AUTO,
-                EmbeddingMode.AUTO, false, false, true);
+                EmbeddingMode.AUTO, false, false, true, false);
     }
 
     /**
@@ -215,6 +217,10 @@ public class EmbedFontInfo implements Serializable {
         return useSVG;
     }
 
+    public boolean isLazyLoad() {
+        return lazyLoad;
+    }
+
     private void readObject(java.io.ObjectInputStream in)
                 throws IOException, ClassNotFoundException {
         in.defaultReadObject();
index a9f222bf17880fb0b1d6dca237034c082d93c44e..9270cacab61df94ef61de6169789d869e99f4f91 100644 (file)
@@ -387,7 +387,7 @@ public final class AFPFontConfig implements FontConfig {
             try {
                 FontUris fontUris = new FontUris(new URI(fontUri), null);
                 EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, false, true, null, subfont, EncodingMode.AUTO,
-                        EmbeddingMode.FULL, false, false, true);
+                        EmbeddingMode.FULL, false, false, true, false);
                 Typeface tf = new LazyFont(embedFontInfo, resourceResolver, false).getRealFont();
                 AFPResourceAccessor accessor = getAccessor(resourceResolver);
                 CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().build(characterset,
index d019f352a91c5cbcf065f8b4eb284113bc22e299..1df83a9f64d34192787f82b888537f80fc35a214 100644 (file)
@@ -27,11 +27,9 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.apache.fop.apps.io.InternalResourceResolver;
-import org.apache.fop.fonts.CustomFont;
 import org.apache.fop.fonts.EmbedFontInfo;
 import org.apache.fop.fonts.FontCollection;
 import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontLoader;
 import org.apache.fop.fonts.FontTriplet;
 import org.apache.fop.fonts.FontUris;
 import org.apache.fop.fonts.LazyFont;
@@ -73,7 +71,7 @@ public class ConfiguredFontCollection implements FontCollection {
             internalName = "F" + num++;
             try {
                 URI fontURI = configFontInfo.getEmbedURI();
-                FontMetricsMapper font;
+                CustomFontMetricsMapper font;
                 URI metricsURI = configFontInfo.getMetricsURI();
                 // If the user specified an XML-based metrics file, we'll use it
                 // Otherwise, calculate metrics directly from the font file.
@@ -83,12 +81,10 @@ public class ConfiguredFontCollection implements FontCollection {
                     font = new CustomFontMetricsMapper(fontMetrics, fontSource);
                 } else {
                     FontUris fontUris = configFontInfo.getFontUris();
-                    CustomFont fontMetrics = FontLoader.loadFont(fontUris, configFontInfo.getSubFontName(), true,
-                            configFontInfo.getEmbeddingMode(), configFontInfo.getEncodingMode(),
-                            configFontInfo.getKerning(), configFontInfo.getAdvanced(), resourceResolver,
-                            configFontInfo.getSimulateStyle(), configFontInfo.getEmbedAsType1(),
-                            configFontInfo.getUseSVG());
-                    font = new CustomFontMetricsMapper(fontMetrics);
+                    font = new CustomFontMetricsMapper(fontUris, configFontInfo, resourceResolver);
+                    if (!configFontInfo.isLazyLoad()) {
+                        font.getRealFont();
+                    }
                 }
 
                 fontInfo.addMetrics(internalName, font);
index 4e656cea8d130eef6a5dc3c911511428085e720a..82a10b4cea362624889ca34dbd4ac77c4cf0bb63 100644 (file)
@@ -29,10 +29,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.fop.apps.io.InternalResourceResolver;
 import org.apache.fop.complexscripts.fonts.Positionable;
 import org.apache.fop.complexscripts.fonts.Substitutable;
 import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.EmbedFontInfo;
+import org.apache.fop.fonts.FontLoader;
 import org.apache.fop.fonts.FontType;
+import org.apache.fop.fonts.FontUris;
 import org.apache.fop.fonts.LazyFont;
 import org.apache.fop.fonts.Typeface;
 
@@ -49,6 +53,9 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
      * Font metrics for the font this class models.
      */
     private Typeface typeface;
+    private FontUris fontUris;
+    private EmbedFontInfo configFontInfo;
+    private InternalResourceResolver resourceResolver;
 
     /**
      * The font required by the Java2D renderer.
@@ -87,6 +94,13 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
         initialize(fontSource);
     }
 
+    public CustomFontMetricsMapper(FontUris fontUris, EmbedFontInfo configFontInfo,
+                                   InternalResourceResolver resourceResolver) {
+        this.fontUris = fontUris;
+        this.configFontInfo = configFontInfo;
+        this.resourceResolver = resourceResolver;
+    }
+
     private static final int TYPE1_FONT = 1; //Defined in Java 1.5
 
     /**
@@ -98,7 +112,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
     private void initialize(final InputStream inStream)
                 throws FontFormatException, IOException {
         int type = Font.TRUETYPE_FONT;
-        if (FontType.TYPE1.equals(typeface.getFontType())) {
+        if (FontType.TYPE1.equals(getRealFont().getFontType())) {
             type = TYPE1_FONT; //Font.TYPE1_FONT; only available in Java 1.5
         }
         this.font = Font.createFont(type, inStream);
@@ -112,16 +126,18 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
 
     /** {@inheritDoc} */
     public final boolean hasChar(final char c) {
+        getRealFont();
         return font.canDisplay(c);
     }
 
     /** {@inheritDoc} */
     public final char mapChar(final char c) {
-        return typeface.mapChar(c);
+        return getRealFont().mapChar(c);
     }
 
     /** {@inheritDoc} */
     public final Font getFont(final int size) {
+        getRealFont();
         if (this.size == size) {
             return font;
         }
@@ -133,104 +149,104 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
 
     /** {@inheritDoc} */
     public final int getAscender(final int size) {
-        return typeface.getAscender(size);
+        return getRealFont().getAscender(size);
     }
 
     /** {@inheritDoc} */
     public final int getCapHeight(final int size) {
-        return typeface.getCapHeight(size);
+        return getRealFont().getCapHeight(size);
     }
 
     /** {@inheritDoc} */
     public final int getDescender(final int size) {
-        return typeface.getDescender(size);
+        return getRealFont().getDescender(size);
     }
 
     /** {@inheritDoc} */
     public final String getEmbedFontName() {
-        return typeface.getEmbedFontName();
+        return getRealFont().getEmbedFontName();
     }
 
     /** {@inheritDoc} */
     public final Set<String> getFamilyNames() {
-        return typeface.getFamilyNames();
+        return getRealFont().getFamilyNames();
     }
 
     /** {@inheritDoc} */
     public final String getFontName() {
-        return typeface.getFontName();
+        return getRealFont().getFontName();
     }
 
     /** {@inheritDoc} */
     public final URI getFontURI() {
-        return typeface.getFontURI();
+        return getRealFont().getFontURI();
     }
 
     /** {@inheritDoc} */
     public final FontType getFontType() {
-        return typeface.getFontType();
+        return getRealFont().getFontType();
     }
 
     /** {@inheritDoc} */
     public final String getFullName() {
-        return typeface.getFullName();
+        return getRealFont().getFullName();
     }
 
     /** {@inheritDoc} */
     public final Map getKerningInfo() {
-        return typeface.getKerningInfo();
+        return getRealFont().getKerningInfo();
     }
 
     /** {@inheritDoc} */
     public final int getWidth(final int i, final int size) {
-        return typeface.getWidth(i, size);
+        return getRealFont().getWidth(i, size);
     }
 
     /** {@inheritDoc} */
     public final int[] getWidths() {
-        return typeface.getWidths();
+        return getRealFont().getWidths();
     }
 
     public Rectangle getBoundingBox(int glyphIndex, int size) {
-        return typeface.getBoundingBox(glyphIndex, size);
+        return getRealFont().getBoundingBox(glyphIndex, size);
     }
 
     /** {@inheritDoc} */
     public final int getXHeight(final int size) {
-        return typeface.getXHeight(size);
+        return getRealFont().getXHeight(size);
     }
 
     public int getUnderlinePosition(int size) {
-        return typeface.getUnderlinePosition(size);
+        return getRealFont().getUnderlinePosition(size);
     }
 
     public int getUnderlineThickness(int size) {
-        return typeface.getUnderlineThickness(size);
+        return getRealFont().getUnderlineThickness(size);
     }
 
     public int getStrikeoutPosition(int size) {
-        return typeface.getStrikeoutPosition(size);
+        return getRealFont().getStrikeoutPosition(size);
     }
 
     public int getStrikeoutThickness(int size) {
-        return typeface.getStrikeoutThickness(size);
+        return getRealFont().getStrikeoutThickness(size);
     }
 
     /** {@inheritDoc} */
     public final boolean hasKerningInfo() {
-        return typeface.hasKerningInfo();
+        return getRealFont().hasKerningInfo();
     }
 
     /** {@inheritDoc} */
     public boolean isMultiByte() {
-        return typeface.isMultiByte();
+        return getRealFont().isMultiByte();
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean performsPositioning() {
-        if (typeface instanceof Positionable) {
+        if (getRealFont() instanceof Positionable) {
             return ((Positionable) typeface).performsPositioning();
         } else {
             return false;
@@ -241,7 +257,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
      * {@inheritDoc}
      */
     public int[][] performPositioning(CharSequence cs, String script, String language, int fontSize) {
-        if (typeface instanceof Positionable) {
+        if (getRealFont() instanceof Positionable) {
             return ((Positionable) typeface).performPositioning(cs, script, language, fontSize);
         } else {
             return null;
@@ -252,7 +268,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
      * {@inheritDoc}
      */
     public int[][] performPositioning(CharSequence cs, String script, String language) {
-        if (typeface instanceof Positionable) {
+        if (getRealFont() instanceof Positionable) {
             return ((Positionable) typeface).performPositioning(cs, script, language);
         } else {
             return null;
@@ -263,7 +279,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
      * {@inheritDoc}
      */
     public boolean performsSubstitution() {
-        if (typeface instanceof Substitutable) {
+        if (getRealFont() instanceof Substitutable) {
             return ((Substitutable) typeface).performsSubstitution();
         } else {
             return false;
@@ -275,7 +291,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
      */
     public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations,
                                             boolean retainControls) {
-        if (typeface instanceof Substitutable) {
+        if (getRealFont() instanceof Substitutable) {
             return ((Substitutable) typeface).performSubstitution(cs, script, language, associations, retainControls);
         } else {
             return cs;
@@ -287,7 +303,7 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
      */
     public CharSequence reorderCombiningMarks(CharSequence cs, int[][] gpa,
         String script, String language, List associations) {
-        if (typeface instanceof Substitutable) {
+        if (getRealFont() instanceof Substitutable) {
             return ((Substitutable) typeface).reorderCombiningMarks(cs, gpa, script, language, associations);
         } else {
             return cs;
@@ -295,7 +311,18 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
     }
 
     public Typeface getRealFont() {
+        if (typeface == null) {
+            try {
+                CustomFont fontMetrics = FontLoader.loadFont(fontUris, configFontInfo.getSubFontName(), true,
+                    configFontInfo.getEmbeddingMode(), configFontInfo.getEncodingMode(),
+                    configFontInfo.getKerning(), configFontInfo.getAdvanced(), resourceResolver,
+                    configFontInfo.getSimulateStyle(), configFontInfo.getEmbedAsType1(), configFontInfo.getUseSVG());
+                typeface = fontMetrics;
+                initialize(fontMetrics.getInputStream());
+            } catch (IOException | FontFormatException e) {
+                throw new RuntimeException("Failed to read font file " + fontUris.getEmbed() + " " + e.getMessage(), e);
+            }
+        }
         return typeface;
     }
-
 }
index 2fb366536bc3059916947ad49b8b17f97a94c576..61f2bad7b9630edea10a4c8b4e0ba9cd37b29ccd 100644 (file)
@@ -54,7 +54,7 @@ public class EmbedFontInfoTestCase {
         triplets.add(triplet);
         FontUris fontUris = new FontUris(embedURI, metricsURI);
         sut = new EmbedFontInfo(fontUris, kerning, useAdvanced, triplets, subFontName, encMode,
-                embedMode, false, false, true);
+                embedMode, false, false, true, false);
     }
 
     @Test
index 7e2f8d4f7875713bea65b9e2aeac9c0ca20cba58..a724972ad6bd7c22e8b0307c003cf4349e5baa86 100644 (file)
@@ -22,7 +22,10 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -31,9 +34,14 @@ import org.junit.Test;
 
 import org.apache.commons.io.IOUtils;
 
+import org.apache.xmlgraphics.io.Resource;
+import org.apache.xmlgraphics.io.ResourceResolver;
+
 import org.apache.fop.apps.io.InternalResourceResolver;
 import org.apache.fop.apps.io.ResourceResolverFactory;
 import org.apache.fop.fonts.EmbedFontInfo;
+import org.apache.fop.fonts.EmbeddingMode;
+import org.apache.fop.fonts.EncodingMode;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.fonts.FontTriplet;
 import org.apache.fop.fonts.FontUris;
@@ -61,6 +69,69 @@ public class ConfiguredFontCollectionTestCase {
         }
     }
 
+    @Test
+    public void testLazyLoading() {
+        List<EmbedFontInfo> list = Arrays.asList(
+                addFont("test/resources/fonts/type1/c0419bt_.pfb", "test/resources/fonts/type1/c0419bt_.afm", true),
+                addFont("x1", "x2", true));
+        List<String> fileReads = new ArrayList<>();
+        ConfiguredFontCollection collection = new ConfiguredFontCollection(getResourceResolver(fileReads), list, true);
+        FontInfo fontInfo = new FontInfo();
+        int numOfFonts = collection.setup(0, fontInfo);
+        Assert.assertEquals(numOfFonts, 2);
+        Assert.assertTrue(fileReads.isEmpty());
+        Assert.assertEquals(fontInfo.getFonts().get("F0").getFontName(), "Courier10PitchBT-Roman");
+        Assert.assertEquals(fileReads.size(), 3);
+        Assert.assertTrue(fileReads.get(0).contains("c0419bt_.afm"));
+        Assert.assertTrue(fileReads.get(2).contains("c0419bt_.pfb"));
+        String ex = "";
+        try {
+            fontInfo.getFonts().get("F1").getFontName();
+        } catch (RuntimeException e) {
+            ex = e.getMessage();
+        }
+        Assert.assertTrue(ex.startsWith("Failed to read font file"));
+        Assert.assertEquals(fileReads.size(), 4);
+    }
+
+    @Test
+    public void testNoLazyLoading() {
+        List<EmbedFontInfo> list = Arrays.asList(
+                addFont("test/resources/fonts/type1/c0419bt_.pfb", "test/resources/fonts/type1/c0419bt_.afm", false),
+                addFont("x1", "x2", false));
+        List<String> fileReads = new ArrayList<>();
+        ConfiguredFontCollection collection = new ConfiguredFontCollection(getResourceResolver(fileReads), list, true);
+        FontInfo fontInfo = new FontInfo();
+        int numOfFonts = collection.setup(0, fontInfo);
+        Assert.assertEquals(numOfFonts, 2);
+        Assert.assertEquals(fileReads.size(), 4);
+        Assert.assertEquals(fontInfo.getFonts().get("F0").getFontName(), "Courier10PitchBT-Roman");
+        Assert.assertTrue(fileReads.get(0).contains("c0419bt_.afm"));
+        Assert.assertTrue(fileReads.get(2).contains("c0419bt_.pfb"));
+        Assert.assertTrue(fileReads.get(3).contains("x2"));
+    }
+
+    private InternalResourceResolver getResourceResolver(final List<String> fileReads) {
+        return ResourceResolverFactory.createInternalResourceResolver(new File(".").toURI(),
+                new ResourceResolver() {
+                    public Resource getResource(URI uri) throws IOException {
+                        fileReads.add(uri.toASCIIString());
+                        return new Resource(uri.toURL().openStream());
+                    }
+                    public OutputStream getOutputStream(URI uri) {
+                        return null;
+                    }
+                });
+    }
+
+    private EmbedFontInfo addFont(String pfb, String afm, boolean lazyLoad) {
+        File pfbFile = new File(pfb);
+        File afmFile = new File(afm);
+        FontUris fontUris = new FontUris(pfbFile.toURI(), null, afmFile.toURI(), null);
+        return new EmbedFontInfo(fontUris, true, true, new ArrayList<FontTriplet>(), null,
+                EncodingMode.AUTO, EmbeddingMode.AUTO, false, false, true, lazyLoad);
+    }
+
     private File getFontFileNoExension(String s) throws IOException {
         FileInputStream pfb = new FileInputStream(s);
         File tmp = File.createTempFile("fop", "font");