*/
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>();
}
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")) {
}
// 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()
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);
}
}
}
try {
instance.referencedFontFamilies.add(match.getAttribute("font-family"));
} catch (ConfigurationException ce) {
- LogUtil.handleException(log, ce, strict);
+ LogUtil.handleException(LOG, ce, strict);
continue;
}
}
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;
}
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;
}
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>();
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;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
this.useSVG = useSVG;
+ this.lazyLoad = lazyLoad;
}
/**
return subFont;
}
+ public String getEncodingMode() {
+ return encodingMode;
+ }
+
public String getEmbeddingMode() {
return embeddingMode;
}
public boolean getUseSVG() {
return useSVG;
}
+
+ public boolean isLazyLoad() {
+ return lazyLoad;
+ }
}
}
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);
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;
* @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;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
this.useSVG = useSVG;
+ this.lazyLoad = lazyLoad;
}
/**
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);
}
/**
return useSVG;
}
+ public boolean isLazyLoad() {
+ return lazyLoad;
+ }
+
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
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,
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;
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.
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);
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;
* 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.
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
/**
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);
/** {@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;
}
/** {@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;
* {@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;
* {@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;
* {@inheritDoc}
*/
public boolean performsSubstitution() {
- if (typeface instanceof Substitutable) {
+ if (getRealFont() instanceof Substitutable) {
return ((Substitutable) typeface).performsSubstitution();
} else {
return false;
*/
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;
*/
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;
}
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;
}
-
}
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
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;
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;
}
}
+ @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");