git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_URI_Unification@1344594 13f79535-47bb-0310-9956-ffa450edef68pull/26/head
@@ -556,6 +556,7 @@ list of possible build targets. | |||
<include name="org/apache/fop/accessibility/StructureTreeElement.class"/> | |||
<include name="org/apache/fop/apps/Fop.class"/> | |||
<include name="org/apache/fop/apps/FOPException.class"/> | |||
<include name="org/apache/fop/apps/io/**"/> | |||
<include name="org/apache/fop/complexscripts/fonts/*.class"/> | |||
<include name="org/apache/fop/fo/Constants.class"/> | |||
<include name="org/apache/fop/fo/FOTreeBuilder.class"/> | |||
@@ -578,7 +579,7 @@ list of possible build targets. | |||
<exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/> | |||
<exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/> | |||
<include name="org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.class"/> | |||
<include name="org/apache/fop/render/**Configurator**"/> | |||
<include name="org/apache/fop/render/**Config**"/> | |||
<include name="org/apache/fop/util/AbstractPaintingState**"/> | |||
<include name="org/apache/fop/pdf/**"/> | |||
</patternset> |
@@ -23,19 +23,16 @@ package embedding; | |||
import java.io.File; | |||
import java.io.IOException; | |||
//JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.stream.StreamSource; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
//Avalon | |||
import org.apache.avalon.framework.ExceptionUtil; | |||
//FOP | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopFactory; | |||
@@ -47,7 +44,7 @@ import org.apache.fop.apps.MimeConstants; | |||
public class ExampleAWTViewer { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Display an FO file in the AWT Preview. |
@@ -22,25 +22,22 @@ package embedding; | |||
// Java | |||
import java.io.File; | |||
import java.io.OutputStream; | |||
import javax.xml.parsers.DocumentBuilderFactory; | |||
import javax.xml.parsers.DocumentBuilder; | |||
import javax.xml.parsers.DocumentBuilderFactory; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
//JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.dom.DOMSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
// DOM | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import org.w3c.dom.Node; | |||
import org.w3c.dom.Text; | |||
// FOP | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopFactory; | |||
@@ -54,7 +51,7 @@ import org.apache.fop.apps.MimeConstants; | |||
public class ExampleDOM2PDF { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** xsl-fo namespace URI */ | |||
protected static String foNS = "http://www.w3.org/1999/XSL/Format"; |
@@ -53,7 +53,7 @@ import org.apache.fop.render.print.PageableRenderer; | |||
public class ExampleFO2JPSPrint { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
private DocPrintJob createDocPrintJob() { | |||
PrintService[] services = PrintServiceLookup.lookupPrintServices( |
@@ -43,7 +43,7 @@ import org.apache.fop.apps.MimeConstants; | |||
public class ExampleFO2OldStylePrint { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Prints an FO file using an old-style PrinterJob. |
@@ -26,19 +26,16 @@ import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
//JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.stream.StreamSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
// FOP | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.FormattingResults; | |||
import org.apache.fop.apps.MimeConstants; | |||
@@ -50,7 +47,7 @@ import org.apache.fop.apps.PageSequenceResults; | |||
public class ExampleFO2PDF { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Converts an FO file to a PDF file using FOP |
@@ -26,17 +26,14 @@ import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
//JAXP | |||
import javax.xml.parsers.SAXParserFactory; | |||
import javax.xml.parsers.FactoryConfigurationError; | |||
import javax.xml.parsers.SAXParser; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import javax.xml.parsers.SAXParser; | |||
import javax.xml.parsers.SAXParserFactory; | |||
//SAX | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
// FOP | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopFactory; | |||
@@ -49,7 +46,7 @@ import org.apache.fop.apps.MimeConstants; | |||
public class ExampleFO2PDFUsingSAXParser { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Converts an FO file to a PDF file using FOP |
@@ -26,18 +26,16 @@ import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
//JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.stream.StreamSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
// FOP | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.MimeConstants; | |||
@@ -50,7 +48,7 @@ import org.apache.fop.apps.MimeConstants; | |||
public class ExampleFO2RTF { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Converts an FO file to a RTF file using FOP |
@@ -21,22 +21,20 @@ package embedding; | |||
// Java | |||
import java.io.File; | |||
import java.io.OutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
// JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.stream.StreamSource; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
// FOP | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.MimeConstants; | |||
@@ -49,7 +47,7 @@ import embedding.model.ProjectTeam; | |||
public class ExampleObj2PDF { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Converts a ProjectTeam object to a PDF file. |
@@ -23,15 +23,13 @@ package embedding; | |||
import java.io.File; | |||
import java.io.OutputStream; | |||
//JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.stream.StreamSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
//FOP | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopFactory; | |||
@@ -69,7 +67,7 @@ public class ExampleXML2PDF { | |||
System.out.println("Transforming..."); | |||
// configure fopFactory as desired | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); | |||
// configure foUserAgent as desired |
@@ -27,20 +27,19 @@ import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
//JAXP | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.stream.StreamSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
// FOP | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.FormattingResults; | |||
import org.apache.fop.apps.MimeConstants; | |||
@@ -55,8 +54,6 @@ import org.apache.fop.apps.PageSequenceResults; | |||
public class MultipleFO2PDF { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
// JAXP TransformerFactory can be reused, too | |||
private TransformerFactory factory = TransformerFactory.newInstance(); | |||
@@ -71,6 +68,7 @@ public class MultipleFO2PDF { | |||
*/ | |||
public FormattingResults convertFO2PDF(File fo, File pdf) | |||
throws TransformerException, IOException, FOPException { | |||
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
OutputStream out = null; | |||
Fop fop; |
@@ -57,7 +57,7 @@ import embedding.model.ProjectTeam; | |||
public class ExampleConcat { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Creates a sample ProjectTeam instance for this demo. |
@@ -50,7 +50,7 @@ import embedding.model.ProjectTeam; | |||
public class ExampleStamp { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Stamps an area tree XML file and renders it to a PDF file. |
@@ -56,7 +56,7 @@ import org.apache.fop.events.model.EventSeverity; | |||
public class ExampleEvents { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Converts an FO file to a PDF file using FOP |
@@ -58,7 +58,7 @@ import embedding.model.ProjectTeam; | |||
public class ExampleConcat { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Creates a sample ProjectTeam instance for this demo. | |||
@@ -95,8 +95,7 @@ public class ExampleConcat { | |||
userAgent, MimeConstants.MIME_PDF); | |||
//Create the IFSerializer to write the intermediate format | |||
IFSerializer ifSerializer = new IFSerializer(); | |||
ifSerializer.setContext(new IFContext(userAgent)); | |||
IFSerializer ifSerializer = new IFSerializer(new IFContext(userAgent)); | |||
//Tell the IFSerializer to mimic the target format | |||
ifSerializer.mimicDocumentHandler(targetHandler); |
@@ -51,7 +51,7 @@ import embedding.model.ProjectTeam; | |||
public class ExampleStamp { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); | |||
/** | |||
* Stamps an intermediate file and renders it to a PDF file. |
@@ -57,6 +57,8 @@ public class AFPDataObjectInfo { | |||
/** controls the mapping of the image data into the image area */ | |||
private byte mappingOption = MappingOptionTriplet.SCALE_TO_FILL; | |||
public static final byte DEFAULT_MAPPING_OPTION = 0x00; | |||
/** | |||
* Default constructor | |||
*/ |
@@ -165,9 +165,8 @@ public class AFPBase12FontCollection implements FontCollection { | |||
} | |||
private RasterFont createReferencedRasterFont(String fontFamily) { | |||
RasterFont font = new RasterFont(fontFamily); | |||
font.setEmbeddable(false); //Font is assumed to be available on the target platform | |||
return font; | |||
boolean embeddable = false; //Font is assumed to be available on the target platform | |||
return new RasterFont(fontFamily, embeddable); | |||
} | |||
} |
@@ -35,16 +35,18 @@ import org.apache.fop.fonts.Typeface; | |||
public abstract class AFPFont extends Typeface { | |||
/** The font name */ | |||
protected String name; | |||
protected final String name; | |||
private boolean embeddable = true; | |||
private final boolean embeddable; | |||
/** | |||
* Constructor for the base font requires the name. | |||
* @param name the name of the font | |||
* @param embeddable whether this font is to be embedded | |||
*/ | |||
public AFPFont(String name) { | |||
public AFPFont(String name, boolean embeddable) { | |||
this.name = name; | |||
this.embeddable = embeddable; | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -89,7 +91,7 @@ public abstract class AFPFont extends Typeface { | |||
* Returns the kerning map for the font. | |||
* @return the kerning map | |||
*/ | |||
public Map getKerningInfo() { | |||
public Map<Integer, Map<Integer, Integer>> getKerningInfo() { | |||
return null; | |||
} | |||
@@ -100,14 +102,6 @@ public abstract class AFPFont extends Typeface { | |||
*/ | |||
public abstract CharacterSet getCharacterSet(int size); | |||
/** | |||
* Controls whether this font is embeddable or not. | |||
* @param value true to enable embedding, false otherwise. | |||
*/ | |||
public void setEmbeddable(boolean value) { | |||
this.embeddable = value; | |||
} | |||
/** | |||
* Indicates if this font may be embedded. | |||
* @return True, if embedding is possible/permitted |
@@ -32,13 +32,12 @@ public abstract class AbstractOutlineFont extends AFPFont { | |||
/** | |||
* Constructor for an outline font. | |||
* | |||
* @param name | |||
* the name of the font | |||
* @param charSet | |||
* the chracter set | |||
* @param name the name of the font | |||
* @param embeddable sets whether or not this font is to be embedded | |||
* @param charSet the chracter set | |||
*/ | |||
public AbstractOutlineFont(String name, CharacterSet charSet) { | |||
super(name); | |||
public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet) { | |||
super(name, embeddable); | |||
this.charSet = charSet; | |||
} | |||
@@ -464,7 +464,6 @@ public abstract class CharacterSetBuilder { | |||
} | |||
} | |||
return orientations.toArray(EMPTY_CSO_ARRAY); | |||
} | |||
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.afp.fonts; | |||
import java.lang.Character.UnicodeBlock; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
/** | |||
@@ -33,7 +35,7 @@ public class DoubleByteFont extends AbstractOutlineFont { | |||
//See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet | |||
//TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.) | |||
private static final Set IDEOGRAPHIC = new java.util.HashSet(); | |||
private static final Set<UnicodeBlock> IDEOGRAPHIC = new HashSet<UnicodeBlock>(); | |||
static { | |||
IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS); | |||
//IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT);//Java 1.5 | |||
@@ -45,10 +47,11 @@ public class DoubleByteFont extends AbstractOutlineFont { | |||
/** | |||
* Constructor for an double-byte outline font. | |||
* @param name the name of the font | |||
* @param embeddable whether or not this font is embeddable | |||
* @param charSet the character set | |||
*/ | |||
public DoubleByteFont(String name, CharacterSet charSet) { | |||
super(name, charSet); | |||
public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet) { | |||
super(name, embeddable, charSet); | |||
} | |||
/** {@inheritDoc} */ |
@@ -27,10 +27,11 @@ public class OutlineFont extends AbstractOutlineFont { | |||
/** | |||
* Construct outline font with specified name and character set. | |||
* @param name font's name | |||
* @param embeddable whether or not this font is embeddable | |||
* @param charSet font's character set | |||
*/ | |||
public OutlineFont(String name, CharacterSet charSet) { | |||
super(name, charSet); | |||
public OutlineFont(String name, boolean embeddable, CharacterSet charSet) { | |||
super(name, embeddable, charSet); | |||
} | |||
} |
@@ -52,8 +52,8 @@ public class RasterFont extends AFPFont { | |||
* @param name | |||
* the name of the font | |||
*/ | |||
public RasterFont(String name) { | |||
super(name); | |||
public RasterFont(String name, boolean embeddable) { | |||
super(name, embeddable); | |||
} | |||
/** | |||
@@ -76,7 +76,7 @@ public class RasterFont extends AFPFont { | |||
public CharacterSet getCharacterSet(int sizeInMpt) { | |||
Integer requestedSize = Integer.valueOf(sizeInMpt); | |||
CharacterSet csm = (CharacterSet) charSets.get(requestedSize); | |||
CharacterSet csm = charSets.get(requestedSize); | |||
double sizeInPt = sizeInMpt / 1000.0; | |||
if (csm != null) { | |||
@@ -85,7 +85,7 @@ public class RasterFont extends AFPFont { | |||
if (substitutionCharSets != null) { | |||
//Check first if a substitution has already been added | |||
csm = (CharacterSet) substitutionCharSets.get(requestedSize); | |||
csm = substitutionCharSets.get(requestedSize); | |||
} | |||
if (csm == null && !charSets.isEmpty()) { | |||
@@ -95,9 +95,9 @@ public class RasterFont extends AFPFont { | |||
SortedMap<Integer, CharacterSet> smallerSizes = charSets.headMap(requestedSize); | |||
SortedMap<Integer, CharacterSet> largerSizes = charSets.tailMap(requestedSize); | |||
int smallerSize = smallerSizes.isEmpty() ? 0 | |||
: ((Integer)smallerSizes.lastKey()).intValue(); | |||
: smallerSizes.lastKey().intValue(); | |||
int largerSize = largerSizes.isEmpty() ? Integer.MAX_VALUE | |||
: ((Integer)largerSizes.firstKey()).intValue(); | |||
: largerSizes.firstKey().intValue(); | |||
Integer fontSize; | |||
if (!smallerSizes.isEmpty() | |||
@@ -106,7 +106,7 @@ public class RasterFont extends AFPFont { | |||
} else { | |||
fontSize = Integer.valueOf(largerSize); | |||
} | |||
csm = (CharacterSet) charSets.get(fontSize); | |||
csm = charSets.get(fontSize); | |||
if (csm != null) { | |||
// Add the substitute mapping, so subsequent calls will |
@@ -19,26 +19,22 @@ | |||
package org.apache.fop.afp.util; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URL; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.commons.io.IOUtils; | |||
import java.net.URISyntaxException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
/** | |||
* Default implementation of the {@link ResourceAccessor} interface for use inside FOP. | |||
*/ | |||
public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { | |||
private FOUserAgent userAgent; | |||
private String categoryBaseURI; | |||
private final URIResolverWrapper resolver; | |||
private final String baseURI; | |||
/** | |||
* Constructor for resource to be accessed via the {@link FOUserAgent}. This contructor | |||
@@ -49,38 +45,32 @@ public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { | |||
* @param categoryBaseURI the category base URI (may be null) | |||
* @param baseURI the custom base URI to resolve relative URIs against (may be null) | |||
*/ | |||
public DefaultFOPResourceAccessor(FOUserAgent userAgent, String categoryBaseURI, URI baseURI) { | |||
super(baseURI); | |||
this.userAgent = userAgent; | |||
this.categoryBaseURI = categoryBaseURI; | |||
public DefaultFOPResourceAccessor(URIResolverWrapper resolver, String baseURI) { | |||
super(resolver.getBaseURI()); | |||
this.resolver = resolver; | |||
this.baseURI = baseURI; | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
//Step 1: resolve against local base URI --> URI | |||
URI resolved = resolveAgainstBase(uri); | |||
//Step 2: resolve against the user agent --> stream | |||
String base = (this.categoryBaseURI != null | |||
? this.categoryBaseURI | |||
: this.userAgent.getBaseURL()); | |||
Source src = userAgent.resolveURI(resolved.toASCIIString(), base); | |||
public DefaultFOPResourceAccessor(URIResolverWrapper resolver) { | |||
super(resolver.getBaseURI()); | |||
this.resolver = resolver; | |||
this.baseURI = null; | |||
} | |||
if (src == null) { | |||
throw new FileNotFoundException("Resource not found: " + uri.toASCIIString()); | |||
} else if (src instanceof StreamSource) { | |||
StreamSource ss = (StreamSource)src; | |||
InputStream in = ss.getInputStream(); | |||
if (in != null) { | |||
return in; | |||
} | |||
if (ss.getReader() != null) { | |||
//Don't support reader, retry using system ID below | |||
IOUtils.closeQuietly(ss.getReader()); | |||
} | |||
private URI getResourceURI(URI uri) { | |||
if (baseURI == null) { | |||
return uri; | |||
} | |||
try { | |||
URI baseURI = URIResolverWrapper.getBaseURI(this.baseURI); | |||
return baseURI.resolve(uri); | |||
} catch (URISyntaxException use) { | |||
return uri; | |||
} | |||
URL url = new URL(src.getSystemId()); | |||
return url.openStream(); | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
return resolver.resolveIn(getResourceURI(uri)); | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
import java.net.URI; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.fonts.FontManager; | |||
/** | |||
* The environment profile represents the restrictions and allowances that FOP is | |||
*/ | |||
public interface EnvironmentProfile { | |||
/** | |||
* Returns resource resolver for this environment. | |||
* | |||
* @return the resource resolver | |||
*/ | |||
ResourceResolver getResourceResolver(); | |||
/** | |||
* Returns the font manager with restrictions/allowances set for this environment. | |||
* | |||
* @return the font manager | |||
*/ | |||
FontManager getFontManager(); | |||
/** | |||
* The default base URI used for resolving URIs. | |||
* | |||
* @return the default base URI | |||
*/ | |||
URI getDefaultBaseURI(); | |||
} |
@@ -0,0 +1,111 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
import java.net.URI; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.FontCacheManager; | |||
import org.apache.fop.fonts.FontCacheManagerFactory; | |||
import org.apache.fop.fonts.FontDetector; | |||
import org.apache.fop.fonts.FontDetectorFactory; | |||
import org.apache.fop.fonts.FontManager; | |||
/** | |||
* Creates an {@link EnvironmentProfile} that sets the environment in which a FOP instance is run. | |||
*/ | |||
public final class EnvironmentalProfileFactory { | |||
private EnvironmentalProfileFactory() { | |||
}; | |||
/** | |||
* Creates the default environment that FOP is invoked in. This default profile has no | |||
* operational restrictions for FOP. | |||
* | |||
* @param defaultBaseUri the default base URI for resolving resource URIs | |||
* @param resourceResolver the resource resolver | |||
* @return the environment profile | |||
*/ | |||
public static EnvironmentProfile createDefault(URI defaultBaseUri, | |||
ResourceResolver resourceResolver) { | |||
return new Profile(defaultBaseUri, resourceResolver, | |||
createFontManager(defaultBaseUri, resourceResolver, | |||
FontDetectorFactory.createDefault(), | |||
FontCacheManagerFactory.createDefault())); | |||
} | |||
/** | |||
* Creates an IO-restricted environment for FOP by disabling some of the environment-specific | |||
* functionality within FOP. | |||
* | |||
* @param defaultBaseUri the default base URI for resolving resource URIs | |||
* @param resourceResolver the resource resolver | |||
* @return the environment profile | |||
*/ | |||
public static EnvironmentProfile createRestrictedIO(URI defaultBaseUri, | |||
ResourceResolver resourceResolver) { | |||
return new Profile(defaultBaseUri, resourceResolver, | |||
createFontManager(defaultBaseUri, resourceResolver, | |||
FontDetectorFactory.createDisabled(), | |||
FontCacheManagerFactory.createDisabled())); | |||
} | |||
private static final class Profile implements EnvironmentProfile { | |||
private final ResourceResolver resourceResolver; | |||
private final FontManager fontManager; | |||
private final URI defaultBaseURI; | |||
private Profile(URI defaultBaseURI, ResourceResolver resourceResolver, | |||
FontManager fontManager) { | |||
if (defaultBaseURI == null) { | |||
throw new IllegalArgumentException("Default base URI must not be null"); | |||
} | |||
if (resourceResolver == null) { | |||
throw new IllegalArgumentException("URI Resolver must not be null"); | |||
} | |||
this.defaultBaseURI = defaultBaseURI; | |||
this.resourceResolver = resourceResolver; | |||
this.fontManager = fontManager; | |||
} | |||
public ResourceResolver getResourceResolver() { | |||
return resourceResolver; | |||
} | |||
public FontManager getFontManager() { | |||
return fontManager; | |||
} | |||
public URI getDefaultBaseURI() { | |||
return defaultBaseURI; | |||
} | |||
} | |||
private static FontManager createFontManager(URI defaultBaseUri, ResourceResolver resourceResolver, | |||
FontDetector fontDetector, FontCacheManager fontCacheManager) { | |||
return new FontManager(new URIResolverWrapper(defaultBaseUri, resourceResolver), fontDetector, | |||
fontCacheManager); | |||
} | |||
} |
@@ -21,37 +21,54 @@ package org.apache.fop.apps; | |||
// Java | |||
import java.io.File; | |||
import java.net.MalformedURLException; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.Date; | |||
import java.util.Map; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.URIResolver; | |||
import javax.xml.transform.stream.StreamSource; | |||
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.xmlgraphics.image.loader.ImageContext; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.ImageSessionContext; | |||
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; | |||
import org.apache.xmlgraphics.util.UnitConv; | |||
import org.apache.xmlgraphics.util.uri.CommonURIResolver; | |||
import org.apache.fop.Version; | |||
import org.apache.fop.accessibility.Accessibility; | |||
import org.apache.fop.accessibility.DummyStructureTreeEventHandler; | |||
import org.apache.fop.accessibility.StructureTreeEventHandler; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.events.DefaultEventBroadcaster; | |||
import org.apache.fop.events.Event; | |||
import org.apache.fop.events.EventBroadcaster; | |||
import org.apache.fop.events.EventListener; | |||
import org.apache.fop.events.FOPEventListenerProxy; | |||
import org.apache.fop.events.LoggingEventListener; | |||
import org.apache.fop.fo.ElementMappingRegistry; | |||
import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.hyphenation.HyphenationTreeResolver; | |||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | |||
import org.apache.fop.render.ImageHandlerRegistry; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.RendererConfig; | |||
import org.apache.fop.render.RendererConfig.RendererConfigParser; | |||
import org.apache.fop.render.RendererConfigOptions; | |||
import org.apache.fop.render.RendererFactory; | |||
import org.apache.fop.render.XMLHandlerRegistry; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.util.ColorSpaceCache; | |||
import org.apache.fop.util.ContentHandlerFactoryRegistry; | |||
/** | |||
* This is the user agent for FOP. | |||
@@ -75,24 +92,13 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
*/ | |||
public class FOUserAgent { | |||
/** Defines the default target resolution (72dpi) for FOP */ | |||
public static final float DEFAULT_TARGET_RESOLUTION | |||
= FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; | |||
private static Log log = LogFactory.getLog("FOP"); | |||
private FopFactory factory; | |||
/** | |||
* The base URL for all URL resolutions, especially for | |||
* external-graphics. | |||
*/ | |||
private String base = null; | |||
private final FopFactory factory; | |||
/** A user settable URI Resolver */ | |||
private URIResolver uriResolver = null; | |||
private final URIResolverWrapper newUriResolver; | |||
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; | |||
private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; | |||
private Map rendererOptions = new java.util.HashMap(); | |||
private File outputFile = null; | |||
private IFDocumentHandler documentHandlerOverride = null; | |||
@@ -131,7 +137,7 @@ public class FOUserAgent { | |||
private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { | |||
public ImageContext getParentContext() { | |||
return getFactory(); | |||
return factory; | |||
} | |||
public float getTargetResolution() { | |||
@@ -150,19 +156,56 @@ public class FOUserAgent { | |||
* @param factory the factory that provides environment-level information | |||
* @see org.apache.fop.apps.FopFactory | |||
*/ | |||
public FOUserAgent(FopFactory factory) { | |||
if (factory == null) { | |||
throw new NullPointerException("The factory parameter must not be null"); | |||
} | |||
FOUserAgent(FopFactory factory, URIResolverWrapper uriResolver) { | |||
this.factory = factory; | |||
setBaseURL(factory.getBaseURL()); | |||
this.newUriResolver = uriResolver; | |||
setTargetResolution(factory.getTargetResolution()); | |||
setAccessibility(factory.isAccessibilityEnabled()); | |||
} | |||
/** @return the associated FopFactory instance */ | |||
public FopFactory getFactory() { | |||
return this.factory; | |||
/** | |||
* Returns a new {@link Fop} instance. Use this factory method if your output type | |||
* requires an output stream and you want to configure this very rendering run, | |||
* i.e. if you want to set some metadata like the title and author of the document | |||
* you want to render. In that case, create a new {@link FOUserAgent} instance | |||
* using {@link #newFOUserAgent()}. | |||
* <p> | |||
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can | |||
* use the constants defined in {@link MimeConstants}. | |||
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). | |||
* @param stream the output stream | |||
* @return the new Fop instance | |||
* @throws FOPException when the constructor fails | |||
*/ | |||
public Fop newFop(String outputFormat, OutputStream stream) throws FOPException { | |||
return new Fop(outputFormat, this, stream); | |||
} | |||
/** | |||
* Returns a new {@link Fop} instance. Use this factory method if you want to configure this | |||
* very rendering run, i.e. if you want to set some metadata like the title and author of the | |||
* document you want to render. In that case, create a new {@link FOUserAgent} | |||
* instance using {@link #newFOUserAgent()}. | |||
* <p> | |||
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can | |||
* use the constants defined in {@link MimeConstants}. | |||
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). | |||
* @return the new Fop instance | |||
* @throws FOPException when the constructor fails | |||
*/ | |||
public Fop newFop(String outputFormat) throws FOPException { | |||
return newFop(outputFormat, null); | |||
} | |||
/** | |||
* Returns the URI Resolver. | |||
* | |||
* @return the URI resolver | |||
*/ | |||
public URIResolverWrapper getNewURIResolver() { | |||
return newUriResolver; | |||
} | |||
// ---------------------------------------------- rendering-run dependent stuff | |||
@@ -345,48 +388,13 @@ public class FOUserAgent { | |||
} | |||
/** | |||
* Sets the base URL. | |||
* @param baseUrl base URL | |||
*/ | |||
public void setBaseURL(String baseUrl) { | |||
this.base = baseUrl; | |||
} | |||
/** | |||
* Sets font base URL. | |||
* @param fontBaseUrl font base URL | |||
* @deprecated Use {@link FontManager#setFontBaseURL(String)} instead. | |||
*/ | |||
public void setFontBaseURL(String fontBaseUrl) { | |||
try { | |||
getFactory().getFontManager().setFontBaseURL(fontBaseUrl); | |||
} catch (MalformedURLException e) { | |||
throw new IllegalArgumentException(e.getMessage()); | |||
} | |||
} | |||
/** | |||
* Returns the base URL. | |||
* @return the base URL | |||
*/ | |||
public String getBaseURL() { | |||
return this.base; | |||
} | |||
/** | |||
* Sets the URI Resolver. | |||
* @param resolver the new URI resolver | |||
*/ | |||
public void setURIResolver(URIResolver resolver) { | |||
this.uriResolver = resolver; | |||
} | |||
/** | |||
* Returns the URI Resolver. | |||
* @return the URI Resolver | |||
*/ | |||
public URIResolver getURIResolver() { | |||
return this.uriResolver; | |||
* Gets the renderer options given an interface representing renderer configuration options. | |||
* | |||
* @param option the renderer option | |||
* @return the value | |||
*/ | |||
public Object getRendererOption(RendererConfigOptions option) { | |||
return rendererOptions.get(option.getName()); | |||
} | |||
/** | |||
@@ -396,39 +404,27 @@ public class FOUserAgent { | |||
* @param uri URI to access | |||
* @return A {@link javax.xml.transform.Source} object, or null if the URI | |||
* cannot be resolved. | |||
* @see org.apache.fop.apps.FOURIResolver | |||
* @see org.apache.fop.apps.io.FOURIResolver | |||
*/ | |||
public Source resolveURI(String uri) { | |||
return resolveURI(uri, getBaseURL()); | |||
} | |||
/** | |||
* Attempts to resolve the given URI. | |||
* Will use the configured resolver and if not successful fall back | |||
* to the default resolver. | |||
* @param href URI to access | |||
* @param base the base URI to resolve against | |||
* @return A {@link javax.xml.transform.Source} object, or null if the URI | |||
* cannot be resolved. | |||
* @see org.apache.fop.apps.FOURIResolver | |||
*/ | |||
public Source resolveURI(String href, String base) { | |||
Source source = null; | |||
//RFC 2397 data URLs don't need to be resolved, just decode them through FOP's default | |||
//URIResolver. | |||
boolean bypassURIResolution = href.startsWith("data:"); | |||
if (!bypassURIResolution && uriResolver != null) { | |||
try { | |||
source = uriResolver.resolve(href, base); | |||
} catch (TransformerException te) { | |||
log.error("Attempt to resolve URI '" + href + "' failed: ", te); | |||
// TODO: What do we want to do when resources aren't found??? | |||
try { | |||
Source src; | |||
// Have to do this so we can resolve data URIs | |||
if (uri.startsWith("data:")) { | |||
CommonURIResolver uriResolver = new CommonURIResolver(); | |||
src = uriResolver.resolve(uri, ""); | |||
} else { | |||
URI actualUri = URIResolverWrapper.cleanURI(uri); | |||
src = new StreamSource(newUriResolver.resolveIn(actualUri)); | |||
src.setSystemId(uri); | |||
} | |||
return src; | |||
} catch (URISyntaxException use) { | |||
return null; | |||
} catch (IOException ioe) { | |||
return null; | |||
} | |||
if (source == null) { | |||
// URI Resolver not configured or returned null, use default resolver from the factory | |||
source = getFactory().resolveURI(href, base); | |||
} | |||
return source; | |||
} | |||
/** | |||
@@ -497,16 +493,6 @@ public class FOUserAgent { | |||
// ---------------------------------------------- environment-level stuff | |||
// (convenience access to FopFactory methods) | |||
/** | |||
* Returns the font base URL. | |||
* @return the font base URL | |||
* @deprecated Use {@link FontManager#getFontBaseURL()} instead. This method is not used by FOP. | |||
*/ | |||
public String getFontBaseURL() { | |||
String fontBase = getFactory().getFontManager().getFontBaseURL(); | |||
return fontBase != null ? fontBase : getBaseURL(); | |||
} | |||
/** | |||
* Returns the conversion factor from pixel units to millimeters. This | |||
* depends on the desired source resolution. | |||
@@ -514,12 +500,12 @@ public class FOUserAgent { | |||
* @see #getSourceResolution() | |||
*/ | |||
public float getSourcePixelUnitToMillimeter() { | |||
return getFactory().getSourcePixelUnitToMillimeter(); | |||
return factory.getSourcePixelUnitToMillimeter(); | |||
} | |||
/** @return the resolution for resolution-dependant input */ | |||
public float getSourceResolution() { | |||
return getFactory().getSourceResolution(); | |||
return factory.getSourceResolution(); | |||
} | |||
/** | |||
@@ -530,7 +516,7 @@ public class FOUserAgent { | |||
* @see FopFactory#getPageHeight() | |||
*/ | |||
public String getPageHeight() { | |||
return getFactory().getPageHeight(); | |||
return factory.getPageHeight(); | |||
} | |||
/** | |||
@@ -541,7 +527,7 @@ public class FOUserAgent { | |||
* @see FopFactory#getPageWidth() | |||
*/ | |||
public String getPageWidth() { | |||
return getFactory().getPageWidth(); | |||
return factory.getPageWidth(); | |||
} | |||
/** | |||
@@ -550,7 +536,7 @@ public class FOUserAgent { | |||
* @see FopFactory#validateStrictly() | |||
*/ | |||
public boolean validateStrictly() { | |||
return getFactory().validateStrictly(); | |||
return factory.validateStrictly(); | |||
} | |||
/** | |||
@@ -559,21 +545,21 @@ public class FOUserAgent { | |||
* @see FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary() | |||
*/ | |||
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { | |||
return getFactory().isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
return factory.isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
} | |||
/** | |||
* @return the RendererFactory | |||
*/ | |||
public RendererFactory getRendererFactory() { | |||
return getFactory().getRendererFactory(); | |||
return factory.getRendererFactory(); | |||
} | |||
/** | |||
* @return the XML handler registry | |||
*/ | |||
public XMLHandlerRegistry getXMLHandlerRegistry() { | |||
return getFactory().getXMLHandlerRegistry(); | |||
return factory.getXMLHandlerRegistry(); | |||
} | |||
/** | |||
@@ -662,12 +648,53 @@ public class FOUserAgent { | |||
} | |||
/** | |||
* Control whether complex script features should be enabled | |||
* Returns the renderer configuration object for a particular MIME type. | |||
* | |||
* @param useComplexScriptFeatures true if FOP is to use complex script features | |||
* @param mimeType the config MIME type | |||
* @param configCreator the parser for creating the config for the first run of parsing. | |||
* @return the renderer configuration object | |||
* @throws FOPException if an error occurs when creating the config object | |||
*/ | |||
public void setComplexScriptFeaturesEnabled(boolean useComplexScriptFeatures) { | |||
factory.setComplexScriptFeaturesEnabled ( useComplexScriptFeatures ); | |||
public RendererConfig getRendererConfig(String mimeType, RendererConfigParser configCreator) | |||
throws FOPException { | |||
return factory.getRendererConfig(this, getRendererConfiguration(mimeType), configCreator); | |||
} | |||
/** | |||
* Returns a {@link Configuration} object for which contains renderer configuration for a given | |||
* MIME type. | |||
* | |||
* @param mimeType the renderer configuration MIME type | |||
* @return the configuration object | |||
*/ | |||
public Configuration getRendererConfiguration(String mimeType) { | |||
Configuration cfg = getUserConfig(); | |||
String type = "renderer"; | |||
String mime = "mime"; | |||
if (cfg == null) { | |||
if (log.isDebugEnabled()) { | |||
log.debug("userconfig is null"); | |||
} | |||
return null; | |||
} | |||
Configuration userConfig = null; | |||
Configuration[] cfgs = cfg.getChild(type + "s").getChildren(type); | |||
for (int i = 0; i < cfgs.length; ++i) { | |||
Configuration child = cfgs[i]; | |||
try { | |||
if (child.getAttribute(mime).equals(mimeType)) { | |||
userConfig = child; | |||
break; | |||
} | |||
} catch (ConfigurationException e) { | |||
// silently pass over configurations without mime type | |||
} | |||
} | |||
log.debug((userConfig == null ? "No u" : "U") | |||
+ "ser configuration found for MIME type " + mimeType); | |||
return userConfig; | |||
} | |||
/** | |||
@@ -713,5 +740,74 @@ public class FOUserAgent { | |||
public StructureTreeEventHandler getStructureTreeEventHandler() { | |||
return this.structureTreeEventHandler; | |||
} | |||
/** @see FopFactory#getLayoutManagerMakerOverride() */ | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return factory.getLayoutManagerMakerOverride(); | |||
} | |||
/** @see FopFactory#getContentHandlerFactoryRegistry() */ | |||
public ContentHandlerFactoryRegistry getContentHandlerFactoryRegistry() { | |||
return factory.getContentHandlerFactoryRegistry(); | |||
} | |||
/** @see FopFactory#getImageManager() */ | |||
public ImageManager getImageManager() { | |||
return factory.getImageManager(); | |||
} | |||
/** @see FopFactory#getElementMappingRegistry() */ | |||
public ElementMappingRegistry getElementMappingRegistry() { | |||
return factory.getElementMappingRegistry(); | |||
} | |||
/** @see FopFactory#getFontManager() */ | |||
public FontManager getFontManager() { | |||
return factory.getFontManager(); | |||
} | |||
/** | |||
* Indicates whether a namespace URI is on the ignored list. | |||
* @param namespaceURI the namespace URI | |||
* @return true if the namespace is ignored by FOP | |||
*/ | |||
public boolean isNamespaceIgnored(String namespaceURI) { | |||
return factory.isNamespaceIgnored(namespaceURI); | |||
} | |||
/** | |||
* Is the user configuration to be validated? | |||
* @return if the user configuration should be validated | |||
*/ | |||
public boolean validateUserConfigStrictly() { | |||
return factory.validateUserConfigStrictly(); | |||
} | |||
/** | |||
* Get the user configuration. | |||
* @return the user configuration | |||
*/ | |||
public Configuration getUserConfig() { | |||
return factory.getUserConfig(); | |||
} | |||
/** @return the image handler registry */ | |||
public ImageHandlerRegistry getImageHandlerRegistry() { | |||
return factory.getImageHandlerRegistry(); | |||
} | |||
/** TODO: javadoc*/ | |||
public ColorSpaceCache getColorSpaceCache() { | |||
return factory.getColorSpaceCache(); | |||
} | |||
/** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ | |||
public HyphenationTreeResolver getHyphenationTreeResolver() { | |||
return factory.getHyphenationTreeResolver(); | |||
} | |||
public Map<String, String> getHyphPatNames() { | |||
return factory.getHyphPatNames(); | |||
} | |||
} | |||
@@ -66,12 +66,12 @@ public class Fop { | |||
* @throws FOPException if setting up the DefaultHandler fails | |||
*/ | |||
Fop(String outputFormat, FOUserAgent ua, OutputStream stream) throws FOPException { | |||
if (ua == null) { | |||
throw new FOPException("Cannot create a new Fop instance without a User Agent."); | |||
} | |||
this.outputFormat = outputFormat; | |||
foUserAgent = ua; | |||
if (foUserAgent == null) { | |||
foUserAgent = FopFactory.newInstance().newFOUserAgent(); | |||
} | |||
this.stream = stream; | |||
@@ -0,0 +1,359 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
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.xmlgraphics.image.loader.spi.ImageImplRegistry; | |||
import org.apache.xmlgraphics.image.loader.util.Penalty; | |||
import org.apache.fop.apps.io.DefaultResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.FontManagerConfigurator; | |||
import org.apache.fop.hyphenation.HyphenationTreeCache; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* Parses the FOP configuration file and returns a {@link FopFactoryBuilder} which builds a | |||
* {@link FopFactory}. | |||
*/ | |||
public class FopConfParser { | |||
private static final String PREFER_RENDERER = "prefer-renderer"; | |||
private final Log log = LogFactory.getLog(FopConfParser.class); | |||
private final FopFactoryBuilder fopFactoryBuilder; | |||
/** | |||
* Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI | |||
* must be given as a fall-back mechanism for URI resolution. | |||
* | |||
* @param fopConfStream the fop conf input stream | |||
* @param enviro the profile of the FOP deployment environment | |||
* @throws SAXException if a SAX error was thrown parsing the FOP conf | |||
* @throws IOException if an I/O error is thrown while parsing the FOP conf | |||
*/ | |||
public FopConfParser(InputStream fopConfStream, EnvironmentProfile enviro) | |||
throws SAXException, IOException { | |||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); | |||
Configuration cfg; | |||
try { | |||
cfg = cfgBuilder.build(fopConfStream); | |||
} catch (ConfigurationException e) { | |||
throw new FOPException(e); | |||
} | |||
// The default base URI is taken from the directory in which the fopConf resides | |||
fopFactoryBuilder = new FopFactoryBuilder(enviro).setConfiguration(cfg); | |||
configure(enviro.getDefaultBaseURI(), enviro.getResourceResolver(), cfg); | |||
} | |||
/** | |||
* Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI | |||
* must be given as a fall-back mechanism for URI resolution. | |||
* | |||
* @param fopConfStream the fop conf input stream | |||
* @param defaultBaseURI the default base URI | |||
* @param resolver the URI resolver | |||
* @throws SAXException if a SAX error was thrown parsing the FOP conf | |||
* @throws IOException if an I/O error is thrown while parsing the FOP conf | |||
*/ | |||
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI, | |||
ResourceResolver resolver) throws SAXException, IOException { | |||
this(fopConfStream, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resolver)); | |||
} | |||
/** | |||
* Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI | |||
* must be given as a fall-back mechanism for URI resolution. The default URI resolvers is used. | |||
* | |||
* @param fopConfStream the fop conf input stream | |||
* @param defaultBaseURI the default base URI | |||
* @throws SAXException if a SAX error was thrown parsing the FOP conf | |||
* @throws IOException if an I/O error is thrown while parsing the FOP conf | |||
*/ | |||
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI) throws SAXException, | |||
IOException { | |||
this(fopConfStream, defaultBaseURI, new DefaultResourceResolver()); | |||
} | |||
/** | |||
* Constructor that takes the FOP conf and uses the default URI resolver. | |||
* | |||
* @param fopConfFile the FOP conf file | |||
* @throws SAXException if a SAX error was thrown parsing the FOP conf | |||
* @throws IOException if an I/O error is thrown while parsing the FOP conf | |||
*/ | |||
public FopConfParser(File fopConfFile) throws SAXException, IOException { | |||
this(fopConfFile, new DefaultResourceResolver()); | |||
} | |||
/** | |||
* Constructor that parses the FOP conf and uses the URI resolver given. | |||
* | |||
* @param fopConfFile the FOP conf file | |||
* @param resolver the URI resolver | |||
* @throws SAXException if a SAX error was thrown parsing the FOP conf | |||
* @throws IOException if an I/O error is thrown while parsing the FOP conf | |||
*/ | |||
public FopConfParser(File fopConfFile, ResourceResolver resolver) | |||
throws SAXException, IOException { | |||
this(new FileInputStream(fopConfFile), | |||
fopConfFile.getAbsoluteFile().getParentFile().toURI(), resolver); | |||
} | |||
private void configure(final URI defaultBaseURI, final ResourceResolver resolver, | |||
Configuration cfg) throws FOPException { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Initializing FopFactory Configuration"); | |||
} | |||
// TODO: This makes this variable both strict FO and user-config validation, is that right? | |||
boolean strict = false; | |||
// strict fo validation | |||
if (cfg.getChild("strict-validation", false) != null) { | |||
try { | |||
strict = cfg.getChild("strict-validation").getValueAsBoolean(); | |||
fopFactoryBuilder.setStrictUserConfigValidation(strict); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, false); | |||
} | |||
} | |||
if (cfg.getChild("accessibility", false) != null) { | |||
try { | |||
fopFactoryBuilder.setAccessibility(cfg.getChild("accessibility").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, false); | |||
} | |||
} | |||
// base definitions for relative path resolution | |||
if (cfg.getChild("base", false) != null) { | |||
try { | |||
URI confUri = URIResolverWrapper.getBaseURI(cfg.getChild("base").getValue(null)); | |||
fopFactoryBuilder.setBaseURI(defaultBaseURI.resolve(confUri)); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, strict); | |||
} | |||
} | |||
if (cfg.getChild("hyphenation-base", false) != null) { | |||
String path = cfg.getChild("hyphenation-base").getValue(null); | |||
if (defaultBaseURI != null) { | |||
try { | |||
URI hyphBaseUri = URIResolverWrapper.getBaseURI(path); | |||
fopFactoryBuilder.setHyphenationBaseURI(defaultBaseURI.resolve(hyphBaseUri)); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, strict); | |||
} | |||
} | |||
} | |||
// renderer options | |||
if (cfg.getChild("source-resolution", false) != null) { | |||
float srcRes = cfg.getChild("source-resolution").getValueAsFloat( | |||
FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION); | |||
fopFactoryBuilder.setSourceResolution(srcRes); | |||
if (log.isDebugEnabled()) { | |||
log.debug("source-resolution set to: " + srcRes + "dpi"); | |||
} | |||
} | |||
if (cfg.getChild("target-resolution", false) != null) { | |||
float targetRes = cfg.getChild("target-resolution").getValueAsFloat( | |||
FopFactoryConfig.DEFAULT_TARGET_RESOLUTION); | |||
fopFactoryBuilder.setTargetResolution(targetRes); | |||
if (log.isDebugEnabled()) { | |||
log.debug("target-resolution set to: " + targetRes + "dpi"); | |||
} | |||
} | |||
if (cfg.getChild("break-indent-inheritance", false) != null) { | |||
try { | |||
fopFactoryBuilder.setBreakIndentInheritanceOnReferenceAreaBoundary( | |||
cfg.getChild("break-indent-inheritance").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
Configuration pageConfig = cfg.getChild("default-page-settings"); | |||
if (pageConfig.getAttribute("height", null) != null) { | |||
String pageHeight = pageConfig.getAttribute("height", | |||
FopFactoryConfig.DEFAULT_PAGE_HEIGHT); | |||
fopFactoryBuilder.setPageHeight(pageHeight); | |||
if (log.isInfoEnabled()) { | |||
log.info("Default page-height set to: " + pageHeight); | |||
} | |||
} | |||
if (pageConfig.getAttribute("width", null) != null) { | |||
String pageWidth = pageConfig.getAttribute("width", | |||
FopFactoryConfig.DEFAULT_PAGE_WIDTH); | |||
fopFactoryBuilder.setPageWidth(pageWidth); | |||
if (log.isInfoEnabled()) { | |||
log.info("Default page-width set to: " + pageWidth); | |||
} | |||
} | |||
if (cfg.getChild("complex-scripts") != null) { | |||
Configuration csConfig = cfg.getChild("complex-scripts"); | |||
fopFactoryBuilder.setComplexScriptFeatures(!csConfig.getAttributeAsBoolean("disabled", | |||
false)); | |||
} | |||
setHyphPatNames(cfg, fopFactoryBuilder, strict); | |||
// prefer Renderer over IFDocumentHandler | |||
if (cfg.getChild(PREFER_RENDERER, false) != null) { | |||
try { | |||
fopFactoryBuilder.setPreferRenderer( | |||
cfg.getChild(PREFER_RENDERER).getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// configure font manager | |||
new FontManagerConfigurator(cfg, fopFactoryBuilder.getBaseUri(), resolver).configure( | |||
fopFactoryBuilder.getFontManager(), strict); | |||
// configure image loader framework | |||
configureImageLoading(cfg.getChild("image-loading", false), strict); | |||
} | |||
private void setHyphPatNames(Configuration cfg, FopFactoryBuilder builder, boolean strict) | |||
throws FOPException { | |||
Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern"); | |||
if (hyphPatConfig.length != 0) { | |||
Map<String, String> hyphPatNames = new HashMap<String, String>(); | |||
for (int i = 0; i < hyphPatConfig.length; ++i) { | |||
String lang; | |||
String country; | |||
String filename; | |||
StringBuffer error = new StringBuffer(); | |||
String location = hyphPatConfig[i].getLocation(); | |||
lang = hyphPatConfig[i].getAttribute("lang", null); | |||
if (lang == null) { | |||
addError("The lang attribute of a hyphenation-pattern configuration" | |||
+ " element must exist (" + location + ")", error); | |||
} else if (!lang.matches("[a-zA-Z]{2}")) { | |||
addError("The lang attribute of a hyphenation-pattern configuration" | |||
+ " element must consist of exactly two letters (" | |||
+ location + ")", error); | |||
} | |||
lang = lang.toLowerCase(); | |||
country = hyphPatConfig[i].getAttribute("country", null); | |||
if ("".equals(country)) { | |||
country = null; | |||
} | |||
if (country != null) { | |||
if (!country.matches("[a-zA-Z]{2}")) { | |||
addError("The country attribute of a hyphenation-pattern configuration" | |||
+ " element must consist of exactly two letters (" | |||
+ location + ")", error); | |||
} | |||
country = country.toUpperCase(); | |||
} | |||
filename = hyphPatConfig[i].getValue(null); | |||
if (filename == null) { | |||
addError("The value of a hyphenation-pattern configuration" | |||
+ " element may not be empty (" + location + ")", error); | |||
} | |||
if (error.length() != 0) { | |||
LogUtil.handleError(log, error.toString(), strict); | |||
continue; | |||
} | |||
String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); | |||
hyphPatNames.put(llccKey, filename); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Using hyphenation pattern filename " + filename | |||
+ " for lang=\"" + lang + "\"" | |||
+ (country != null ? ", country=\"" + country + "\"" : "")); | |||
} | |||
} | |||
builder.setHyphPatNames(hyphPatNames); | |||
} | |||
} | |||
private static void addError(String message, StringBuffer error) { | |||
if (error.length() != 0) { | |||
error.append(". "); | |||
} | |||
error.append(message); | |||
} | |||
private void configureImageLoading(Configuration parent, boolean strict) throws FOPException { | |||
if (parent == null) { | |||
return; | |||
} | |||
ImageImplRegistry registry = fopFactoryBuilder.getImageManager().getRegistry(); | |||
Configuration[] penalties = parent.getChildren("penalty"); | |||
try { | |||
for (int i = 0, c = penalties.length; i < c; i++) { | |||
Configuration penaltyCfg = penalties[i]; | |||
String className = penaltyCfg.getAttribute("class"); | |||
String value = penaltyCfg.getAttribute("value"); | |||
Penalty p = null; | |||
if (value.toUpperCase().startsWith("INF")) { | |||
p = Penalty.INFINITE_PENALTY; | |||
} else { | |||
try { | |||
p = Penalty.toPenalty(Integer.parseInt(value)); | |||
} catch (NumberFormatException nfe) { | |||
LogUtil.handleException(log, nfe, strict); | |||
} | |||
} | |||
if (p != null) { | |||
registry.setAdditionalPenalty(className, p); | |||
} | |||
} | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
/** | |||
* Returns the {@link FopFactoryBuilder}. | |||
* | |||
* @return the object for configuring the {@link FopFactory} | |||
*/ | |||
public FopFactoryBuilder getFopFactoryBuilder() { | |||
return fopFactoryBuilder; | |||
} | |||
} |
@@ -21,18 +21,15 @@ package org.apache.fop.apps; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.URIResolver; | |||
import org.xml.sax.SAXException; | |||
@@ -44,13 +41,15 @@ import org.apache.xmlgraphics.image.loader.ImageContext; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.util.UnitConv; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fo.ElementMapping; | |||
import org.apache.fop.fo.ElementMappingRegistry; | |||
import org.apache.fop.fonts.FontCache; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.hyphenation.HyphenationTreeResolver; | |||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | |||
import org.apache.fop.render.ImageHandlerRegistry; | |||
import org.apache.fop.render.RendererConfig; | |||
import org.apache.fop.render.RendererConfig.RendererConfigParser; | |||
import org.apache.fop.render.RendererFactory; | |||
import org.apache.fop.render.XMLHandlerRegistry; | |||
import org.apache.fop.util.ColorSpaceCache; | |||
@@ -59,57 +58,48 @@ import org.apache.fop.util.ContentHandlerFactoryRegistry; | |||
/** | |||
* Factory class which instantiates new Fop and FOUserAgent instances. This | |||
* class also holds environmental information and configuration used by FOP. | |||
* Information that may potentially be different for each rendering run can be | |||
* Information that may potentially be different for each renderingq run can be | |||
* found and managed in the FOUserAgent. | |||
*/ | |||
public class FopFactory implements ImageContext { | |||
public final class FopFactory implements ImageContext { | |||
/** logger instance */ | |||
private static Log log = LogFactory.getLog(FopFactory.class); | |||
/** Factory for Renderers and FOEventHandlers */ | |||
private RendererFactory rendererFactory; | |||
private final RendererFactory rendererFactory; | |||
/** Registry for XML handlers */ | |||
private XMLHandlerRegistry xmlHandlers; | |||
private final XMLHandlerRegistry xmlHandlers; | |||
/** Registry for image handlers */ | |||
private ImageHandlerRegistry imageHandlers; | |||
private final ImageHandlerRegistry imageHandlers; | |||
/** The registry for ElementMapping instances */ | |||
private ElementMappingRegistry elementMappingRegistry; | |||
private final ElementMappingRegistry elementMappingRegistry; | |||
/** The registry for ContentHandlerFactory instance */ | |||
private ContentHandlerFactoryRegistry contentHandlerFactoryRegistry | |||
= new ContentHandlerFactoryRegistry(); | |||
private final ContentHandlerFactoryRegistry contentHandlerFactoryRegistry | |||
= new ContentHandlerFactoryRegistry(); | |||
/** The resolver for user-supplied hyphenation patterns */ | |||
private HyphenationTreeResolver hyphResolver = null; | |||
private final ColorSpaceCache colorSpaceCache; | |||
private ColorSpaceCache colorSpaceCache = null; | |||
private final FopFactoryConfig config; | |||
/** Image manager for loading and caching image objects */ | |||
private ImageManager imageManager; | |||
private final URIResolverWrapper uriResolverWrapper; | |||
/** Font manager for font substitution, autodetection and caching **/ | |||
private FontManager fontManager; | |||
private final Map<String, RendererConfig> rendererConfig; | |||
/** Configuration layer used to configure fop */ | |||
private FopFactoryConfigurator config = null; | |||
/** | |||
* The base URL for all URL resolutions, especially for | |||
* external-graphics. | |||
*/ | |||
private String base = null; | |||
/** | |||
* Controls if accessibility is turned on or off | |||
*/ | |||
private boolean accessibility = false; | |||
/** The base URL for all hyphen URL resolutions. */ | |||
private String hyphenBase = null; | |||
private FopFactory(FopFactoryConfig config) { | |||
this.config = config; | |||
this.uriResolverWrapper = new URIResolverWrapper(config.getBaseURI(), config.getNewURIResolver()); | |||
this.elementMappingRegistry = new ElementMappingRegistry(this); | |||
this.colorSpaceCache = new ColorSpaceCache(config.getURIResolver()); | |||
this.rendererFactory = new RendererFactory(config.preferRenderer()); | |||
this.xmlHandlers = new XMLHandlerRegistry(); | |||
this.imageHandlers = new ImageHandlerRegistry(); | |||
rendererConfig = new HashMap<String, RendererConfig>(); | |||
} | |||
/** | |||
* Map of configured names of hyphenation pattern file names: ll_CC => name | |||
@@ -121,73 +111,52 @@ public class FopFactory implements ImageContext { | |||
* input XSL violates that FO's content model. This is the default | |||
* behavior for FOP. However, this flag, if set, provides the user the | |||
* ability for FOP to halt on all content model violations if desired. | |||
* Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object. | |||
* | |||
* @param config the fop configuration | |||
* @return the requested FopFactory instance. | |||
*/ | |||
private boolean strictFOValidation = FopFactoryConfigurator.DEFAULT_STRICT_FO_VALIDATION; | |||
public static FopFactory newInstance(FopFactoryConfig config) { | |||
return new FopFactory(config); | |||
} | |||
/** | |||
* FOP will validate the contents of the user configuration strictly | |||
* (e.g. base-urls and font urls/paths). | |||
* Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object that | |||
* is created when the fopConf is parsed. | |||
* | |||
* @param fopConf the fop conf configuration file to parse | |||
* @return the requested FopFactory instance. | |||
* @throws IOException | |||
* @throws SAXException | |||
*/ | |||
private boolean strictUserConfigValidation | |||
= FopFactoryConfigurator.DEFAULT_STRICT_USERCONFIG_VALIDATION; | |||
/** Source resolution in dpi */ | |||
private float sourceResolution = FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION; | |||
/** Target resolution in dpi */ | |||
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; | |||
/** Page height */ | |||
private String pageHeight = FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT; | |||
/** Page width */ | |||
private String pageWidth = FopFactoryConfigurator.DEFAULT_PAGE_WIDTH; | |||
/** Complex scripts support enabled */ | |||
private boolean useComplexScriptFeatures | |||
= FopFactoryConfigurator.DEFAULT_COMPLEX_SCRIPT_FEATURES; | |||
/** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */ | |||
private boolean breakIndentInheritanceOnReferenceAreaBoundary | |||
= FopFactoryConfigurator.DEFAULT_BREAK_INDENT_INHERITANCE; | |||
/** Optional overriding LayoutManagerMaker */ | |||
private LayoutManagerMaker lmMakerOverride = null; | |||
private Set<String> ignoredNamespaces; | |||
private FOURIResolver foURIResolver; | |||
public static FopFactory newInstance(File fopConf) throws SAXException, IOException { | |||
return new FopConfParser(fopConf).getFopFactoryBuilder().build(); | |||
} | |||
/** | |||
* Main constructor. | |||
* Returns a new FopFactory instance that is configured only by the default configuration | |||
* parameters. | |||
* | |||
* @param baseURI the base URI to resolve resource URIs against | |||
* @return the requested FopFactory instance. | |||
*/ | |||
protected FopFactory() { | |||
this.config = new FopFactoryConfigurator(this); | |||
this.elementMappingRegistry = new ElementMappingRegistry(this); | |||
this.foURIResolver = new FOURIResolver(validateUserConfigStrictly()); | |||
this.fontManager = new FontManager() { | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | |||
super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase)); | |||
} | |||
}; | |||
this.colorSpaceCache = new ColorSpaceCache(foURIResolver); | |||
this.imageManager = new ImageManager(this); | |||
this.rendererFactory = new RendererFactory(); | |||
this.xmlHandlers = new XMLHandlerRegistry(); | |||
this.imageHandlers = new ImageHandlerRegistry(); | |||
this.ignoredNamespaces = new java.util.HashSet<String>(); | |||
public static FopFactory newInstance(URI baseURI) { | |||
return new FopFactoryBuilder(baseURI).build(); | |||
} | |||
/** | |||
* Returns a new FopFactory instance. | |||
* Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object that | |||
* is created when the fopConf is parsed. | |||
* | |||
* @param baseURI the base URI to resolve resource URIs against | |||
* @param confStream the fop conf configuration stream to parse | |||
* @return the requested FopFactory instance. | |||
* @throws SAXException | |||
* @throws IOException | |||
*/ | |||
public static FopFactory newInstance() { | |||
return new FopFactory(); | |||
public static FopFactory newInstance(URI baseURI, InputStream confStream) throws SAXException, | |||
IOException { | |||
return new FopConfParser(confStream, baseURI).getFopFactoryBuilder().build(); | |||
} | |||
/** | |||
@@ -198,34 +167,12 @@ public class FopFactory implements ImageContext { | |||
* @throws FOPException | |||
*/ | |||
public FOUserAgent newFOUserAgent() { | |||
FOUserAgent userAgent = new FOUserAgent(this); | |||
FOUserAgent userAgent = new FOUserAgent(this, uriResolverWrapper); | |||
return userAgent; | |||
} | |||
/** | |||
* Sets accessibility support. | |||
* | |||
* @param value <code>true</code> to enable accessibility, <code>false</code> otherwise | |||
*/ | |||
void setAccessibility(boolean value) { | |||
this.accessibility = value; | |||
} | |||
boolean isAccessibilityEnabled() { | |||
return accessibility; | |||
} | |||
/** | |||
* Sets complex script support. | |||
* @param value <code>true</code> to enable complex script features, | |||
* <code>false</code> otherwise | |||
*/ | |||
void setComplexScriptFeaturesEnabled(boolean value) { | |||
this.useComplexScriptFeatures = value; | |||
} | |||
boolean isComplexScriptFeaturesEnabled() { | |||
return useComplexScriptFeatures; | |||
return config.isComplexScriptFeaturesEnabled(); | |||
} | |||
/** | |||
@@ -239,7 +186,7 @@ public class FopFactory implements ImageContext { | |||
* @throws FOPException when the constructor fails | |||
*/ | |||
public Fop newFop(String outputFormat) throws FOPException { | |||
return newFop(outputFormat, newFOUserAgent()); | |||
return newFOUserAgent().newFop(outputFormat); | |||
} | |||
/** | |||
@@ -256,7 +203,7 @@ public class FopFactory implements ImageContext { | |||
* @throws FOPException when the constructor fails | |||
*/ | |||
public Fop newFop(String outputFormat, FOUserAgent userAgent) throws FOPException { | |||
return newFop(outputFormat, userAgent, null); | |||
return userAgent.newFop(outputFormat, null); | |||
} | |||
/** | |||
@@ -271,7 +218,7 @@ public class FopFactory implements ImageContext { | |||
* @throws FOPException when the constructor fails | |||
*/ | |||
public Fop newFop(String outputFormat, OutputStream stream) throws FOPException { | |||
return newFop(outputFormat, newFOUserAgent(), stream); | |||
return newFOUserAgent().newFop(outputFormat, stream); | |||
} | |||
/** | |||
@@ -290,11 +237,8 @@ public class FopFactory implements ImageContext { | |||
* @throws FOPException when the constructor fails | |||
*/ | |||
public Fop newFop(String outputFormat, FOUserAgent userAgent, OutputStream stream) | |||
throws FOPException { | |||
if (userAgent == null) { | |||
throw new NullPointerException("The userAgent parameter must not be null!"); | |||
} | |||
return new Fop(outputFormat, userAgent, stream); | |||
throws FOPException { | |||
return userAgent.newFop(outputFormat, stream); | |||
} | |||
/** | |||
@@ -343,11 +287,28 @@ public class FopFactory implements ImageContext { | |||
} | |||
/** | |||
* Returns the image manager. | |||
* @return the image manager | |||
*/ | |||
public ImageManager getImageManager() { | |||
return this.imageManager; | |||
* Returns the renderer configuration object for a specific renderer given the parser and | |||
* configuration to read. The renderer config is cached such that the {@link Configuration} is | |||
* only parsed once per renderer, per FopFactory instance. | |||
* | |||
* @param userAgent the user agent | |||
* @param cfg the configuration to be parsed | |||
* @param configCreator the parser that creates the config object | |||
* @return the config object | |||
* @throws FOPException when an error occurs while creating the configuration object | |||
*/ | |||
public RendererConfig getRendererConfig(FOUserAgent userAgent, Configuration cfg, | |||
RendererConfigParser configCreator) throws FOPException { | |||
RendererConfig config = rendererConfig.get(configCreator.getMimeType()); | |||
if (config == null) { | |||
try { | |||
config = configCreator.build(userAgent, cfg); | |||
rendererConfig.put(configCreator.getMimeType(), config); | |||
} catch (Exception e) { | |||
throw new FOPException(e); | |||
} | |||
} | |||
return config; | |||
} | |||
/** | |||
@@ -359,143 +320,41 @@ public class FopFactory implements ImageContext { | |||
} | |||
/** | |||
* Sets an explicit LayoutManagerMaker instance which overrides the one | |||
* defined by the AreaTreeHandler. | |||
* @param lmMaker the LayoutManagerMaker instance | |||
*/ | |||
public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { | |||
this.lmMakerOverride = lmMaker; | |||
} | |||
/** | |||
* Returns the overriding LayoutManagerMaker instance, if any. | |||
* @return the overriding LayoutManagerMaker or null | |||
*/ | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return this.lmMakerOverride; | |||
} | |||
/** | |||
* Sets the base URL. | |||
* @param base the base URL | |||
* @throws MalformedURLException if there's a problem with a file URL | |||
* Returns whether accessibility is enabled. | |||
* @return true if accessibility is enabled | |||
*/ | |||
public void setBaseURL(String base) throws MalformedURLException { | |||
this.base = foURIResolver.checkBaseURL(base); | |||
} | |||
/** | |||
* Returns the base URL. | |||
* @return the base URL | |||
*/ | |||
public String getBaseURL() { | |||
return this.base; | |||
} | |||
/** | |||
* Sets the font base URL. | |||
* @param fontBase font base URL | |||
* @throws MalformedURLException if there's a problem with a file URL | |||
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead | |||
*/ | |||
@Deprecated | |||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | |||
getFontManager().setFontBaseURL(fontBase); | |||
} | |||
/** | |||
* @return the font base URL | |||
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead | |||
*/ | |||
@Deprecated | |||
public String getFontBaseURL() { | |||
return getFontManager().getFontBaseURL(); | |||
} | |||
/** @return the hyphen base URL */ | |||
public String getHyphenBaseURL() { | |||
return this.hyphenBase; | |||
} | |||
/** | |||
* Sets the hyphen base URL. | |||
* @param hyphenBase hythen base URL | |||
* @throws MalformedURLException if there's a problem with a file URL | |||
* */ | |||
public void setHyphenBaseURL(final String hyphenBase) throws MalformedURLException { | |||
if (hyphenBase != null) { | |||
setHyphenationTreeResolver( | |||
new HyphenationTreeResolver() { | |||
public Source resolve(String href) { | |||
return resolveURI(href, hyphenBase); | |||
} | |||
}); | |||
} | |||
this.hyphenBase = foURIResolver.checkBaseURL(hyphenBase); | |||
} | |||
/** | |||
* @return the hyphPatNames | |||
*/ | |||
public Map getHyphPatNames() { | |||
return hyphPatNames; | |||
} | |||
/** | |||
* @param hyphPatNames the hyphPatNames to set | |||
*/ | |||
public void setHyphPatNames(Map hyphPatNames) { | |||
if (hyphPatNames == null) { | |||
hyphPatNames = new HashMap(); | |||
} | |||
this.hyphPatNames = hyphPatNames; | |||
boolean isAccessibilityEnabled() { | |||
return config.isAccessibilityEnabled(); | |||
} | |||
/** | |||
* Sets the URI Resolver. It is used for resolving factory-level URIs like hyphenation | |||
* patterns and as backup for URI resolution performed during a rendering run. | |||
* @param uriResolver the new URI resolver | |||
* Returns the image manager. | |||
* @return the image manager | |||
*/ | |||
public void setURIResolver(URIResolver uriResolver) { | |||
foURIResolver.setCustomURIResolver(uriResolver); | |||
public ImageManager getImageManager() { | |||
return config.getImageManager(); | |||
} | |||
/** | |||
* Returns the URI Resolver. | |||
* @return the URI Resolver | |||
* Returns the overriding LayoutManagerMaker instance, if any. | |||
* @return the overriding LayoutManagerMaker or null | |||
*/ | |||
public URIResolver getURIResolver() { | |||
return foURIResolver; | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return config.getLayoutManagerMakerOverride(); | |||
} | |||
/** | |||
* Returns the FO URI Resolver. | |||
* @return the FO URI Resolver | |||
*/ | |||
public FOURIResolver getFOURIResolver() { | |||
return foURIResolver; | |||
/** @return the hyphen base URI */ | |||
public String getHyphenBaseURI() { | |||
return config.getHyphenationBaseURI().toASCIIString(); | |||
} | |||
/** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ | |||
public HyphenationTreeResolver getHyphenationTreeResolver() { | |||
return this.hyphResolver; | |||
} | |||
/** | |||
* Sets the HyphenationTreeResolver to be used for resolving user-supplied hyphenation files. | |||
* @param hyphResolver the HyphenationTreeResolver instance | |||
*/ | |||
public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) { | |||
this.hyphResolver = hyphResolver; | |||
return config.getHyphenationTreeResolver(); | |||
} | |||
/** | |||
* Activates strict XSL content model validation for FOP | |||
* Default is false (FOP will continue processing where it can) | |||
* @param validateStrictly true to turn on strict validation | |||
*/ | |||
public void setStrictValidation(boolean validateStrictly) { | |||
this.strictFOValidation = validateStrictly; | |||
public Map<String, String> getHyphPatNames() { | |||
return config.getHyphPatNames(); | |||
} | |||
/** | |||
@@ -503,7 +362,7 @@ public class FopFactory implements ImageContext { | |||
* @return true of strict validation turned on, false otherwise | |||
*/ | |||
public boolean validateStrictly() { | |||
return strictFOValidation; | |||
return config.validateStrictly(); | |||
} | |||
/** | |||
@@ -511,48 +370,12 @@ public class FopFactory implements ImageContext { | |||
* boundaries (for more info, see the javadoc for the relative member variable) | |||
*/ | |||
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { | |||
return breakIndentInheritanceOnReferenceAreaBoundary; | |||
} | |||
/** | |||
* Controls whether to enable a feature that breaks indent inheritance when crossing | |||
* reference area boundaries. | |||
* <p> | |||
* This flag controls whether FOP will enable special code that breaks property | |||
* inheritance for start-indent and end-indent when the evaluation of the inherited | |||
* value would cross a reference area. This is described under | |||
* http://wiki.apache.org/xmlgraphics-fop/IndentInheritance as is intended to | |||
* improve interoperability with commercial FO implementations and to produce | |||
* results that are more in line with the expectation of unexperienced FO users. | |||
* Note: Enabling this features violates the XSL specification! | |||
* @param value true to enable the feature | |||
*/ | |||
public void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value) { | |||
this.breakIndentInheritanceOnReferenceAreaBoundary = value; | |||
return config.isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
} | |||
/** | |||
* @return true if kerning on base 14 fonts is enabled | |||
* @deprecated use getFontManager().isBase14KerningEnabled() instead | |||
*/ | |||
@Deprecated | |||
public boolean isBase14KerningEnabled() { | |||
return getFontManager().isBase14KerningEnabled(); | |||
} | |||
/** | |||
* Controls whether kerning is activated on base 14 fonts. | |||
* @param value true if kerning should be activated | |||
* @deprecated use getFontManager().setBase14KerningEnabled(boolean) instead | |||
*/ | |||
@Deprecated | |||
public void setBase14KerningEnabled(boolean value) { | |||
getFontManager().setBase14KerningEnabled(value); | |||
} | |||
/** @return the resolution for resolution-dependant input */ | |||
/** @return the resolution for resolution-dependent input */ | |||
public float getSourceResolution() { | |||
return this.sourceResolution; | |||
return config.getSourceResolution(); | |||
} | |||
/** | |||
@@ -565,22 +388,9 @@ public class FopFactory implements ImageContext { | |||
return UnitConv.IN2MM / getSourceResolution(); | |||
} | |||
/** | |||
* Sets the source resolution in dpi. This value is used to interpret the pixel size | |||
* of source documents like SVG images and bitmap images without resolution information. | |||
* @param dpi resolution in dpi | |||
*/ | |||
public void setSourceResolution(float dpi) { | |||
this.sourceResolution = dpi; | |||
if (log.isDebugEnabled()) { | |||
log.debug("source-resolution set to: " + sourceResolution | |||
+ "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")"); | |||
} | |||
} | |||
/** @return the resolution for resolution-dependant output */ | |||
public float getTargetResolution() { | |||
return this.targetResolution; | |||
return config.getTargetResolution(); | |||
} | |||
/** | |||
@@ -590,25 +400,7 @@ public class FopFactory implements ImageContext { | |||
* @see #getTargetResolution() | |||
*/ | |||
public float getTargetPixelUnitToMillimeter() { | |||
return UnitConv.IN2MM / this.targetResolution; | |||
} | |||
/** | |||
* Sets the source resolution in dpi. This value is used to interpret the pixel size | |||
* of source documents like SVG images and bitmap images without resolution information. | |||
* @param dpi resolution in dpi | |||
*/ | |||
public void setTargetResolution(float dpi) { | |||
this.targetResolution = dpi; | |||
} | |||
/** | |||
* Sets the source resolution in dpi. This value is used to interpret the pixel size | |||
* of source documents like SVG images and bitmap images without resolution information. | |||
* @param dpi resolution in dpi | |||
*/ | |||
public void setSourceResolution(int dpi) { | |||
setSourceResolution((float)dpi); | |||
return 25.4f / getTargetResolution(); | |||
} | |||
/** | |||
@@ -618,20 +410,7 @@ public class FopFactory implements ImageContext { | |||
* @return the page-height, as a String | |||
*/ | |||
public String getPageHeight() { | |||
return this.pageHeight; | |||
} | |||
/** | |||
* Sets the page-height to use as fallback, in case | |||
* page-height="auto" | |||
* | |||
* @param pageHeight page-height as a String | |||
*/ | |||
public void setPageHeight(String pageHeight) { | |||
this.pageHeight = pageHeight; | |||
if (log.isDebugEnabled()) { | |||
log.debug("Default page-height set to: " + pageHeight); | |||
} | |||
return config.getPageHeight(); | |||
} | |||
/** | |||
@@ -641,40 +420,7 @@ public class FopFactory implements ImageContext { | |||
* @return the page-width, as a String | |||
*/ | |||
public String getPageWidth() { | |||
return this.pageWidth; | |||
} | |||
/** | |||
* Sets the page-width to use as fallback, in case | |||
* page-width="auto" | |||
* | |||
* @param pageWidth page-width as a String | |||
*/ | |||
public void setPageWidth(String pageWidth) { | |||
this.pageWidth = pageWidth; | |||
if (log.isDebugEnabled()) { | |||
log.debug("Default page-width set to: " + pageWidth); | |||
} | |||
} | |||
/** | |||
* Adds a namespace to the set of ignored namespaces. | |||
* If FOP encounters a namespace which it cannot handle, it issues a warning except if this | |||
* namespace is in the ignored set. | |||
* @param namespaceURI the namespace URI | |||
*/ | |||
public void ignoreNamespace(String namespaceURI) { | |||
this.ignoredNamespaces.add(namespaceURI); | |||
} | |||
/** | |||
* Adds a collection of namespaces to the set of ignored namespaces. | |||
* If FOP encounters a namespace which it cannot handle, it issues a warning except if this | |||
* namespace is in the ignored set. | |||
* @param namespaceURIs the namespace URIs | |||
*/ | |||
public void ignoreNamespaces(Collection<String> namespaceURIs) { | |||
this.ignoredNamespaces.addAll(namespaceURIs); | |||
return config.getPageWidth(); | |||
} | |||
/** | |||
@@ -683,54 +429,16 @@ public class FopFactory implements ImageContext { | |||
* @return true if the namespace is ignored by FOP | |||
*/ | |||
public boolean isNamespaceIgnored(String namespaceURI) { | |||
return this.ignoredNamespaces.contains(namespaceURI); | |||
return config.isNamespaceIgnored(namespaceURI); | |||
} | |||
/** @return the set of namespaces that are ignored by FOP */ | |||
public Set<String> getIgnoredNamespace() { | |||
return Collections.unmodifiableSet(this.ignoredNamespaces); | |||
return config.getIgnoredNamespaces(); | |||
} | |||
//------------------------------------------- Configuration stuff | |||
/** | |||
* Set the user configuration. | |||
* @param userConfigFile the configuration file | |||
* @throws IOException if an I/O error occurs | |||
* @throws SAXException if a parsing error occurs | |||
*/ | |||
public void setUserConfig(File userConfigFile) throws SAXException, IOException { | |||
config.setUserConfig(userConfigFile); | |||
} | |||
/** | |||
* Set the user configuration from an URI. | |||
* @param uri the URI to the configuration file | |||
* @throws IOException if an I/O error occurs | |||
* @throws SAXException if a parsing error occurs | |||
*/ | |||
public void setUserConfig(String uri) throws SAXException, IOException { | |||
config.setUserConfig(uri); | |||
} | |||
/** | |||
* Set the user configuration. | |||
* @param userConfig configuration | |||
* @throws FOPException if a configuration problem occurs | |||
*/ | |||
public void setUserConfig(Configuration userConfig) throws FOPException { | |||
config.setUserConfig(userConfig); | |||
} | |||
/** | |||
* Set the base URI for the user configuration | |||
* Useful for programmatic configurations | |||
* @param baseURI the base URI | |||
*/ | |||
public void setUserConfigBaseURI(URI baseURI) { | |||
config.setBaseURI(baseURI); | |||
} | |||
/** | |||
* Get the user configuration. | |||
* @return the user configuration | |||
@@ -739,61 +447,22 @@ public class FopFactory implements ImageContext { | |||
return config.getUserConfig(); | |||
} | |||
/** | |||
* Is the user configuration to be validated? | |||
* @param strictUserConfigValidation strict user config validation | |||
*/ | |||
public void setStrictUserConfigValidation(boolean strictUserConfigValidation) { | |||
this.strictUserConfigValidation = strictUserConfigValidation; | |||
this.foURIResolver.setThrowExceptions(strictUserConfigValidation); | |||
} | |||
/** | |||
* Is the user configuration to be validated? | |||
* @return if the user configuration should be validated | |||
*/ | |||
public boolean validateUserConfigStrictly() { | |||
return this.strictUserConfigValidation; | |||
return config.validateUserConfigStrictly(); | |||
} | |||
//------------------------------------------- Font related stuff | |||
/** | |||
* Whether or not to cache results of font triplet detection/auto-config | |||
* @param useCache use cache or not | |||
* @deprecated use getFontManager().setUseCache(boolean) instead | |||
*/ | |||
@Deprecated | |||
public void setUseCache(boolean useCache) { | |||
getFontManager().setUseCache(useCache); | |||
} | |||
/** | |||
* Cache results of font triplet detection/auto-config? | |||
* @return whether this factory is uses the cache | |||
* @deprecated use getFontManager().useCache() instead | |||
*/ | |||
@Deprecated | |||
public boolean useCache() { | |||
return getFontManager().useCache(); | |||
} | |||
/** | |||
* Returns the font cache instance used by this factory. | |||
* @return the font cache | |||
* @deprecated use getFontManager().getFontCache() instead | |||
*/ | |||
@Deprecated | |||
public FontCache getFontCache() { | |||
return getFontManager().getFontCache(); | |||
} | |||
/** | |||
* Returns the font manager. | |||
* @return the font manager | |||
*/ | |||
public FontManager getFontManager() { | |||
return this.fontManager; | |||
return config.getFontManager(); | |||
} | |||
/** | |||
@@ -804,12 +473,12 @@ public class FopFactory implements ImageContext { | |||
* @param baseUri the base URI to resolve against | |||
* @return A {@link javax.xml.transform.Source} object, or null if the URI | |||
* cannot be resolved. | |||
* @see org.apache.fop.apps.FOURIResolver | |||
* @see org.apache.fop.apps.io.FOURIResolver | |||
*/ | |||
public Source resolveURI(String href, String baseUri) { | |||
Source source = null; | |||
try { | |||
source = foURIResolver.resolve(href, baseUri); | |||
source = config.getURIResolver().resolve(href, baseUri); | |||
} catch (TransformerException e) { | |||
log.error("Attempt to resolve URI '" + href + "' failed: ", e); | |||
} | |||
@@ -825,5 +494,4 @@ public class FopFactory implements ImageContext { | |||
public ColorSpaceCache getColorSpaceCache() { | |||
return this.colorSpaceCache; | |||
} | |||
} |
@@ -0,0 +1,744 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
import java.net.URI; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.xml.transform.URIResolver; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.xmlgraphics.image.loader.ImageContext; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.fop.apps.io.DefaultResourceResolver; | |||
import org.apache.fop.apps.io.FOURIResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.hyphenation.HyphenationTreeResolver; | |||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | |||
/** | |||
* This is the builder class for {@link FopFactory}. Setters can be chained to | |||
* make building a {@link FopFactory} object more concise and intuitive e.g. | |||
* | |||
* <pre> | |||
* {@code | |||
* FopFactoryBuilder fopFactoryBuilder = new FopFactoryBuilder(<URI>) | |||
* .setURIResolver(<URIResolver>) | |||
* .setPageHeight(<String>) | |||
* .setPageWidth(<String>) | |||
* .setStrictUserConfigValidation(<boolean>) | |||
* ... etc ... | |||
* FopFactory fopFactory = fopFactoryBuilder.build(); | |||
* } | |||
* </pre> | |||
*/ | |||
public final class FopFactoryBuilder { | |||
private final FopFactoryConfig config; | |||
private FopFactoryConfigBuilder fopFactoryConfigBuilder; | |||
/** | |||
* A builder class for {@link FopFactory} which can be used for setting configuration. This is | |||
* a helper constructor that uses the default URI resolver implementation that FOP packages | |||
* provide ({@link DefaultResourceResolver}). | |||
* | |||
* @param defaultBaseURI the default base URI for resolving URIs against | |||
*/ | |||
public FopFactoryBuilder(URI defaultBaseURI) { | |||
this(defaultBaseURI, new DefaultResourceResolver()); | |||
} | |||
/** | |||
* A builder class for {@link FopFactory} which can be used for setting configuration. | |||
* | |||
* @param defaultBaseURI the default base URI for resolving URIs against | |||
* @param uriResolver the URI resolver | |||
*/ | |||
public FopFactoryBuilder(URI defaultBaseURI, ResourceResolver uriResolver) { | |||
this(EnvironmentalProfileFactory.createDefault(defaultBaseURI, uriResolver)); | |||
} | |||
/** | |||
* A builder class for {@link FopFactory} which can be used for setting configuration. | |||
* | |||
* @param enviro the profile of the FOP deployment environment | |||
*/ | |||
public FopFactoryBuilder(EnvironmentProfile enviro) { | |||
config = new FopFactoryConfigImpl(enviro); | |||
fopFactoryConfigBuilder = new ActiveFopFactoryConfigBuilder((FopFactoryConfigImpl) config); | |||
} | |||
/** | |||
* Returns the {@link FopFactoryConfig} which is needed to get an instance of | |||
* {@link FopFactory}. | |||
* | |||
* @return build the {@link FopFactoryConfig} | |||
* @deprecated Exposing the {@link FopFactoryConfig} is only to maintain backwards compatibility | |||
*/ | |||
public FopFactoryConfig buildConfig() { | |||
fopFactoryConfigBuilder = CompletedFopFactoryConfigBuilder.INSTANCE; | |||
return config; | |||
} | |||
/** | |||
* Builds an instance of the the {@link FopFactory}. | |||
* | |||
* @return the FopFactory instance | |||
*/ | |||
public FopFactory build() { | |||
return FopFactory.newInstance(buildConfig()); | |||
} | |||
/** | |||
* Gets the base URI used to resolve all URIs within FOP. | |||
* | |||
* @return the base URI | |||
*/ | |||
URI getBaseUri() { | |||
return config.getBaseURI(); | |||
} | |||
/** | |||
* Returns the {@link FontManager} used for managing the fonts within FOP. | |||
* | |||
* @return the font managing object | |||
*/ | |||
public FontManager getFontManager() { | |||
return config.getFontManager(); | |||
} | |||
/** | |||
* Return the {@link ImageManager} used for handling images through out FOP. | |||
* | |||
* @return the image manager | |||
*/ | |||
public ImageManager getImageManager() { | |||
return config.getImageManager(); | |||
} | |||
/** | |||
* Sets whether to include accessibility features in document creation. | |||
* | |||
* @param enableAccessibility true to set accessibility on | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setAccessibility(boolean enableAccessibility) { | |||
fopFactoryConfigBuilder.setAccessibility(enableAccessibility); | |||
return this; | |||
} | |||
/** | |||
* Sets the {@link LayoutManagerMaker} so that users can configure how FOP creates | |||
* {@link LayoutManager}s. | |||
* | |||
* @param lmMaker he layout manager maker | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setLayoutManagerMakerOverride( | |||
LayoutManagerMaker lmMaker) { | |||
fopFactoryConfigBuilder.setLayoutManagerMakerOverride(lmMaker); | |||
return this; | |||
} | |||
/** | |||
* Sets the URI resolver to be used for controlling FOP's file access. | |||
* | |||
* @param resolver the URI resolver | |||
* @return <code>this</code> | |||
* @deprecated this URIResolver will be phased out in favour of a unified URI resolution | |||
* mechanism | |||
*/ | |||
public FopFactoryBuilder setURIResolver(URIResolver resolver) { | |||
fopFactoryConfigBuilder.setURIResolver(resolver); | |||
return this; | |||
} | |||
/** | |||
* Sets the base URI, this will be used for resolving all URIs given to FOP. | |||
* | |||
* @param baseURI the base URI | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setBaseURI(URI baseURI) { | |||
fopFactoryConfigBuilder.setBaseURI(baseURI); | |||
return this; | |||
} | |||
/** | |||
* Sets the base URI for hyphenation data. | |||
* | |||
* @param hyphenationBase the hyphenation-base-URI | |||
* @return <code>this</code> | |||
* @deprecated this will be phased out in favour of a unified URI resolution mechanism | |||
*/ | |||
public FopFactoryBuilder setHyphenationBaseURI(URI hyphenationBase) { | |||
fopFactoryConfigBuilder.setHyphenationBaseURI(hyphenationBase); | |||
return this; | |||
} | |||
/** | |||
* Sets the URI resolver specific to Hyphenation data. | |||
* | |||
* @param hyphResolver the hyphenation-URI-resolver | |||
* @return <code>this</code> | |||
* @deprecated this will be phased out in favour of a unified URI resolution mechanism | |||
*/ | |||
public FopFactoryBuilder setHyphenationTreeResolver( | |||
HyphenationTreeResolver hyphResolver) { | |||
fopFactoryConfigBuilder.setHyphenationTreeResolver(hyphResolver); | |||
return this; | |||
} | |||
/** | |||
* Sets whether to perform strict validation on the FO used. | |||
* | |||
* @param validateStrictly true if the FO is to be strictly validated | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setStrictFOValidation(boolean validateStrictly) { | |||
fopFactoryConfigBuilder.setStrictFOValidation(validateStrictly); | |||
return this; | |||
} | |||
/** | |||
* Sets whether to perform strict alidation on the user-configuration. | |||
* | |||
* @param validateStrictly true if the fop conf is to be strictly validated | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setStrictUserConfigValidation( | |||
boolean validateStrictly) { | |||
fopFactoryConfigBuilder.setStrictUserConfigValidation(validateStrictly); | |||
return this; | |||
} | |||
/** | |||
* Sets whether the indent inheritance should be broken when crossing reference area boundaries. | |||
* | |||
* @param value true to break inheritance when crossing reference area boundaries | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setBreakIndentInheritanceOnReferenceAreaBoundary( | |||
boolean value) { | |||
fopFactoryConfigBuilder.setBreakIndentInheritanceOnReferenceAreaBoundary(value); | |||
return this; | |||
} | |||
/** | |||
* Sets the resolution of resolution-dependent input. | |||
* | |||
* @param dpi the source resolution | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setSourceResolution(float dpi) { | |||
fopFactoryConfigBuilder.setSourceResolution(dpi); | |||
return this; | |||
} | |||
/** | |||
* Sets the resolution of resolution-dependent output. | |||
* | |||
* @param dpi the target resolution | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setTargetResolution(float dpi) { | |||
fopFactoryConfigBuilder.setTargetResolution(dpi); | |||
return this; | |||
} | |||
/** | |||
* Sets the page height of the paginated output. | |||
* | |||
* @param pageHeight the page height | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setPageHeight(String pageHeight) { | |||
fopFactoryConfigBuilder.setPageHeight(pageHeight); | |||
return this; | |||
} | |||
/** | |||
* Sets the page width of the paginated output. | |||
* | |||
* @param pageWidth the page width | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setPageWidth(String pageWidth) { | |||
fopFactoryConfigBuilder.setPageWidth(pageWidth); | |||
return this; | |||
} | |||
/** | |||
* FOP will ignore the specified XML element namespace. | |||
* | |||
* @param namespaceURI the namespace URI to ignore | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder ignoreNamespace(String namespaceURI) { | |||
fopFactoryConfigBuilder.ignoreNamespace(namespaceURI); | |||
return this; | |||
} | |||
/** | |||
* FOP will ignore the colletion of XML element namespaces. | |||
* | |||
* @param namespaceURIs a collection of namespace URIs to ignore | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder ignoreNamespaces(Collection<String> namespaceURIs) { | |||
fopFactoryConfigBuilder.ignoreNamespaces(namespaceURIs); | |||
return this; | |||
} | |||
/** | |||
* Sets the Avalon configuration if a FOP conf is used. | |||
* | |||
* @param cfg the fop conf configuration | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setConfiguration(Configuration cfg) { | |||
fopFactoryConfigBuilder.setConfiguration(cfg); | |||
return this; | |||
} | |||
/** | |||
* Sets whether to chose a {@link Renderer} in preference to an | |||
* {@link org.apache.fop.render.intermediate.IFDocumentHandler}. | |||
* | |||
* @see {@link RendererFactory} | |||
* @param preferRenderer true to prefer {@link Renderer} | |||
* @return <code>this</code> | |||
*/ | |||
public FopFactoryBuilder setPreferRenderer(boolean preferRenderer) { | |||
fopFactoryConfigBuilder.setPreferRenderer(preferRenderer); | |||
return this; | |||
} | |||
public FopFactoryBuilder setComplexScriptFeatures(boolean csf) { | |||
fopFactoryConfigBuilder.setComplexScriptFeaturesEnabled(csf); | |||
return this; | |||
} | |||
public FopFactoryBuilder setHyphPatNames(Map<String, String> hyphPatNames) { | |||
fopFactoryConfigBuilder.setHyphPatNames(hyphPatNames); | |||
return this; | |||
} | |||
public static class FopFactoryConfigImpl implements FopFactoryConfig { | |||
private final EnvironmentProfile enviro; | |||
private final ImageManager imageManager; | |||
private boolean accessibility; | |||
private LayoutManagerMaker layoutManagerMaker; | |||
private URI baseURI; | |||
private URI hyphenationBaseURI; | |||
private HyphenationTreeResolver hyphenationTreeResolver; | |||
private boolean hasStrictFOValidation = true; | |||
private boolean hasStrictUserValidation = FopFactoryConfig.DEFAULT_STRICT_USERCONFIG_VALIDATION; | |||
private boolean breakIndentInheritanceOnReferenceBoundary | |||
= FopFactoryConfig.DEFAULT_BREAK_INDENT_INHERITANCE; | |||
private float sourceResolution = FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION; | |||
private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; | |||
private String pageHeight = FopFactoryConfig.DEFAULT_PAGE_HEIGHT; | |||
private String pageWidth = FopFactoryConfig.DEFAULT_PAGE_WIDTH; | |||
private Set<String> ignoredNamespaces = new HashSet<String>(); | |||
private URIResolver resolver; | |||
private Configuration cfg; | |||
private boolean preferRenderer; | |||
private boolean isComplexScript = true; | |||
private Map<String, String> hyphPatNames; | |||
private static final class ImageContextImpl implements ImageContext { | |||
private final FopFactoryConfig config; | |||
ImageContextImpl(FopFactoryConfig config) { | |||
this.config = config; | |||
} | |||
public float getSourceResolution() { | |||
return config.getSourceResolution(); | |||
} | |||
} | |||
FopFactoryConfigImpl(EnvironmentProfile enviro) { | |||
this.enviro = enviro; | |||
this.baseURI = enviro.getDefaultBaseURI(); | |||
this.imageManager = new ImageManager(new ImageContextImpl(this)); | |||
this.resolver = new FOURIResolver(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isAccessibilityEnabled() { | |||
return accessibility; | |||
} | |||
/** {@inheritDoc} */ | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return layoutManagerMaker; | |||
} | |||
/** {@inheritDoc} */ | |||
public ResourceResolver getNewURIResolver() { | |||
return enviro.getResourceResolver(); | |||
} | |||
/** {@inheritDoc} */ | |||
public URIResolver getURIResolver() { | |||
return resolver; | |||
} | |||
/** {@inheritDoc} */ | |||
public URI getBaseURI() { | |||
return baseURI; | |||
} | |||
/** {@inheritDoc} */ | |||
public URI getHyphenationBaseURI() { | |||
return hyphenationBaseURI; | |||
} | |||
/** {@inheritDoc} */ | |||
public HyphenationTreeResolver getHyphenationTreeResolver() { | |||
return hyphenationTreeResolver; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean validateStrictly() { | |||
return hasStrictFOValidation; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean validateUserConfigStrictly() { | |||
return hasStrictUserValidation; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { | |||
return breakIndentInheritanceOnReferenceBoundary; | |||
} | |||
/** {@inheritDoc} */ | |||
public float getSourceResolution() { | |||
return sourceResolution; | |||
} | |||
/** {@inheritDoc} */ | |||
public float getTargetResolution() { | |||
return targetResolution; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getPageHeight() { | |||
return pageHeight; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getPageWidth() { | |||
return pageWidth; | |||
} | |||
/** {@inheritDoc} */ | |||
public Set<String> getIgnoredNamespaces() { | |||
return Collections.unmodifiableSet(ignoredNamespaces); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isNamespaceIgnored(String namespace) { | |||
return ignoredNamespaces.contains(namespace); | |||
} | |||
/** {@inheritDoc} */ | |||
public Configuration getUserConfig() { | |||
return cfg; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean preferRenderer() { | |||
return preferRenderer; | |||
} | |||
/** {@inheritDoc} */ | |||
public FontManager getFontManager() { | |||
return enviro.getFontManager(); | |||
} | |||
/** {@inheritDoc} */ | |||
public ImageManager getImageManager() { | |||
return imageManager; | |||
} | |||
public boolean isComplexScriptFeaturesEnabled() { | |||
return isComplexScript; | |||
} | |||
public Map<String, String> getHyphPatNames() { | |||
return hyphPatNames; | |||
} | |||
} | |||
private interface FopFactoryConfigBuilder { | |||
void setAccessibility(boolean enableAccessibility); | |||
void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker); | |||
void setURIResolver(URIResolver resolver); | |||
void setBaseURI(URI baseURI); | |||
void setHyphenationBaseURI(URI hyphenationBase); | |||
void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver); | |||
void setStrictFOValidation(boolean validateStrictly); | |||
void setStrictUserConfigValidation(boolean validateStrictly); | |||
void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value); | |||
void setSourceResolution(float dpi); | |||
void setTargetResolution(float dpi); | |||
void setPageHeight(String pageHeight); | |||
void setPageWidth(String pageWidth); | |||
void ignoreNamespace(String namespaceURI); | |||
void ignoreNamespaces(Collection<String> namespaceURIs); | |||
void setConfiguration(Configuration cfg); | |||
void setPreferRenderer(boolean preferRenderer); | |||
void setComplexScriptFeaturesEnabled(boolean csf); | |||
void setHyphPatNames(Map<String, String> hyphPatNames); | |||
} | |||
private static final class CompletedFopFactoryConfigBuilder implements FopFactoryConfigBuilder { | |||
private static final CompletedFopFactoryConfigBuilder INSTANCE | |||
= new CompletedFopFactoryConfigBuilder(); | |||
private void throwIllegalStateException() { | |||
throw new IllegalStateException("The final FOP Factory configuration has already been built"); | |||
} | |||
public void setAccessibility(boolean enableAccessibility) { | |||
throwIllegalStateException(); | |||
} | |||
public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { | |||
throwIllegalStateException(); | |||
} | |||
public void setURIResolver(URIResolver resolver) { | |||
throwIllegalStateException(); | |||
} | |||
public void setBaseURI(URI baseURI) { | |||
throwIllegalStateException(); | |||
} | |||
public void setHyphenationBaseURI(URI hyphenationBase) { | |||
throwIllegalStateException(); | |||
} | |||
public void setHyphenationTreeResolver( | |||
HyphenationTreeResolver hyphResolver) { | |||
throwIllegalStateException(); | |||
} | |||
public void setStrictFOValidation(boolean validateStrictly) { | |||
throwIllegalStateException(); | |||
} | |||
public void setStrictUserConfigValidation(boolean validateStrictly) { | |||
throwIllegalStateException(); | |||
} | |||
public void setBreakIndentInheritanceOnReferenceAreaBoundary( | |||
boolean value) { | |||
throwIllegalStateException(); | |||
} | |||
public void setSourceResolution(float dpi) { | |||
throwIllegalStateException(); | |||
} | |||
public void setTargetResolution(float dpi) { | |||
throwIllegalStateException(); | |||
} | |||
public void setPageHeight(String pageHeight) { | |||
throwIllegalStateException(); | |||
} | |||
public void setPageWidth(String pageWidth) { | |||
throwIllegalStateException(); | |||
} | |||
public void ignoreNamespace(String namespaceURI) { | |||
throwIllegalStateException(); | |||
} | |||
public void ignoreNamespaces(Collection<String> namespaceURIs) { | |||
throwIllegalStateException(); | |||
} | |||
public void setConfiguration(Configuration cfg) { | |||
throwIllegalStateException(); | |||
} | |||
public void setPreferRenderer(boolean preferRenderer) { | |||
throwIllegalStateException(); | |||
} | |||
public void setComplexScriptFeaturesEnabled(boolean csf) { | |||
throwIllegalStateException(); | |||
} | |||
public void setHyphPatNames(Map<String, String> hyphPatNames) { | |||
throwIllegalStateException(); | |||
} | |||
} | |||
private static final class ActiveFopFactoryConfigBuilder implements FopFactoryConfigBuilder { | |||
private final FopFactoryConfigImpl config; | |||
private ActiveFopFactoryConfigBuilder(FopFactoryConfigImpl config) { | |||
this.config = config; | |||
} | |||
public void setAccessibility(boolean enableAccessibility) { | |||
config.accessibility = enableAccessibility; | |||
} | |||
public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { | |||
config.layoutManagerMaker = lmMaker; | |||
} | |||
public void setURIResolver(URIResolver resolver) { | |||
config.resolver = resolver; | |||
} | |||
public void setBaseURI(URI baseURI) { | |||
config.baseURI = baseURI; | |||
} | |||
public void setHyphenationBaseURI(URI hyphenationBase) { | |||
config.hyphenationBaseURI = hyphenationBase; | |||
} | |||
public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) { | |||
config.hyphenationTreeResolver = hyphResolver; | |||
} | |||
public void setStrictFOValidation(boolean validateStrictly) { | |||
config.hasStrictFOValidation = validateStrictly; | |||
} | |||
public void setStrictUserConfigValidation( | |||
boolean validateStrictly) { | |||
config.hasStrictUserValidation = validateStrictly; | |||
} | |||
public void setBreakIndentInheritanceOnReferenceAreaBoundary( | |||
boolean value) { | |||
config.breakIndentInheritanceOnReferenceBoundary = value; | |||
} | |||
public void setSourceResolution(float dpi) { | |||
config.sourceResolution = dpi; | |||
} | |||
public void setTargetResolution(float dpi) { | |||
config.targetResolution = dpi; | |||
} | |||
public void setPageHeight(String pageHeight) { | |||
config.pageHeight = pageHeight; | |||
} | |||
public void setPageWidth(String pageWidth) { | |||
config.pageWidth = pageWidth; | |||
} | |||
public void ignoreNamespace(String namespaceURI) { | |||
config.ignoredNamespaces.add(namespaceURI); | |||
} | |||
public void ignoreNamespaces( | |||
Collection<String> namespaceURIs) { | |||
config.ignoredNamespaces.addAll(namespaceURIs); | |||
} | |||
public void setConfiguration(Configuration cfg) { | |||
config.cfg = cfg; | |||
} | |||
public void setPreferRenderer(boolean preferRenderer) { | |||
config.preferRenderer = preferRenderer; | |||
} | |||
public void setComplexScriptFeaturesEnabled(boolean csf) { | |||
config.isComplexScript = csf; | |||
} | |||
public void setHyphPatNames(Map<String, String> hyphPatNames) { | |||
config.hyphPatNames = hyphPatNames; | |||
} | |||
} | |||
} |
@@ -0,0 +1,159 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
import java.net.URI; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.xml.transform.URIResolver; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.hyphenation.HyphenationTreeResolver; | |||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | |||
/** | |||
* The configuration data for a {@link FopFactory} instance. | |||
*/ | |||
public interface FopFactoryConfig { | |||
/** Defines if FOP should use an alternative rule to determine text indents */ | |||
boolean DEFAULT_BREAK_INDENT_INHERITANCE = false; | |||
/** Defines if FOP should validate the user config strictly */ | |||
boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true; | |||
/** Defines if FOP should use strict validation for FO and user config */ | |||
boolean DEFAULT_STRICT_FO_VALIDATION = true; | |||
/** Defines the default page-width */ | |||
String DEFAULT_PAGE_WIDTH = "8.26in"; | |||
/** Defines the default page-height */ | |||
String DEFAULT_PAGE_HEIGHT = "11in"; | |||
/** Defines the default source resolution (72dpi) for FOP */ | |||
float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi | |||
/** Defines the default target resolution (72dpi) for FOP */ | |||
float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi | |||
/** | |||
* Whether accessibility features are switched on. | |||
* | |||
* @return true if accessibility features have been requested | |||
*/ | |||
boolean isAccessibilityEnabled(); | |||
/** @see {@link FopFactory#getLayoutManagerMakerOverride()} */ | |||
LayoutManagerMaker getLayoutManagerMakerOverride(); | |||
/** | |||
* The URI resolver used through-out FOP for controlling all file access. | |||
* | |||
* @return the URI resolver | |||
*/ | |||
ResourceResolver getNewURIResolver(); | |||
/** | |||
* The URI resolver for controlling file access. | |||
* | |||
* @return the URI resolver | |||
* @deprecated please use the {@link #getNewURIResolver()} method. | |||
*/ | |||
URIResolver getURIResolver(); | |||
/** | |||
* The base URI from which URIs are resolved against. | |||
* | |||
* @return the base URI | |||
*/ | |||
URI getBaseURI(); | |||
/** | |||
* The base URI of hyphenation data. | |||
* | |||
* @return the hyphenation-base-URI | |||
* @deprecated this intelligence can be configured in the URI resolver set in | |||
* {@link #getNewURIResolver()} | |||
*/ | |||
URI getHyphenationBaseURI(); | |||
/** | |||
* The URI resolver for resolving hyphenation data. | |||
* | |||
* @return the hyphenation-URI-resolver | |||
* @deprecated this intelligence can be configured in the URI resolver set in | |||
* {@link #getNewURIResolver()} | |||
*/ | |||
HyphenationTreeResolver getHyphenationTreeResolver(); | |||
/** @see {@link FopFactory#validateStrictly()} */ | |||
boolean validateStrictly(); | |||
/** @see {@link FopFactory#validateUserConfigStrictly()} */ | |||
boolean validateUserConfigStrictly(); | |||
/** @see {@link FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()} */ | |||
boolean isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
/** @see {@link FopFactory#getSourceResolution()} */ | |||
float getSourceResolution(); | |||
/** @see {@link FopFactory#getTargetResolution()} */ | |||
float getTargetResolution(); | |||
/** @see {@link FopFactory#getPageHeight()} */ | |||
String getPageHeight(); | |||
/** @see {@link FopFactory#getPageWidth()} */ | |||
String getPageWidth(); | |||
/** @see {@link FopFactory#getIgnoredNamespace()} */ | |||
Set<String> getIgnoredNamespaces(); | |||
/** @see {@link FopFactory#isNamespaceIgnored(String)} */ | |||
boolean isNamespaceIgnored(String namespace); | |||
/** | |||
* Returns the Avalon {@link Configuration} object. | |||
* | |||
* @return the Avalon config object | |||
*/ | |||
Configuration getUserConfig(); | |||
/** @see {@link org.apache.fop.render.RendererFactory#isRendererPreferred()} */ | |||
boolean preferRenderer(); | |||
/** @see {@link FopFactory#getFontManager()} */ | |||
FontManager getFontManager(); | |||
/** @see {@link FopFactory#getImageManager()} */ | |||
ImageManager getImageManager(); | |||
boolean isComplexScriptFeaturesEnabled(); | |||
Map<String, String> getHyphPatNames(); | |||
} |
@@ -1,406 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
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.xmlgraphics.image.GraphicsConstants; | |||
import org.apache.xmlgraphics.image.loader.spi.ImageImplRegistry; | |||
import org.apache.xmlgraphics.image.loader.util.Penalty; | |||
import org.apache.fop.fonts.FontManagerConfigurator; | |||
import org.apache.fop.hyphenation.HyphenationTreeCache; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* FopFactory configurator | |||
*/ | |||
public class FopFactoryConfigurator { | |||
/** Defines if FOP should use an alternative rule to determine text indents */ | |||
public static final boolean DEFAULT_BREAK_INDENT_INHERITANCE = false; | |||
/** Defines if FOP should validate the user config strictly */ | |||
public static final boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true; | |||
/** Defines if FOP should use strict validation for FO and user config */ | |||
public static final boolean DEFAULT_STRICT_FO_VALIDATION = true; | |||
/** Defines the default page-width */ | |||
public static final String DEFAULT_PAGE_WIDTH = "8.26in"; | |||
/** Defines the default page-height */ | |||
public static final String DEFAULT_PAGE_HEIGHT = "11in"; | |||
/** Defines the default source resolution (72dpi) for FOP */ | |||
public static final float DEFAULT_SOURCE_RESOLUTION = GraphicsConstants.DEFAULT_DPI; //dpi | |||
/** Defines the default target resolution (72dpi) for FOP */ | |||
public static final float DEFAULT_TARGET_RESOLUTION = GraphicsConstants.DEFAULT_DPI; //dpi | |||
/** Defines the default complex script support */ | |||
public static final boolean DEFAULT_COMPLEX_SCRIPT_FEATURES = true; | |||
private static final String PREFER_RENDERER = "prefer-renderer"; | |||
/** logger instance */ | |||
private final Log log = LogFactory.getLog(FopFactoryConfigurator.class); | |||
/** Fop factory */ | |||
private FopFactory factory = null; | |||
/** Fop factory configuration */ | |||
private Configuration cfg = null; | |||
/** The base URI of the configuration file **/ | |||
private URI baseURI = null; | |||
/** | |||
* Default constructor | |||
* @param factory fop factory | |||
*/ | |||
public FopFactoryConfigurator(FopFactory factory) { | |||
super(); | |||
this.factory = factory; | |||
} | |||
/** | |||
* Initializes user agent settings from the user configuration | |||
* file, if present: baseURL, resolution, default page size,... | |||
* @param factory fop factory | |||
* @throws FOPException fop exception | |||
*/ | |||
public void configure(FopFactory factory) throws FOPException { // CSOK: MethodLength | |||
// strict configuration | |||
if (cfg.getChild("strict-configuration", false) != null) { | |||
try { | |||
factory.setStrictUserConfigValidation( | |||
cfg.getChild("strict-configuration").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, false); | |||
} | |||
} | |||
boolean strict = factory.validateUserConfigStrictly(); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Initializing FopFactory Configuration" | |||
+ "with " + (strict ? "strict" : "permissive") + " validation"); | |||
} | |||
if (cfg.getChild("accessibility", false) != null) { | |||
try { | |||
this.factory.setAccessibility( | |||
cfg.getChild("accessibility").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// strict fo validation | |||
if (cfg.getChild("strict-validation", false) != null) { | |||
try { | |||
factory.setStrictValidation( | |||
cfg.getChild("strict-validation").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// base definitions for relative path resolution | |||
if (cfg.getChild("base", false) != null) { | |||
String path = cfg.getChild("base").getValue(null); | |||
if (baseURI != null) { | |||
path = baseURI.resolve(path).normalize().toString(); | |||
} | |||
try { | |||
factory.setBaseURL(path); | |||
} catch (MalformedURLException mfue) { | |||
LogUtil.handleException(log, mfue, strict); | |||
} | |||
} | |||
if (cfg.getChild("hyphenation-base", false) != null) { | |||
String path = cfg.getChild("hyphenation-base").getValue(null); | |||
if (baseURI != null) { | |||
path = baseURI.resolve(path).normalize().toString(); | |||
} | |||
try { | |||
factory.setHyphenBaseURL(path); | |||
} catch (MalformedURLException mfue) { | |||
LogUtil.handleException(log, mfue, strict); | |||
} | |||
} | |||
/** | |||
* Read configuration elements hyphenation-pattern, | |||
* construct a map ll_CC => filename, and set it on the factory | |||
*/ | |||
Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern"); | |||
if (hyphPatConfig.length != 0) { | |||
Map/*<String,String>*/ hyphPatNames = new HashMap/*<String,String>*/(); | |||
for (int i = 0; i < hyphPatConfig.length; ++i) { | |||
String lang; | |||
String country; | |||
String filename; | |||
StringBuffer error = new StringBuffer(); | |||
String location = hyphPatConfig[i].getLocation(); | |||
lang = hyphPatConfig[i].getAttribute("lang", null); | |||
if (lang == null) { | |||
addError("The lang attribute of a hyphenation-pattern configuration" | |||
+ " element must exist (" + location + ")", error); | |||
} else if (!lang.matches("[a-zA-Z]{2}")) { | |||
addError("The lang attribute of a hyphenation-pattern configuration" | |||
+ " element must consist of exactly two letters (" | |||
+ location + ")", error); | |||
} | |||
lang = lang.toLowerCase(); | |||
country = hyphPatConfig[i].getAttribute("country", null); | |||
if ("".equals(country)) { | |||
country = null; | |||
} | |||
if (country != null) { | |||
if (!country.matches("[a-zA-Z]{2}")) { | |||
addError("The country attribute of a hyphenation-pattern configuration" | |||
+ " element must consist of exactly two letters (" | |||
+ location + ")", error); | |||
} | |||
country = country.toUpperCase(); | |||
} | |||
filename = hyphPatConfig[i].getValue(null); | |||
if (filename == null) { | |||
addError("The value of a hyphenation-pattern configuration" | |||
+ " element may not be empty (" + location + ")", error); | |||
} | |||
if (error.length() != 0) { | |||
LogUtil.handleError(log, error.toString(), strict); | |||
continue; | |||
} | |||
String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); | |||
hyphPatNames.put(llccKey, filename); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Using hyphenation pattern filename " + filename | |||
+ " for lang=\"" + lang + "\"" | |||
+ (country != null ? ", country=\"" + country + "\"" : "")); | |||
} | |||
} | |||
factory.setHyphPatNames(hyphPatNames); | |||
} | |||
// renderer options | |||
if (cfg.getChild("source-resolution", false) != null) { | |||
factory.setSourceResolution( | |||
cfg.getChild("source-resolution").getValueAsFloat( | |||
FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION)); | |||
if (log.isDebugEnabled()) { | |||
log.debug("source-resolution set to: " + factory.getSourceResolution() | |||
+ "dpi (px2mm=" + factory.getSourcePixelUnitToMillimeter() + ")"); | |||
} | |||
} | |||
if (cfg.getChild("target-resolution", false) != null) { | |||
factory.setTargetResolution( | |||
cfg.getChild("target-resolution").getValueAsFloat( | |||
FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION)); | |||
if (log.isDebugEnabled()) { | |||
log.debug("target-resolution set to: " + factory.getTargetResolution() | |||
+ "dpi (px2mm=" + factory.getTargetPixelUnitToMillimeter() | |||
+ ")"); | |||
} | |||
} | |||
if (cfg.getChild("break-indent-inheritance", false) != null) { | |||
try { | |||
factory.setBreakIndentInheritanceOnReferenceAreaBoundary( | |||
cfg.getChild("break-indent-inheritance").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
Configuration pageConfig = cfg.getChild("default-page-settings"); | |||
if (pageConfig.getAttribute("height", null) != null) { | |||
factory.setPageHeight( | |||
pageConfig.getAttribute("height", FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT)); | |||
if (log.isInfoEnabled()) { | |||
log.info("Default page-height set to: " + factory.getPageHeight()); | |||
} | |||
} | |||
if (pageConfig.getAttribute("width", null) != null) { | |||
factory.setPageWidth( | |||
pageConfig.getAttribute("width", FopFactoryConfigurator.DEFAULT_PAGE_WIDTH)); | |||
if (log.isInfoEnabled()) { | |||
log.info("Default page-width set to: " + factory.getPageWidth()); | |||
} | |||
} | |||
// prefer Renderer over IFDocumentHandler | |||
if (cfg.getChild(PREFER_RENDERER, false) != null) { | |||
try { | |||
factory.getRendererFactory().setRendererPreferred( | |||
cfg.getChild(PREFER_RENDERER).getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// configure complex script support | |||
Configuration csConfig = cfg.getChild("complex-scripts"); | |||
if (csConfig != null) { | |||
this.factory.setComplexScriptFeaturesEnabled | |||
(!csConfig.getAttributeAsBoolean ( "disabled", false )); | |||
} | |||
// configure font manager | |||
new FontManagerConfigurator(cfg, baseURI).configure(factory.getFontManager(), strict); | |||
// configure image loader framework | |||
configureImageLoading(cfg.getChild("image-loading", false), strict); | |||
} | |||
private static void addError(String message, StringBuffer error) { | |||
if (error.length() != 0) { | |||
error.append(". "); | |||
} | |||
error.append(message); | |||
} | |||
private void configureImageLoading(Configuration parent, boolean strict) throws FOPException { | |||
if (parent == null) { | |||
return; | |||
} | |||
ImageImplRegistry registry = factory.getImageManager().getRegistry(); | |||
Configuration[] penalties = parent.getChildren("penalty"); | |||
try { | |||
for (int i = 0, c = penalties.length; i < c; i++) { | |||
Configuration penaltyCfg = penalties[i]; | |||
String className = penaltyCfg.getAttribute("class"); | |||
String value = penaltyCfg.getAttribute("value"); | |||
Penalty p = null; | |||
if (value.toUpperCase().startsWith("INF")) { | |||
p = Penalty.INFINITE_PENALTY; | |||
} else { | |||
try { | |||
p = Penalty.toPenalty(Integer.parseInt(value)); | |||
} catch (NumberFormatException nfe) { | |||
LogUtil.handleException(log, nfe, strict); | |||
} | |||
} | |||
if (p != null) { | |||
registry.setAdditionalPenalty(className, p); | |||
} | |||
} | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
/** | |||
* Set the user configuration. | |||
* @param userConfigFile the configuration file | |||
* @throws IOException if an I/O error occurs | |||
* @throws SAXException if a parsing error occurs | |||
*/ | |||
public void setUserConfig(File userConfigFile) throws SAXException, IOException { | |||
try { | |||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); | |||
setUserConfig(cfgBuilder.buildFromFile(userConfigFile)); | |||
} catch (ConfigurationException e) { | |||
throw new FOPException(e); | |||
} | |||
} | |||
/** | |||
* Set the user configuration from an URI. | |||
* @param uri the URI to the configuration file | |||
* @throws IOException if an I/O error occurs | |||
* @throws SAXException if a parsing error occurs | |||
*/ | |||
public void setUserConfig(String uri) throws SAXException, IOException { | |||
try { | |||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); | |||
setUserConfig(cfgBuilder.build(uri)); | |||
} catch (ConfigurationException e) { | |||
throw new FOPException(e); | |||
} | |||
} | |||
/** | |||
* Set the user configuration. | |||
* @param cfg avalon configuration | |||
* @throws FOPException if a configuration problem occurs | |||
*/ | |||
public void setUserConfig(Configuration cfg) throws FOPException { | |||
this.cfg = cfg; | |||
setBaseURI(); | |||
configure(this.factory); | |||
} | |||
/** | |||
* Get the avalon user configuration. | |||
* @return the user configuration | |||
*/ | |||
public Configuration getUserConfig() { | |||
return this.cfg; | |||
} | |||
/** | |||
* @return the baseURI | |||
*/ | |||
public URI getBaseURI() { | |||
return baseURI; | |||
} | |||
/** | |||
* @param baseURI the baseURI to set | |||
*/ | |||
public void setBaseURI(URI baseURI) { | |||
this.baseURI = baseURI; | |||
} | |||
private void setBaseURI() throws FOPException { | |||
String loc = cfg.getLocation(); | |||
try { | |||
if (loc != null && loc.startsWith("file:")) { | |||
baseURI = new URI(loc); | |||
baseURI = baseURI.resolve(".").normalize(); | |||
} | |||
if (baseURI == null) { | |||
baseURI = new File(System.getProperty("user.dir")).toURI(); | |||
} | |||
} catch (URISyntaxException e) { | |||
throw new FOPException(e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps.io; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
public class DefaultResourceResolver implements ResourceResolver { | |||
public Resource getResource(URI uri) throws IOException { | |||
try { | |||
return new Resource(uri.toURL().openStream()); | |||
} catch (MalformedURLException mue) { | |||
throw new RuntimeException(mue); | |||
} | |||
} | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
throw new UnsupportedOperationException(); | |||
} | |||
public static URIResolverWrapper createDefaultWrapper() { | |||
// Not sure if this is the right place for this, but I don't have any better ideas as of yet | |||
URI thisUri = new File(".").getAbsoluteFile().toURI(); | |||
return new URIResolverWrapper(thisUri, new DefaultResourceResolver()); | |||
} | |||
} |
@@ -17,7 +17,7 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.apps; | |||
package org.apache.fop.apps.io; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.File; | |||
@@ -37,6 +37,7 @@ import javax.xml.transform.stream.StreamSource; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.xmlgraphics.util.io.Base64EncodeStream; | |||
import org.apache.xmlgraphics.util.uri.CommonURIResolver; |
@@ -17,36 +17,43 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.render; | |||
package org.apache.fop.apps.io; | |||
import javax.xml.transform.Source; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fonts.FontResolver; | |||
import java.io.FilterInputStream; | |||
import java.io.InputStream; | |||
/** | |||
* Default FontResolver implementation which uses the FOUserAgent to resolve font URIs. | |||
* This class represents a resolved resource. The type property is used by FOP to identify the resource | |||
* content. | |||
* | |||
*/ | |||
public class DefaultFontResolver implements FontResolver { | |||
public class Resource extends FilterInputStream { | |||
private FOUserAgent userAgent; | |||
private final String type; | |||
/** | |||
* Main constructor. | |||
* @param userAgent the user agent | |||
* @param type resource type | |||
* @param inputStream input stream of the resource | |||
*/ | |||
public DefaultFontResolver(FOUserAgent userAgent) { | |||
this.userAgent = userAgent; | |||
public Resource(String type, InputStream inputStream) { | |||
super(inputStream); | |||
this.type = type; | |||
} | |||
/** {@inheritDoc} */ | |||
public Source resolve(String href) { | |||
return userAgent.resolveURI(href, userAgent.getFactory().getFontManager().getFontBaseURL()); | |||
/** | |||
* Constructs a resource of 'unknown' type. | |||
* | |||
* @param inputStream input stream of the resource | |||
*/ | |||
public Resource(InputStream inputStream) { | |||
this("unknown", inputStream); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isComplexScriptFeaturesEnabled() { | |||
return userAgent.isComplexScriptFeaturesEnabled(); | |||
/** | |||
* @return the resource type | |||
*/ | |||
public String getType() { | |||
return this.type; | |||
} | |||
} |
@@ -17,15 +17,16 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.config; | |||
package org.apache.fop.apps.io; | |||
/** | |||
* this font has a malformed embed-url | |||
*/ | |||
public class FontEmbedUrlMalformedTestCase extends BaseDestructiveUserConfigTest { | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
public interface ResourceResolver { | |||
Resource getResource(URI uri) throws IOException; | |||
OutputStream getOutputStream(URI uri) throws IOException; | |||
@Override | |||
public String getUserConfigFilename() { | |||
return "test_font_embedurl_malformed.xconf"; | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps.io; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
public class URIResolverWrapper { | |||
private final URI baseUri; | |||
private final ResourceResolver uriResolver; | |||
public URIResolverWrapper(URI baseUri, ResourceResolver uriResolver) { | |||
this.baseUri = baseUri; | |||
this.uriResolver = uriResolver; | |||
} | |||
public URI getBaseURI() { | |||
return baseUri; | |||
} | |||
public InputStream resolveIn(String stringUri) throws IOException, URISyntaxException { | |||
return resolveIn(cleanURI(stringUri)); | |||
} | |||
public InputStream resolveIn(URI uri) throws IOException { | |||
return uriResolver.getResource(resolveFromBase(uri)); | |||
} | |||
public OutputStream resolveOut(URI uri) throws IOException { | |||
return uriResolver.getOutputStream(resolveFromBase(uri)); | |||
} | |||
private URI resolveFromBase(URI uri) { | |||
return baseUri.resolve(uri); | |||
} | |||
public static URI cleanURI(String base) throws URISyntaxException { | |||
// replace back slash with forward slash to ensure windows file:/// URLS are supported | |||
if (base == null) { | |||
return null; | |||
} | |||
String fixedUri = base.replace('\\', '/'); | |||
fixedUri = fixedUri.replace(" ", "%20"); | |||
URI baseURI = new URI(fixedUri); | |||
return baseURI; | |||
} | |||
public static URI getBaseURI(String base) throws URISyntaxException { | |||
String path = base + (base.endsWith("/") ? "" : "/"); | |||
return cleanURI(path); | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
<HTML> | |||
<TITLE>org.apache.fop.io Package</TITLE> | |||
<BODY> | |||
<P>Classes that control all IO in FOP.</P> | |||
</BODY> | |||
</HTML> |
@@ -104,7 +104,7 @@ public class AreaTreeHandler extends FOEventHandler { | |||
setupModel(userAgent, outputFormat, stream); | |||
this.lmMaker = userAgent.getFactory().getLayoutManagerMakerOverride(); | |||
this.lmMaker = userAgent.getLayoutManagerMakerOverride(); | |||
if (lmMaker == null) { | |||
lmMaker = new LayoutManagerMapping(); | |||
} |
@@ -132,7 +132,7 @@ public class AreaTreeParser { | |||
*/ | |||
public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) { | |||
ElementMappingRegistry elementMappingRegistry | |||
= userAgent.getFactory().getElementMappingRegistry(); | |||
= userAgent.getElementMappingRegistry(); | |||
return new Handler(treeModel, userAgent, elementMappingRegistry); | |||
} | |||
@@ -292,7 +292,7 @@ public class AreaTreeParser { | |||
} | |||
} else { | |||
ContentHandlerFactoryRegistry registry | |||
= userAgent.getFactory().getContentHandlerFactoryRegistry(); | |||
= userAgent.getContentHandlerFactoryRegistry(); | |||
ContentHandlerFactory factory = registry.getFactory(uri); | |||
if (factory != null) { | |||
delegate = factory.createContentHandler(); | |||
@@ -1102,7 +1102,7 @@ public class AreaTreeParser { | |||
bkg.setURL(uri); | |||
try { | |||
ImageManager manager = userAgent.getFactory().getImageManager(); | |||
ImageManager manager = userAgent.getImageManager(); | |||
ImageSessionContext sessionContext | |||
= userAgent.getImageSessionContext(); | |||
ImageInfo info = manager.getImageInfo(uri, sessionContext); |
@@ -39,9 +39,10 @@ import org.apache.fop.Version; | |||
import org.apache.fop.accessibility.Accessibility; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopConfParser; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.FopFactoryBuilder; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.pdf.PDFAMode; | |||
import org.apache.fop.pdf.PDFEncryptionManager; | |||
import org.apache.fop.pdf.PDFEncryptionParams; | |||
@@ -51,12 +52,13 @@ import org.apache.fop.render.awt.AWTRenderer; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFSerializer; | |||
import org.apache.fop.render.pdf.PDFConfigurationConstants; | |||
import org.apache.fop.render.print.PagesMode; | |||
import org.apache.fop.render.print.PrintRenderer; | |||
import org.apache.fop.render.xml.XMLRenderer; | |||
import org.apache.fop.util.CommandLineLogger; | |||
import static org.apache.fop.render.pdf.PDFRendererConfigOptions.ENCRYPTION_PARAMS; | |||
/** | |||
* Options parses the commandline arguments | |||
*/ | |||
@@ -116,12 +118,14 @@ public class CommandLineOptions { | |||
private Map renderingOptions = new java.util.HashMap(); | |||
/* target resolution (for the user agent) */ | |||
private int targetResolution = 0; | |||
private boolean strictValidation = true; | |||
/* control memory-conservation policy */ | |||
private boolean conserveMemoryPolicy = false; | |||
/* true if a complex script features are enabled */ | |||
private boolean useComplexScriptFeatures = true; | |||
private FopFactory factory = FopFactory.newInstance(); | |||
private FopFactory factory; | |||
private FOUserAgent foUserAgent; | |||
private InputHandler inputHandler; | |||
@@ -183,9 +187,10 @@ public class CommandLineOptions { | |||
addXSLTParameter("fop-output-format", getOutputFormat()); | |||
addXSLTParameter("fop-version", Version.getVersion()); | |||
foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy); | |||
if (!useComplexScriptFeatures) { | |||
foUserAgent.setComplexScriptFeaturesEnabled(false); | |||
} | |||
// TODO: Handle this!! | |||
//if (!useComplexScriptFeatures) { | |||
// foUserAgent.setComplexScriptFeaturesEnabled(false); | |||
//} | |||
} else { | |||
return false; | |||
} | |||
@@ -225,9 +230,7 @@ public class CommandLineOptions { | |||
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode) | |||
&& mimicRenderer != null) { | |||
// render from FO to Intermediate Format | |||
IFSerializer serializer = new IFSerializer(); | |||
serializer.setContext(new IFContext(foUserAgent)); | |||
IFSerializer serializer = new IFSerializer(new IFContext(foUserAgent)); | |||
IFDocumentHandler targetHandler | |||
= foUserAgent.getRendererFactory().createDocumentHandler( | |||
foUserAgent, mimicRenderer); | |||
@@ -288,7 +291,7 @@ public class CommandLineOptions { | |||
} else if (args[i].equals("-d")) { | |||
setLogOption("debug", "debug"); | |||
} else if (args[i].equals("-r")) { | |||
factory.setStrictValidation(false); | |||
strictValidation = false; | |||
} else if (args[i].equals("-conserve")) { | |||
conserveMemoryPolicy = true; | |||
} else if (args[i].equals("-flush")) { | |||
@@ -819,15 +822,14 @@ public class CommandLineOptions { | |||
} | |||
private PDFEncryptionParams getPDFEncryptionParams() throws FOPException { | |||
PDFEncryptionParams params = (PDFEncryptionParams)renderingOptions.get( | |||
PDFConfigurationConstants.ENCRYPTION_PARAMS); | |||
PDFEncryptionParams params = (PDFEncryptionParams) renderingOptions.get(ENCRYPTION_PARAMS); | |||
if (params == null) { | |||
if (!PDFEncryptionManager.checkAvailableAlgorithms()) { | |||
throw new FOPException("PDF encryption requested but it is not available." | |||
+ " Please make sure MD5 and RC4 algorithms are available."); | |||
} | |||
params = new PDFEncryptionParams(); | |||
renderingOptions.put(PDFConfigurationConstants.ENCRYPTION_PARAMS, params); | |||
renderingOptions.put(ENCRYPTION_PARAMS, params); | |||
} | |||
return params; | |||
} | |||
@@ -860,7 +862,7 @@ public class CommandLineOptions { | |||
throw new FOPException("You must specify a PDF profile"); | |||
} else { | |||
String profile = args[i + 1]; | |||
PDFAMode pdfAMode = PDFAMode.valueOf(profile); | |||
PDFAMode pdfAMode = PDFAMode.getValueOf(profile); | |||
if (pdfAMode != null && pdfAMode != PDFAMode.DISABLED) { | |||
if (renderingOptions.get("pdf-a-mode") != null) { | |||
throw new FOPException("PDF/A mode already set"); | |||
@@ -868,7 +870,7 @@ public class CommandLineOptions { | |||
renderingOptions.put("pdf-a-mode", pdfAMode.getName()); | |||
return 1; | |||
} else { | |||
PDFXMode pdfXMode = PDFXMode.valueOf(profile); | |||
PDFXMode pdfXMode = PDFXMode.getValueOf(profile); | |||
if (pdfXMode != null && pdfXMode != PDFXMode.DISABLED) { | |||
if (renderingOptions.get("pdf-x-mode") != null) { | |||
throw new FOPException("PDF/X mode already set"); | |||
@@ -1027,14 +1029,18 @@ public class CommandLineOptions { | |||
* @throws IOException | |||
*/ | |||
private void setUserConfig() throws FOPException, IOException { | |||
FopFactoryBuilder fopFactoryBuilder; | |||
if (userConfigFile == null) { | |||
return; | |||
} | |||
try { | |||
factory.setUserConfig(userConfigFile); | |||
} catch (SAXException e) { | |||
throw new FOPException(e); | |||
fopFactoryBuilder = new FopFactoryBuilder(new File(".").toURI()); | |||
} else { | |||
try { | |||
fopFactoryBuilder = new FopConfParser(userConfigFile).getFopFactoryBuilder(); | |||
} catch (SAXException e) { | |||
throw new FOPException(e); | |||
} | |||
fopFactoryBuilder.setStrictFOValidation(strictValidation); | |||
} | |||
factory = fopFactoryBuilder.build(); | |||
} | |||
/** | |||
@@ -1390,13 +1396,7 @@ public class CommandLineOptions { | |||
} | |||
private void flushCache() throws FOPException { | |||
FontManager fontManager = factory.getFontManager(); | |||
File cacheFile = fontManager.getCacheFile(); | |||
if (!fontManager.deleteCache()) { | |||
System.err.println("Failed to flush the font cache file '" | |||
+ cacheFile + "'."); | |||
System.exit(1); | |||
} | |||
factory.getFontManager().deleteCache(); | |||
} | |||
} | |||
@@ -62,7 +62,7 @@ public class IFInputHandler extends InputHandler { | |||
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) | |||
throws FOPException { | |||
IFDocumentHandler documentHandler | |||
= userAgent.getFactory().getRendererFactory().createDocumentHandler( | |||
= userAgent.getRendererFactory().createDocumentHandler( | |||
userAgent, outputFormat); | |||
try { | |||
documentHandler.setResult(new StreamResult(out)); |
@@ -51,7 +51,6 @@ import org.apache.fop.ResourceEventProducer; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.render.awt.viewer.Renderable; | |||
/** | |||
@@ -103,25 +102,11 @@ public class InputHandler implements ErrorListener, Renderable { | |||
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) | |||
throws FOPException { | |||
FopFactory factory = userAgent.getFactory(); | |||
Fop fop; | |||
if (out != null) { | |||
fop = factory.newFop(outputFormat, userAgent, out); | |||
fop = userAgent.newFop(outputFormat, out); | |||
} else { | |||
fop = factory.newFop(outputFormat, userAgent); | |||
} | |||
// if base URL was not explicitly set in FOUserAgent, obtain here | |||
if (fop.getUserAgent().getBaseURL() == null && sourcefile != null) { | |||
String baseURL = null; | |||
try { | |||
baseURL = new File(sourcefile.getAbsolutePath()) | |||
.getParentFile().toURI().toURL().toExternalForm(); | |||
} catch (Exception e) { | |||
baseURL = ""; | |||
} | |||
fop.getUserAgent().setBaseURL(baseURL); | |||
fop = userAgent.newFop(outputFormat); | |||
} | |||
// Resulting SAX events (the generated FO) must be piped through to FOP |
@@ -99,7 +99,7 @@ public class FOTreeBuilder extends DefaultHandler { | |||
throws FOPException { | |||
this.userAgent = foUserAgent; | |||
this.elementMappingRegistry = userAgent.getFactory().getElementMappingRegistry(); | |||
this.elementMappingRegistry = userAgent.getElementMappingRegistry(); | |||
//This creates either an AreaTreeHandler and ultimately a Renderer, or | |||
//one of the RTF-, MIF- etc. Handlers. | |||
foEventHandler = foUserAgent.getRendererFactory().createFOEventHandler( |
@@ -27,7 +27,7 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fo.expr.PropertyException; | |||
import org.apache.fop.fo.properties.CommonAbsolutePosition; | |||
import org.apache.fop.fo.properties.CommonAural; | |||
@@ -308,7 +308,7 @@ public abstract class PropertyList { | |||
String attributeNS; | |||
String attributeName; | |||
String attributeValue; | |||
FopFactory factory = getFObj().getUserAgent().getFactory(); | |||
FOUserAgent userAgent = getFObj().getUserAgent(); | |||
for (int i = 0; i < attributes.getLength(); i++) { | |||
/* convert all attributes with the same namespace as the fo element | |||
* the "xml:lang" and "xml:base" properties are special cases */ | |||
@@ -319,8 +319,8 @@ public abstract class PropertyList { | |||
|| "xml:lang".equals(attributeName) | |||
|| "xml:base".equals(attributeName)) { | |||
convertAttributeToProperty(attributes, attributeName, attributeValue); | |||
} else if (!factory.isNamespaceIgnored(attributeNS)) { | |||
ElementMapping mapping = factory.getElementMappingRegistry().getElementMapping( | |||
} else if (!userAgent.isNamespaceIgnored(attributeNS)) { | |||
ElementMapping mapping = userAgent.getElementMappingRegistry().getElementMapping( | |||
attributeNS); | |||
QName attr = new QName(attributeNS, attributeName); | |||
if (mapping != null) { |
@@ -23,7 +23,8 @@ package org.apache.fop.fo.extensions.svg; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.net.URL; | |||
import java.io.File; | |||
import java.net.URI; | |||
import org.w3c.dom.Element; | |||
@@ -71,12 +72,11 @@ public class SVGElement extends SVGObj { | |||
/* if width and height are zero, get the bounds of the content. */ | |||
try { | |||
URL baseURL = new URL(getUserAgent().getBaseURL() == null | |||
? new java.io.File("").toURI().toURL().toExternalForm() | |||
: getUserAgent().getBaseURL()); | |||
if (baseURL != null) { | |||
URI baseUri = getUserAgent().getNewURIResolver().getBaseURI(); | |||
baseUri = baseUri == null ? new File("").toURI() : baseUri; | |||
if (baseUri != null) { | |||
SVGOMDocument svgdoc = (SVGOMDocument)doc; | |||
svgdoc.setURLObject(baseURL); | |||
svgdoc.setURLObject(baseUri.toURL()); | |||
//The following line should not be called to leave FOP compatible to Batik 1.6. | |||
//svgdoc.setDocumentURI(baseURL.toString()); | |||
} |
@@ -75,7 +75,7 @@ public class ExternalGraphic extends AbstractGraphics { | |||
//Additional processing: obtain the image's intrinsic size and baseline information | |||
url = URISpecification.getURL(src); | |||
FOUserAgent userAgent = getUserAgent(); | |||
ImageManager manager = userAgent.getFactory().getImageManager(); | |||
ImageManager manager = userAgent.getImageManager(); | |||
ImageInfo info = null; | |||
try { | |||
info = manager.getImageInfo(url, userAgent.getImageSessionContext()); |
@@ -374,7 +374,7 @@ public class CommonBorderPaddingBackground { | |||
String uri = URISpecification.getURL(newInstance.backgroundImage); | |||
FObj fobj = pList.getFObj(); | |||
FOUserAgent userAgent = pList.getFObj().getUserAgent(); | |||
ImageManager manager = userAgent.getFactory().getImageManager(); | |||
ImageManager manager = userAgent.getImageManager(); | |||
ImageSessionContext sessionContext = userAgent.getImageSessionContext(); | |||
ImageInfo info; | |||
try { |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.fonts; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
//Java | |||
/** | |||
@@ -29,6 +31,13 @@ public abstract class CIDFont extends CustomFont { | |||
/** Contains the character widths for all characters in the font */ | |||
protected int[] width = null; | |||
/** | |||
* @param resolver the URI resolver for controlling file access | |||
*/ | |||
public CIDFont(URIResolverWrapper resolver) { | |||
super(resolver); | |||
} | |||
// ---- Required ---- | |||
/** | |||
* Returns the type of the CID font. |
@@ -20,13 +20,15 @@ | |||
package org.apache.fop.fonts; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.xml.transform.Source; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
/** | |||
@@ -35,26 +37,26 @@ import javax.xml.transform.Source; | |||
public abstract class CustomFont extends Typeface | |||
implements FontDescriptor, MutableFont { | |||
private String fontName = null; | |||
private String fullName = null; | |||
private Set<String> familyNames = null; | |||
private String fontSubName = null; | |||
private String embedFileName = null; | |||
private String embedResourceName = null; | |||
private FontResolver resolver = null; | |||
private int capHeight = 0; | |||
private int xHeight = 0; | |||
private int ascender = 0; | |||
private int descender = 0; | |||
private String fontName; | |||
private String fullName; | |||
private Set<String> familyNames; | |||
private String fontSubName; | |||
private URI embedFileURI; | |||
private String embedResourceName; | |||
private final URIResolverWrapper resolver; | |||
private int capHeight; | |||
private int xHeight; | |||
private int ascender; | |||
private int descender; | |||
private int[] fontBBox = {0, 0, 0, 0}; | |||
private int flags = 4; | |||
private int weight = 0; //0 means unknown weight | |||
private int stemV = 0; | |||
private int italicAngle = 0; | |||
private int missingWidth = 0; | |||
private int weight; //0 means unknown weight | |||
private int stemV; | |||
private int italicAngle; | |||
private int missingWidth; | |||
private FontType fontType = FontType.TYPE1; | |||
private int firstChar = 0; | |||
private int firstChar; | |||
private int lastChar = 255; | |||
private Map<Integer, Map<Integer, Integer>> kerning; | |||
@@ -62,6 +64,13 @@ public abstract class CustomFont extends Typeface | |||
private boolean useKerning = true; | |||
private boolean useAdvanced = true; | |||
/** | |||
* @param resolver the URI resolver for controlling file access | |||
*/ | |||
public CustomFont(URIResolverWrapper resolver) { | |||
this.resolver = resolver; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getFontName() { | |||
return fontName; | |||
@@ -103,29 +112,22 @@ public abstract class CustomFont extends Typeface | |||
} | |||
/** | |||
* Returns an URI representing an embeddable font file. The URI will often | |||
* be a filename or an URL. | |||
* Returns an URI representing an embeddable font file. | |||
* | |||
* @return URI to an embeddable font file or null if not available. | |||
*/ | |||
public String getEmbedFileName() { | |||
return embedFileName; | |||
public URI getEmbedFileURI() { | |||
return embedFileURI; | |||
} | |||
/** | |||
* Returns a Source representing an embeddable font file. | |||
* @return Source for an embeddable font file | |||
* Returns an {@link InputStream} representing an embeddable font file. | |||
* | |||
* @return {@link InputStream} for an embeddable font file | |||
* @throws IOException if embedFileName is not null but Source is not found | |||
*/ | |||
public Source getEmbedFileSource() throws IOException { | |||
Source result = null; | |||
if (resolver != null && embedFileName != null) { | |||
result = resolver.resolve(embedFileName); | |||
if (result == null) { | |||
throw new IOException("Unable to resolve Source '" | |||
+ embedFileName + "' for embedded font"); | |||
} | |||
} | |||
return result; | |||
public InputStream getInputStream() throws IOException { | |||
return resolver.resolveIn(embedFileURI); | |||
} | |||
/** | |||
@@ -323,8 +325,8 @@ public abstract class CustomFont extends Typeface | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public void setEmbedFileName(String path) { | |||
this.embedFileName = path; | |||
public void setEmbedURI(URI path) { | |||
this.embedFileURI = path; | |||
} | |||
/** | |||
@@ -444,14 +446,6 @@ public abstract class CustomFont extends Typeface | |||
this.useAdvanced = enabled; | |||
} | |||
/** | |||
* Sets the font resolver. Needed for URI resolution. | |||
* @param resolver the font resolver | |||
*/ | |||
public void setResolver(FontResolver resolver) { | |||
this.resolver = resolver; | |||
} | |||
/** {@inheritDoc} */ | |||
public void putKerningEntry(Integer key, Map<Integer, Integer> value) { | |||
if (kerning == null) { |
@@ -21,13 +21,16 @@ package org.apache.fop.fonts; | |||
import java.util.List; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
/** | |||
* Sets up a set of custom (embedded) fonts | |||
*/ | |||
public class CustomFontCollection implements FontCollection { | |||
private FontResolver fontResolver; | |||
private final List<EmbedFontInfo> embedFontInfoList; | |||
private final URIResolverWrapper uriResolver; | |||
private final boolean useComplexScripts; | |||
/** | |||
* Main constructor. | |||
@@ -35,14 +38,11 @@ public class CustomFontCollection implements FontCollection { | |||
* @param customFonts the list of custom fonts | |||
* @param useComplexScriptFeatures true if complex script features enabled | |||
*/ | |||
public CustomFontCollection(FontResolver fontResolver, | |||
List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { | |||
this.fontResolver = fontResolver; | |||
if (this.fontResolver == null) { | |||
//Ensure that we have minimal font resolution capabilities | |||
this.fontResolver = FontManager.createMinimalFontResolver(useComplexScriptFeatures); | |||
} | |||
public CustomFontCollection(URIResolverWrapper fontResolver, | |||
List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { | |||
this.uriResolver = fontResolver; | |||
this.embedFontInfoList = customFonts; | |||
this.useComplexScripts = useComplexScriptFeatures; | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -52,27 +52,19 @@ public class CustomFontCollection implements FontCollection { | |||
} | |||
String internalName = null; | |||
//FontReader reader = null; | |||
for (int i = 0; i < embedFontInfoList.size(); i++) { | |||
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, this.fontResolver); | |||
LazyFont font = new LazyFont(embedFontInfo, this.uriResolver, useComplexScripts); | |||
fontInfo.addMetrics(internalName, font); | |||
List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); | |||
for (int tripletIndex = 0; tripletIndex < triplets.size(); tripletIndex++) { | |||
FontTriplet triplet = (FontTriplet) triplets.get(tripletIndex); | |||
FontTriplet triplet = triplets.get(tripletIndex); | |||
fontInfo.addFontProperties(internalName, triplet); | |||
} | |||
} |
@@ -0,0 +1,335 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
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.events.EventProducer; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* The font configuration data for the more generic fonts such as TTF and Type1, that are used by | |||
* most the renderers. | |||
*/ | |||
public final class DefaultFontConfig implements FontConfig { | |||
protected static Log log = LogFactory.getLog(DefaultFontConfig.class); | |||
private final List<Directory> directories = new ArrayList<Directory>(); | |||
private final List<Font> fonts = new ArrayList<Font>(); | |||
private final List<String> referencedFontFamilies = new ArrayList<String>(); | |||
private final boolean autoDetectFonts; | |||
private DefaultFontConfig(boolean autoDetectFonts) { | |||
this.autoDetectFonts = autoDetectFonts; | |||
} | |||
/** | |||
* Parses the morge generic font information. | |||
*/ | |||
public static final class DefaultFontConfigParser implements FontConfig.FontConfigParser { | |||
/** | |||
* Parses the font configuration and return the configuration object. | |||
* | |||
* @param cfg the configuration data | |||
* @param strict whether or not to enforce strict validation | |||
* @return the font configuration object | |||
* @throws FOPException if an error occurs when creating the configuration object | |||
*/ | |||
public DefaultFontConfig parse(Configuration cfg, boolean strict) throws FOPException { | |||
return new ParserHelper(cfg, strict).instance; | |||
} | |||
/** {@inheritDoc} */ | |||
public FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, | |||
EventProducer eventProducer) throws FOPException { | |||
return parse(cfg, strict); | |||
} | |||
} | |||
private static final class ParserHelper { | |||
private boolean strict; | |||
private Configuration fontInfoCfg; | |||
private DefaultFontConfig instance; | |||
private ParserHelper(Configuration cfg, boolean strict) throws FOPException { | |||
if (cfg == null || cfg.getChild("fonts", false) == null) { | |||
instance = null; | |||
} else { | |||
this.strict = strict; | |||
this.fontInfoCfg = cfg.getChild("fonts", false); | |||
instance = new DefaultFontConfig(cfg.getChild("auto-detect", false) != null); | |||
parse(); | |||
} | |||
} | |||
private void parse() throws FOPException { | |||
parseFonts(); | |||
parseReferencedFonts(); | |||
parseDirectories(); | |||
} | |||
private void parseFonts() throws FOPException { | |||
for (Configuration fontCfg : fontInfoCfg.getChildren("font")) { | |||
String embed = fontCfg.getAttribute("embed-url", null); | |||
if (embed == null) { | |||
LogUtil.handleError(log, "Font configuration without embed-url attribute", | |||
strict); | |||
continue; | |||
} | |||
Font font = new Font(fontCfg.getAttribute("metrics-url", null), embed, | |||
fontCfg.getAttribute("sub-font", null), fontCfg.getAttributeAsBoolean( | |||
"kerning", true), fontCfg.getAttributeAsBoolean("advanced", true), | |||
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); | |||
instance.fonts.add(font); | |||
boolean hasTriplets = false; | |||
for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) { | |||
FontTriplet fontTriplet = getFontTriplet(tripletCfg, strict); | |||
font.tripletList.add(fontTriplet); | |||
hasTriplets = true; | |||
} | |||
// no font triplet info | |||
if (!hasTriplets) { | |||
LogUtil.handleError(log, "font without font-triplet", strict); | |||
} | |||
} | |||
} | |||
private void parseReferencedFonts() throws FOPException { | |||
Configuration referencedFontsCfg = fontInfoCfg.getChild("referenced-fonts", false); | |||
if (referencedFontsCfg != null) { | |||
for (Configuration match : referencedFontsCfg.getChildren("match")) { | |||
try { | |||
instance.referencedFontFamilies.add(match.getAttribute("font-family")); | |||
} catch (ConfigurationException ce) { | |||
LogUtil.handleException(log, ce, strict); | |||
continue; | |||
} | |||
} | |||
} | |||
} | |||
private void parseDirectories() throws FOPException { | |||
for (Configuration directoriesCfg : fontInfoCfg.getChildren("directory")) { | |||
boolean recursive = directoriesCfg.getAttributeAsBoolean("recursive", false); | |||
String directory; | |||
try { | |||
directory = directoriesCfg.getValue(); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
continue; | |||
} | |||
if (directory == null) { | |||
LogUtil.handleException(log, | |||
new FOPException("directory defined without value"), strict); | |||
continue; | |||
} | |||
instance.directories.add(new Directory(directory, recursive)); | |||
} | |||
} | |||
/** | |||
* Creates a new FontTriplet given a triple Configuration | |||
* | |||
* @param tripletCfg a triplet configuration | |||
* @return a font triplet font key | |||
* @throws FOPException thrown if a FOP exception occurs | |||
*/ | |||
private FontTriplet getFontTriplet(Configuration tripletCfg, boolean strict) | |||
throws FOPException { | |||
try { | |||
String name = tripletCfg.getAttribute("name"); | |||
if (name == null) { | |||
LogUtil.handleError(log, "font-triplet without name", strict); | |||
return null; | |||
} | |||
String weightStr = tripletCfg.getAttribute("weight"); | |||
if (weightStr == null) { | |||
LogUtil.handleError(log, "font-triplet without weight", strict); | |||
return null; | |||
} | |||
int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr)); | |||
String style = tripletCfg.getAttribute("style"); | |||
if (style == null) { | |||
LogUtil.handleError(log, "font-triplet without style", strict); | |||
return null; | |||
} else { | |||
style = FontUtil.stripWhiteSpace(style); | |||
} | |||
return FontInfo.createFontKey(name, style, weight); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
return null; | |||
} | |||
} | |||
/** | |||
* Returns the list of fonts that were parsed. | |||
* @return a list of fonts | |||
*/ | |||
public List<Font> getFonts() { | |||
return Collections.unmodifiableList(fonts); | |||
} | |||
/** | |||
* Returns a list of directories that were parsed. | |||
* @return a list of directories | |||
*/ | |||
public List<Directory> getDirectories() { | |||
return Collections.unmodifiableList(directories); | |||
} | |||
/** | |||
* Returns a list of referenced font families. | |||
* @return the referenced font families | |||
*/ | |||
public List<String> getReferencedFontFamily() { | |||
return Collections.unmodifiableList(referencedFontFamilies); | |||
} | |||
/** | |||
* Whether or not to enable auto-detecting of fonts in the system. | |||
* @return true to enable auto-detect | |||
*/ | |||
public boolean isAutoDetectFonts() { | |||
return autoDetectFonts; | |||
} | |||
/** | |||
* The directory to find fonts within. | |||
*/ | |||
public static final class Directory { | |||
private final String directory; | |||
private final boolean recursive; | |||
private Directory(String directory, boolean recurse) { | |||
this.directory = directory; | |||
this.recursive = recurse; | |||
} | |||
/** | |||
* Returns a String representing the directory to find fonts within. | |||
* @return the directory | |||
*/ | |||
public String getDirectory() { | |||
return directory; | |||
} | |||
/** | |||
* Returns whether or not to recurse through the directory when finding fonts. | |||
* @return true to recurse through the directory and sub-directories | |||
*/ | |||
public boolean isRecursive() { | |||
return recursive; | |||
} | |||
} | |||
/** | |||
* Represents a font object within the FOP conf. | |||
*/ | |||
public static final class Font { | |||
private final String metrics; | |||
private final String embedUri; | |||
private final String subFont; | |||
private final boolean kerning; | |||
private final boolean advanced; | |||
private final String encodingMode; | |||
public String getEncodingMode() { | |||
return encodingMode; | |||
} | |||
private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>(); | |||
public List<FontTriplet> getTripletList() { | |||
return Collections.unmodifiableList(tripletList); | |||
} | |||
private Font(String metrics, String embed, String subFont, boolean kerning, | |||
boolean advanced, String encodingMode) { | |||
this.metrics = metrics; | |||
this.embedUri = embed; | |||
this.subFont = subFont; | |||
this.kerning = kerning; | |||
this.advanced = advanced; | |||
this.encodingMode = encodingMode; | |||
} | |||
/** | |||
* Whether or not to allow kerning of glyphs. | |||
* @return true to allow glyph kerning | |||
*/ | |||
public boolean isKerning() { | |||
return kerning; | |||
} | |||
public boolean isAdvanced() { | |||
return advanced; | |||
} | |||
/** | |||
* Gets the String representing the metrics file. | |||
* @return the metrics file | |||
*/ | |||
public String getMetrics() { | |||
return metrics; | |||
} | |||
/** | |||
* Gets the URI of the font to embed. | |||
* @return the font URI | |||
*/ | |||
public String getEmbedURI() { | |||
return embedUri; | |||
} | |||
/** | |||
* Gets the sub font within, for example, a TTC. | |||
* @return the sub font name | |||
*/ | |||
public String getSubFont() { | |||
return subFont; | |||
} | |||
} | |||
} |
@@ -0,0 +1,190 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.io.IOException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.DefaultFontConfig.Directory; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* The default configurator for fonts. This configurator can configure the more generic fonts used | |||
* by the renderers i.e. TTF, Type1 etc... | |||
*/ | |||
public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo> { | |||
/** logger instance */ | |||
protected static Log log = LogFactory.getLog(DefaultFontConfigurator.class); | |||
private final FontManager fontManager; | |||
private final URIResolverWrapper uriResolver; | |||
private final FontEventListener listener; | |||
private final boolean strict; | |||
/** | |||
* Main constructor | |||
* @param fontInfoConfig the configuration object | |||
* @param fontManager the font manager | |||
* @param listener the font event listener | |||
* @param strict true if an Exception should be thrown if an error is found. | |||
*/ | |||
public DefaultFontConfigurator(FontManager fontManager, FontEventListener listener, boolean strict) { | |||
this.fontManager = fontManager; | |||
this.uriResolver = fontManager.getURIResolver(); | |||
this.listener = listener; | |||
this.strict = strict; | |||
} | |||
/** | |||
* Initializes font info settings from the user configuration | |||
* @throws FOPException if an exception occurs while processing the configuration | |||
*/ | |||
public List<EmbedFontInfo> configure(FontConfig fontInfoConfig) | |||
throws FOPException { | |||
List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>(); | |||
DefaultFontConfig adobeFontInfoConfig = (DefaultFontConfig) fontInfoConfig; | |||
if (adobeFontInfoConfig != null) { | |||
long start = 0; | |||
if (log.isDebugEnabled()) { | |||
log.debug("Starting font configuration..."); | |||
start = System.currentTimeMillis(); | |||
} | |||
FontAdder fontAdder = new FontAdder(fontManager, uriResolver, listener); | |||
// native o/s search (autodetect) configuration | |||
fontManager.autoDetectFonts(adobeFontInfoConfig.isAutoDetectFonts(), fontAdder, strict, | |||
listener, fontInfoList); | |||
// Add configured directories to FontInfo list | |||
addDirectories(adobeFontInfoConfig, fontAdder, fontInfoList); | |||
// Add configured fonts to FontInfo | |||
FontCache fontCache = fontManager.getFontCache(); | |||
try { | |||
addFonts(adobeFontInfoConfig, fontCache, fontInfoList); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, strict); | |||
} | |||
// Update referenced fonts (fonts which are not to be embedded) | |||
fontManager.updateReferencedFonts(fontInfoList); | |||
// Renderer-specific referenced fonts | |||
List<String> referencedFonts = adobeFontInfoConfig.getReferencedFontFamily(); | |||
if (referencedFonts.size() > 0) { | |||
FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher( | |||
referencedFonts, strict); | |||
fontManager.updateReferencedFonts(fontInfoList, matcher); | |||
} | |||
// Update font cache if it has changed | |||
fontManager.saveCache(); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Finished font configuration in " | |||
+ (System.currentTimeMillis() - start) + "ms"); | |||
} | |||
} | |||
return Collections.unmodifiableList(fontInfoList); | |||
} | |||
private void addDirectories(DefaultFontConfig fontInfoConfig, FontAdder fontAdder, | |||
List<EmbedFontInfo> fontInfoList) throws FOPException { | |||
// directory (multiple font) configuration | |||
List<Directory> directories = fontInfoConfig.getDirectories(); | |||
for (Directory directory : directories) { | |||
// add fonts found in directory | |||
FontFileFinder fontFileFinder = new FontFileFinder(directory.isRecursive() ? -1 : 1, listener); | |||
List<URL> fontURLList; | |||
try { | |||
fontURLList = fontFileFinder.find(directory.getDirectory()); | |||
fontAdder.add(fontURLList, fontInfoList); | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, strict); | |||
} | |||
} | |||
} | |||
private void addFonts(DefaultFontConfig fontInfoConfig, FontCache fontCache, | |||
List<EmbedFontInfo> fontInfoList) throws FOPException, URISyntaxException { | |||
// font file (singular) configuration | |||
List<DefaultFontConfig.Font> fonts = fontInfoConfig.getFonts(); | |||
for (DefaultFontConfig.Font font : fonts) { | |||
EmbedFontInfo embedFontInfo = getFontInfo(font, fontCache); | |||
if (embedFontInfo != null) { | |||
fontInfoList.add(embedFontInfo); | |||
} | |||
} | |||
} | |||
private EmbedFontInfo getFontInfo(DefaultFontConfig.Font font, FontCache fontCache) | |||
throws FOPException, URISyntaxException { | |||
String embed = font.getEmbedURI(); | |||
String metrics = font.getMetrics(); | |||
String subFont = font.getSubFont(); | |||
URI metricsUri = metrics == null ? null : URIResolverWrapper.cleanURI(metrics); | |||
URI embedUri = URIResolverWrapper.cleanURI(embed); | |||
List<FontTriplet> tripletList = font.getTripletList(); | |||
// no font triplet info | |||
if (tripletList.size() == 0) { | |||
//TODO: could be problematic!! | |||
URI fontUri = uriResolver.getBaseURI().resolve(embedUri); | |||
if (fontUri != null) { | |||
FontInfoFinder finder = new FontInfoFinder(); | |||
finder.setEventListener(listener); | |||
EmbedFontInfo[] infos = finder.find(fontUri, uriResolver, fontCache); | |||
return infos[0]; //When subFont is set, only one font is returned | |||
} else { | |||
return null; | |||
} | |||
} | |||
EncodingMode encodingMode = EncodingMode.getEncodingMode(font.getEncodingMode()); | |||
EmbedFontInfo embedFontInfo = new EmbedFontInfo(metricsUri, font.isKerning(), | |||
font.isAdvanced(), tripletList, embedUri, subFont, encodingMode); | |||
if (fontCache != null) { | |||
if (!fontCache.containsFont(embedFontInfo)) { | |||
fontCache.addFont(embedFontInfo, uriResolver); | |||
} | |||
} | |||
if (log.isDebugEnabled()) { | |||
URI embedFile = embedFontInfo.getEmbedURI(); | |||
log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") | |||
+ "metrics URI " + embedFontInfo.getMetricsURI()); | |||
for (int j = 0; j < tripletList.size(); ++j) { | |||
FontTriplet triplet = tripletList.get(j); | |||
log.debug(" Font triplet " | |||
+ triplet.getName() + ", " | |||
+ triplet.getStyle() + ", " | |||
+ triplet.getWeight()); | |||
} | |||
} | |||
return embedFontInfo; | |||
} | |||
} |
@@ -21,6 +21,7 @@ package org.apache.fop.fonts; | |||
import java.io.IOException; | |||
import java.io.Serializable; | |||
import java.net.URI; | |||
import java.util.List; | |||
/** | |||
@@ -31,60 +32,74 @@ public class EmbedFontInfo implements Serializable { | |||
/** Serialization Version UID */ | |||
private static final long serialVersionUID = 8755432068669997369L; | |||
/** filename of the metrics file */ | |||
protected String metricsFile; | |||
/** filename of the main font file */ | |||
protected String embedFile; | |||
protected final URI metricsURI; | |||
protected final URI embedURI; | |||
/** false, to disable kerning */ | |||
protected boolean kerning; | |||
protected final boolean kerning; | |||
/** false, to disable advanced typographic features */ | |||
protected boolean advanced; | |||
protected final boolean advanced; | |||
/** the requested encoding mode for the font */ | |||
protected EncodingMode encodingMode = EncodingMode.AUTO; | |||
private final EncodingMode encodingMode; | |||
/** the PostScript name of the font */ | |||
protected String postScriptName = null; | |||
protected String postScriptName; | |||
/** the sub-fontname of the font (used for TrueType Collections, null otherwise) */ | |||
protected String subFontName = null; | |||
protected String subFontName; | |||
/** the list of associated font triplets */ | |||
private List<FontTriplet> fontTriplets = null; | |||
private List<FontTriplet> fontTriplets; | |||
private transient boolean embedded = true; | |||
/** | |||
* Main constructor | |||
* @param metricsFile path to the xml file containing font metrics | |||
* @param kerning true if kerning should be enabled | |||
* @param metricsURI the URI of the XML resource containing font metrics | |||
* @param kerning True if kerning should be enabled | |||
* @param advanced true if advanced typography features should be enabled | |||
* @param fontTriplets list of font triplets to associate with this font | |||
* @param embedFile path to the embeddable font file (may be null) | |||
* @param fontTriplets List of font triplets to associate with this font | |||
* @param embedURI Path to the embeddable font file (may be null) | |||
* @param subFontName the sub-fontname used for TrueType Collections (null otherwise) | |||
* @param encodingMode the encoding mode to use for this font | |||
*/ | |||
public EmbedFontInfo(String metricsFile, boolean kerning, boolean advanced, | |||
List<FontTriplet> fontTriplets, String embedFile, String subFontName) { | |||
this.metricsFile = metricsFile; | |||
this.embedFile = embedFile; | |||
public EmbedFontInfo(URI metricsURI, boolean kerning, boolean advanced, | |||
List<FontTriplet> fontTriplets, URI embedURI, String subFontName) { | |||
this.metricsURI = metricsURI; | |||
this.embedURI = embedURI; | |||
this.kerning = kerning; | |||
this.advanced = advanced; | |||
this.fontTriplets = fontTriplets; | |||
this.subFontName = subFontName; | |||
this.encodingMode = EncodingMode.AUTO; | |||
} | |||
public EmbedFontInfo(URI metricsURI, boolean kerning, boolean advanced, | |||
List<FontTriplet> fontTriplets, URI embedURI, String subFontName, | |||
EncodingMode encodingMode) { | |||
this.metricsURI = metricsURI; | |||
this.embedURI = embedURI; | |||
this.kerning = kerning; | |||
this.advanced = advanced; | |||
this.fontTriplets = fontTriplets; | |||
this.subFontName = subFontName; | |||
this.encodingMode = encodingMode; | |||
} | |||
/** | |||
* Returns the path to the metrics file | |||
* Returns the URI of the metrics XML resource | |||
* | |||
* @return the metrics file path | |||
*/ | |||
public String getMetricsFile() { | |||
return metricsFile; | |||
public URI getMetricsURI() { | |||
return metricsURI; | |||
} | |||
/** | |||
* Returns the path to the embeddable font file | |||
* @return the font file path | |||
* Returns the URI to the embeddable font resource | |||
* | |||
* @return the font resource URI | |||
*/ | |||
public String getEmbedFile() { | |||
return embedFile; | |||
public URI getEmbedURI() { | |||
return embedURI; | |||
} | |||
/** | |||
@@ -141,7 +156,7 @@ public class EmbedFontInfo implements Serializable { | |||
* @return true if the font is embedded, false if it is referenced. | |||
*/ | |||
public boolean isEmbedded() { | |||
if (metricsFile != null && embedFile == null) { | |||
if (embedURI == null) { | |||
return false; | |||
} else { | |||
return this.embedded; | |||
@@ -164,17 +179,6 @@ public class EmbedFontInfo implements Serializable { | |||
return this.encodingMode; | |||
} | |||
/** | |||
* Sets the requested encoding mode for this font. | |||
* @param mode the new encoding mode | |||
*/ | |||
public void setEncodingMode(EncodingMode mode) { | |||
if (mode == null) { | |||
throw new NullPointerException("mode must not be null"); | |||
} | |||
this.encodingMode = mode; | |||
} | |||
private void readObject(java.io.ObjectInputStream in) | |||
throws IOException, ClassNotFoundException { | |||
in.defaultReadObject(); | |||
@@ -183,7 +187,7 @@ public class EmbedFontInfo implements Serializable { | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
return "metrics-url=" + metricsFile + ", embed-url=" + embedFile | |||
return "metrics-uri=" + metricsURI + ", embed-uri=" + embedURI | |||
+ ", kerning=" + kerning | |||
+ ", advanced=" + advanced | |||
+ ", enc-mode=" + encodingMode |
@@ -19,9 +19,11 @@ | |||
package org.apache.fop.fonts; | |||
import java.net.URISyntaxException; | |||
import java.net.URL; | |||
import java.util.List; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
/** | |||
@@ -29,7 +31,7 @@ import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
*/ | |||
public class FontAdder { | |||
private final FontEventListener listener; | |||
private final FontResolver resolver; | |||
private final URIResolverWrapper resolver; | |||
private final FontManager manager; | |||
/** | |||
@@ -38,7 +40,7 @@ public class FontAdder { | |||
* @param resolver a font resolver | |||
* @param listener a font event handler | |||
*/ | |||
public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) { | |||
public FontAdder(FontManager manager, URIResolverWrapper resolver, FontEventListener listener) { | |||
this.manager = manager; | |||
this.resolver = resolver; | |||
this.listener = listener; | |||
@@ -48,14 +50,16 @@ public class FontAdder { | |||
* Iterates over font url list adding to font info list | |||
* @param fontURLList font file list | |||
* @param fontInfoList a configured font info list | |||
* @throws URISyntaxException if a URI syntax error is found | |||
*/ | |||
public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList) { | |||
public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList) | |||
throws URISyntaxException { | |||
FontCache cache = manager.getFontCache(); | |||
FontInfoFinder finder = new FontInfoFinder(); | |||
finder.setEventListener(listener); | |||
for (URL fontURL : fontURLList) { | |||
EmbedFontInfo[] embedFontInfos = finder.find(fontURL, resolver, cache); | |||
EmbedFontInfo[] embedFontInfos = finder.find(fontURL.toURI(), resolver, cache); | |||
if (embedFontInfos == null) { | |||
continue; | |||
} |
@@ -29,6 +29,7 @@ import java.io.ObjectOutputStream; | |||
import java.io.OutputStream; | |||
import java.io.Serializable; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.net.URL; | |||
import java.net.URLConnection; | |||
import java.util.HashMap; | |||
@@ -40,6 +41,7 @@ import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
@@ -234,9 +236,9 @@ public final class FontCache implements Serializable { | |||
*/ | |||
protected static String getCacheKey(EmbedFontInfo fontInfo) { | |||
if (fontInfo != null) { | |||
String embedFile = fontInfo.getEmbedFile(); | |||
String metricsFile = fontInfo.getMetricsFile(); | |||
return (embedFile != null) ? embedFile : metricsFile; | |||
URI embedFile = fontInfo.getEmbedURI(); | |||
URI metricsFile = fontInfo.getMetricsURI(); | |||
return (embedFile != null) ? embedFile.toASCIIString() : metricsFile.toASCIIString(); | |||
} | |||
return null; | |||
} | |||
@@ -318,7 +320,7 @@ public final class FontCache implements Serializable { | |||
* @param fontInfo | |||
* font info | |||
*/ | |||
public void addFont(EmbedFontInfo fontInfo) { | |||
public void addFont(EmbedFontInfo fontInfo, URIResolverWrapper resolver) { | |||
String cacheKey = getCacheKey(fontInfo); | |||
synchronized (changeLock) { | |||
CachedFontFile cachedFontFile; | |||
@@ -329,10 +331,10 @@ public final class FontCache implements Serializable { | |||
} | |||
} else { | |||
// try and determine modified date | |||
File fontFile = getFileFromUrls(new String[] { | |||
fontInfo.getEmbedFile(), fontInfo.getMetricsFile() }); | |||
long lastModified = (fontFile != null ? fontFile.lastModified() | |||
: -1); | |||
// TODO: This could be problematic?!!?!?! | |||
URI fontUri = resolver.getBaseURI().resolve(fontInfo.getEmbedURI()); | |||
File fontFile = new File(fontUri); | |||
long lastModified = (fontFile != null ? fontFile.lastModified() : -1); | |||
cachedFontFile = new CachedFontFile(lastModified); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Font added to cache: " + cacheKey); | |||
@@ -467,8 +469,9 @@ public final class FontCache implements Serializable { | |||
* the URL | |||
* @return the last modified date/time | |||
*/ | |||
public static long getLastModified(URL url) { | |||
public static long getLastModified(URI uri) { | |||
try { | |||
URL url = uri.toURL(); | |||
URLConnection conn = url.openConnection(); | |||
try { | |||
return conn.getLastModified(); |
@@ -19,27 +19,35 @@ | |||
package org.apache.fop.fonts; | |||
import javax.xml.transform.Source; | |||
import java.io.File; | |||
import org.apache.fop.apps.FOPException; | |||
/** | |||
* This interface is used to resolve absolute and relative font URIs. | |||
* Fop cache (currently only used for font info caching) | |||
*/ | |||
public interface FontResolver { | |||
public interface FontCacheManager { | |||
/** | |||
* Loads the font cache into memory from the given file. | |||
* @param file the serialized font cache | |||
* @return the de-serialized font cache | |||
*/ | |||
FontCache load(File file); | |||
/** | |||
* Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's | |||
* resolve() method is defined to be implicitly available in this case. If the URI cannot | |||
* be resolved, null is returned and it is assumed that the FontResolver implementation | |||
* already warned the user about the problem. | |||
* @param href An href attribute, which may be relative or absolute. | |||
* @return A Source object, or null if the href could not resolved. | |||
* Serializes the font cache to file. | |||
* @param file the file to serialize the font cache to | |||
* @throws FOPException if an error occurs serializing the font cache | |||
*/ | |||
Source resolve(String href); | |||
void save(File file) throws FOPException; | |||
/** | |||
* Check whether complex script features are enabled. | |||
* @return true if FOP is to use complex script features | |||
* Deletes the font cache from the file-system. | |||
* @param file delete the serialized font cache | |||
* @throws FOPException if an error occurs deleting the font cache | |||
*/ | |||
boolean isComplexScriptFeaturesEnabled(); | |||
void delete(File file) throws FOPException; | |||
} |
@@ -0,0 +1,92 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import org.apache.fop.apps.FOPException; | |||
/** | |||
* A factory that provides the font caching manager mechanism. | |||
* | |||
*/ | |||
public final class FontCacheManagerFactory { | |||
private FontCacheManagerFactory() { | |||
} | |||
/** | |||
* Create the default font caching mechanism. | |||
* @return the font cache manager | |||
*/ | |||
public static FontCacheManager createDefault() { | |||
return new FontCacheManagerImpl(); | |||
} | |||
/** | |||
* Create a disabled font caching mechanism which by definition does nothing to cache fonts. | |||
* @return a completely restricted font cache manager | |||
*/ | |||
public static FontCacheManager createDisabled() { | |||
return new DisabledFontCacheManager(); | |||
} | |||
private static final class FontCacheManagerImpl implements FontCacheManager { | |||
private FontCache fontCache; | |||
public FontCache load(File cacheFile) { | |||
if (fontCache == null) { | |||
fontCache = FontCache.loadFrom(cacheFile); | |||
if (fontCache == null) { | |||
fontCache = new FontCache(); | |||
} | |||
} | |||
return fontCache; | |||
} | |||
public void save(File cacheFile) throws FOPException { | |||
if (fontCache != null && fontCache.hasChanged()) { | |||
fontCache.saveTo(cacheFile); | |||
} | |||
} | |||
public void delete(File cacheFile) throws FOPException { | |||
if (!cacheFile.delete()) { | |||
throw new FOPException("Failed to flush the font cache file '" + cacheFile + "'."); | |||
} | |||
} | |||
} | |||
private static final class DisabledFontCacheManager implements FontCacheManager { | |||
public FontCache load(File cacheFile) { | |||
return null; | |||
} | |||
public void save(File cacheFile) throws FOPException { | |||
// nop | |||
} | |||
public void delete(File cacheFile) throws FOPException { | |||
throw new FOPException("Font Cache disabled"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.events.EventProducer; | |||
/** | |||
* An interface for font configuration information. | |||
*/ | |||
public interface FontConfig { | |||
/** | |||
* An interface for parsing font configuration information. | |||
*/ | |||
public interface FontConfigParser { | |||
/** | |||
* Parse the font configuration and return an object containing all the necessary data. | |||
* | |||
* @param cfg the configuration object | |||
* @param fontManager the font manager | |||
* @param strict whether or not to enforce strict validation | |||
* @param eventProducer the event producer for handling font events | |||
* @return the configuration object | |||
* @throws FOPException if an error occurs creating the font configuration object | |||
*/ | |||
FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, | |||
EventProducer eventProducer) throws FOPException; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.util.List; | |||
import org.apache.fop.apps.FOPException; | |||
/** | |||
* An abstract FontInfo configurator | |||
*/ | |||
// TODO: Make T extends some interface to make the font info type explicit | |||
public interface FontConfigurator<T> { | |||
/** | |||
* Initializes font info settings from the user configuration | |||
* @return a font info list | |||
* @throws FOPException if an exception occurs while processing the configuration | |||
*/ | |||
List<T> configure(FontConfig fontInfoConfig) throws FOPException; | |||
} |
@@ -17,90 +17,18 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.util.ClasspathResource; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* Detector of operating system and classpath fonts | |||
* An interface for the font detecting mechanism. | |||
*/ | |||
public class FontDetector { | |||
private static Log log = LogFactory.getLog(FontDetector.class); | |||
private static final String[] FONT_MIMETYPES = { | |||
"application/x-font", "application/x-font-truetype" | |||
}; | |||
private final FontManager fontManager; | |||
private final FontAdder fontAdder; | |||
private final boolean strict; | |||
private final FontEventListener eventListener; | |||
/** | |||
* Main constructor | |||
* @param manager the font manager | |||
* @param adder the font adder | |||
* @param strict true if an Exception should be thrown if an error is found. | |||
* @param listener for throwing font related events | |||
*/ | |||
public FontDetector(FontManager manager, FontAdder adder, boolean strict, | |||
FontEventListener listener) { | |||
this.fontManager = manager; | |||
this.fontAdder = adder; | |||
this.strict = strict; | |||
this.eventListener = listener; | |||
} | |||
/** | |||
* Detect installed fonts on the system | |||
* @param fontInfoList a list of fontinfo to populate | |||
* @throws FOPException thrown if a problem occurred during detection | |||
*/ | |||
public void detect(List<EmbedFontInfo> fontInfoList) throws FOPException { | |||
// search in font base if it is defined and | |||
// is a directory but don't recurse | |||
FontFileFinder fontFileFinder = new FontFileFinder(eventListener); | |||
String fontBaseURL = fontManager.getFontBaseURL(); | |||
if (fontBaseURL != null) { | |||
try { | |||
File fontBase = FileUtils.toFile(new URL(fontBaseURL)); | |||
if (fontBase != null) { | |||
List<URL> fontURLList = fontFileFinder.find(fontBase.getAbsolutePath()); | |||
fontAdder.add(fontURLList, fontInfoList); | |||
//Can only use the font base URL if it's a file URL | |||
} | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// native o/s font directory finding | |||
List<URL> systemFontList; | |||
try { | |||
systemFontList = fontFileFinder.find(); | |||
fontAdder.add(systemFontList, fontInfoList); | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
// classpath font finding | |||
ClasspathResource resource = ClasspathResource.getInstance(); | |||
for (int i = 0; i < FONT_MIMETYPES.length; i++) { | |||
fontAdder.add(resource.listResourcesOfMimeType(FONT_MIMETYPES[i]), fontInfoList); | |||
} | |||
} | |||
public interface FontDetector { | |||
void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, | |||
FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) throws FOPException; | |||
} |
@@ -0,0 +1,121 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.net.URL; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.util.ClasspathResource; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* A factory that provides the font detecting machanism. | |||
*/ | |||
public final class FontDetectorFactory { | |||
private FontDetectorFactory() { | |||
} | |||
/** | |||
* Creates the default font detector | |||
* @return the default font detector | |||
*/ | |||
public static FontDetector createDefault() { | |||
return new DefaultFontDetector(); | |||
} | |||
/** | |||
* Creates a disabled font detector which, by definition, does nothing to detect fonts. | |||
* @return the completely restricted font detector | |||
*/ | |||
public static FontDetector createDisabled() { | |||
return new DisabledFontDetector(); | |||
} | |||
private static class DisabledFontDetector implements FontDetector { | |||
public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, | |||
FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) | |||
throws FOPException { | |||
// nop | |||
} | |||
} | |||
/** | |||
* Detector of operating system and classpath fonts | |||
*/ | |||
private static class DefaultFontDetector implements FontDetector { | |||
private static Log log = LogFactory.getLog(DefaultFontDetector.class); | |||
private static final String[] FONT_MIMETYPES = { | |||
"application/x-font", "application/x-font-truetype" | |||
}; | |||
/** | |||
* Detect installed fonts on the system | |||
* @param fontInfoList a list of fontinfo to populate | |||
* @throws FOPException thrown if a problem occurred during detection | |||
*/ | |||
public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, | |||
FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) | |||
throws FOPException { | |||
try { | |||
// search in font base if it is defined and | |||
// is a directory but don't recurse | |||
FontFileFinder fontFileFinder = new FontFileFinder(eventListener); | |||
URI fontBaseURI = fontManager.getURIResolver().getBaseURI(); | |||
if (fontBaseURI != null) { | |||
File fontBase = FileUtils.toFile(fontBaseURI.toURL()); | |||
if (fontBase != null) { | |||
List<URL> fontURLList = fontFileFinder.find(fontBase.getAbsolutePath()); | |||
fontAdder.add(fontURLList, fontInfoList); | |||
//Can only use the font base URL if it's a file URL | |||
} | |||
} | |||
// native o/s font directory finding | |||
List<URL> systemFontList; | |||
systemFontList = fontFileFinder.find(); | |||
fontAdder.add(systemFontList, fontInfoList); | |||
// classpath font finding | |||
ClasspathResource resource = ClasspathResource.getInstance(); | |||
for (String mimeTypes : FONT_MIMETYPES) { | |||
fontAdder.add(resource.listResourcesOfMimeType(mimeTypes), fontInfoList); | |||
} | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, strict); | |||
} | |||
} | |||
} | |||
} |
@@ -1,324 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.List; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* An abstract FontInfo configurator | |||
*/ | |||
public class FontInfoConfigurator { | |||
/** logger instance */ | |||
protected static final Log log = LogFactory.getLog(FontInfoConfigurator.class); | |||
private final Configuration cfg; | |||
private final FontManager fontManager; | |||
private final FontResolver fontResolver; | |||
private final FontEventListener listener; | |||
private final boolean strict; | |||
/** | |||
* Main constructor | |||
* @param cfg the configuration object | |||
* @param fontManager the font manager | |||
* @param fontResolver the font resolver | |||
* @param listener the font event listener | |||
* @param strict true if an Exception should be thrown if an error is found. | |||
*/ | |||
public FontInfoConfigurator(Configuration cfg, FontManager fontManager, | |||
FontResolver fontResolver, FontEventListener listener, boolean strict) { | |||
this.cfg = cfg; | |||
this.fontManager = fontManager; | |||
this.fontResolver = fontResolver; | |||
this.listener = listener; | |||
this.strict = strict; | |||
} | |||
/** | |||
* Initializes font info settings from the user configuration | |||
* @param fontInfoList a font info list | |||
* @throws FOPException if an exception occurs while processing the configuration | |||
*/ | |||
public void configure(List<EmbedFontInfo> fontInfoList) | |||
throws FOPException { | |||
Configuration fontsCfg = cfg.getChild("fonts", false); | |||
if (fontsCfg != null) { | |||
long start = 0; | |||
if (log.isDebugEnabled()) { | |||
log.debug("Starting font configuration..."); | |||
start = System.currentTimeMillis(); | |||
} | |||
FontAdder fontAdder = new FontAdder(fontManager, fontResolver, listener); | |||
// native o/s search (autodetect) configuration | |||
boolean autodetectFonts = (fontsCfg.getChild("auto-detect", false) != null); | |||
if (autodetectFonts) { | |||
FontDetector fontDetector = new FontDetector(fontManager, fontAdder, strict, | |||
listener); | |||
fontDetector.detect(fontInfoList); | |||
} | |||
// Add configured directories to FontInfo list | |||
addDirectories(fontsCfg, fontAdder, fontInfoList); | |||
// Add fonts from configuration to FontInfo list | |||
addFonts(fontsCfg, fontManager.getFontCache(), fontInfoList); | |||
// Update referenced fonts (fonts which are not to be embedded) | |||
fontManager.updateReferencedFonts(fontInfoList); | |||
// Renderer-specific referenced fonts | |||
Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false); | |||
if (referencedFontsCfg != null) { | |||
FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher( | |||
referencedFontsCfg, strict); | |||
fontManager.updateReferencedFonts(fontInfoList, matcher); | |||
} | |||
// Update font cache if it has changed | |||
fontManager.saveCache(); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Finished font configuration in " | |||
+ (System.currentTimeMillis() - start) + "ms"); | |||
} | |||
} | |||
} | |||
private void addDirectories(Configuration fontsCfg, | |||
FontAdder fontAdder, List<EmbedFontInfo> fontInfoList) throws FOPException { | |||
// directory (multiple font) configuration | |||
Configuration[] directories = fontsCfg.getChildren("directory"); | |||
for (int i = 0; i < directories.length; i++) { | |||
boolean recursive = directories[i].getAttributeAsBoolean("recursive", false); | |||
String directory = null; | |||
try { | |||
directory = directories[i].getValue(); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
continue; | |||
} | |||
if (directory == null) { | |||
LogUtil.handleException(log, | |||
new FOPException("directory defined without value"), strict); | |||
continue; | |||
} | |||
// add fonts found in directory | |||
FontFileFinder fontFileFinder = new FontFileFinder(recursive ? -1 : 1, listener); | |||
List<URL> fontURLList; | |||
try { | |||
fontURLList = fontFileFinder.find(directory); | |||
fontAdder.add(fontURLList, fontInfoList); | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
} | |||
/** | |||
* Populates the font info list from the fonts configuration | |||
* @param fontsCfg a fonts configuration | |||
* @param fontCache a font cache | |||
* @param fontInfoList a font info list | |||
* @throws FOPException if an exception occurs while processing the configuration | |||
*/ | |||
protected void addFonts(Configuration fontsCfg, FontCache fontCache, | |||
List<EmbedFontInfo> fontInfoList) throws FOPException { | |||
// font file (singular) configuration | |||
Configuration[] font = fontsCfg.getChildren("font"); | |||
for (int i = 0; i < font.length; i++) { | |||
EmbedFontInfo embedFontInfo = getFontInfo( | |||
font[i], fontCache); | |||
if (embedFontInfo != null) { | |||
fontInfoList.add(embedFontInfo); | |||
} | |||
} | |||
} | |||
private static void closeSource(Source src) { | |||
if (src instanceof StreamSource) { | |||
StreamSource streamSource = (StreamSource)src; | |||
IOUtils.closeQuietly(streamSource.getInputStream()); | |||
IOUtils.closeQuietly(streamSource.getReader()); | |||
} | |||
} | |||
/** | |||
* Returns a font info from a font node Configuration definition | |||
* | |||
* @param fontCfg Configuration object (font node) | |||
* @param fontCache the font cache (or null if it is disabled) | |||
* @return the embedded font info | |||
* @throws FOPException if something's wrong with the config data | |||
*/ | |||
protected EmbedFontInfo getFontInfo(Configuration fontCfg, FontCache fontCache) | |||
throws FOPException { | |||
String metricsUrl = fontCfg.getAttribute("metrics-url", null); | |||
String embedUrl = fontCfg.getAttribute("embed-url", null); | |||
String subFont = fontCfg.getAttribute("sub-font", null); | |||
if (metricsUrl == null && embedUrl == null) { | |||
LogUtil.handleError(log, | |||
"Font configuration without metric-url or embed-url attribute", | |||
strict); | |||
return null; | |||
} | |||
if (strict) { | |||
//This section just checks early whether the URIs can be resolved | |||
//Stream are immediately closed again since they will never be used anyway | |||
if (embedUrl != null) { | |||
Source source = fontResolver.resolve(embedUrl); | |||
closeSource(source); | |||
if (source == null) { | |||
LogUtil.handleError(log, | |||
"Failed to resolve font with embed-url '" + embedUrl + "'", strict); | |||
return null; | |||
} | |||
} | |||
if (metricsUrl != null) { | |||
Source source = fontResolver.resolve(metricsUrl); | |||
closeSource(source); | |||
if (source == null) { | |||
LogUtil.handleError(log, | |||
"Failed to resolve font with metric-url '" + metricsUrl + "'", strict); | |||
return null; | |||
} | |||
} | |||
} | |||
Configuration[] tripletCfg = fontCfg.getChildren("font-triplet"); | |||
// no font triplet info | |||
if (tripletCfg.length == 0) { | |||
LogUtil.handleError(log, "font without font-triplet", strict); | |||
File fontFile = FontCache.getFileFromUrls(new String[] {embedUrl, metricsUrl}); | |||
URL fontURL = null; | |||
try { | |||
fontURL = fontFile.toURI().toURL(); | |||
} catch (MalformedURLException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
if (fontFile != null) { | |||
FontInfoFinder finder = new FontInfoFinder(); | |||
finder.setEventListener(listener); | |||
EmbedFontInfo[] infos = finder.find(fontURL, fontResolver, fontCache); | |||
return infos[0]; //When subFont is set, only one font is returned | |||
} else { | |||
return null; | |||
} | |||
} | |||
List<FontTriplet> tripletList = new java.util.ArrayList<FontTriplet>(); | |||
for (int j = 0; j < tripletCfg.length; j++) { | |||
FontTriplet fontTriplet = getFontTriplet(tripletCfg[j]); | |||
tripletList.add(fontTriplet); | |||
} | |||
boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); | |||
boolean useAdvanced = fontCfg.getAttributeAsBoolean("advanced", true); | |||
EncodingMode encodingMode = EncodingMode.getEncodingMode( | |||
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); | |||
EmbedFontInfo embedFontInfo | |||
= new EmbedFontInfo(metricsUrl, useKerning, useAdvanced, tripletList, embedUrl, | |||
subFont); | |||
embedFontInfo.setEncodingMode(encodingMode); | |||
boolean skipCachedFont = false; | |||
if (fontCache != null) { | |||
if (!fontCache.containsFont(embedFontInfo)) { | |||
fontCache.addFont(embedFontInfo); | |||
} else { | |||
skipCachedFont = true; | |||
} | |||
} | |||
if (log.isDebugEnabled()) { | |||
String embedFile = embedFontInfo.getEmbedFile(); | |||
log.debug( ( skipCachedFont ? "Skipping (cached) font " : "Adding font " ) | |||
+ (embedFile != null ? embedFile + ", " : "") | |||
+ "metric file " + embedFontInfo.getMetricsFile()); | |||
for (int j = 0; j < tripletList.size(); ++j) { | |||
FontTriplet triplet = tripletList.get(j); | |||
log.debug(" Font triplet " | |||
+ triplet.getName() + ", " | |||
+ triplet.getStyle() + ", " | |||
+ triplet.getWeight()); | |||
} | |||
} | |||
return embedFontInfo; | |||
} | |||
/** | |||
* Creates a new FontTriplet given a triple Configuration | |||
* | |||
* @param tripletCfg a triplet configuration | |||
* @return a font triplet font key | |||
* @throws FOPException thrown if a FOP exception occurs | |||
*/ | |||
private FontTriplet getFontTriplet(Configuration tripletCfg) throws FOPException { | |||
try { | |||
String name = tripletCfg.getAttribute("name"); | |||
if (name == null) { | |||
LogUtil.handleError(log, "font-triplet without name", strict); | |||
return null; | |||
} | |||
String weightStr = tripletCfg.getAttribute("weight"); | |||
if (weightStr == null) { | |||
LogUtil.handleError(log, "font-triplet without weight", strict); | |||
return null; | |||
} | |||
int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr)); | |||
String style = tripletCfg.getAttribute("style"); | |||
if (style == null) { | |||
LogUtil.handleError(log, "font-triplet without style", strict); | |||
return null; | |||
} else { | |||
style = FontUtil.stripWhiteSpace(style); | |||
} | |||
return FontInfo.createFontKey(name, style, weight); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
return null; | |||
} | |||
} |
@@ -19,18 +19,13 @@ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import java.net.URI; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.truetype.TTFFontLoader; | |||
import org.apache.fop.fonts.type1.Type1FontLoader; | |||
@@ -43,9 +38,9 @@ public abstract class FontLoader { | |||
protected static final Log log = LogFactory.getLog(FontLoader.class); | |||
/** URI representing the font file */ | |||
protected String fontFileURI; | |||
protected final URI fontFileURI; | |||
/** the FontResolver to use for font URI resolution */ | |||
protected FontResolver resolver; | |||
protected final URIResolverWrapper resolver; | |||
/** the loaded font */ | |||
protected CustomFont returnFont; | |||
@@ -67,8 +62,8 @@ public abstract class FontLoader { | |||
* available | |||
* @param resolver the font resolver used to resolve URIs | |||
*/ | |||
public FontLoader(String fontFileURI, boolean embedded, boolean useKerning, | |||
boolean useAdvanced, FontResolver resolver) { | |||
public FontLoader(URI fontFileURI, boolean embedded, boolean useKerning, | |||
boolean useAdvanced, URIResolverWrapper resolver) { | |||
this.fontFileURI = fontFileURI; | |||
this.embedded = embedded; | |||
this.useKerning = useKerning; | |||
@@ -76,42 +71,8 @@ public abstract class FontLoader { | |||
this.resolver = resolver; | |||
} | |||
private static boolean isType1(String fontURI) { | |||
return fontURI.toLowerCase().endsWith(".pfb"); | |||
} | |||
/** | |||
* 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 encodingMode the requested encoding mode | |||
* @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, | |||
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { | |||
return loadFont(fontFile.toURI().toURL(), subFontName, | |||
embedded, encodingMode, 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 encodingMode the requested encoding mode | |||
* @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, | |||
boolean embedded, EncodingMode encodingMode, | |||
FontResolver resolver) throws IOException { | |||
return loadFont(fontUrl.toExternalForm(), subFontName, | |||
embedded, encodingMode, true, true, | |||
resolver); | |||
private static boolean isType1(URI fontURI) { | |||
return fontURI.toASCIIString().toLowerCase().endsWith(".pfb"); | |||
} | |||
/** | |||
@@ -127,10 +88,9 @@ public abstract class FontLoader { | |||
* @return the newly loaded font | |||
* @throws IOException In case of an I/O error | |||
*/ | |||
public static CustomFont loadFont(String fontFileURI, String subFontName, | |||
public static CustomFont loadFont(URI fontFileURI, String subFontName, | |||
boolean embedded, EncodingMode encodingMode, boolean useKerning, | |||
boolean useAdvanced, FontResolver resolver) throws IOException { | |||
fontFileURI = fontFileURI.trim(); | |||
boolean useAdvanced, URIResolverWrapper resolver) throws IOException { | |||
boolean type1 = isType1(fontFileURI); | |||
FontLoader loader; | |||
if (type1) { | |||
@@ -146,41 +106,6 @@ public abstract class FontLoader { | |||
return loader.getFont(); | |||
} | |||
/** | |||
* Opens a font URI and returns an input stream. | |||
* @param resolver the FontResolver to use for font URI resolution | |||
* @param uri the URI representing the font | |||
* @return the InputStream to read the font from. | |||
* @throws IOException In case of an I/O error | |||
* @throws MalformedURLException If an invalid URL is built | |||
*/ | |||
public static InputStream openFontUri(FontResolver resolver, String uri) | |||
throws IOException, MalformedURLException { | |||
InputStream in = null; | |||
if (resolver != null) { | |||
Source source = resolver.resolve(uri); | |||
if (source == null) { | |||
String err = "Cannot load font: failed to create Source for font file " | |||
+ uri; | |||
throw new IOException(err); | |||
} | |||
if (source instanceof StreamSource) { | |||
in = ((StreamSource) source).getInputStream(); | |||
} | |||
if (in == null && source.getSystemId() != null) { | |||
in = new java.net.URL(source.getSystemId()).openStream(); | |||
} | |||
if (in == null) { | |||
String err = "Cannot load font: failed to create InputStream from" | |||
+ " Source for font file " + uri; | |||
throw new IOException(err); | |||
} | |||
} else { | |||
in = new URL(uri).openStream(); | |||
} | |||
return in; | |||
} | |||
/** | |||
* Reads/parses the font data. | |||
* @throws IOException In case of an I/O error |
@@ -20,13 +20,10 @@ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.net.MalformedURLException; | |||
import java.util.List; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.FontTriplet.Matcher; | |||
import org.apache.fop.fonts.substitute.FontSubstitutions; | |||
@@ -38,14 +35,13 @@ import org.apache.fop.fonts.substitute.FontSubstitutions; | |||
* font substitution, referenced fonts and similar. | |||
*/ | |||
public class FontManager { | |||
/** Use cache (record previously detected font triplet info) */ | |||
public static final boolean DEFAULT_USE_CACHE = true; | |||
/** The base URL for all font URL resolutions. */ | |||
private String fontBase = null; | |||
private URIResolverWrapper uriResolver; | |||
private final FontDetector fontDetector; | |||
/** Font cache to speed up auto-font configuration (null if disabled) */ | |||
private FontCache fontCache = null; | |||
private FontCacheManager fontCacheManager; | |||
/** Font substitutions */ | |||
private FontSubstitutions fontSubstitutions = null; | |||
@@ -56,33 +52,33 @@ public class FontManager { | |||
/** FontTriplet matcher for fonts that shall be referenced rather than embedded. */ | |||
private FontTriplet.Matcher referencedFontsMatcher; | |||
/** Enables/disables the use of font caching */ | |||
private boolean useCache = DEFAULT_USE_CACHE; | |||
/** Provides a font cache file path **/ | |||
private File cacheFile; | |||
/** | |||
* Main constructor | |||
* | |||
* @param uriResolver the URI resolver | |||
* @param fontDetector the font detector | |||
* @param fontCacheManager the font cache manager | |||
*/ | |||
public FontManager() { | |||
public FontManager(URIResolverWrapper uriResolver, FontDetector fontDetector, | |||
FontCacheManager fontCacheManager) { | |||
this.uriResolver = uriResolver; | |||
this.fontDetector = fontDetector; | |||
this.fontCacheManager = fontCacheManager; | |||
} | |||
/** | |||
* Sets the font base URL. | |||
* @param fontBase font base URL | |||
* @throws MalformedURLException if there's a problem with a URL | |||
* Sets the font URI resolver | |||
* @param uriResolver font base URI | |||
*/ | |||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | |||
this.fontBase = fontBase; | |||
public void setFontURIResolver(URIResolverWrapper uriResolver) { | |||
this.uriResolver = uriResolver; | |||
} | |||
/** | |||
* Returns the font base URL. | |||
* @return the font base URL (or null if none was set) | |||
*/ | |||
public String getFontBaseURL() { | |||
return this.fontBase; | |||
public URIResolverWrapper getURIResolver() { | |||
return this.uriResolver; | |||
} | |||
/** @return true if kerning on base 14 fonts is enabled */ | |||
@@ -130,29 +126,22 @@ public class FontManager { | |||
* @return the font cache file | |||
*/ | |||
public File getCacheFile() { | |||
return getCacheFile(false); | |||
} | |||
private File getCacheFile(boolean writable) { | |||
if (cacheFile != null) { | |||
return this.cacheFile; | |||
return cacheFile; | |||
} | |||
return FontCache.getDefaultCacheFile(false); | |||
return FontCache.getDefaultCacheFile(writable); | |||
} | |||
/** | |||
* Whether or not to cache results of font triplet detection/auto-config | |||
* @param useCache use cache or not | |||
*/ | |||
public void setUseCache(boolean useCache) { | |||
this.useCache = useCache; | |||
if (!useCache) { | |||
this.fontCache = null; | |||
} | |||
} | |||
/** | |||
* Cache results of font triplet detection/auto-config? | |||
* @return true if this font manager uses the cache | |||
*/ | |||
public boolean useCache() { | |||
return useCache; | |||
public void disableFontCache() { | |||
fontCacheManager = FontCacheManagerFactory.createDisabled(); | |||
} | |||
/** | |||
@@ -160,19 +149,7 @@ public class FontManager { | |||
* @return the font cache | |||
*/ | |||
public FontCache getFontCache() { | |||
if (fontCache == null) { | |||
if (useCache) { | |||
if (cacheFile != null) { | |||
fontCache = FontCache.loadFrom(cacheFile); | |||
} else { | |||
fontCache = FontCache.load(); | |||
} | |||
if (fontCache == null) { | |||
fontCache = new FontCache(); | |||
} | |||
} | |||
} | |||
return fontCache; | |||
return fontCacheManager.load(getCacheFile()); | |||
} | |||
/** | |||
@@ -181,31 +158,16 @@ public class FontManager { | |||
* @throws FOPException fop exception | |||
*/ | |||
public void saveCache() throws FOPException { | |||
if (useCache) { | |||
if (fontCache != null && fontCache.hasChanged()) { | |||
if (cacheFile != null) { | |||
fontCache.saveTo(cacheFile); | |||
} else { | |||
fontCache.save(); | |||
} | |||
} | |||
} | |||
fontCacheManager.save(getCacheFile()); | |||
} | |||
/** | |||
* Deletes the current FontCache file | |||
* @return Returns true if the font cache file was successfully deleted. | |||
* @throws FOPException - | |||
*/ | |||
public boolean deleteCache() { | |||
boolean deleted = false; | |||
if (useCache) { | |||
if (cacheFile != null) { | |||
deleted = cacheFile.delete(); | |||
} else { | |||
deleted = FontCache.getDefaultCacheFile(true).delete(); | |||
} | |||
} | |||
return deleted; | |||
public void deleteCache() throws FOPException { | |||
fontCacheManager.delete(getCacheFile(true)); | |||
} | |||
/** | |||
@@ -224,34 +186,6 @@ public class FontManager { | |||
getFontSubstitutions().adjustFontInfo(fontInfo); | |||
} | |||
/** | |||
* Minimum implemenation of FontResolver. | |||
*/ | |||
public static class MinimalFontResolver implements FontResolver { | |||
private boolean useComplexScriptFeatures; | |||
MinimalFontResolver(boolean useComplexScriptFeatures) { | |||
this.useComplexScriptFeatures = useComplexScriptFeatures; | |||
} | |||
/** {@inheritDoc} */ | |||
public Source resolve(String href) { | |||
//Minimal functionality here | |||
return new StreamSource(href); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isComplexScriptFeaturesEnabled() { | |||
return useComplexScriptFeatures; | |||
} | |||
} | |||
/** | |||
* Create minimal font resolver. | |||
* @param useComplexScriptFeatures true if complex script features enabled | |||
* @return a new FontResolver to be used by the font subsystem | |||
*/ | |||
public static FontResolver createMinimalFontResolver(boolean useComplexScriptFeatures) { | |||
return new MinimalFontResolver ( useComplexScriptFeatures ); | |||
} | |||
/** | |||
* Sets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall | |||
* be referenced rather than embedded. | |||
@@ -298,4 +232,11 @@ public class FontManager { | |||
} | |||
} | |||
} | |||
public void autoDetectFonts(boolean autoDetectFonts, FontAdder fontAdder, boolean strict, | |||
FontEventListener listener, List<EmbedFontInfo> fontInfoList) throws FOPException { | |||
if (autoDetectFonts) { | |||
fontDetector.detect(this, fontAdder, strict, listener, fontInfoList); | |||
} | |||
} | |||
} |
@@ -20,8 +20,8 @@ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.List; | |||
import java.util.regex.Pattern; | |||
@@ -31,6 +31,8 @@ import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.substitute.FontSubstitutions; | |||
import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator; | |||
import org.apache.fop.util.LogUtil; | |||
@@ -45,24 +47,21 @@ public class FontManagerConfigurator { | |||
private final Configuration cfg; | |||
private URI baseURI = null; | |||
private final URI defaultBaseUri; | |||
/** | |||
* Main constructor | |||
* @param cfg the font manager configuration object | |||
*/ | |||
public FontManagerConfigurator(Configuration cfg) { | |||
this.cfg = cfg; | |||
} | |||
private final ResourceResolver uriResolver; | |||
/** | |||
* Main constructor | |||
* @param cfg the font manager configuration object | |||
* @param baseURI the base URI of the configuration | |||
* @param defaultBaseUri the default URI base to use for URI resolution | |||
* @param resolver the URI resolver | |||
*/ | |||
public FontManagerConfigurator(Configuration cfg, URI baseURI) { | |||
public FontManagerConfigurator(Configuration cfg, URI defaultBaseUri, | |||
ResourceResolver resolver) { | |||
this.cfg = cfg; | |||
this.baseURI = baseURI; | |||
this.defaultBaseUri = defaultBaseUri; | |||
this.uriResolver = resolver; | |||
} | |||
/** | |||
@@ -75,28 +74,29 @@ public class FontManagerConfigurator { | |||
// caching (fonts) | |||
if (cfg.getChild("use-cache", false) != null) { | |||
try { | |||
fontManager.setUseCache(cfg.getChild("use-cache").getValueAsBoolean()); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, true); | |||
} | |||
} | |||
if (cfg.getChild("cache-file", false) != null) { | |||
try { | |||
fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue())); | |||
} catch (ConfigurationException e) { | |||
LogUtil.handleException(log, e, true); | |||
// TODO: Find some way to deal with this!! | |||
if (!cfg.getChild("use-cache").getValueAsBoolean()) { | |||
fontManager.disableFontCache(); | |||
} else { | |||
if (cfg.getChild("cache-file", false) != null) { | |||
fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue())); | |||
} | |||
} | |||
} catch (ConfigurationException mfue) { | |||
LogUtil.handleException(log, mfue, true); | |||
} | |||
} | |||
if (cfg.getChild("font-base", false) != null) { | |||
String path = cfg.getChild("font-base").getValue(null); | |||
if (baseURI != null) { | |||
path = baseURI.resolve(path).normalize().toString(); | |||
} | |||
try { | |||
fontManager.setFontBaseURL(path); | |||
} catch (MalformedURLException mfue) { | |||
LogUtil.handleException(log, mfue, true); | |||
URI fontBase = URIResolverWrapper.getBaseURI(cfg.getChild("font-base").getValue( | |||
null)); | |||
fontManager.setFontURIResolver(new URIResolverWrapper( | |||
defaultBaseUri.resolve(fontBase), uriResolver)); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, true); | |||
} | |||
} else { | |||
fontManager.setFontURIResolver(new URIResolverWrapper(defaultBaseUri, uriResolver)); | |||
} | |||
// [GA] permit configuration control over base14 kerning; without this, | |||
@@ -114,7 +114,6 @@ public class FontManagerConfigurator { | |||
// global font configuration | |||
Configuration fontsCfg = cfg.getChild("fonts", false); | |||
if (fontsCfg != null) { | |||
// font substitution | |||
Configuration substitutionsCfg = fontsCfg.getChild("substitutions", false); | |||
if (substitutionsCfg != null) { | |||
@@ -122,7 +121,6 @@ public class FontManagerConfigurator { | |||
new FontSubstitutionsConfigurator(substitutionsCfg).configure(substitutions); | |||
fontManager.setFontSubstitutions(substitutions); | |||
} | |||
// referenced fonts (fonts which are not to be embedded) | |||
Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false); | |||
if (referencedFontsCfg != null) { | |||
@@ -130,7 +128,6 @@ public class FontManagerConfigurator { | |||
referencedFontsCfg, strict); | |||
fontManager.setReferencedFontsMatcher(matcher); | |||
} | |||
} | |||
} | |||
@@ -159,6 +156,24 @@ public class FontManagerConfigurator { | |||
return orMatcher; | |||
} | |||
/** | |||
* Creates a font triplet matcher from a configuration object. | |||
* @param fontFamilies the list of font families | |||
* @param strict true for strict configuraton error handling | |||
* @return the font matcher | |||
* @throws FOPException if an error occurs while building the matcher | |||
*/ | |||
public static FontTriplet.Matcher createFontsMatcher( | |||
List<String> fontFamilies, boolean strict) throws FOPException { | |||
List<FontTriplet.Matcher> matcherList = new java.util.ArrayList<FontTriplet.Matcher>(); | |||
for (String fontFamily : fontFamilies) { | |||
matcherList.add(new FontFamilyRegExFontTripletMatcher(fontFamily)); | |||
} | |||
FontTriplet.Matcher orMatcher = new OrFontTripletMatcher( | |||
matcherList.toArray(new FontTriplet.Matcher[matcherList.size()])); | |||
return orMatcher; | |||
} | |||
private static class OrFontTripletMatcher implements FontTriplet.Matcher { | |||
private final FontTriplet.Matcher[] matchers; |
@@ -21,6 +21,8 @@ package org.apache.fop.fonts; | |||
//Java | |||
import java.io.IOException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
@@ -32,12 +34,12 @@ import javax.xml.parsers.SAXParserFactory; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.InputSource; | |||
import org.xml.sax.Locator; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.XMLReader; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.apps.TTFReader; | |||
/** | |||
@@ -52,19 +54,30 @@ import org.apache.fop.fonts.apps.TTFReader; | |||
*/ | |||
public class FontReader extends DefaultHandler { | |||
// private Locator locator = null; // not used at present | |||
private boolean isCID = false; | |||
private CustomFont returnFont = null; | |||
private MultiByteFont multiFont = null; | |||
private SingleByteFont singleFont = null; | |||
private boolean isCID; | |||
private CustomFont returnFont; | |||
private MultiByteFont multiFont; | |||
private SingleByteFont singleFont; | |||
private final URIResolverWrapper resolver; | |||
private StringBuffer text = new StringBuffer(); | |||
private List<Integer> cidWidths = null; | |||
private int cidWidthIndex = 0; | |||
private List<Integer> cidWidths; | |||
//private int cidWidthIndex; | |||
private Map<Integer, Integer> currentKerning = null; | |||
private Map<Integer, Integer> currentKerning; | |||
private List<BFEntry> bfranges = null; | |||
private List<BFEntry> bfranges; | |||
/** | |||
* Construct a FontReader object from a path to a metric.xml file | |||
* and read metric data | |||
* @param source Source of the font metric file | |||
* @throws FOPException if loading the font fails | |||
*/ | |||
public FontReader(InputSource source, URIResolverWrapper resolver) throws FOPException { | |||
this.resolver = resolver; | |||
createFont(source); | |||
} | |||
private void createFont(InputSource source) throws FOPException { | |||
XMLReader parser = null; | |||
@@ -81,11 +94,9 @@ public class FontReader extends DefaultHandler { | |||
} | |||
try { | |||
parser.setFeature("http://xml.org/sax/features/namespace-prefixes", | |||
false); | |||
parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); | |||
} catch (SAXException e) { | |||
throw new FOPException("You need a SAX parser which supports SAX version 2", | |||
e); | |||
throw new FOPException("You need a SAX parser which supports SAX version 2", e); | |||
} | |||
parser.setContentHandler(this); | |||
@@ -104,8 +115,8 @@ public class FontReader extends DefaultHandler { | |||
* Sets the path to embed a font. A null value disables font embedding. | |||
* @param path URI for the embeddable file | |||
*/ | |||
public void setFontEmbedPath(String path) { | |||
returnFont.setEmbedFileName(path); | |||
public void setFontEmbedURI(URI path) { | |||
returnFont.setEmbedURI(path); | |||
} | |||
/** | |||
@@ -124,15 +135,6 @@ public class FontReader extends DefaultHandler { | |||
returnFont.setAdvancedEnabled(enabled); | |||
} | |||
/** | |||
* Sets the font resolver. Needed for URI resolution. | |||
* @param resolver the font resolver | |||
*/ | |||
public void setResolver(FontResolver resolver) { | |||
returnFont.setResolver(resolver); | |||
} | |||
/** | |||
* Get the generated font object | |||
* @return the font | |||
@@ -141,16 +143,6 @@ public class FontReader extends DefaultHandler { | |||
return returnFont; | |||
} | |||
/** | |||
* Construct a FontReader object from a path to a metric.xml file | |||
* and read metric data | |||
* @param source Source of the font metric file | |||
* @throws FOPException if loading the font fails | |||
*/ | |||
public FontReader(InputSource source) throws FOPException { | |||
createFont(source); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@@ -160,65 +152,62 @@ public class FontReader extends DefaultHandler { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public void setDocumentLocator(Locator locator) { | |||
// this.locator = locator; // not used at present | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public void startElement(String uri, String localName, String qName, | |||
Attributes attributes) throws SAXException { | |||
public void startElement(String uri, String localName, String qName, Attributes attributes) | |||
throws SAXException { | |||
if (localName.equals("font-metrics")) { | |||
if ("TYPE0".equals(attributes.getValue("type"))) { | |||
multiFont = new MultiByteFont(); | |||
multiFont = new MultiByteFont(resolver); | |||
returnFont = multiFont; | |||
isCID = true; | |||
TTFReader.checkMetricsVersion(attributes); | |||
} else if ("TRUETYPE".equals(attributes.getValue("type"))) { | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resolver); | |||
singleFont.setFontType(FontType.TRUETYPE); | |||
returnFont = singleFont; | |||
isCID = false; | |||
TTFReader.checkMetricsVersion(attributes); | |||
} else { | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resolver); | |||
singleFont.setFontType(FontType.TYPE1); | |||
returnFont = singleFont; | |||
isCID = false; | |||
} | |||
} else if ("embed".equals(localName)) { | |||
returnFont.setEmbedFileName(attributes.getValue("file")); | |||
try { | |||
returnFont.setEmbedURI(URIResolverWrapper.cleanURI(attributes.getValue("file"))); | |||
} catch (URISyntaxException e) { | |||
// TODO: dunno what to do here?!?! | |||
} | |||
returnFont.setEmbedResourceName(attributes.getValue("class")); | |||
} else if ("cid-widths".equals(localName)) { | |||
cidWidthIndex = getInt(attributes.getValue("start-index")); | |||
// This is unused | |||
// cidWidthIndex = getInt(attributes.getValue("start-index")); | |||
cidWidths = new ArrayList<Integer>(); | |||
} else if ("kerning".equals(localName)) { | |||
currentKerning = new HashMap<Integer, Integer>(); | |||
returnFont.putKerningEntry(new Integer(attributes.getValue("kpx1")), | |||
currentKerning); | |||
returnFont.putKerningEntry(getInt(attributes.getValue("kpx1")), | |||
currentKerning); | |||
} else if ("bfranges".equals(localName)) { | |||
bfranges = new ArrayList<BFEntry>(); | |||
} else if ("bf".equals(localName)) { | |||
BFEntry entry = new BFEntry(getInt(attributes.getValue("us")), | |||
getInt(attributes.getValue("ue")), | |||
getInt(attributes.getValue("gi"))); | |||
getInt(attributes.getValue("ue")), | |||
getInt(attributes.getValue("gi"))); | |||
bfranges.add(entry); | |||
} else if ("wx".equals(localName)) { | |||
cidWidths.add(new Integer(attributes.getValue("w"))); | |||
} else if ("widths".equals(localName)) { | |||
//singleFont.width = new int[256]; | |||
cidWidths.add(getInt(attributes.getValue("w"))); | |||
// } else if ("widths".equals(localName)) { | |||
// singleFont.width = new int[256]; | |||
} else if ("char".equals(localName)) { | |||
try { | |||
singleFont.setWidth(Integer.parseInt(attributes.getValue("idx")), | |||
Integer.parseInt(attributes.getValue("wdt"))); | |||
singleFont.setWidth(getInt(attributes.getValue("idx")), | |||
getInt(attributes.getValue("wdt"))); | |||
} catch (NumberFormatException ne) { | |||
throw new SAXException("Malformed width in metric file: " | |||
+ ne.getMessage(), ne); | |||
throw new SAXException("Malformed width in metric file: " + ne.getMessage(), ne); | |||
} | |||
} else if ("pair".equals(localName)) { | |||
currentKerning.put(new Integer(attributes.getValue("kpx2")), | |||
new Integer(attributes.getValue("kern"))); | |||
currentKerning.put(getInt(attributes.getValue("kpx2")), | |||
getInt(attributes.getValue("kern"))); | |||
} | |||
} | |||
@@ -314,5 +303,4 @@ public class FontReader extends DefaultHandler { | |||
public void characters(char[] ch, int start, int length) { | |||
text.append(ch, start, length); | |||
} | |||
} |
@@ -22,9 +22,7 @@ package org.apache.fop.fonts; | |||
// FOP (base 14 fonts) | |||
import java.util.List; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.base14.Courier; | |||
import org.apache.fop.fonts.base14.CourierBold; | |||
import org.apache.fop.fonts.base14.CourierBoldOblique; | |||
@@ -74,8 +72,8 @@ public final class FontSetup { | |||
* @param resolver the font resolver | |||
* @param base14Kerning true if base14 kerning applies | |||
*/ | |||
public static void setup(FontInfo fontInfo, List<EmbedFontInfo> embedFontInfoList, | |||
FontResolver resolver, boolean base14Kerning) { | |||
public static void setup(FontInfo fontInfo, List embedFontInfoList, | |||
URIResolverWrapper resolver, boolean base14Kerning) { | |||
fontInfo.addMetrics("F1", new Helvetica(base14Kerning)); | |||
fontInfo.addMetrics("F2", new HelveticaOblique(base14Kerning)); | |||
fontInfo.addMetrics("F3", new HelveticaBold(base14Kerning)); | |||
@@ -192,18 +190,12 @@ public final class FontSetup { | |||
* @param resolver the font resolver | |||
*/ | |||
private static void addConfiguredFonts(FontInfo fontInfo, | |||
List<EmbedFontInfo> embedFontInfoList, int num, FontResolver resolver, | |||
List<EmbedFontInfo> embedFontInfoList, int num, URIResolverWrapper resolver, | |||
boolean base14Kerning) { | |||
if (embedFontInfoList == null) { | |||
return; //No fonts to process | |||
} | |||
if (resolver == null) { | |||
//Ensure that we have minimal font resolution capabilities | |||
//None of the built-in base14 fonts have advanced typographic data | |||
boolean useAdvanced = false; | |||
resolver = createMinimalFontResolver(useAdvanced); | |||
} | |||
assert resolver != null; | |||
String internalName = null; | |||
@@ -211,7 +203,7 @@ public final class FontSetup { | |||
internalName = "F" + num; | |||
num++; | |||
LazyFont font = new LazyFont(embedFontInfo, resolver); | |||
LazyFont font = new LazyFont(embedFontInfo, resolver, false); | |||
fontInfo.addMetrics(internalName, font); | |||
List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); | |||
@@ -221,32 +213,4 @@ public final class FontSetup { | |||
} | |||
} | |||
} | |||
/** | |||
* Minimum implemenation of FontResolver. | |||
*/ | |||
public static class MinimalFontResolver implements FontResolver { | |||
private boolean useComplexScriptFeatures; | |||
MinimalFontResolver(boolean useComplexScriptFeatures) { | |||
this.useComplexScriptFeatures = useComplexScriptFeatures; | |||
} | |||
/** {@inheritDoc} */ | |||
public Source resolve(String href) { | |||
//Minimal functionality here | |||
return new StreamSource(href); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isComplexScriptFeaturesEnabled() { | |||
return useComplexScriptFeatures; | |||
} | |||
} | |||
/** | |||
* Create minimal font resolver. | |||
* @param useComplexScriptFeatures true if complex script features enabled | |||
* @return a new FontResolver to be used by the font subsystem | |||
*/ | |||
public static FontResolver createMinimalFontResolver(boolean useComplexScriptFeatures) { | |||
return new MinimalFontResolver ( useComplexScriptFeatures ); | |||
} | |||
} |
@@ -38,14 +38,6 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable { | |||
//This is only a cache | |||
private transient String key; | |||
/** | |||
* Creates a new font triplet (for base14 use). | |||
* @param name font name | |||
*/ | |||
public FontTriplet(String name) { | |||
this.name = name; | |||
} | |||
/** | |||
* Creates a new font triplet. | |||
* @param name font name | |||
@@ -64,7 +56,7 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable { | |||
* @param priority priority of this triplet/font mapping | |||
*/ | |||
public FontTriplet(String name, String style, int weight, int priority) { | |||
this(name); | |||
this.name = name; | |||
this.style = style; | |||
this.weight = weight; | |||
this.priority = priority; |
@@ -20,23 +20,20 @@ | |||
package org.apache.fop.fonts; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.net.URI; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.xml.sax.InputSource; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.complexscripts.fonts.Positionable; | |||
import org.apache.fop.complexscripts.fonts.Substitutable; | |||
/** | |||
* This class is used to defer the loading of a font until it is really used. | |||
*/ | |||
@@ -44,36 +41,35 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, | |||
private static Log log = LogFactory.getLog(LazyFont.class); | |||
private String metricsFileName; | |||
private String fontEmbedPath; | |||
private boolean useKerning; | |||
private boolean useAdvanced; | |||
private EncodingMode encodingMode = EncodingMode.AUTO; | |||
private boolean embedded; | |||
private String subFontName; | |||
private final URI metricsURI; | |||
private final URI fontEmbedURI; | |||
private final boolean useKerning; | |||
private final boolean useAdvanced; | |||
private final EncodingMode encodingMode; | |||
private final boolean embedded; | |||
private final String subFontName; | |||
private final URIResolverWrapper resolver; | |||
private boolean isMetricsLoaded; | |||
private Typeface realFont; | |||
private FontDescriptor realFontDescriptor; | |||
private FontResolver resolver; | |||
/** | |||
* Main constructor | |||
* @param fontInfo the font info to embed | |||
* @param resolver the font resolver to handle font URIs | |||
*/ | |||
public LazyFont(EmbedFontInfo fontInfo, FontResolver resolver) { | |||
this.metricsFileName = fontInfo.getMetricsFile(); | |||
this.fontEmbedPath = fontInfo.getEmbedFile(); | |||
public LazyFont(EmbedFontInfo fontInfo, URIResolverWrapper resolver, boolean useComplexScripts) { | |||
this.metricsURI = fontInfo.getMetricsURI(); | |||
this.fontEmbedURI = fontInfo.getEmbedURI(); | |||
this.useKerning = fontInfo.getKerning(); | |||
if ( resolver != null ) { | |||
this.useAdvanced = resolver.isComplexScriptFeaturesEnabled(); | |||
if (resolver != null) { | |||
this.useAdvanced = useComplexScripts; | |||
} else { | |||
this.useAdvanced = fontInfo.getAdvanced(); | |||
} | |||
this.encodingMode = fontInfo.getEncodingMode(); | |||
this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode() | |||
: EncodingMode.AUTO; | |||
this.subFontName = fontInfo.getSubFontName(); | |||
this.embedded = fontInfo.isEmbedded(); | |||
this.resolver = resolver; | |||
@@ -83,8 +79,8 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, | |||
public String toString() { | |||
StringBuffer sbuf = new StringBuffer(super.toString()); | |||
sbuf.append('{'); | |||
sbuf.append("metrics-url=" + metricsFileName); | |||
sbuf.append(",embed-url=" + fontEmbedPath); | |||
sbuf.append("metrics-url=" + metricsURI); | |||
sbuf.append(",embed-url=" + fontEmbedURI); | |||
sbuf.append(",kerning=" + useKerning); | |||
sbuf.append(",advanced=" + useAdvanced); | |||
sbuf.append('}'); | |||
@@ -94,74 +90,38 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, | |||
private void load(boolean fail) { | |||
if (!isMetricsLoaded) { | |||
try { | |||
if (metricsFileName != null) { | |||
if (metricsURI != null) { | |||
/**@todo Possible thread problem here */ | |||
FontReader reader = null; | |||
if (resolver != null) { | |||
Source source = resolver.resolve(metricsFileName); | |||
if (source == null) { | |||
String err | |||
= "Cannot load font: failed to create Source from metrics file " | |||
+ metricsFileName; | |||
if (fail) { | |||
throw new RuntimeException(err); | |||
} else { | |||
log.error(err); | |||
} | |||
return; | |||
} | |||
InputStream in = null; | |||
if (source instanceof StreamSource) { | |||
in = ((StreamSource) source).getInputStream(); | |||
} | |||
if (in == null && source.getSystemId() != null) { | |||
in = new java.net.URL(source.getSystemId()).openStream(); | |||
} | |||
if (in == null) { | |||
String err = "Cannot load font: After URI resolution, the returned" | |||
+ " Source object does not contain an InputStream" | |||
+ " or a valid URL (system identifier) for metrics file: " | |||
+ metricsFileName; | |||
if (fail) { | |||
throw new RuntimeException(err); | |||
} else { | |||
log.error(err); | |||
} | |||
return; | |||
} | |||
InputSource src = new InputSource(in); | |||
src.setSystemId(source.getSystemId()); | |||
reader = new FontReader(src); | |||
} else { | |||
reader = new FontReader(new InputSource( | |||
new URL(metricsFileName).openStream())); | |||
} | |||
InputStream in = resolver.resolveIn(metricsURI); | |||
InputSource src = new InputSource(in); | |||
src.setSystemId(metricsURI.toASCIIString()); | |||
reader = new FontReader(src, resolver); | |||
reader.setKerningEnabled(useKerning); | |||
reader.setAdvancedEnabled(useAdvanced); | |||
if (this.embedded) { | |||
reader.setFontEmbedPath(fontEmbedPath); | |||
reader.setFontEmbedURI(fontEmbedURI); | |||
} | |||
reader.setResolver(resolver); | |||
realFont = reader.getFont(); | |||
} else { | |||
if (fontEmbedPath == null) { | |||
if (fontEmbedURI == null) { | |||
throw new RuntimeException("Cannot load font. No font URIs available."); | |||
} | |||
realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, | |||
realFont = FontLoader.loadFont(fontEmbedURI, this.subFontName, | |||
this.embedded, this.encodingMode, useKerning, useAdvanced, resolver); | |||
} | |||
if (realFont instanceof FontDescriptor) { | |||
realFontDescriptor = (FontDescriptor) realFont; | |||
} | |||
} catch (FOPException fopex) { | |||
log.error("Failed to read font metrics file " + metricsFileName, fopex); | |||
log.error("Failed to read font metrics file " + metricsURI, fopex); | |||
if (fail) { | |||
throw new RuntimeException(fopex.getMessage()); | |||
throw new RuntimeException(fopex); | |||
} | |||
} catch (IOException ioex) { | |||
log.error("Failed to read font metrics file " + metricsFileName, ioex); | |||
log.error("Failed to read font metrics file " + metricsURI, ioex); | |||
if (fail) { | |||
throw new RuntimeException(ioex.getMessage()); | |||
throw new RuntimeException(ioex); | |||
} | |||
} | |||
realFont.setEventListener(this.eventListener); |
@@ -26,6 +26,7 @@ import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; | |||
@@ -74,9 +75,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
private int lastUnmapped; | |||
/** | |||
* Default constructor | |||
* @param resolver the URI resolver for controlling file access | |||
*/ | |||
public MultiByteFont() { | |||
public MultiByteFont(URIResolverWrapper resolver) { | |||
super(resolver); | |||
subset.setupFirstGlyph(); | |||
setFontType(FontType.TYPE0); | |||
} | |||
@@ -125,7 +127,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
/** {@inheritDoc} */ | |||
public boolean isEmbeddable() { | |||
return !(getEmbedFileName() == null && getEmbedResourceName() == null); | |||
return !(getEmbedFileURI() == null && getEmbedResourceName() == null); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -561,7 +563,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
} | |||
} | |||
cb.flip(); | |||
return (CharSequence) cb; | |||
return cb; | |||
} | |||
} |
@@ -19,6 +19,7 @@ | |||
package org.apache.fop.fonts; | |||
import java.net.URI; | |||
import java.util.Map; | |||
import java.util.Set; | |||
@@ -49,10 +50,10 @@ public interface MutableFont { | |||
void setFamilyNames(Set<String> names); | |||
/** | |||
* Sets the path to the embeddable font file. | |||
* @param path URI to the file | |||
* Sets the URI to the embeddable font. | |||
* @param path URI to the font | |||
*/ | |||
void setEmbedFileName(String path); | |||
void setEmbedURI(URI path); | |||
/** | |||
* Sets the resource name of the embeddable font file. |
@@ -31,6 +31,8 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.fonts.Glyphs; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
/** | |||
* Generic SingleByte font | |||
*/ | |||
@@ -50,15 +52,16 @@ public class SingleByteFont extends CustomFont { | |||
/** | |||
* Main constructor. | |||
* @param resolver the URI resolver for controlling file access | |||
*/ | |||
public SingleByteFont() { | |||
public SingleByteFont(URIResolverWrapper resolver) { | |||
super(resolver); | |||
setEncoding(CodePointMapping.WIN_ANSI_ENCODING); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isEmbeddable() { | |||
return (!(getEmbedFileName() == null | |||
return (!(getEmbedFileURI() == null | |||
&& getEmbedResourceName() == null)); | |||
} | |||
@@ -19,7 +19,9 @@ | |||
package org.apache.fop.fonts.apps; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import java.util.Set; | |||
@@ -220,12 +222,17 @@ public class TTFReader extends AbstractFontReader { | |||
public TTFFile loadTTF(String fileName, String fontName, boolean useKerning, boolean useAdvanced) throws IOException { | |||
TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); | |||
log.info("Reading " + fileName + "..."); | |||
FontFileReader reader = new FontFileReader(fileName); | |||
boolean supported = ttfFile.readFont(reader, fontName); | |||
if (!supported) { | |||
return null; | |||
InputStream stream = new FileInputStream(fileName); | |||
try { | |||
FontFileReader reader = new FontFileReader(stream); | |||
boolean supported = ttfFile.readFont(reader, fontName); | |||
if (!supported) { | |||
return null; | |||
} | |||
} finally { | |||
stream.close(); | |||
} | |||
log.info("Font Family: " + ttfFile.getFamilyNames()); | |||
if (ttfFile.isCFF()) { | |||
throw new UnsupportedOperationException( | |||
@@ -460,9 +467,9 @@ public class TTFReader extends AbstractFontReader { | |||
Map h2; | |||
if (isCid) { | |||
h2 = (Map)ttf.getKerning().get(kpx1); | |||
h2 = ttf.getKerning().get(kpx1); | |||
} else { | |||
h2 = (Map)ttf.getAnsiKerning().get(kpx1); | |||
h2 = ttf.getAnsiKerning().get(kpx1); | |||
} | |||
Iterator iter2 = h2.keySet().iterator(); |
@@ -20,7 +20,7 @@ | |||
package org.apache.fop.fonts.autodetect; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.net.URI; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import java.util.Set; | |||
@@ -30,6 +30,7 @@ import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.CustomFont; | |||
import org.apache.fop.fonts.EmbedFontInfo; | |||
import org.apache.fop.fonts.EncodingMode; | |||
@@ -37,7 +38,6 @@ import org.apache.fop.fonts.Font; | |||
import org.apache.fop.fonts.FontCache; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontLoader; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.fonts.FontUtil; | |||
import org.apache.fop.fonts.MultiByteFont; | |||
@@ -133,26 +133,24 @@ public class FontInfoFinder { | |||
/** | |||
* Attempts to determine FontInfo from a given custom font | |||
* @param fontURL the font URL | |||
* @param fontUri the font URI | |||
* @param customFont the custom font | |||
* @param fontCache font cache (may be null) | |||
* @return FontInfo from the given custom font | |||
*/ | |||
private EmbedFontInfo getFontInfoFromCustomFont( | |||
URL fontURL, CustomFont customFont, FontCache fontCache) { | |||
private EmbedFontInfo getFontInfoFromCustomFont(URI fontUri, CustomFont customFont, | |||
FontCache fontCache, URIResolverWrapper resolver) { | |||
List<FontTriplet> fontTripletList = new java.util.ArrayList<FontTriplet>(); | |||
generateTripletsFromFont(customFont, fontTripletList); | |||
String embedUrl; | |||
embedUrl = fontURL.toExternalForm(); | |||
String subFontName = null; | |||
if (customFont instanceof MultiByteFont) { | |||
subFontName = ((MultiByteFont)customFont).getTTCName(); | |||
subFontName = ((MultiByteFont) customFont).getTTCName(); | |||
} | |||
EmbedFontInfo fontInfo = new EmbedFontInfo(null, customFont.isKerningEnabled(), | |||
customFont.isAdvancedEnabled(), fontTripletList, embedUrl, subFontName); | |||
customFont.isAdvancedEnabled(), fontTripletList, fontUri, subFontName); | |||
fontInfo.setPostScriptName(customFont.getFontName()); | |||
if (fontCache != null) { | |||
fontCache.addFont(fontInfo); | |||
fontCache.addFont(fontInfo, resolver); | |||
} | |||
return fontInfo; | |||
} | |||
@@ -160,32 +158,31 @@ public class FontInfoFinder { | |||
/** | |||
* Attempts to determine EmbedFontInfo from a given font file. | |||
* | |||
* @param fontURL font URL. Assumed to be local. | |||
* @param fontURI the URI of the font resource | |||
* @param resolver font resolver used to resolve font | |||
* @param fontCache font cache (may be null) | |||
* @return an array of newly created embed font info. Generally, this array | |||
* will have only one entry, unless the fontUrl is a TrueType Collection | |||
*/ | |||
public EmbedFontInfo[] find(URL fontURL, FontResolver resolver, FontCache fontCache) { | |||
String embedURL = null; | |||
embedURL = fontURL.toExternalForm(); | |||
public EmbedFontInfo[] find(URI fontURI, URIResolverWrapper resolver, FontCache fontCache) { | |||
URI embedUri = resolver.getBaseURI().resolve(fontURI); | |||
String embedStr = embedUri.toASCIIString(); | |||
boolean useKerning = true; | |||
boolean useAdvanced = ( resolver != null ) | |||
? resolver.isComplexScriptFeaturesEnabled() : true; | |||
boolean useAdvanced = true; | |||
long fileLastModified = -1; | |||
if (fontCache != null) { | |||
fileLastModified = FontCache.getLastModified(fontURL); | |||
fileLastModified = FontCache.getLastModified(fontURI); | |||
// firstly try and fetch it from cache before loading/parsing the font file | |||
if (fontCache.containsFont(embedURL)) { | |||
EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedURL, fileLastModified); | |||
if (fontCache.containsFont(embedStr)) { | |||
EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedStr, fileLastModified); | |||
if (fontInfos != null) { | |||
return fontInfos; | |||
} | |||
// is this a previously failed parsed font? | |||
} else if (fontCache.isFailedFont(embedURL, fileLastModified)) { | |||
} else if (fontCache.isFailedFont(embedStr, fileLastModified)) { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Skipping font file that failed to load previously: " + embedURL); | |||
log.debug("Skipping font file that failed to load previously: " + embedUri); | |||
} | |||
return null; | |||
} | |||
@@ -194,19 +191,19 @@ public class FontInfoFinder { | |||
// try to determine triplet information from font file | |||
CustomFont customFont = null; | |||
if (fontURL.toExternalForm().toLowerCase().endsWith(".ttc")) { | |||
if (fontURI.toASCIIString().toLowerCase().endsWith(".ttc")) { | |||
// Get a list of the TTC Font names | |||
List<String> ttcNames = null; | |||
String fontFileURL = fontURL.toExternalForm().trim(); | |||
InputStream in = null; | |||
try { | |||
in = FontLoader.openFontUri(resolver, fontFileURL); | |||
in = resolver.resolveIn(fontURI); | |||
TTFFile ttf = new TTFFile(false, false); | |||
FontFileReader reader = new FontFileReader(in); | |||
ttcNames = ttf.getTTCnames(reader); | |||
} catch (Exception e) { | |||
if (this.eventListener != null) { | |||
this.eventListener.fontLoadingErrorAtAutoDetection(this, fontFileURL, e); | |||
this.eventListener.fontLoadingErrorAtAutoDetection(this, | |||
fontURI.toASCIIString(), e); | |||
} | |||
return null; | |||
} finally { | |||
@@ -221,23 +218,24 @@ public class FontInfoFinder { | |||
log.debug("Loading " + fontName); | |||
} | |||
try { | |||
TTFFontLoader ttfLoader = new TTFFontLoader( | |||
fontFileURL, fontName, true, EncodingMode.AUTO, | |||
useKerning, useAdvanced, resolver); | |||
TTFFontLoader ttfLoader = new TTFFontLoader(fontURI, fontName, true, | |||
EncodingMode.AUTO, useKerning, useAdvanced, resolver); | |||
customFont = ttfLoader.getFont(); | |||
if (this.eventListener != null) { | |||
customFont.setEventListener(this.eventListener); | |||
} | |||
} catch (Exception e) { | |||
if (fontCache != null) { | |||
fontCache.registerFailedFont(embedURL, fileLastModified); | |||
fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified); | |||
} | |||
if (this.eventListener != null) { | |||
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedURL, e); | |||
this.eventListener.fontLoadingErrorAtAutoDetection(this, | |||
embedUri.toASCIIString(), e); | |||
} | |||
continue; | |||
} | |||
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURL, customFont, fontCache); | |||
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, | |||
resolver); | |||
if (fi != null) { | |||
embedFontInfoList.add(fi); | |||
} | |||
@@ -247,20 +245,22 @@ public class FontInfoFinder { | |||
} else { | |||
// The normal case | |||
try { | |||
customFont = FontLoader.loadFont(fontURL, null, true, EncodingMode.AUTO, resolver); | |||
customFont = FontLoader.loadFont(fontURI, null, true, EncodingMode.AUTO, | |||
useKerning, useAdvanced, resolver); | |||
if (this.eventListener != null) { | |||
customFont.setEventListener(this.eventListener); | |||
} | |||
} catch (Exception e) { | |||
if (fontCache != null) { | |||
fontCache.registerFailedFont(embedURL, fileLastModified); | |||
fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified); | |||
} | |||
if (this.eventListener != null) { | |||
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedURL, e); | |||
this.eventListener.fontLoadingErrorAtAutoDetection(this, | |||
embedUri.toASCIIString(), e); | |||
} | |||
return null; | |||
} | |||
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURL, customFont, fontCache); | |||
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, resolver); | |||
if (fi != null) { | |||
return new EmbedFontInfo[] {fi}; | |||
} else { |
@@ -19,7 +19,6 @@ | |||
package org.apache.fop.fonts.truetype; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
@@ -31,38 +30,9 @@ import org.apache.commons.io.IOUtils; | |||
*/ | |||
public class FontFileReader { | |||
private int fsize; // file size | |||
private final int fsize; // file size | |||
private int current; // current position in file | |||
private byte[] file; | |||
/** | |||
* Initializes class and reads stream. Init does not close stream. | |||
* | |||
* @param in InputStream to read from new array with size + inc | |||
* @throws IOException In case of an I/O problem | |||
*/ | |||
private void init(InputStream in) throws java.io.IOException { | |||
this.file = IOUtils.toByteArray(in); | |||
this.fsize = this.file.length; | |||
this.current = 0; | |||
} | |||
/** | |||
* Constructor | |||
* | |||
* @param fileName filename to read | |||
* @throws IOException In case of an I/O problem | |||
*/ | |||
public FontFileReader(String fileName) throws IOException { | |||
final File f = new File(fileName); | |||
InputStream in = new java.io.FileInputStream(f); | |||
try { | |||
init(in); | |||
} finally { | |||
in.close(); | |||
} | |||
} | |||
private final byte[] file; | |||
/** | |||
* Constructor | |||
@@ -71,7 +41,9 @@ public class FontFileReader { | |||
* @throws IOException In case of an I/O problem | |||
*/ | |||
public FontFileReader(InputStream in) throws IOException { | |||
init(in); | |||
this.file = IOUtils.toByteArray(in); | |||
this.fsize = this.file.length; | |||
this.current = 0; | |||
} | |||
@@ -19,13 +19,16 @@ | |||
package org.apache.fop.fonts.truetype; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.BitSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -1816,12 +1819,14 @@ public class TTFFile { | |||
* @param args The command line arguments | |||
*/ | |||
public static void main(String[] args) { | |||
InputStream stream = null; | |||
try { | |||
boolean useKerning = true; | |||
boolean useAdvanced = true; | |||
stream = new FileInputStream(args[0]); | |||
TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); | |||
FontFileReader reader = new FontFileReader(args[0]); | |||
FontFileReader reader = new FontFileReader(stream); | |||
String name = null; | |||
if (args.length >= 2) { | |||
@@ -1834,6 +1839,9 @@ public class TTFFile { | |||
} catch (IOException ioe) { | |||
System.err.println("Problem reading font: " + ioe.toString()); | |||
ioe.printStackTrace(System.err); | |||
} finally { | |||
IOUtils.closeQuietly(stream); | |||
} | |||
} | |||
} |
@@ -21,6 +21,7 @@ package org.apache.fop.fonts.truetype; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
@@ -30,11 +31,11 @@ import org.apache.commons.io.IOUtils; | |||
import org.apache.xmlgraphics.fonts.Glyphs; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.BFEntry; | |||
import org.apache.fop.fonts.CIDFontType; | |||
import org.apache.fop.fonts.EncodingMode; | |||
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; | |||
@@ -55,7 +56,7 @@ public class TTFFontLoader extends FontLoader { | |||
* @param fontFileURI the URI representing the font file | |||
* @param resolver the FontResolver for font URI resolution | |||
*/ | |||
public TTFFontLoader(String fontFileURI, FontResolver resolver) { | |||
public TTFFontLoader(URI fontFileURI, URIResolverWrapper resolver) { | |||
this(fontFileURI, null, true, EncodingMode.AUTO, true, true, resolver); | |||
} | |||
@@ -70,9 +71,9 @@ public class TTFFontLoader extends FontLoader { | |||
* @param useAdvanced true to enable loading advanced info if available, false to disable | |||
* @param resolver the FontResolver for font URI resolution | |||
*/ | |||
public TTFFontLoader(String fontFileURI, String subFontName, | |||
public TTFFontLoader(URI fontFileURI, String subFontName, | |||
boolean embedded, EncodingMode encodingMode, boolean useKerning, | |||
boolean useAdvanced, FontResolver resolver) { | |||
boolean useAdvanced, URIResolverWrapper resolver) { | |||
super(fontFileURI, embedded, useKerning, useAdvanced, resolver); | |||
this.subFontName = subFontName; | |||
this.encodingMode = encodingMode; | |||
@@ -94,7 +95,7 @@ public class TTFFontLoader extends FontLoader { | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
private void read(String ttcFontName) throws IOException { | |||
InputStream in = openFontUri(resolver, this.fontFileURI); | |||
InputStream in = resolver.resolveIn(this.fontFileURI); | |||
try { | |||
TTFFile ttf = new TTFFile(useKerning, useAdvanced); | |||
FontFileReader reader = new FontFileReader(in); | |||
@@ -122,14 +123,13 @@ public class TTFFontLoader extends FontLoader { | |||
} | |||
if (isCid) { | |||
multiFont = new MultiByteFont(); | |||
multiFont = new MultiByteFont(resolver); | |||
returnFont = multiFont; | |||
multiFont.setTTCName(ttcFontName); | |||
} else { | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resolver); | |||
returnFont = singleFont; | |||
} | |||
returnFont.setResolver(resolver); | |||
returnFont.setFontName(ttf.getPostScriptName()); | |||
returnFont.setFullName(ttf.getFullName()); | |||
@@ -177,7 +177,7 @@ public class TTFFontLoader extends FontLoader { | |||
} | |||
if (this.embedded) { | |||
if (ttf.isEmbeddable()) { | |||
returnFont.setEmbedFileName(this.fontFileURI); | |||
returnFont.setEmbedURI(this.fontFileURI); | |||
} else { | |||
String msg = "The font " + this.fontFileURI + " is not embeddable due to a" | |||
+ " licensing restriction."; |
@@ -46,38 +46,6 @@ public class PFBParser { | |||
} | |||
/** | |||
* Parses a PFB file into a PFBData object. | |||
* @param url URL to load the PFB file from | |||
* @return PFBData memory representation of the font | |||
* @throws IOException In case of an I/O problem | |||
*/ | |||
public PFBData parsePFB(java.net.URL url) throws IOException { | |||
InputStream in = url.openStream(); | |||
try { | |||
return parsePFB(in); | |||
} finally { | |||
in.close(); | |||
} | |||
} | |||
/** | |||
* Parses a PFB file into a PFBData object. | |||
* @param pfbFile File to load the PFB file from | |||
* @return PFBData memory representation of the font | |||
* @throws IOException In case of an I/O problem | |||
*/ | |||
public PFBData parsePFB(java.io.File pfbFile) throws IOException { | |||
InputStream in = new java.io.FileInputStream(pfbFile); | |||
try { | |||
return parsePFB(in); | |||
} finally { | |||
in.close(); | |||
} | |||
} | |||
/** | |||
* Parses a PFB file into a PFBData object. | |||
* @param in InputStream to load the PFB file from | |||
@@ -113,7 +81,6 @@ public class PFBParser { | |||
private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException { | |||
int segmentHead; | |||
int segmentType; | |||
int bytesRead; | |||
//Read first segment | |||
segmentHead = din.readUnsignedByte(); |
@@ -23,6 +23,7 @@ package org.apache.fop.fonts.type1; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.commons.io.IOUtils; | |||
@@ -40,7 +41,7 @@ public class PFMFile { | |||
private String windowsName; | |||
private String postscriptName; | |||
private short dfItalic; | |||
private int dfWeight; | |||
//private int dfWeight; | |||
private short dfCharSet; | |||
private short dfPitchAndFamily; | |||
private int dfAvgWidth; | |||
@@ -61,7 +62,7 @@ public class PFMFile { | |||
// Extent table | |||
private int[] extentTable; | |||
private Map kerningTab = new java.util.HashMap(); | |||
private Map<Integer, Map<Integer, Integer>> kerningTab = new HashMap<Integer, Map<Integer, Integer>>(); | |||
/** | |||
* logging instance | |||
@@ -119,7 +120,7 @@ public class PFMFile { | |||
inStream.skip(80); | |||
dfItalic = inStream.readByte(); | |||
inStream.skip(2); | |||
dfWeight = inStream.readShort(); | |||
inStream.readShort(); // dfWeight = | |||
dfCharSet = inStream.readByte(); | |||
inStream.skip(4); | |||
dfPitchAndFamily = inStream.readByte(); | |||
@@ -192,10 +193,10 @@ public class PFMFile { | |||
log.trace(i + " kerning pairs"); | |||
} | |||
while (i > 0) { | |||
int g1 = (int)inStream.readByte(); | |||
int g1 = (int) inStream.readByte(); | |||
i--; | |||
int g2 = (int)inStream.readByte(); | |||
int g2 = (int) inStream.readByte(); | |||
int adj = inStream.readShort(); | |||
if (adj > 0x8000) { | |||
@@ -209,12 +210,12 @@ public class PFMFile { | |||
log.trace("glyphs: " + glyph1 + ", " + glyph2); | |||
} | |||
Map adjTab = (Map)kerningTab.get(new Integer(g1)); | |||
Map<Integer, Integer> adjTab = kerningTab.get(Integer.valueOf(g1)); | |||
if (adjTab == null) { | |||
adjTab = new java.util.HashMap(); | |||
adjTab = new HashMap<Integer, Integer>(); | |||
} | |||
adjTab.put(new Integer(g2), new Integer(adj)); | |||
kerningTab.put(new Integer(g1), adjTab); | |||
adjTab.put(Integer.valueOf(g2), Integer.valueOf(adj)); | |||
kerningTab.put(Integer.valueOf(g1), adjTab); | |||
} | |||
} | |||
@@ -270,7 +271,7 @@ public class PFMFile { | |||
* | |||
* @return A Map containing the kerning table | |||
*/ | |||
public Map getKerning() { | |||
public Map<Integer, Map<Integer, Integer>> getKerning() { | |||
return kerningTab; | |||
} | |||
@@ -453,9 +454,9 @@ public class PFMFile { | |||
public int getStemV() { | |||
// Just guessing.... | |||
if (dfItalic != 0) { | |||
return (int)Math.round(dfMinWidth * 0.25); | |||
return (int) Math.round(dfMinWidth * 0.25); | |||
} else { | |||
return (int)Math.round(dfMinWidth * 0.6); | |||
return (int) Math.round(dfMinWidth * 0.6); | |||
} | |||
} | |||
@@ -22,15 +22,17 @@ package org.apache.fop.fonts.type1; | |||
import java.awt.geom.RectangularShape; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.CodePointMapping; | |||
import org.apache.fop.fonts.FontLoader; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.FontType; | |||
import org.apache.fop.fonts.SingleByteEncoding; | |||
import org.apache.fop.fonts.SingleByteFont; | |||
@@ -50,8 +52,8 @@ public class Type1FontLoader extends FontLoader { | |||
* @param resolver the font resolver used to resolve URIs | |||
* @throws IOException In case of an I/O error | |||
*/ | |||
public Type1FontLoader(String fontFileURI, boolean embedded, boolean useKerning, | |||
FontResolver resolver) throws IOException { | |||
public Type1FontLoader(URI fontFileURI, boolean embedded, boolean useKerning, | |||
URIResolverWrapper resolver) throws IOException { | |||
super(fontFileURI, embedded, useKerning, true, resolver); | |||
} | |||
@@ -71,17 +73,21 @@ public class Type1FontLoader extends FontLoader { | |||
PFMFile pfm = null; | |||
InputStream afmIn = null; | |||
String fontFileStr = fontFileURI.toASCIIString(); | |||
String partialAfmUri = fontFileStr.substring(0, fontFileStr.length() - 4); | |||
String afmUri = null; | |||
for (int i = 0; i < AFM_EXTENSIONS.length; i++) { | |||
try { | |||
afmUri = this.fontFileURI.substring(0, this.fontFileURI.length() - 4) | |||
+ AFM_EXTENSIONS[i]; | |||
afmIn = openFontUri(resolver, afmUri); | |||
afmUri = partialAfmUri + AFM_EXTENSIONS[i]; | |||
afmIn = resolver.resolveIn(afmUri); | |||
if (afmIn != null) { | |||
break; | |||
} | |||
} catch (IOException ioe) { | |||
// Ignore, AFM probably not available under the URI | |||
} catch (URISyntaxException e) { | |||
// TODO: Not sure what the best thing to do here is?!? | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
if (afmIn != null) { | |||
@@ -93,12 +99,14 @@ public class Type1FontLoader extends FontLoader { | |||
} | |||
} | |||
String pfmUri = getPFMURI(this.fontFileURI); | |||
String pfmUri = getPFMURI(fontFileStr); | |||
InputStream pfmIn = null; | |||
try { | |||
pfmIn = openFontUri(resolver, pfmUri); | |||
pfmIn = resolver.resolveIn(pfmUri); | |||
} catch (IOException ioe) { | |||
// Ignore, PFM probably not available under the URI | |||
} catch (URISyntaxException e) { | |||
// Ignore, PFM probably not available under the URI | |||
} | |||
if (pfmIn != null) { | |||
try { | |||
@@ -126,11 +134,10 @@ public class Type1FontLoader extends FontLoader { | |||
if (afm == null && pfm == null) { | |||
throw new IllegalArgumentException("Need at least an AFM or a PFM!"); | |||
} | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resolver); | |||
singleFont.setFontType(FontType.TYPE1); | |||
singleFont.setResolver(this.resolver); | |||
if (this.embedded) { | |||
singleFont.setEmbedFileName(this.fontFileURI); | |||
singleFont.setEmbedURI(this.fontFileURI); | |||
} | |||
returnFont = singleFont; | |||
@@ -91,7 +91,7 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan | |||
initialize(); | |||
FOUserAgent userAgent = pageSeq.getUserAgent(); | |||
ImageManager imageManager = userAgent.getFactory().getImageManager(); | |||
ImageManager imageManager = userAgent.getImageManager(); | |||
String uri = URISpecification.getURL(getExternalDocument().getSrc()); | |||
Integer firstPageIndex = ImageUtil.getPageIndexFromURI(uri); |
@@ -1399,8 +1399,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
Hyphenation hyph | |||
= Hyphenator.hyphenate(hyphenationProperties.language.getString(), | |||
hyphenationProperties.country.getString(), | |||
getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(), | |||
getFObj().getUserAgent().getFactory().getHyphPatNames(), | |||
getFObj().getUserAgent().getHyphenationTreeResolver(), | |||
getFObj().getUserAgent().getHyphPatNames(), | |||
sbChars.toString(), | |||
hyphenationProperties.hyphenationRemainCharacterCount.getValue(), | |||
hyphenationProperties.hyphenationPushCharacterCount.getValue()); |
@@ -20,14 +20,14 @@ | |||
package org.apache.fop.pdf; | |||
/** Enum class for PDF/A modes. */ | |||
public final class PDFAMode { | |||
public enum PDFAMode { | |||
/** PDF/A disabled */ | |||
public static final PDFAMode DISABLED = new PDFAMode("PDF/A disabled"); | |||
DISABLED("PDF/A disabled"), | |||
/** PDF/A-1a enabled */ | |||
public static final PDFAMode PDFA_1A = new PDFAMode("PDF/A-1a"); | |||
PDFA_1A("PDF/A-1a"), | |||
/** PDF/A-1b enabled */ | |||
public static final PDFAMode PDFA_1B = new PDFAMode("PDF/A-1b"); | |||
PDFA_1B("PDF/A-1b"); | |||
private String name; | |||
@@ -66,7 +66,7 @@ public final class PDFAMode { | |||
* @param s the string | |||
* @return the PDFAMode enum object (DISABLED will be returned if no match is found) | |||
*/ | |||
public static PDFAMode valueOf(String s) { | |||
public static PDFAMode getValueOf(String s) { | |||
if (PDFA_1A.getName().equalsIgnoreCase(s)) { | |||
return PDFA_1A; | |||
} else if (PDFA_1B.getName().equalsIgnoreCase(s)) { |
@@ -273,4 +273,17 @@ public class PDFEncryptionParams { | |||
this.encryptionLengthInBits = encryptionLength; | |||
} | |||
public String toString() { | |||
return "userPassword = " + userPassword + "\n" | |||
+ "ownerPassword = " + ownerPassword + "\n" | |||
+ "allowPrint = " + allowPrint + "\n" | |||
+ "allowCopyContent = " + allowCopyContent + "\n" | |||
+ "allowEditContent = " + allowEditContent + "\n" | |||
+ "allowEditAnnotations = " + allowEditAnnotations + "\n" | |||
+ "allowFillInForms = " + allowFillInForms + "\n" | |||
+ "allowAccessContent = " + allowAccessContent + "\n" | |||
+ "allowAssembleDocument = " + allowAssembleDocument + "\n" | |||
+ "allowPrintHq = " + allowPrintHq; | |||
} | |||
} |
@@ -23,10 +23,8 @@ package org.apache.fop.pdf; | |||
import java.awt.Color; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.text.DecimalFormat; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
@@ -35,9 +33,6 @@ import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.io.output.ByteArrayOutputStream; | |||
import org.apache.commons.logging.Log; | |||
@@ -1636,79 +1631,48 @@ public class PDFFactory { | |||
InputStream in = null; | |||
try { | |||
Source source = font.getEmbedFileSource(); | |||
if (source == null && font.getEmbedResourceName() != null) { | |||
source = new StreamSource(this.getClass() | |||
.getResourceAsStream(font.getEmbedResourceName())); | |||
} | |||
if (source == null) { | |||
return null; | |||
} | |||
if (source instanceof StreamSource) { | |||
in = ((StreamSource) source).getInputStream(); | |||
} | |||
if (in == null && source.getSystemId() != null) { | |||
try { | |||
in = new java.net.URL(source.getSystemId()).openStream(); | |||
} catch (MalformedURLException e) { | |||
//TODO: Why construct a new exception here, when it is not thrown? | |||
new FileNotFoundException( | |||
"File not found. URL could not be resolved: " | |||
+ e.getMessage()); | |||
} | |||
} | |||
if (in == null) { | |||
return null; | |||
} | |||
//Make sure the InputStream is decorated with a BufferedInputStream | |||
if (!(in instanceof java.io.BufferedInputStream)) { | |||
in = new java.io.BufferedInputStream(in); | |||
} | |||
in = font.getInputStream(); | |||
if (in == null) { | |||
return null; | |||
} else { | |||
try { | |||
AbstractPDFStream embeddedFont; | |||
if (desc.getFontType() == FontType.TYPE0) { | |||
MultiByteFont mbfont = (MultiByteFont)font; | |||
FontFileReader reader = new FontFileReader(in); | |||
TTFSubSetFile subset = new TTFSubSetFile(); | |||
byte[] subsetFont = subset.readFont(reader, | |||
mbfont.getTTCName(), mbfont.getUsedGlyphs()); | |||
// Only TrueType CID fonts are supported now | |||
embeddedFont = new PDFTTFStream(subsetFont.length); | |||
((PDFTTFStream)embeddedFont).setData(subsetFont, subsetFont.length); | |||
} else if (desc.getFontType() == FontType.TYPE1) { | |||
PFBParser parser = new PFBParser(); | |||
PFBData pfb = parser.parsePFB(in); | |||
embeddedFont = new PDFT1Stream(); | |||
((PDFT1Stream)embeddedFont).setData(pfb); | |||
} else { | |||
byte[] file = IOUtils.toByteArray(in); | |||
embeddedFont = new PDFTTFStream(file.length); | |||
((PDFTTFStream)embeddedFont).setData(file, file.length); | |||
} | |||
AbstractPDFStream embeddedFont; | |||
if (desc.getFontType() == FontType.TYPE0) { | |||
MultiByteFont mbfont = (MultiByteFont) font; | |||
FontFileReader reader = new FontFileReader(in); | |||
TTFSubSetFile subset = new TTFSubSetFile(); | |||
byte[] subsetFont = subset.readFont(reader, | |||
mbfont.getTTCName(), mbfont.getUsedGlyphs()); | |||
// Only TrueType CID fonts are supported now | |||
embeddedFont = new PDFTTFStream(subsetFont.length); | |||
((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length); | |||
} else if (desc.getFontType() == FontType.TYPE1) { | |||
PFBParser parser = new PFBParser(); | |||
PFBData pfb = parser.parsePFB(in); | |||
embeddedFont = new PDFT1Stream(); | |||
((PDFT1Stream) embeddedFont).setData(pfb); | |||
} else { | |||
byte[] file = IOUtils.toByteArray(in); | |||
embeddedFont = new PDFTTFStream(file.length); | |||
((PDFTTFStream) embeddedFont).setData(file, file.length); | |||
} | |||
/* | |||
embeddedFont.getFilterList().addFilter("flate"); | |||
if (getDocument().isEncryptionActive()) { | |||
getDocument().applyEncryption(embeddedFont); | |||
} else { | |||
embeddedFont.getFilterList().addFilter("ascii-85"); | |||
}*/ | |||
/* | |||
embeddedFont.getFilterList().addFilter("flate"); | |||
if (getDocument().isEncryptionActive()) { | |||
getDocument().applyEncryption(embeddedFont); | |||
} else { | |||
embeddedFont.getFilterList().addFilter("ascii-85"); | |||
}*/ | |||
return embeddedFont; | |||
} finally { | |||
in.close(); | |||
} | |||
return embeddedFont; | |||
} | |||
} catch (IOException ioe) { | |||
log.error( | |||
"Failed to embed font [" + desc + "] " | |||
+ desc.getEmbedFontName(), ioe); | |||
log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe); | |||
return null; | |||
} finally { | |||
IOUtils.closeQuietly(in); | |||
} | |||
} | |||
@@ -21,9 +21,9 @@ package org.apache.fop.pdf; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.LinkedHashMap; | |||
import java.util.LinkedHashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
@@ -46,33 +46,33 @@ public class PDFResources extends PDFDictionary { | |||
/** | |||
* /Font objects keyed by their internal name | |||
*/ | |||
protected Map fonts = new HashMap(); | |||
protected Map fonts = new LinkedHashMap(); | |||
/** | |||
* Set of XObjects | |||
*/ | |||
protected Set xObjects = new HashSet(); | |||
protected Set xObjects = new LinkedHashSet(); | |||
/** | |||
* Set of patterns | |||
*/ | |||
protected Set patterns = new HashSet(); | |||
protected Set patterns = new LinkedHashSet(); | |||
/** | |||
* Set of shadings | |||
*/ | |||
protected Set shadings = new HashSet(); | |||
protected Set shadings = new LinkedHashSet(); | |||
/** | |||
* Set of ExtGStates | |||
*/ | |||
protected Set gstates = new HashSet(); | |||
protected Set gstates = new LinkedHashSet(); | |||
/** Map of color spaces (key: color space name) */ | |||
protected Map colorSpaces = new HashMap(); | |||
protected Map colorSpaces = new LinkedHashMap(); | |||
/** Map of ICC color spaces (key: ICC profile description) */ | |||
protected Map iccColorSpaces = new HashMap(); | |||
protected Map iccColorSpaces = new LinkedHashMap(); | |||
/** | |||
* create a /Resources object. | |||
@@ -205,7 +205,7 @@ public class PDFResources extends PDFDictionary { | |||
Iterator fontIterator = this.fonts.keySet().iterator(); | |||
while (fontIterator.hasNext()) { | |||
String fontName = (String)fontIterator.next(); | |||
dict.put(fontName, (PDFFont)this.fonts.get(fontName)); | |||
dict.put(fontName, this.fonts.get(fontName)); | |||
} | |||
put("Font", dict); | |||
} |
@@ -20,12 +20,12 @@ | |||
package org.apache.fop.pdf; | |||
/** Enum class for PDF/X modes. */ | |||
public final class PDFXMode { | |||
public enum PDFXMode { | |||
/** PDF/X disabled */ | |||
public static final PDFXMode DISABLED = new PDFXMode("PDF/X disabled"); | |||
DISABLED("PDF/X disabled"), | |||
/** PDF/X-3:2003 enabled */ | |||
public static final PDFXMode PDFX_3_2003 = new PDFXMode("PDF/X-3:2003"); | |||
PDFX_3_2003("PDF/X-3:2003"); | |||
private String name; | |||
@@ -47,7 +47,7 @@ public final class PDFXMode { | |||
* @param s the string | |||
* @return the PDFAMode enum object (DISABLED will be returned if no match is found) | |||
*/ | |||
public static PDFXMode valueOf(String s) { | |||
public static PDFXMode getValueOf(String s) { | |||
if (PDFX_3_2003.getName().equalsIgnoreCase(s)) { | |||
return PDFX_3_2003; | |||
} else { |
@@ -19,9 +19,6 @@ | |||
package org.apache.fop.render; | |||
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; | |||
@@ -48,41 +45,6 @@ public abstract class AbstractConfigurator { | |||
this.userAgent = userAgent; | |||
} | |||
/** | |||
* Returns the configuration subtree for a specific renderer. | |||
* @param mimeType the MIME type of the renderer | |||
* @return the requested configuration subtree, null if there's no configuration | |||
*/ | |||
protected Configuration getConfig(String mimeType) { | |||
Configuration cfg = userAgent.getFactory().getUserConfig(); | |||
if (cfg == null) { | |||
if (log.isDebugEnabled()) { | |||
log.debug("userconfig is null"); | |||
} | |||
return null; | |||
} | |||
Configuration userConfig = null; | |||
String type = getType(); | |||
Configuration[] cfgs | |||
= cfg.getChild(type + "s").getChildren(type); | |||
for (int i = 0; i < cfgs.length; ++i) { | |||
Configuration child = cfgs[i]; | |||
try { | |||
if (child.getAttribute(MIME).equals(mimeType)) { | |||
userConfig = child; | |||
break; | |||
} | |||
} catch (ConfigurationException e) { | |||
// silently pass over configurations without mime type | |||
} | |||
} | |||
log.debug((userConfig == null ? "No u" : "U") | |||
+ "ser configuration found for MIME type " + mimeType); | |||
return userConfig; | |||
} | |||
/** | |||
* Returns the configurator type | |||
* @return the configurator type |
@@ -19,49 +19,30 @@ | |||
package org.apache.fop.render; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
* Abstract base classes for renderer-related configurator classes. This class basically just | |||
* provides an accessor to the specific renderer configuration object. | |||
*/ | |||
public abstract class AbstractRendererConfigurator extends AbstractConfigurator { | |||
public abstract class AbstractRendererConfigurator { | |||
private static final String TYPE = "renderer"; | |||
/** fop factory configuration */ | |||
protected final FOUserAgent userAgent; | |||
/** | |||
* Default constructor | |||
* @param userAgent user agent | |||
*/ | |||
public AbstractRendererConfigurator(FOUserAgent userAgent) { | |||
super(userAgent); | |||
} | |||
/** | |||
* Returns the configuration subtree for a specific renderer. | |||
* @param renderer the renderer | |||
* @return the requested configuration subtree, null if there's no configuration | |||
*/ | |||
protected Configuration getRendererConfig(Renderer renderer) { | |||
return super.getConfig(renderer.getMimeType()); | |||
this.userAgent = userAgent; | |||
} | |||
/** | |||
* Returns the configuration subtree for a specific renderer. | |||
* @param mimeType the MIME type of the renderer | |||
* @return the requested configuration subtree, null if there's no configuration | |||
* Returns the configurator type | |||
* @return the configurator type | |||
*/ | |||
protected Configuration getRendererConfig(String mimeType) { | |||
return super.getConfig(mimeType); | |||
public static String getType() { | |||
return "renderer"; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public String getType() { | |||
return TYPE; | |||
} | |||
} |
@@ -19,6 +19,7 @@ | |||
package org.apache.fop.render; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
@@ -50,9 +51,8 @@ public abstract class AbstractRendererMaker { | |||
* @param userAgent user agent | |||
* @return a config object that can be used to configure the renderer | |||
*/ | |||
public RendererConfigurator getConfigurator(FOUserAgent userAgent) { | |||
return null; | |||
} | |||
public abstract void configureRenderer(FOUserAgent userAgent, Renderer renderer) | |||
throws FOPException; | |||
/** | |||
* Indicates whether a specific MIME type is supported by this renderer. |
@@ -36,10 +36,11 @@ import org.apache.fop.fonts.Font; | |||
import org.apache.fop.fonts.FontCollection; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.fonts.base14.Base14FontCollection; | |||
import sun.font.FontResolver; | |||
/** Abstract base class of "Print" type renderers. */ | |||
public abstract class PrintRenderer extends AbstractRenderer { | |||
@@ -88,11 +89,11 @@ public abstract class PrintRenderer extends AbstractRenderer { | |||
/** {@inheritDoc} */ | |||
public void setupFontInfo(FontInfo inFontInfo) throws FOPException { | |||
this.fontInfo = inFontInfo; | |||
FontManager fontManager = userAgent.getFactory().getFontManager(); | |||
FontManager fontManager = userAgent.getFontManager(); | |||
FontCollection[] fontCollections = new FontCollection[] { | |||
new Base14FontCollection(fontManager.isBase14KerningEnabled()), | |||
new CustomFontCollection(getFontResolver(), getFontList(), | |||
userAgent.isComplexScriptFeaturesEnabled()) | |||
new CustomFontCollection(fontManager.getURIResolver(), getFontList(), | |||
userAgent.isComplexScriptFeaturesEnabled()) | |||
}; | |||
fontManager.setup(getFontInfo(), fontCollections); | |||
} | |||
@@ -179,18 +180,6 @@ public abstract class PrintRenderer extends AbstractRenderer { | |||
renderXML(context, doc, ns); | |||
} | |||
/** | |||
* Get FontResolver | |||
* | |||
* @return FontResolver | |||
*/ | |||
public FontResolver getFontResolver() { | |||
if (this.fontResolver == null) { | |||
this.fontResolver = new DefaultFontResolver(super.userAgent); | |||
} | |||
return this.fontResolver; | |||
} | |||
/** | |||
* @return the font info | |||
*/ |
@@ -19,46 +19,74 @@ | |||
package org.apache.fop.render; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.io.URIResolverWrapper; | |||
import org.apache.fop.fonts.CustomFontCollection; | |||
import org.apache.fop.fonts.DefaultFontConfigurator; | |||
import org.apache.fop.fonts.EmbedFontInfo; | |||
import org.apache.fop.fonts.FontCollection; | |||
import org.apache.fop.fonts.FontConfigurator; | |||
import org.apache.fop.fonts.FontEventAdapter; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontInfoConfigurator; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.base14.Base14FontCollection; | |||
import org.apache.fop.render.RendererConfig.RendererConfigParser; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
/** | |||
* Base Print renderer configurator (mostly handles font configuration) | |||
*/ | |||
public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
implements RendererConfigurator, IFDocumentHandlerConfigurator { | |||
public abstract class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
implements IFDocumentHandlerConfigurator { | |||
/** logger instance */ | |||
protected static final Log log = LogFactory.getLog(PrintRendererConfigurator.class); | |||
private static Log LOG = LogFactory.getLog(PrintRendererConfigurator.class); | |||
private final RendererConfigParser rendererConfigParser; | |||
private final FontConfigurator<EmbedFontInfo> fontInfoConfigurator; | |||
/** | |||
* Default constructor | |||
* @param userAgent user agent | |||
*/ | |||
public PrintRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) { | |||
this(userAgent, rendererConfigParser, | |||
new DefaultFontConfigurator(userAgent.getFontManager(), new FontEventAdapter( | |||
userAgent.getEventBroadcaster()), userAgent.validateUserConfigStrictly())); | |||
} | |||
/** | |||
* Default constructor | |||
* @param userAgent user agent | |||
*/ | |||
public PrintRendererConfigurator(FOUserAgent userAgent) { | |||
public PrintRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser, | |||
FontConfigurator<EmbedFontInfo> fontInfoConfigurator) { | |||
super(userAgent); | |||
this.rendererConfigParser = rendererConfigParser; | |||
this.fontInfoConfigurator = fontInfoConfigurator; | |||
} | |||
protected RendererConfig getRendererConfig(IFDocumentHandler documentHandler) throws FOPException { | |||
return getRendererConfig(documentHandler.getMimeType()); | |||
} | |||
protected RendererConfig getRendererConfig(String mimeType) throws FOPException { | |||
return userAgent.getRendererConfig(mimeType, rendererConfigParser); | |||
} | |||
protected RendererConfig getRendererConfig(Renderer renderer) throws FOPException { | |||
return getRendererConfig(renderer.getMimeType()); | |||
} | |||
/** | |||
* Builds a list of EmbedFontInfo objects for use with the setup() method. | |||
* | |||
@@ -66,77 +94,44 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
* @throws FOPException if something's wrong with the config data | |||
*/ | |||
public void configure(Renderer renderer) throws FOPException { | |||
Configuration cfg = getRendererConfig(renderer); | |||
if (cfg == null) { | |||
log.trace("no configuration found for " + renderer); | |||
return; | |||
} | |||
PrintRenderer printRenderer = (PrintRenderer)renderer; | |||
FontResolver fontResolver = printRenderer.getFontResolver(); | |||
FontEventListener listener = new FontEventAdapter( | |||
renderer.getUserAgent().getEventBroadcaster()); | |||
List<EmbedFontInfo> embedFontInfoList = buildFontList(cfg, fontResolver, listener); | |||
PrintRenderer printRenderer = (PrintRenderer) renderer; | |||
List<EmbedFontInfo> embedFontInfoList = buildFontList(renderer.getMimeType()); | |||
printRenderer.addFontList(embedFontInfoList); | |||
} | |||
/** | |||
* Builds the font list from configuration. | |||
* @param cfg the configuration object | |||
* @param fontResolver a font resolver | |||
* @param listener the font event listener | |||
* @return the list of {@link EmbedFontInfo} objects | |||
* @throws FOPException if an error occurs while processing the configuration | |||
*/ | |||
protected List<EmbedFontInfo> buildFontList(Configuration cfg, FontResolver fontResolver, | |||
FontEventListener listener) throws FOPException { | |||
FopFactory factory = userAgent.getFactory(); | |||
FontManager fontManager = factory.getFontManager(); | |||
if (fontResolver == null) { | |||
//Ensure that we have minimal font resolution capabilities | |||
fontResolver | |||
= FontManager.createMinimalFontResolver | |||
( userAgent.isComplexScriptFeaturesEnabled() ); | |||
} | |||
boolean strict = factory.validateUserConfigStrictly(); | |||
//Read font configuration | |||
FontInfoConfigurator fontInfoConfigurator | |||
= new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); | |||
List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>(); | |||
fontInfoConfigurator.configure(fontInfoList); | |||
return fontInfoList; | |||
} | |||
// ---=== IFDocumentHandler configuration ===--- | |||
/** {@inheritDoc} */ | |||
public void configure(IFDocumentHandler documentHandler) throws FOPException { | |||
//nop | |||
} | |||
/** {@inheritDoc} */ | |||
public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) | |||
throws FOPException { | |||
FontManager fontManager = userAgent.getFactory().getFontManager(); | |||
List<FontCollection> fontCollections = new ArrayList<FontCollection>(); | |||
fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled())); | |||
Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); | |||
if (cfg != null) { | |||
FontResolver fontResolver = new DefaultFontResolver(userAgent); | |||
FontEventListener listener = new FontEventAdapter( | |||
userAgent.getEventBroadcaster()); | |||
List<EmbedFontInfo> fontList = buildFontList(cfg, fontResolver, listener); | |||
fontCollections.add(new CustomFontCollection(fontResolver, fontList, | |||
userAgent.isComplexScriptFeaturesEnabled())); | |||
public void setupFontInfo(String mimeType, FontInfo fontInfo) throws FOPException { | |||
FontManager fontManager = userAgent.getFontManager(); | |||
List<FontCollection> fontCollections = getDefaultFontCollection(); | |||
fontCollections.add(getCustomFontCollection(fontManager.getURIResolver(), mimeType)); | |||
fontManager.setup(fontInfo, fontCollections.toArray(new FontCollection[fontCollections.size()])); | |||
} | |||
protected abstract List<FontCollection> getDefaultFontCollection(); | |||
protected FontCollection getCustomFontCollection(URIResolverWrapper uriResolverWrapper, String mimeType) | |||
throws FOPException { | |||
List<EmbedFontInfo> fontList; | |||
if (rendererConfigParser == null) { | |||
fontList = Collections.<EmbedFontInfo>emptyList(); | |||
} else { | |||
fontList = fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig()); | |||
} | |||
return createCollectionFromFontList(uriResolverWrapper, fontList); | |||
} | |||
protected FontCollection createCollectionFromFontList(URIResolverWrapper uriResolverWrapper, | |||
List<EmbedFontInfo> fontList) { | |||
return new CustomFontCollection(uriResolverWrapper, fontList, | |||
userAgent.isComplexScriptFeaturesEnabled()); | |||
} | |||
fontManager.setup(fontInfo, | |||
(FontCollection[])fontCollections.toArray( | |||
new FontCollection[fontCollections.size()])); | |||
documentHandler.setFontInfo(fontInfo); | |||
private List<EmbedFontInfo> buildFontList(String mimeType) throws FOPException { | |||
return fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig()); | |||
} | |||
} |
@@ -19,16 +19,20 @@ | |||
package org.apache.fop.render; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fonts.FontConfig; | |||
/** | |||
* Renderer configurator interface | |||
*/ | |||
public interface RendererConfigurator { | |||
/** | |||
* Configures a renderer | |||
* @param renderer renderer | |||
* @throws FOPException fop exception | |||
*/ | |||
void configure(Renderer renderer) throws FOPException; | |||
public interface RendererConfig { | |||
FontConfig getFontInfoConfig(); | |||
public interface RendererConfigParser { | |||
RendererConfig build(FOUserAgent userAgent, Configuration rendererConfiguration) throws FOPException; | |||
String getMimeType(); | |||
} | |||
} |
@@ -17,15 +17,8 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.config; | |||
package org.apache.fop.render; | |||
/** | |||
* This font base does not exist and a relative font path is used. | |||
*/ | |||
public class FontBaseBadTestCase extends BaseDestructiveUserConfigTest { | |||
@Override | |||
public String getUserConfigFilename() { | |||
return "test_fontbase_bad.xconf"; | |||
} | |||
public interface RendererConfigOptions { | |||
String getName(); | |||
} |
@@ -36,6 +36,7 @@ import org.apache.fop.area.AreaTreeHandler; | |||
import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; | |||
import org.apache.fop.render.intermediate.EventProducingFilter; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
import org.apache.fop.render.intermediate.IFRenderer; | |||
@@ -52,25 +53,19 @@ public class RendererFactory { | |||
private Map eventHandlerMakerMapping = new java.util.HashMap(); | |||
private Map documentHandlerMakerMapping = new java.util.HashMap(); | |||
private boolean rendererPreferred = false; | |||
private final boolean rendererPreferred; | |||
/** | |||
* Main constructor. | |||
* @param rendererPreferred Controls whether a {@link Renderer} is preferred over a | |||
* {@link IFDocumentHandler} if both are available for the same MIME type. True to prefer the | |||
* {@link Renderer}, false to prefer the {@link IFDocumentHandler}. | |||
*/ | |||
public RendererFactory() { | |||
public RendererFactory(boolean rendererPreferred) { | |||
discoverRenderers(); | |||
discoverFOEventHandlers(); | |||
discoverDocumentHandlers(); | |||
} | |||
/** | |||
* Controls whether a {@link Renderer} is preferred over a {@link IFDocumentHandler} if | |||
* both are available for the same MIME type. | |||
* @param value true to prefer the {@link Renderer}, | |||
* false to prefer the {@link IFDocumentHandler}. | |||
*/ | |||
public void setRendererPreferred(boolean value) { | |||
this.rendererPreferred = value; | |||
this.rendererPreferred = rendererPreferred; | |||
} | |||
/** | |||
@@ -239,7 +234,7 @@ public class RendererFactory { | |||
* @param mime the requested output format | |||
* @return the requested RendererMaker or null if none is available | |||
*/ | |||
public AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) { | |||
private AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) { | |||
AbstractIFDocumentHandlerMaker maker | |||
= (AbstractIFDocumentHandlerMaker)documentHandlerMakerMapping.get(mime); | |||
return maker; | |||
@@ -299,10 +294,7 @@ public class RendererFactory { | |||
AbstractRendererMaker maker = getRendererMaker(outputFormat); | |||
if (maker != null) { | |||
Renderer rend = maker.makeRenderer(userAgent); | |||
RendererConfigurator configurator = maker.getConfigurator(userAgent); | |||
if (configurator != null) { | |||
configurator.configure(rend); | |||
} | |||
maker.configureRenderer(userAgent, rend); | |||
return rend; | |||
} else { | |||
return null; | |||
@@ -383,7 +375,10 @@ public class RendererFactory { | |||
throw new UnsupportedOperationException( | |||
"No IF document handler for the requested format available: " + outputFormat); | |||
} | |||
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent); | |||
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(new IFContext(userAgent)); | |||
// TODO: do all the configuration in the makeIfDocumentHandler method, that would beam when | |||
// you ask for a document handler, a configured one is returned to you. Getting it and | |||
// configuring it in two steps doesn't make sense. | |||
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); | |||
if (configurator != null) { | |||
configurator.configure(documentHandler); | |||
@@ -398,15 +393,15 @@ public class RendererFactory { | |||
List lst = new java.util.ArrayList(); | |||
Iterator iter = this.rendererMakerMapping.keySet().iterator(); | |||
while (iter.hasNext()) { | |||
lst.add(((String)iter.next())); | |||
lst.add(iter.next()); | |||
} | |||
iter = this.eventHandlerMakerMapping.keySet().iterator(); | |||
while (iter.hasNext()) { | |||
lst.add(((String)iter.next())); | |||
lst.add(iter.next()); | |||
} | |||
iter = this.documentHandlerMakerMapping.keySet().iterator(); | |||
while (iter.hasNext()) { | |||
lst.add(((String)iter.next())); | |||
lst.add(iter.next()); | |||
} | |||
Collections.sort(lst); | |||
return (String[])lst.toArray(new String[lst.size()]); |
@@ -83,7 +83,7 @@ public class XMLHandlerConfigurator extends AbstractRendererConfigurator { | |||
*/ | |||
public void configure(RendererContext context, String ns) throws FOPException { | |||
//Optional XML handler configuration | |||
Configuration cfg = getRendererConfig(context.getRenderer()); | |||
Configuration cfg = userAgent.getRendererConfiguration(context.getRenderer().getMimeType()); | |||
if (cfg != null) { | |||
cfg = getHandlerConfig(cfg, ns); | |||
if (cfg != null) { |