From 2f1858567a8d68bd9c09eb33955d2cbae2aa03ac Mon Sep 17 00:00:00 2001 From: Simon Steiner Date: Tue, 19 Nov 2024 10:52:59 +0000 Subject: [PATCH] FOP-3220: Add option to lazy load fonts for PNG/TIFF/PCL output --- .../apache/fop/fonts/DefaultFontConfig.java | 46 ++++++---- .../fop/fonts/DefaultFontConfigurator.java | 2 +- .../org/apache/fop/fonts/EmbedFontInfo.java | 14 ++- .../apache/fop/render/afp/AFPFontConfig.java | 2 +- .../java2d/ConfiguredFontCollection.java | 14 ++- .../java2d/CustomFontMetricsMapper.java | 85 ++++++++++++------- .../fop/fonts/EmbedFontInfoTestCase.java | 2 +- .../ConfiguredFontCollectionTestCase.java | 71 ++++++++++++++++ 8 files changed, 173 insertions(+), 63 deletions(-) diff --git a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java index 2b67dbd2e..39ebc49f5 100644 --- a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java +++ b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java @@ -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 directories = new ArrayList(); @@ -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 tripletList = new ArrayList(); @@ -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; + } } } diff --git a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java index 6e8c493cd..9181937e4 100644 --- a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java +++ b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java @@ -168,7 +168,7 @@ public class DefaultFontConfigurator implements FontConfigurator 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); diff --git a/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java b/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java index 27a0a4db2..269356a6d 100644 --- a/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java +++ b/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java @@ -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 fontTriplets, String subFontName, EncodingMode encodingMode, - EmbeddingMode embeddingMode, boolean simulateStyle, boolean embedAsType1, boolean useSVG) { + public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced, List 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 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(); diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java index a9f222bf1..9270cacab 100644 --- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java +++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java @@ -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, diff --git a/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java index d019f352a..1df83a9f6 100644 --- a/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java +++ b/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java @@ -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); diff --git a/fop-core/src/main/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java b/fop-core/src/main/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java index 4e656cea8..82a10b4ce 100644 --- a/fop-core/src/main/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java +++ b/fop-core/src/main/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java @@ -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 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; } - } diff --git a/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java index 2fb366536..61f2bad7b 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java @@ -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 diff --git a/fop-core/src/test/java/org/apache/fop/render/java2d/ConfiguredFontCollectionTestCase.java b/fop-core/src/test/java/org/apache/fop/render/java2d/ConfiguredFontCollectionTestCase.java index 7e2f8d4f7..a724972ad 100644 --- a/fop-core/src/test/java/org/apache/fop/render/java2d/ConfiguredFontCollectionTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/java2d/ConfiguredFontCollectionTestCase.java @@ -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 list = Arrays.asList( + addFont("test/resources/fonts/type1/c0419bt_.pfb", "test/resources/fonts/type1/c0419bt_.afm", true), + addFont("x1", "x2", true)); + List 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 list = Arrays.asList( + addFont("test/resources/fonts/type1/c0419bt_.pfb", "test/resources/fonts/type1/c0419bt_.afm", false), + addFont("x1", "x2", false)); + List 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 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(), 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"); -- 2.39.5