diff options
Diffstat (limited to 'src')
17 files changed, 361 insertions, 119 deletions
diff --git a/src/documentation/content/xdocs/trunk/fonts.xml b/src/documentation/content/xdocs/trunk/fonts.xml index eb466ec73..30b72ffac 100644 --- a/src/documentation/content/xdocs/trunk/fonts.xml +++ b/src/documentation/content/xdocs/trunk/fonts.xml @@ -177,10 +177,8 @@ 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: @@ -375,20 +373,56 @@ </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> diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index bd54ffb2f..c196e1204 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -692,12 +692,19 @@ public class FopFactory implements ImageContext { } /** - * 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; } diff --git a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java index 89388ae77..cc3ce2d0b 100644 --- a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java +++ b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java @@ -23,15 +23,17 @@ import java.io.File; 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 @@ -174,7 +176,7 @@ public class FopFactoryConfigurator { // configure font manager FontManager fontManager = factory.getFontManager(); FontManagerConfigurator fontManagerConfigurator = new FontManagerConfigurator(cfg); - fontManagerConfigurator.configure(fontManager); + fontManagerConfigurator.configure(fontManager, strict); } /** diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java index dc40da780..0d0bcafdb 100644 --- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java +++ b/src/java/org/apache/fop/fonts/EmbedFontInfo.java @@ -19,6 +19,7 @@ package org.apache.fop.fonts; +import java.io.IOException; import java.io.Serializable; import java.util.List; @@ -45,6 +46,8 @@ public class EmbedFontInfo implements Serializable { /** 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 @@ -120,11 +123,37 @@ public class EmbedFontInfo implements Serializable { } /** - * {@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"); } + } diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java index 69c55ceae..2699ca6d5 100644 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ b/src/java/org/apache/fop/fonts/FontLoader.java @@ -39,9 +39,7 @@ import org.apache.fop.fonts.type1.Type1FontLoader; */ public abstract class FontLoader { - /** - * logging instance - */ + /** logging instance */ protected static Log log = LogFactory.getLog(FontLoader.class); /** URI representing the font file */ @@ -53,14 +51,18 @@ public abstract class FontLoader { /** 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; } @@ -72,46 +74,48 @@ public abstract class FontLoader { * 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(); } diff --git a/src/java/org/apache/fop/fonts/FontManager.java b/src/java/org/apache/fop/fonts/FontManager.java index 8ff85afb4..d25d2d390 100644 --- a/src/java/org/apache/fop/fonts/FontManager.java +++ b/src/java/org/apache/fop/fonts/FontManager.java @@ -25,7 +25,7 @@ import java.net.MalformedURLException; 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; @@ -34,7 +34,8 @@ 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) */ @@ -49,42 +50,31 @@ public class FontManager { /** 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; @@ -218,4 +208,22 @@ public class FontManager { } }; } + + /** + * 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; + } } diff --git a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java index edee46a0f..d44470e6b 100644 --- a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java +++ b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java @@ -20,11 +20,14 @@ 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; @@ -51,9 +54,11 @@ public class FontManagerConfigurator { /** * 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 { @@ -84,6 +89,68 @@ public class FontManagerConfigurator { 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(); + } + + } + } diff --git a/src/java/org/apache/fop/fonts/FontSetup.java b/src/java/org/apache/fop/fonts/FontSetup.java index ab893d385..9aa8440db 100644 --- a/src/java/org/apache/fop/fonts/FontSetup.java +++ b/src/java/org/apache/fop/fonts/FontSetup.java @@ -27,6 +27,7 @@ import javax.xml.transform.stream.StreamSource; 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; @@ -205,20 +206,12 @@ public class FontSetup { } 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); diff --git a/src/java/org/apache/fop/fonts/FontTriplet.java b/src/java/org/apache/fop/fonts/FontTriplet.java index 9091219f5..a989cf0f7 100644 --- a/src/java/org/apache/fop/fonts/FontTriplet.java +++ b/src/java/org/apache/fop/fonts/FontTriplet.java @@ -128,5 +128,20 @@ public class FontTriplet implements Comparable, Serializable { 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); + } + } diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index 5490e13f1..b4f7773a3 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -44,6 +44,7 @@ public class LazyFont extends Typeface implements FontDescriptor { private String metricsFileName = null; private String fontEmbedPath = null; private boolean useKerning = false; + private boolean embedded = true; private String subFontName = null; private boolean isMetricsLoaded = false; @@ -63,6 +64,7 @@ public class LazyFont extends Typeface implements FontDescriptor { this.fontEmbedPath = fontInfo.getEmbedFile(); this.useKerning = fontInfo.getKerning(); this.subFontName = fontInfo.getSubFontName(); + this.embedded = fontInfo.isEmbedded(); this.resolver = resolver; } @@ -118,14 +120,17 @@ public class LazyFont extends Typeface implements FontDescriptor { 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; diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java index b2ee4a274..987b7e918 100644 --- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java +++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java @@ -223,7 +223,8 @@ public class FontInfoFinder { 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); @@ -247,7 +248,7 @@ public class FontInfoFinder { } 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); } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 9cd59b5b3..325c46971 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -27,11 +27,16 @@ import java.util.Map; 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. @@ -39,6 +44,7 @@ import org.apache.fop.fonts.MultiByteFont; public class TTFFontLoader extends FontLoader { private MultiByteFont multiFont; + private SingleByteFont singleFont; private String subFontName; /** @@ -47,7 +53,7 @@ public class TTFFontLoader extends FontLoader { * @param resolver the FontResolver for font URI resolution */ public TTFFontLoader(String fontFileURI, FontResolver resolver) { - this(fontFileURI, null, resolver); + this(fontFileURI, null, true, resolver); } /** @@ -55,10 +61,12 @@ public class TTFFontLoader extends FontLoader { * @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; } @@ -95,43 +103,86 @@ public class TTFFontLoader extends FontLoader { 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); } /** diff --git a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java index 3187379d5..ffb572109 100644 --- a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java +++ b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java @@ -44,12 +44,13 @@ public class Type1FontLoader extends FontLoader { /** * 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) { @@ -119,7 +120,9 @@ public class Type1FontLoader extends FontLoader { 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); diff --git a/src/java/org/apache/fop/render/PrintRendererConfigurator.java b/src/java/org/apache/fop/render/PrintRendererConfigurator.java index 6273b7050..50d06932d 100644 --- a/src/java/org/apache/fop/render/PrintRendererConfigurator.java +++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java @@ -95,8 +95,7 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator FontCache fontCache = fontManager.getFontCache(); List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg, - userAgent.getFontBaseURL(), fontResolver, strict, - fontCache); + fontResolver, strict, fontManager); if (fontCache != null && fontCache.hasChanged()) { fontCache.save(); @@ -108,16 +107,17 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator * 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>*/(); @@ -213,7 +213,10 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator 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"); @@ -222,6 +225,25 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator 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 diff --git a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java index 771d3f2d7..4981905fa 100644 --- a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java +++ b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java @@ -25,6 +25,7 @@ import javax.xml.transform.Source; 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; @@ -87,7 +88,7 @@ public class ConfiguredFontCollection implements 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); } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 1566ef799..63b12c5c8 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -191,8 +191,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } 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) diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java index 02e9d6da4..789a7c247 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java @@ -23,8 +23,8 @@ import java.util.List; 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; @@ -55,17 +55,18 @@ public class PDFDocumentGraphics2DConfigurator { //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); |