]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Added support for font referencing for auto-detected fonts.
authorJeremias Maerki <jeremias@apache.org>
Thu, 8 May 2008 09:55:55 +0000 (09:55 +0000)
committerJeremias Maerki <jeremias@apache.org>
Thu, 8 May 2008 09:55:55 +0000 (09:55 +0000)
Referenced TrueType fonts can now use glyphs outside the WinAnsi charset (Same approach as for extended glyph support with Type 1 fonts).

Removed FopFactory reference from FontManager to make the class more useful outside this context (ex. transcoders).
Updated fonts documentation with information that TTCs are now supported through auto-detection.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@654461 13f79535-47bb-0310-9956-ffa450edef68

18 files changed:
src/documentation/content/xdocs/trunk/fonts.xml
src/java/org/apache/fop/apps/FopFactory.java
src/java/org/apache/fop/apps/FopFactoryConfigurator.java
src/java/org/apache/fop/fonts/EmbedFontInfo.java
src/java/org/apache/fop/fonts/FontLoader.java
src/java/org/apache/fop/fonts/FontManager.java
src/java/org/apache/fop/fonts/FontManagerConfigurator.java
src/java/org/apache/fop/fonts/FontSetup.java
src/java/org/apache/fop/fonts/FontTriplet.java
src/java/org/apache/fop/fonts/LazyFont.java
src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
src/java/org/apache/fop/fonts/type1/Type1FontLoader.java
src/java/org/apache/fop/render/PrintRendererConfigurator.java
src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
src/java/org/apache/fop/render/ps/PSFontUtils.java
src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java
status.xml

index eb466ec73be8e43256da9905a7aa99049906c318..30b72ffac82ae2e280899141ef46f9b878f965b7 100644 (file)
         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>
index bd54ffb2f9e39379d204707bdb7d50b6d3a666dd..c196e120488f1c3b970cbed4ded060e16a7e2ea0 100644 (file)
@@ -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;
     }
index 89388ae77bb85f9137279451e5354807f9cc39a0..cc3ce2d0b9cb52e2562988937207d5e8a2bed1a0 100644 (file)
@@ -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);
     }
     
     /**
index dc40da78089159b23aa7b7da96251676251dabf1..0d0bcafdb2315e9510933522a9e3ccd493f2aac7 100644 (file)
@@ -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"); 
     }
+
 }
index 69c55ceaefd28b413ccc137917b20489c3a9a577..2699ca6d5abd76d70813c90d12d301b3c8745c04 100644 (file)
@@ -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();
     }
index 8ff85afb4118680c1dfd54ba7a83d520c3fa6e40..d25d2d39099587a6ec5ca4e89afdd17862fa8ccd 100644 (file)
@@ -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;
+    }
 }
index edee46a0f9e0870cc1f6f90e2b6d8a1044897837..d44470e6be3b37f278258d2fc077a4813b8d1344 100644 (file)
 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();
+        }
+        
+    }
+    
 }
index ab893d3850815d3d23ca7f0703f244f5d68ffef1..9aa8440db7f11f011cba3c6a40412949aaade8e7 100644 (file)
@@ -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);
index 9091219f569a6bd198fc63ad56562cfe5c1bf3f4..a989cf0f7a2b3614120b4a8337a43a730eb6e771 100644 (file)
@@ -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);
+    }
+    
 }
 
index 5490e13f1487afe31ac9fbdef8fdbff56d084eef..b4f7773a3269e46db388da8d7c2c5fd43a7da187 100644 (file)
@@ -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;
index b2ee4a274a94a378c26b2a5d55691e4d53482bd6..987b7e918bebe00b8f579094fb8355ca68402c24 100644 (file)
@@ -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);
                 }
index 9cd59b5b36fa927661198f612fc2d67b2f217c4f..325c46971ef3e1f8372feba2ceb93bf5606abc55 100644 (file)
@@ -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);
     }
     
     /**
index 3187379d5c2f22652f1e459fa7afa65b0ac82caf..ffb5721094ffe60f53696b99041ef29e7776baf2 100644 (file)
@@ -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);
index 6273b7050e19dfe6e6676bd806998afc9a76156d..50d06932d6d1032425d6eabd6388e484236cb19f 100644 (file)
@@ -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
index 771d3f2d73ca230ee4690bace1297d2d791aacdf..4981905fa041ec7409b5791bdd5f23c68a043d7f 100644 (file)
@@ -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);
                 }
 
index 1566ef7995a97a869663ccc840dd515cb7d4521a..63b12c5c87b6e2f7038cf595242c8da5df21087c 100644 (file)
@@ -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) 
index 02e9d6da430d300f0931e56bd1c5e90de05dc823..789a7c2475c407fd18c9007f17eb8bb1f2680eb1 100644 (file)
@@ -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);
index c25e0b93a34aaeba6cb9c0255e90276fdfad2d39..e1432b85649270965223001084a8619c347d6bc7 100644 (file)
       <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.