if you wanted to add a custom font. This unconvenient step has been removed and in
addition to that, FOP supports auto-registration of fonts, i.e. FOP can find fonts
installed in your operating system or can scan user-specified directories for fonts.
- Font registration via XML font metrics file is still supported and is still necessary
- if you want to use a TrueType Collection (*.ttc). Direct support for TrueType
- collections may be added later. Furthermore, the XML font metrics files are still
- required if you don't want to embed, but only reference a font.
+ Font registration via XML font metrics file is still supported and may still be necessary
+ for some very special cases as fallback variant while we stabilize font auto-detection.
</p>
<p>
Basic information about fonts can be found at:
</section>
<section id="embedding">
<title>Embedding</title>
- <note>The PostScript renderer does not yet support TrueType fonts, but can embed Type 1 fonts.</note>
- <note>The font is simply embedded into the PDF file, it is not converted.</note>
- <p>Font embedding is enabled in the userconfig.xml file and controlled by the embed-url attribute.
- If you don't specify the embed-url attribute the font will not be embedded, but will only be referenced.</p>
- <warning>
- Omitting the embed-url attribute for CID-encoded TrueType fonts will currently produce invalid
- PDF files! If you create the XML font metric file using the "-enc ansi" option, you can omit
- the embed-url attribute for TrueType fonts but you're restricted to the WinAnsi character set.
- </warning>
- <p>When FOP embeds a font, it adds a prefix to the fontname to ensure that the name will not match the fontname of an installed font.
- This is helpful with older versions of Acrobat Reader that preferred installed fonts over embedded fonts.</p>
- <p>When embedding PostScript fonts, the entire font is always embedded.</p>
- <p>When embedding TrueType fonts (ttf) or TrueType Collections (ttc), a subset of the
- original font, containing only the glyphs used, is embedded in the output document.</p>
+ <p>
+ By default, all fonts are embedded if an output format supports font embedding. In some
+ cases, however, it is preferred that some fonts are only referenced. When working
+ with referenced fonts it is important to be in control of the target environment where
+ the produced document is consumed, i.e. the necessary fonts have to be installed there.
+ </p>
+ <p>
+ There are two different ways how you can specify that a font should be referenced:
+ </p>
+ <ol>
+ <li>
+ When using the old-style "font" element to configure a single font, font referencing
+ is controlled by the embed-url attribute. If you don't specify the embed-url attribute
+ the font will not be embedded, but will only be referenced.
+ </li>
+ <li>
+ For automatically configured fonts there's a different mechanism to specify which
+ fonts should be referenced rather than embedded. This is done in the "referenced-fonts"
+ element in the configuration. Here's an example:
+ </li>
+ </ol>
+ <source><![CDATA[
+<fop version="1.0">
+ <fonts>
+ <referenced-fonts>
+ <match font-family="Helvetica"/>
+ <match font-family="DejaVu.*"/>
+ </referenced-fonts>
+ </fonts>
+</fop>]]></source>
+ <p>
+ At the moment, you can only match fonts against their font-family. It is possible to use
+ regular expressions as is shown in the second example above ("DejaVu.*"). The syntax for
+ the regular expressions used here are the one used by the
+ <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/regex/package-summary.html"><code>java.util.regex</code> package</a>.
+ So, in the above snippet "Helvetica" and all variants of the "DejaVu" font family are
+ referenced. If you want to reference all fonts, just specify <code>font-family=".*"</code>.
+ </p>
+ <p>
+ Various notes related to embedded fonts:
+ </p>
+ <ul>
+ <li>The PostScript renderer does not yet support TrueType fonts, but can embed Type 1 fonts.</li>
+ <li>The font is simply embedded into the PDF file, it is not converted.</li>
+ <li>When FOP embeds a font, it adds a prefix to the fontname to ensure that the name will not match the fontname of an installed font.
+ This is helpful with older versions of Acrobat Reader that preferred installed fonts over embedded fonts.</li>
+ <li>When embedding PostScript fonts, the entire font is always embedded.</li>
+ <li>When embedding TrueType fonts (ttf) or TrueType Collections (ttc), a subset of the
+ original font, containing only the glyphs used, is embedded in the output document.</li>
+ </ul>
</section>
<section id="substitution">
<title>Substitution</title>
}
/**
- * Returns the font manager
+ * Returns the font manager.
* @return the font manager
*/
public FontManager getFontManager() {
if (fontManager == null) {
- this.fontManager = new FontManager(this);
+ this.fontManager = new FontManager() {
+
+ /** {@inheritDoc} */
+ public void setFontBaseURL(String fontBase) throws MalformedURLException {
+ super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase));
+ }
+
+ };
}
return this.fontManager;
}
import java.io.IOException;
import java.net.MalformedURLException;
+import org.xml.sax.SAXException;
+
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.util.LogUtil;
-import org.xml.sax.SAXException;
/**
* FopFactory configurator
// configure font manager
FontManager fontManager = factory.getFontManager();
FontManagerConfigurator fontManagerConfigurator = new FontManagerConfigurator(cfg);
- fontManagerConfigurator.configure(fontManager);
+ fontManagerConfigurator.configure(fontManager, strict);
}
/**
package org.apache.fop.fonts;
+import java.io.IOException;
import java.io.Serializable;
import java.util.List;
/** the list of associated font triplets */
private List/*<FontTriplet>*/ fontTriplets = null;
+ private transient boolean embedded = true;
+
/**
* Main constructor
* @param metricsFile Path to the xml file containing font metrics
}
/**
- * {@inheritDoc}
+ * Indicates whether the font is only referenced rather than embedded.
+ * @return true if the font is embedded, false if it is referenced.
+ */
+ public boolean isEmbedded() {
+ if (metricsFile != null && embedFile == null) {
+ return false;
+ } else {
+ return this.embedded;
+ }
+ }
+
+ /**
+ * Defines whether the font is embedded or not.
+ * @param value true to embed the font, false to reference it
*/
+ public void setEmbedded(boolean value) {
+ this.embedded = value;
+ }
+
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ this.embedded = true;
+ }
+
+ /** {@inheritDoc} */
public String toString() {
return "metrics-url=" + metricsFile + ",embed-url=" + embedFile
+ ", kerning=" + kerning + ", " + "font-triplet=" + fontTriplets
- + (getSubFontName() != null ? ", sub-font=" + getSubFontName() : "");
+ + (getSubFontName() != null ? ", sub-font=" + getSubFontName() : "")
+ + (isEmbedded() ? "" : ", NOT embedded");
}
+
}
*/
public abstract class FontLoader {
- /**
- * logging instance
- */
+ /** logging instance */
protected static Log log = LogFactory.getLog(FontLoader.class);
/** URI representing the font file */
/** true if the font has been loaded */
protected boolean loaded = false;
+ /** true if the font will be embedded, false if it will be referenced only. */
+ protected boolean embedded = true;
/**
* Default constructor.
* @param fontFileURI the URI to the PFB file of a Type 1 font
+ * @param embedded indicates whether the font is embedded or referenced
* @param resolver the font resolver used to resolve URIs
*/
- public FontLoader(String fontFileURI, FontResolver resolver) {
+ public FontLoader(String fontFileURI, boolean embedded, FontResolver resolver) {
this.fontFileURI = fontFileURI;
+ this.embedded = embedded;
this.resolver = resolver;
}
* Loads a custom font from a File. In the case of Type 1 fonts, the PFB file must be specified.
* @param fontFile the File representation of the font
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
+ * @param embedded indicates whether the font is embedded or referenced
* @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
- public static CustomFont loadFont(File fontFile, String subFontName, FontResolver resolver)
- throws IOException {
- return loadFont(fontFile.getAbsolutePath(), subFontName, resolver);
+ public static CustomFont loadFont(File fontFile, String subFontName,
+ boolean embedded, FontResolver resolver) throws IOException {
+ return loadFont(fontFile.getAbsolutePath(), subFontName, embedded, resolver);
}
/**
* Loads a custom font from an URL. In the case of Type 1 fonts, the PFB file must be specified.
* @param fontUrl the URL representation of the font
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
+ * @param embedded indicates whether the font is embedded or referenced
* @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
- public static CustomFont loadFont(URL fontUrl, String subFontName, FontResolver resolver)
- throws IOException {
- return loadFont(fontUrl.toExternalForm(), subFontName, resolver);
+ public static CustomFont loadFont(URL fontUrl, String subFontName,
+ boolean embedded, FontResolver resolver) throws IOException {
+ return loadFont(fontUrl.toExternalForm(), subFontName, embedded, resolver);
}
-
/**
* Loads a custom font from a URI. In the case of Type 1 fonts, the PFB file must be specified.
* @param fontFileURI the URI to the font
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
+ * @param embedded indicates whether the font is embedded or referenced
* @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
- public static CustomFont loadFont(String fontFileURI, String subFontName, FontResolver resolver)
- throws IOException {
+ public static CustomFont loadFont(String fontFileURI, String subFontName,
+ boolean embedded, FontResolver resolver) throws IOException {
fontFileURI = fontFileURI.trim();
boolean type1 = isType1(fontFileURI);
FontLoader loader;
if (type1) {
- loader = new Type1FontLoader(fontFileURI, resolver);
+ loader = new Type1FontLoader(fontFileURI, embedded, resolver);
} else {
- loader = new TTFFontLoader(fontFileURI, subFontName, resolver);
+ loader = new TTFFontLoader(fontFileURI, subFontName, embedded, resolver);
}
return loader.getFont();
}
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
-import org.apache.fop.apps.FopFactory;
+import org.apache.fop.fonts.FontTriplet.Matcher;
import org.apache.fop.fonts.substitute.FontSubstitutions;
import org.apache.fop.render.PrintRenderer;
// and start using POJO config/properties type classes
/**
- * The manager of fonts
+ * The manager of fonts. The class holds a reference to the font cache and information about
+ * font substitution, referenced fonts and similar.
*/
public class FontManager {
/** Use cache (record previously detected font triplet info) */
/** Font substitutions */
private FontSubstitutions fontSubstitutions = null;
- private FopFactory fopFactory = null;
-
/** Allows enabling kerning on the base 14 fonts, default is false */
private boolean enableBase14Kerning = false;
+ /** FontTriplet matcher for fonts that shall be referenced rather than embedded. */
+ private FontTriplet.Matcher referencedFontsMatcher;
+
/**
* Main constructor
- *
- * @param fopFactory the fo URI resolver
*/
- public FontManager(FopFactory fopFactory) {
- this(fopFactory, DEFAULT_USE_CACHE);
- }
-
- /**
- * Constructor
- *
- * @param fopFactory the fo URI resolver
- * @param useCache true if the FontCache should be used
- */
- public FontManager(FopFactory fopFactory, boolean useCache) {
- this.fopFactory = fopFactory;
- setUseCache(useCache);
+ public FontManager() {
+ setUseCache(DEFAULT_USE_CACHE);
}
/**
* Sets the font base URL.
* @param fontBase font base URL
- * @throws MalformedURLException if there's a problem with a file URL
+ * @throws MalformedURLException if there's a problem with a URL
*/
public void setFontBaseURL(String fontBase) throws MalformedURLException {
- this.fontBase = fopFactory.getFOURIResolver().checkBaseURL(fontBase);
+ this.fontBase = fontBase;
}
/**
- * @return the font base URL
+ * Returns the font base URL.
+ * @return the font base URL (or null if none was set)
*/
public String getFontBaseURL() {
return this.fontBase;
}
};
}
+
+ /**
+ * Sets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall
+ * be referenced rather than embedded.
+ * @param matcher the font triplet matcher
+ */
+ public void setReferencedFontsMatcher(FontTriplet.Matcher matcher) {
+ this.referencedFontsMatcher = matcher;
+ }
+
+ /**
+ * Gets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall
+ * be referenced rather than embedded.
+ * @return the font triplet matcher (or null if none is set)
+ */
+ public Matcher getReferencedFontsMatcher() {
+ return this.referencedFontsMatcher;
+ }
}
package org.apache.fop.fonts;
import java.net.MalformedURLException;
+import java.util.List;
+import java.util.regex.Pattern;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.apps.FOPException;
import org.apache.fop.fonts.substitute.FontSubstitutions;
import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator;
/**
* Initializes font settings from the user configuration
* @param fontManager a font manager
- * @throws FOPException fop exception
+ * @param strict true if strict checking of the configuration is enabled
+ * @throws FOPException if an exception occurs while processing the configuration
*/
- public void configure(FontManager fontManager) throws FOPException {
+ public void configure(FontManager fontManager, boolean strict) throws FOPException {
+
// caching (fonts)
if (cfg.getChild("use-cache", false) != null) {
try {
fontSubstitutionsConfigurator.configure(substitutions);
fontManager.setFontSubstitutions(substitutions);
}
+
+ // referenced fonts (fonts which are not to be embedded)
+ Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false);
+ if (referencedFontsCfg != null) {
+ createReferencedFontsMatcher(referencedFontsCfg, strict, fontManager);
+ }
+
}
- }
+ }
+
+ private static void createReferencedFontsMatcher(Configuration referencedFontsCfg,
+ boolean strict, FontManager fontManager) throws FOPException {
+ List matcherList = new java.util.ArrayList();
+ Configuration[] matches = referencedFontsCfg.getChildren("match");
+ for (int i = 0; i < matches.length; i++) {
+ try {
+ matcherList.add(new FontFamilyRegExFontTripletMatcher(
+ matches[i].getAttribute("font-family")));
+ } catch (ConfigurationException ce) {
+ LogUtil.handleException(log, ce, strict);
+ continue;
+ }
+ }
+ FontTriplet.Matcher orMatcher = new OrFontTripletMatcher(
+ (FontTriplet.Matcher[])matcherList.toArray(
+ new FontTriplet.Matcher[matcherList.size()]));
+ fontManager.setReferencedFontsMatcher(orMatcher);
+ }
+
+ private static class OrFontTripletMatcher implements FontTriplet.Matcher {
+
+ private FontTriplet.Matcher[] matchers;
+
+ public OrFontTripletMatcher(FontTriplet.Matcher[] matchers) {
+ this.matchers = matchers;
+ }
+
+ /** {@inheritDoc} */
+ public boolean matches(FontTriplet triplet) {
+ for (int i = 0, c = matchers.length; i < c; i++) {
+ if (matchers[i].matches(triplet)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }
+
+ private static class FontFamilyRegExFontTripletMatcher implements FontTriplet.Matcher {
+
+ private Pattern regex;
+
+ public FontFamilyRegExFontTripletMatcher(String regex) {
+ this.regex = Pattern.compile(regex);
+ }
+
+ /** {@inheritDoc} */
+ public boolean matches(FontTriplet triplet) {
+ return regex.matcher(triplet.getName()).matches();
+ }
+
+ }
+
}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.fonts.base14.Courier;
import org.apache.fop.fonts.base14.CourierBold;
import org.apache.fop.fonts.base14.CourierBoldOblique;
}
String internalName = null;
- //FontReader reader = null;
for (int i = 0; i < embedFontInfoList.size(); i++) {
EmbedFontInfo embedFontInfo = (EmbedFontInfo)embedFontInfoList.get(i);
- //String metricsFile = configFontInfo.getMetricsFile();
internalName = "F" + num;
num++;
- /*
- reader = new FontReader(metricsFile);
- reader.useKerning(configFontInfo.getKerning());
- reader.setFontEmbedPath(configFontInfo.getEmbedFile());
- fontInfo.addMetrics(internalName, reader.getFont());
- */
LazyFont font = new LazyFont(embedFontInfo, resolver);
fontInfo.addMetrics(internalName, font);
public String toString() {
return getKey();
}
+
+
+ /**
+ * Matcher interface for {@link FontTriplet}.
+ */
+ public interface Matcher {
+
+ /**
+ * Indicates whether the given {@link FontTriplet} matches a particular criterium.
+ * @param triplet the font triplet
+ * @return true if the font triplet is a match
+ */
+ boolean matches(FontTriplet triplet);
+ }
+
}
private String metricsFileName = null;
private String fontEmbedPath = null;
private boolean useKerning = false;
+ private boolean embedded = true;
private String subFontName = null;
private boolean isMetricsLoaded = false;
this.fontEmbedPath = fontInfo.getEmbedFile();
this.useKerning = fontInfo.getKerning();
this.subFontName = fontInfo.getSubFontName();
+ this.embedded = fontInfo.isEmbedded();
this.resolver = resolver;
}
new URL(metricsFileName).openStream()));
}
reader.setKerningEnabled(useKerning);
- reader.setFontEmbedPath(fontEmbedPath);
+ if (this.embedded) {
+ reader.setFontEmbedPath(fontEmbedPath);
+ }
reader.setResolver(resolver);
realFont = reader.getFont();
} else {
if (fontEmbedPath == null) {
throw new RuntimeException("Cannot load font. No font URIs available.");
}
- realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, resolver);
+ realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName,
+ this.embedded, resolver);
}
if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont;
log.debug("Loading " + fontName);
}
try {
- TTFFontLoader ttfLoader = new TTFFontLoader(fontFileURI, fontName, resolver);
+ TTFFontLoader ttfLoader = new TTFFontLoader(
+ fontFileURI, fontName, true, resolver);
customFont = ttfLoader.getFont();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
} else {
// The normal case
try {
- customFont = FontLoader.loadFont(fontUrl, null, resolver);
+ customFont = FontLoader.loadFont(fontUrl, null, true, resolver);
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
import org.apache.commons.io.IOUtils;
+import org.apache.xmlgraphics.fonts.Glyphs;
+
import org.apache.fop.fonts.BFEntry;
import org.apache.fop.fonts.CIDFontType;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
+import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.NamedCharacter;
+import org.apache.fop.fonts.SingleByteFont;
/**
* Loads a TrueType font into memory directly from the original font file.
public class TTFFontLoader extends FontLoader {
private MultiByteFont multiFont;
+ private SingleByteFont singleFont;
private String subFontName;
/**
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, FontResolver resolver) {
- this(fontFileURI, null, resolver);
+ this(fontFileURI, null, true, resolver);
}
/**
* @param fontFileURI the URI representing the font file
* @param subFontName the sub-fontname of a font in a TrueType Collection (or null for normal
* TrueType fonts)
+ * @param embedded indicates whether the font is embedded or referenced
* @param resolver the FontResolver for font URI resolution
*/
- public TTFFontLoader(String fontFileURI, String subFontName, FontResolver resolver) {
- super(fontFileURI, resolver);
+ public TTFFontLoader(String fontFileURI, String subFontName,
+ boolean embedded, FontResolver resolver) {
+ super(fontFileURI, embedded, resolver);
this.subFontName = subFontName;
}
throw new UnsupportedOperationException(
"OpenType fonts with CFF data are not supported, yet");
}
- multiFont = new MultiByteFont();
- multiFont.setResolver(this.resolver);
- returnFont = multiFont;
+
+ boolean isCid = this.embedded;
+
+ if (isCid) {
+ multiFont = new MultiByteFont();
+ returnFont = multiFont;
+ multiFont.setTTCName(ttcFontName);
+ } else {
+ singleFont = new SingleByteFont();
+ returnFont = singleFont;
+ }
+ returnFont.setResolver(resolver);
returnFont.setFontName(ttf.getPostScriptName());
returnFont.setFullName(ttf.getFullName());
returnFont.setFamilyNames(ttf.getFamilyNames());
returnFont.setFontSubFamilyName(ttf.getSubFamilyName());
- multiFont.setTTCName(ttcFontName);
returnFont.setCapHeight(ttf.getCapHeight());
returnFont.setXHeight(ttf.getXHeight());
returnFont.setAscender(ttf.getLowerCaseAscent());
returnFont.setDescender(ttf.getLowerCaseDescent());
returnFont.setFontBBox(ttf.getFontBBox());
- //returnFont.setFirstChar(ttf.getFirstChar();)
returnFont.setFlags(ttf.getFlags());
returnFont.setStemV(Integer.parseInt(ttf.getStemV())); //not used for TTF
returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle()));
returnFont.setMissingWidth(0);
returnFont.setWeight(ttf.getWeightClass());
-
- multiFont.setCIDType(CIDFontType.CIDTYPE2);
+
+ if (isCid) {
+ multiFont.setCIDType(CIDFontType.CIDTYPE2);
+ int[] wx = ttf.getWidths();
+ multiFont.setWidthArray(wx);
+ List entries = ttf.getCMaps();
+ BFEntry[] bfentries = new BFEntry[entries.size()];
+ int pos = 0;
+ Iterator iter = ttf.getCMaps().listIterator();
+ while (iter.hasNext()) {
+ TTFCmapEntry ce = (TTFCmapEntry)iter.next();
+ bfentries[pos] = new BFEntry(ce.getUnicodeStart(), ce.getUnicodeEnd(),
+ ce.getGlyphStartIndex());
+ pos++;
+ }
+ multiFont.setBFEntries(bfentries);
+ } else {
+ singleFont.setFontType(FontType.TRUETYPE);
+ singleFont.setEncoding(ttf.getCharSetName());
+ returnFont.setFirstChar(ttf.getFirstChar());
+ returnFont.setLastChar(ttf.getLastChar());
+ copyWidthsSingleByte(ttf);
+ }
+
+ copyKerning(ttf, isCid);
+ if (this.embedded && ttf.isEmbeddable()) {
+ multiFont.setEmbedFileName(this.fontFileURI);
+ }
+ }
+
+ private void copyWidthsSingleByte(TTFFile ttf) {
int[] wx = ttf.getWidths();
- multiFont.setWidthArray(wx);
- List entries = ttf.getCMaps();
- BFEntry[] bfentries = new BFEntry[entries.size()];
- int pos = 0;
+ for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) {
+ singleFont.setWidth(i, ttf.getCharWidth(i));
+ }
Iterator iter = ttf.getCMaps().listIterator();
while (iter.hasNext()) {
TTFCmapEntry ce = (TTFCmapEntry)iter.next();
- bfentries[pos] = new BFEntry(ce.getUnicodeStart(), ce.getUnicodeEnd(),
- ce.getGlyphStartIndex());
- pos++;
+ if (ce.getUnicodeStart() < 0xFFFE) {
+ for (char u = (char)ce.getUnicodeStart(); u <= ce.getUnicodeEnd(); u++) {
+ int codePoint = singleFont.getEncoding().mapChar(u);
+ if (codePoint <= 0) {
+ String unicode = Character.toString(u);
+ String charName = Glyphs.stringToGlyph(unicode);
+ if (charName.length() > 0) {
+ NamedCharacter nc = new NamedCharacter(charName, unicode);
+ int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart();
+ singleFont.addUnencodedCharacter(nc, wx[glyphIndex]);
+ }
+ }
+ }
+ }
}
- multiFont.setBFEntries(bfentries);
- copyKerning(ttf, true);
- multiFont.setEmbedFileName(this.fontFileURI);
}
/**
/**
* Constructs a new Type 1 font loader.
* @param fontFileURI the URI to the PFB file of a Type 1 font
+ * @param embedded indicates whether the font is embedded or referenced
* @param resolver the font resolver used to resolve URIs
* @throws IOException In case of an I/O error
*/
- public Type1FontLoader(String fontFileURI, FontResolver resolver)
+ public Type1FontLoader(String fontFileURI, boolean embedded, FontResolver resolver)
throws IOException {
- super(fontFileURI, resolver);
+ super(fontFileURI, embedded, resolver);
}
private String getPFMURI(String pfbURI) {
singleFont = new SingleByteFont();
singleFont.setFontType(FontType.TYPE1);
singleFont.setResolver(this.resolver);
- singleFont.setEmbedFileName(this.fontFileURI);
+ if (this.embedded) {
+ singleFont.setEmbedFileName(this.fontFileURI);
+ }
returnFont = singleFont;
handleEncoding(afm, pfm);
FontCache fontCache = fontManager.getFontCache();
List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg,
- userAgent.getFontBaseURL(), fontResolver, strict,
- fontCache);
+ fontResolver, strict, fontManager);
if (fontCache != null && fontCache.hasChanged()) {
fontCache.save();
* Builds a list of EmbedFontInfo objects for use with the setup() method.
*
* @param cfg Configuration object
- * @param fontBaseURL the base URL to resolve relative font URLs with
* @param fontResolver the FontResolver to use
* @param strict true if an Exception should be thrown if an error is found.
- * @param fontCache the font cache (or null if it is disabled)
+ * @param fontManager the font manager
* @return a List of EmbedFontInfo objects.
* @throws FOPException If an error occurs while processing the configuration
*/
public static List/*<EmbedFontInfo>*/ buildFontListFromConfiguration(Configuration cfg,
- String fontBaseURL, FontResolver fontResolver,
- boolean strict, FontCache fontCache) throws FOPException {
+ FontResolver fontResolver,
+ boolean strict, FontManager fontManager) throws FOPException {
+ FontCache fontCache = fontManager.getFontCache();
+ String fontBaseURL = fontManager.getFontBaseURL();
List/*<EmbedFontInfo>*/ fontInfoList
= new java.util.ArrayList/*<EmbedFontInfo>*/();
fontInfoList.add(embedFontInfo);
}
}
-
+
+ // Update referenced fonts (fonts which are not to be embedded)
+ updateReferencedFonts(fontInfoList, fontManager.getReferencedFontsMatcher());
+
if (log.isDebugEnabled()) {
log.debug("Finished font configuration in "
+ (System.currentTimeMillis() - start) + "ms");
return fontInfoList;
}
+ private static void updateReferencedFonts(List fontInfoList, FontTriplet.Matcher matcher) {
+ if (matcher == null) {
+ return; //No referenced fonts
+ }
+ Iterator iter = fontInfoList.iterator();
+ while (iter.hasNext()) {
+ EmbedFontInfo fontInfo = (EmbedFontInfo)iter.next();
+ Iterator triplets = fontInfo.getFontTriplets().iterator();
+ while (triplets.hasNext()) {
+ FontTriplet triplet = (FontTriplet)triplets.next();
+ if (matcher.matches(triplet)) {
+ fontInfo.setEmbedded(false);
+ break;
+ }
+ }
+ }
+ }
+
+
/**
* Iterates over font file list adding font info to list
* @param fontFileList font file list
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.FontCollection;
Source fontSource = resolver.resolve(configFontInfo.getEmbedFile());
font = new CustomFontMetricsMapper(fontMetrics, fontSource);
} else {
- CustomFont fontMetrics = FontLoader.loadFont(fontFile, null, resolver);
+ CustomFont fontMetrics = FontLoader.loadFont(fontFile, null, true, resolver);
font = new CustomFontMetricsMapper(fontMetrics);
}
}
private static boolean isEmbeddable(CustomFont font) {
- return font.isEmbeddable()
- && (font.getEmbedFileName() != null || font.getEmbedResourceName() != null);
+ return font.isEmbeddable();
}
private static InputStream getInputStreamOnFont(PSGenerator gen, CustomFont font)
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
+
import org.apache.fop.apps.FOPException;
-import org.apache.fop.fonts.FontCache;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontResolver;
//Fonts
try {
FontResolver fontResolver = FontManager.createMinimalFontResolver();
- //TODO The following could be optimized by retaining the FontCache somewhere
- FontCache fontCache = FontCache.load();
- if (fontCache == null) {
- fontCache = new FontCache();
- }
- //TODO Provide fontBaseURL to this method call
- final String fontBaseURL = null;
+ //TODO The following could be optimized by retaining the FontManager somewhere
+ FontManager fontManager = new FontManager();
+
+ //TODO Make use of fontBaseURL, font substitution and referencing configuration
+ //Requires a change to the expected configuration layout
+
List/*<EmbedFontInfo>*/ embedFontInfoList
= PrintRendererConfigurator.buildFontListFromConfiguration(
- cfg, fontBaseURL, fontResolver, false, fontCache);
- fontCache.save();
+ cfg, fontResolver, false, fontManager);
+ if (fontManager.useCache()) {
+ fontManager.getFontCache().save();
+ }
FontInfo fontInfo = new FontInfo();
FontSetup.setup(fontInfo, embedFontInfoList, fontResolver);
graphics.setFontInfo(fontInfo);
<action context="Renderers" dev="AC" importance="high" type="add">
Added SVG support for AFP (GOCA).
</action -->
+ <action context="Fonts" dev="JM" type="add">
+ For auto-detected fonts it is now possible to specify that a font needs to be referenced
+ rather than embedded (for the output formats that support this distinction).
+ </action>
<action context="Layout" dev="AD" type="fix" fixes-bug="42423">
Added support for the "id" attribute on fo:wrappers when used
as a child of the fo:flow.