git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_RoundedCorners@1356804 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -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. |
@@ -58,7 +58,7 @@ | |||
recent XML/XSL-FO convert, he has been nit-picking FAQs & assorted web | |||
pages since his first webmaster position @brain.com in 1996. Most | |||
important creation? He's got a couple of cool kids.</li> | |||
<li id="jm"><link href="mailto:jeremias@apache.org">Jeremias M�rki</link> (JM) | |||
<li id="jm"><link href="mailto:jeremias@apache.org">Jeremias Märki</link> (JM) | |||
is an independent software engineer and consultant from Lucerne, Switzerland. He's also | |||
the creator of <fork href="http://barcode4j.sourceforge.net">Barcode4J</fork>. | |||
See his <fork href="http://www.jeremias-maerki.ch">home page</fork> for more information | |||
@@ -67,20 +67,25 @@ | |||
<li id="sp"><link href="mailto:spepping@apache.org">Simon Pepping</link> (SP) came to FOP | |||
from the TeX/LaTeX world. See his <fork href="http://www.leverkruid.eu">home | |||
page</fork> for some of his private projects.</li> | |||
<li id="jp"><link href="mailto:pietsch@apache.org">J�rg Pietschmann</link> (JP)</li> | |||
<li id="jp"><link href="mailto:pietsch@apache.org">Jörg Pietschmann</link> (JP)</li> | |||
<li id="ps"><link href="mailto:tcho@club-internet.fr">Pascal Sancho</link> (PS) | |||
is an XML developper from Aix-en-Provence (France). He works on software solutions for | |||
rendering various kind of documents on various supports, more specifically taking care | |||
of PDF generation with FOP.</li> | |||
is an XML developper from Aix-en-Provence (France). He works on software solutions for | |||
rendering various kind of documents on various supports, more specifically taking care | |||
of PDF generation with FOP.</li> | |||
</ul> | |||
</section> | |||
<section id="contribute-active"> | |||
<title>Active Contributors</title> | |||
<ul> | |||
<li id="ag">Alexios Giotis holds a Ph.D. in the optimization of turbomachinery cascades | |||
using evolutionary algorithms, neural networks and parallel processing. He is one of | |||
the founding members of i-docs (software for enterprises) and he has been leading its | |||
technical design & implementation based on open source libraries since its inception. | |||
He is relying on Apache FOP for generating high volumes of documents on major banks and | |||
telecom operators since FOP's 1.0 release. He lives in Athens, Greece.</li> | |||
<li id="gd">Georg Datterl is a software developer from Austria, currently working for | |||
Geneon media solutions gmbh in Nuremberg, Germany. He needs FOP to wrestle gigabytes of | |||
electronic data into thousands of printed pages.</li> | |||
<li id="lm">Louis Masters</li> | |||
<li id="lb">Luis Bernardo</li> | |||
</ul> | |||
</section> |
@@ -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 | |||
*/ |
@@ -28,6 +28,7 @@ import java.io.IOException; | |||
import org.apache.xmlgraphics.image.loader.ImageSize; | |||
import org.apache.xmlgraphics.util.MimeConstants; | |||
import org.apache.fop.afp.AFPResourceLevel.ResourceType; | |||
import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; | |||
import org.apache.fop.util.bitmap.DitherUtil; | |||
@@ -66,7 +67,7 @@ public class AFPDitheredRectanglePainter extends AbstractAFPPainter { | |||
AFPImageObjectInfo imageObjectInfo = new AFPImageObjectInfo(); | |||
imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10); | |||
//imageObjectInfo.setCreatePageSegment(true); | |||
imageObjectInfo.getResourceInfo().setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); | |||
imageObjectInfo.getResourceInfo().setLevel(new AFPResourceLevel(ResourceType.INLINE)); | |||
imageObjectInfo.getResourceInfo().setImageDimension(ditherSize); | |||
imageObjectInfo.setBitsPerPixel(1); | |||
imageObjectInfo.setColor(false); |
@@ -21,6 +21,7 @@ package org.apache.fop.afp; | |||
import java.awt.Dimension; | |||
import org.apache.fop.afp.AFPResourceLevel.ResourceType; | |||
/** | |||
* The level at which a resource is to reside in the AFP output | |||
@@ -29,7 +30,7 @@ public class AFPResourceInfo { | |||
/** the general default resource level */ | |||
public static final AFPResourceLevel DEFAULT_LEVEL | |||
= new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
= new AFPResourceLevel(ResourceType.PRINT_FILE); | |||
/** the URI of this resource */ | |||
private String uri = null; |
@@ -19,46 +19,56 @@ | |||
package org.apache.fop.afp; | |||
import java.net.URI; | |||
import static org.apache.fop.afp.AFPResourceLevel.ResourceType.DOCUMENT; | |||
import static org.apache.fop.afp.AFPResourceLevel.ResourceType.EXTERNAL; | |||
import static org.apache.fop.afp.AFPResourceLevel.ResourceType.INLINE; | |||
import static org.apache.fop.afp.AFPResourceLevel.ResourceType.PAGE; | |||
import static org.apache.fop.afp.AFPResourceLevel.ResourceType.PAGE_GROUP; | |||
import static org.apache.fop.afp.AFPResourceLevel.ResourceType.PRINT_FILE; | |||
/** | |||
* A resource level | |||
*/ | |||
public class AFPResourceLevel { | |||
public enum ResourceType { | |||
/** directly in page **/ | |||
INLINE("inline"), | |||
/** page level **/ | |||
PAGE("page"), | |||
/** page group level **/ | |||
PAGE_GROUP("page-group"), | |||
/** document level **/ | |||
DOCUMENT("document"), | |||
/** print file level **/ | |||
PRINT_FILE("print-file"), | |||
/** external level **/ | |||
EXTERNAL("external"); | |||
private final String name; | |||
private ResourceType(String name) { | |||
this.name = name; | |||
} | |||
/** directly in page **/ | |||
public static final int INLINE = 0; | |||
/** page level **/ | |||
public static final int PAGE = 1; | |||
/** page group level **/ | |||
public static final int PAGE_GROUP = 2; | |||
/** document level **/ | |||
public static final int DOCUMENT = 3; | |||
/** print file level **/ | |||
public static final int PRINT_FILE = 4; | |||
/** external level **/ | |||
public static final int EXTERNAL = 5; | |||
private static final String NAME_INLINE = "inline"; | |||
private static final String NAME_PAGE = "page"; | |||
private static final String NAME_PAGE_GROUP = "page-group"; | |||
private static final String NAME_DOCUMENT = "document"; | |||
private static final String NAME_PRINT_FILE = "print-file"; | |||
private static final String NAME_EXTERNAL = "external"; | |||
private static final String[] NAMES = new String[] { | |||
NAME_INLINE, NAME_PAGE, NAME_PAGE_GROUP, NAME_DOCUMENT, NAME_PRINT_FILE, NAME_EXTERNAL | |||
}; | |||
public static ResourceType getValueOf(String levelString) { | |||
for (ResourceType resType : ResourceType.values()) { | |||
if (resType.name.equalsIgnoreCase(levelString)) { | |||
return resType; | |||
} | |||
} | |||
return null; | |||
} | |||
/** where the resource will reside in the AFP output */ | |||
private int level = PRINT_FILE; // default is print-file level (images) | |||
public String getName() { | |||
return name; | |||
} | |||
} | |||
/** the external resource group file path */ | |||
private String extFilePath = null; | |||
private URI extUri = null; | |||
private ResourceType resourceType; | |||
/** | |||
* Sets the resource placement level within the AFP output | |||
@@ -67,18 +77,8 @@ public class AFPResourceLevel { | |||
* @return true if the resource level was successfully set | |||
*/ | |||
public static AFPResourceLevel valueOf(String levelString) { | |||
if (levelString != null) { | |||
levelString = levelString.toLowerCase(); | |||
AFPResourceLevel resourceLevel = null; | |||
for (int i = 0; i < NAMES.length; i++) { | |||
if (NAMES[i].equals(levelString)) { | |||
resourceLevel = new AFPResourceLevel(i); | |||
break; | |||
} | |||
} | |||
return resourceLevel; | |||
} | |||
return null; | |||
ResourceType resType = ResourceType.getValueOf(levelString); | |||
return resType != null ? new AFPResourceLevel(resType) : null; | |||
} | |||
/** | |||
@@ -86,17 +86,8 @@ public class AFPResourceLevel { | |||
* | |||
* @param level the resource level | |||
*/ | |||
public AFPResourceLevel(int level) { | |||
setLevel(level); | |||
} | |||
/** | |||
* Sets the resource level | |||
* | |||
* @param level the resource level | |||
*/ | |||
public void setLevel(int level) { | |||
this.level = level; | |||
public AFPResourceLevel(ResourceType resourceType) { | |||
this.resourceType = resourceType; | |||
} | |||
/** | |||
@@ -105,7 +96,7 @@ public class AFPResourceLevel { | |||
* @return true if this is at page level | |||
*/ | |||
public boolean isPage() { | |||
return level == PAGE; | |||
return resourceType == PAGE; | |||
} | |||
/** | |||
@@ -114,7 +105,7 @@ public class AFPResourceLevel { | |||
* @return true if this is at page group level | |||
*/ | |||
public boolean isPageGroup() { | |||
return level == PAGE_GROUP; | |||
return resourceType == PAGE_GROUP; | |||
} | |||
/** | |||
@@ -123,7 +114,7 @@ public class AFPResourceLevel { | |||
* @return true if this is at document level | |||
*/ | |||
public boolean isDocument() { | |||
return level == DOCUMENT; | |||
return resourceType == DOCUMENT; | |||
} | |||
/** | |||
@@ -132,7 +123,7 @@ public class AFPResourceLevel { | |||
* @return true if this is at external level | |||
*/ | |||
public boolean isExternal() { | |||
return level == EXTERNAL; | |||
return resourceType == EXTERNAL; | |||
} | |||
/** | |||
@@ -141,7 +132,7 @@ public class AFPResourceLevel { | |||
* @return true if this is at print-file level | |||
*/ | |||
public boolean isPrintFile() { | |||
return level == PRINT_FILE; | |||
return resourceType == PRINT_FILE; | |||
} | |||
/** | |||
@@ -150,30 +141,30 @@ public class AFPResourceLevel { | |||
* @return true if this resource level is inline | |||
*/ | |||
public boolean isInline() { | |||
return level == INLINE; | |||
return resourceType == INLINE; | |||
} | |||
/** | |||
* Returns the destination file path of the external resource group file | |||
* Returns the URI of the external resource group. | |||
* | |||
* @return the destination file path of the external resource group file | |||
* @return the destination URI of the external resource group | |||
*/ | |||
public String getExternalFilePath() { | |||
return this.extFilePath; | |||
public URI getExternalURI() { | |||
return this.extUri; | |||
} | |||
/** | |||
* Sets the external destination of the resource | |||
* Sets the URI of the external resource group. | |||
* | |||
* @param filePath the external resource group file | |||
* @param filePath the URI of the external resource group | |||
*/ | |||
public void setExternalFilePath(String filePath) { | |||
this.extFilePath = filePath; | |||
public void setExternalUri(URI uri) { | |||
this.extUri = uri; | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
return NAMES[level] + (isExternal() ? ", file=" + extFilePath : ""); | |||
return resourceType + (isExternal() ? ", uri=" + extUri : ""); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -186,16 +177,16 @@ public class AFPResourceLevel { | |||
} | |||
AFPResourceLevel rl = (AFPResourceLevel)obj; | |||
return (level == rl.level) | |||
&& (extFilePath == rl.extFilePath | |||
|| extFilePath != null && extFilePath.equals(rl.extFilePath)); | |||
return (resourceType == rl.resourceType) | |||
&& (extUri == rl.extUri | |||
|| extUri != null && extUri.equals(rl.extUri)); | |||
} | |||
/** {@inheritDoc} */ | |||
public int hashCode() { | |||
int hash = 7; | |||
hash = 31 * hash + level; | |||
hash = 31 * hash + (null == extFilePath ? 0 : extFilePath.hashCode()); | |||
hash = 31 * hash + resourceType.hashCode(); | |||
hash = 31 * hash + (null == extUri ? 0 : extUri.hashCode()); | |||
return hash; | |||
} | |||
} |
@@ -22,6 +22,7 @@ package org.apache.fop.afp; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import org.apache.fop.afp.AFPResourceLevel.ResourceType; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
/** | |||
@@ -58,7 +59,7 @@ public class AFPResourceLevelDefaults { | |||
// level not explicitly set/changed so default to inline for GOCA graphic objects | |||
// (due to a bug in the IBM AFP Workbench Viewer (2.04.01.07), hard copy works just fine) | |||
setDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC, | |||
new AFPResourceLevel(AFPResourceLevel.INLINE)); | |||
new AFPResourceLevel(ResourceType.INLINE)); | |||
} | |||
/** |
@@ -31,6 +31,7 @@ import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPResourceLevel.ResourceType; | |||
import org.apache.fop.afp.fonts.AFPFont; | |||
import org.apache.fop.afp.fonts.CharacterSet; | |||
import org.apache.fop.afp.modca.AbstractNamedAFPObject; | |||
@@ -41,8 +42,9 @@ import org.apache.fop.afp.modca.PageSegment; | |||
import org.apache.fop.afp.modca.Registry; | |||
import org.apache.fop.afp.modca.ResourceGroup; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.afp.util.AFPResourceAccessor; | |||
import org.apache.fop.afp.util.AFPResourceUtil; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
/** | |||
* Manages the creation and storage of document resources | |||
@@ -74,9 +76,9 @@ public class AFPResourceManager { | |||
/** | |||
* Main constructor | |||
*/ | |||
public AFPResourceManager() { | |||
public AFPResourceManager(InternalResourceResolver resourceResolver) { | |||
this.factory = new Factory(); | |||
this.streamer = new AFPStreamer(factory); | |||
this.streamer = new AFPStreamer(factory, resourceResolver); | |||
this.dataObjectFactory = new AFPDataObjectFactory(factory); | |||
} | |||
@@ -119,8 +121,8 @@ public class AFPResourceManager { | |||
* @param filePath the default resource group file path | |||
*/ | |||
public void setDefaultResourceGroupFilePath(String filePath) { | |||
streamer.setDefaultResourceGroupFilePath(filePath); | |||
public void setDefaultResourceGroupUri(URI uri) { | |||
streamer.setDefaultResourceGroupUri(uri); | |||
} | |||
/** | |||
@@ -325,7 +327,7 @@ public class AFPResourceManager { | |||
if (afpFont.isEmbeddable()) { | |||
//Embed fonts (char sets and code pages) | |||
if (charSet.getResourceAccessor() != null) { | |||
ResourceAccessor accessor = charSet.getResourceAccessor(); | |||
AFPResourceAccessor accessor = charSet.getResourceAccessor(); | |||
createIncludedResource( | |||
charSet.getName(), accessor, | |||
ResourceObject.TYPE_FONT_CHARACTER_SET); | |||
@@ -352,7 +354,7 @@ public class AFPResourceManager { | |||
* @param resourceObjectType the resource object type ({@link ResourceObject}.*) | |||
* @throws IOException if an I/O error occurs while loading the resource | |||
*/ | |||
public void createIncludedResource(String resourceName, ResourceAccessor accessor, | |||
public void createIncludedResource(String resourceName, AFPResourceAccessor accessor, | |||
byte resourceObjectType) throws IOException { | |||
URI uri; | |||
try { | |||
@@ -373,9 +375,9 @@ public class AFPResourceManager { | |||
* @param resourceObjectType the resource object type ({@link ResourceObject}.*) | |||
* @throws IOException if an I/O error occurs while loading the resource | |||
*/ | |||
public void createIncludedResource(String resourceName, URI uri, ResourceAccessor accessor, | |||
public void createIncludedResource(String resourceName, URI uri, AFPResourceAccessor accessor, | |||
byte resourceObjectType) throws IOException { | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE); | |||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | |||
resourceInfo.setLevel(resourceLevel); | |||
@@ -416,9 +418,9 @@ public class AFPResourceManager { | |||
* @throws IOException if an I/O error occurs while loading the resource | |||
*/ | |||
public void createIncludedResourceFromExternal(final String resourceName, | |||
final URI uri, final ResourceAccessor accessor) throws IOException { | |||
final URI uri, final AFPResourceAccessor accessor) throws IOException { | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(ResourceType.PRINT_FILE); | |||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | |||
resourceInfo.setLevel(resourceLevel); |
@@ -20,20 +20,22 @@ | |||
package org.apache.fop.afp; | |||
import java.io.BufferedOutputStream; | |||
import java.io.File; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.RandomAccessFile; | |||
import java.net.URI; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.modca.ResourceGroup; | |||
import org.apache.fop.afp.modca.StreamedResourceGroup; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.apps.io.TempResourceURIGenerator; | |||
/** | |||
* Manages the streaming of the AFP output | |||
@@ -42,43 +44,45 @@ public class AFPStreamer implements Streamable { | |||
/** Static logging instance */ | |||
private static final Log LOG = LogFactory.getLog(AFPStreamer.class); | |||
private static final String AFPDATASTREAM_TEMP_FILE_PREFIX = "AFPDataStream_"; | |||
private static final int BUFFER_SIZE = 4096; // 4k writing buffer | |||
private static final String DEFAULT_EXTERNAL_RESOURCE_FILENAME = "resources.afp"; | |||
private static final TempResourceURIGenerator TEMP_URI_GENERATOR | |||
= new TempResourceURIGenerator("AFPDataStream_"); | |||
private final Factory factory; | |||
private final InternalResourceResolver resourceResolver; | |||
/** A mapping of external resource destinations to resource groups */ | |||
private final Map/*<String,AFPExternalResourceGroup>*/pathResourceGroupMap | |||
= new java.util.HashMap/*<String,AFPExternalResourceGroup>*/(); | |||
private final Map<URI, ResourceGroup> pathResourceGroupMap = new HashMap<URI, ResourceGroup>(); | |||
private StreamedResourceGroup printFileResourceGroup; | |||
/** Sets the default resource group file path */ | |||
private String defaultResourceGroupFilePath = DEFAULT_EXTERNAL_RESOURCE_FILENAME; | |||
private URI defaultResourceGroupUri; | |||
private File tempFile; | |||
private final URI tempUri; | |||
/** temporary document outputstream */ | |||
private OutputStream documentOutputStream; | |||
private OutputStream tempOutputStream; | |||
/** the final outputstream */ | |||
private OutputStream outputStream; | |||
private RandomAccessFile documentFile; | |||
private DataStream dataStream; | |||
/** | |||
* Main constructor | |||
* | |||
* @param factory a factory | |||
* @param resourceResolver resource resolver | |||
*/ | |||
public AFPStreamer(Factory factory) { | |||
public AFPStreamer(Factory factory, InternalResourceResolver resourceResolver) { | |||
this.factory = factory; | |||
this.resourceResolver = resourceResolver; | |||
this.tempUri = TEMP_URI_GENERATOR.generate(); | |||
defaultResourceGroupUri = URI.create(DEFAULT_EXTERNAL_RESOURCE_FILENAME); | |||
} | |||
/** | |||
@@ -89,11 +93,8 @@ public class AFPStreamer implements Streamable { | |||
* @throws IOException thrown if an I/O exception of some sort has occurred | |||
*/ | |||
public DataStream createDataStream(AFPPaintingState paintingState) throws IOException { | |||
this.tempFile = File.createTempFile(AFPDATASTREAM_TEMP_FILE_PREFIX, null); | |||
this.documentFile = new RandomAccessFile(tempFile, "rw"); | |||
this.documentOutputStream = new BufferedOutputStream( | |||
new FileOutputStream(documentFile.getFD())); | |||
this.dataStream = factory.createDataStream(paintingState, documentOutputStream); | |||
this.tempOutputStream = new BufferedOutputStream(resourceResolver.getOutputStream(tempUri)); | |||
this.dataStream = factory.createDataStream(paintingState, tempOutputStream); | |||
return dataStream; | |||
} | |||
@@ -102,8 +103,8 @@ public class AFPStreamer implements Streamable { | |||
* | |||
* @param filePath the default resource group file path | |||
*/ | |||
public void setDefaultResourceGroupFilePath(String filePath) { | |||
this.defaultResourceGroupFilePath = filePath; | |||
public void setDefaultResourceGroupUri(URI uri) { | |||
this.defaultResourceGroupUri = uri; | |||
} | |||
/** | |||
@@ -118,23 +119,23 @@ public class AFPStreamer implements Streamable { | |||
return null; | |||
} | |||
if (level.isExternal()) { | |||
String filePath = level.getExternalFilePath(); | |||
if (filePath == null) { | |||
URI uri = level.getExternalURI(); | |||
if (uri == null) { | |||
LOG.warn("No file path provided for external resource, using default."); | |||
filePath = defaultResourceGroupFilePath; | |||
uri = defaultResourceGroupUri; | |||
} | |||
resourceGroup = (ResourceGroup)pathResourceGroupMap.get(filePath); | |||
resourceGroup = pathResourceGroupMap.get(uri); | |||
if (resourceGroup == null) { | |||
OutputStream os = null; | |||
try { | |||
os = new BufferedOutputStream(new FileOutputStream(filePath)); | |||
} catch (FileNotFoundException fnfe) { | |||
LOG.error("Failed to create/open external resource group file '" | |||
+ filePath + "'"); | |||
os = new BufferedOutputStream(resourceResolver.getOutputStream(uri)); | |||
} catch (IOException ioe) { | |||
LOG.error("Failed to create/open external resource group for uri '" | |||
+ uri + "'"); | |||
} finally { | |||
if (os != null) { | |||
resourceGroup = factory.createStreamedResourceGroup(os); | |||
pathResourceGroupMap.put(filePath, resourceGroup); | |||
pathResourceGroupMap.put(uri, resourceGroup); | |||
} | |||
} | |||
} | |||
@@ -156,34 +157,20 @@ public class AFPStreamer implements Streamable { | |||
* | |||
* @throws IOException if an an I/O exception of some sort has occurred | |||
*/ | |||
// write out any external resource groups | |||
// write out any external resource groups | |||
public void close() throws IOException { | |||
Iterator it = pathResourceGroupMap.values().iterator(); | |||
while (it.hasNext()) { | |||
StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next(); | |||
resourceGroup.close(); | |||
} | |||
// close any open print-file resource group | |||
if (printFileResourceGroup != null) { | |||
printFileResourceGroup.close(); | |||
} | |||
// write out document | |||
writeToStream(outputStream); | |||
outputStream.close(); | |||
if (documentOutputStream != null) { | |||
documentOutputStream.close(); | |||
} | |||
if (documentFile != null) { | |||
documentFile.close(); | |||
} | |||
// delete temporary file | |||
tempFile.delete(); | |||
} | |||
/** | |||
@@ -197,28 +184,11 @@ public class AFPStreamer implements Streamable { | |||
/** {@inheritDoc} */ | |||
public void writeToStream(OutputStream os) throws IOException { | |||
// long start = System.currentTimeMillis(); | |||
int len = (int)documentFile.length(); | |||
int numChunks = len / BUFFER_SIZE; | |||
int remainingChunkSize = len % BUFFER_SIZE; | |||
byte[] buffer; | |||
documentFile.seek(0); | |||
if (numChunks > 0) { | |||
buffer = new byte[BUFFER_SIZE]; | |||
for (int i = 0; i < numChunks; i++) { | |||
documentFile.read(buffer, 0, BUFFER_SIZE); | |||
os.write(buffer, 0, BUFFER_SIZE); | |||
} | |||
} else { | |||
buffer = new byte[remainingChunkSize]; | |||
} | |||
if (remainingChunkSize > 0) { | |||
documentFile.read(buffer, 0, remainingChunkSize); | |||
os.write(buffer, 0, remainingChunkSize); | |||
} | |||
tempOutputStream.close(); | |||
InputStream tempInputStream = resourceResolver.getResource(tempUri); | |||
IOUtils.copy(tempInputStream, os); | |||
//TODO this should notify the stream provider that it is safe to delete the temp data | |||
tempInputStream.close(); | |||
os.flush(); | |||
// long end = System.currentTimeMillis(); | |||
// log.debug("writing time " + (end - start) + "ms"); | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -30,7 +30,7 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPConstants; | |||
import org.apache.fop.afp.AFPEventProducer; | |||
import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.afp.util.AFPResourceAccessor; | |||
import org.apache.fop.afp.util.StringUtils; | |||
/** | |||
@@ -77,7 +77,7 @@ public class CharacterSet { | |||
protected final String name; | |||
/** The path to the installed fonts */ | |||
private final ResourceAccessor accessor; | |||
private final AFPResourceAccessor accessor; | |||
/** The current orientation (currently only 0 is supported by FOP) */ | |||
private final String currentOrientation = "0"; | |||
@@ -100,7 +100,7 @@ public class CharacterSet { | |||
* @param eventProducer for handling AFP related events | |||
*/ | |||
CharacterSet(String codePage, String encoding, CharacterSetType charsetType, String name, | |||
ResourceAccessor accessor, AFPEventProducer eventProducer) { | |||
AFPResourceAccessor accessor, AFPEventProducer eventProducer) { | |||
if (name.length() > MAX_NAME_LEN) { | |||
String msg = "Character set name '" + name + "' must be a maximum of " | |||
+ MAX_NAME_LEN + " characters"; | |||
@@ -115,7 +115,7 @@ public class CharacterSet { | |||
} | |||
this.codePage = codePage; | |||
this.encoding = encoding; | |||
this.encoder = CharactersetEncoder.newInstance(encoding, charsetType); | |||
this.encoder = charsetType.getEncoder(encoding); | |||
this.accessor = accessor; | |||
this.characterSetOrientations = new HashMap<String, CharacterSetOrientation>(4); | |||
@@ -211,7 +211,7 @@ public class CharacterSet { | |||
* Returns the resource accessor to load the font resources with. | |||
* @return the resource accessor to load the font resources with | |||
*/ | |||
public ResourceAccessor getResourceAccessor() { | |||
public AFPResourceAccessor getResourceAccessor() { | |||
return this.accessor; | |||
} | |||
@@ -19,9 +19,9 @@ | |||
package org.apache.fop.afp.fonts; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.ArrayList; | |||
@@ -38,8 +38,9 @@ import org.apache.xmlgraphics.image.loader.util.SoftMapCache; | |||
import org.apache.fop.afp.AFPConstants; | |||
import org.apache.fop.afp.AFPEventProducer; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.afp.util.AFPResourceAccessor; | |||
import org.apache.fop.afp.util.StructuredFieldReader; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.fonts.Typeface; | |||
/** | |||
@@ -138,28 +139,24 @@ public abstract class CharacterSetBuilder { | |||
* Returns an InputStream to a given file path and filename | |||
* | |||
* * @param accessor the resource accessor | |||
* @param filename the file name | |||
* @param uriStr the URI | |||
* @param eventProducer for handling AFP related events | |||
* @return an inputStream | |||
* | |||
* @throws IOException in the event that an I/O exception of some sort has occurred | |||
*/ | |||
protected InputStream openInputStream(ResourceAccessor accessor, String filename, | |||
private InputStream openInputStream(AFPResourceAccessor accessor, String uriStr, | |||
AFPEventProducer eventProducer) | |||
throws IOException { | |||
URI uri; | |||
try { | |||
uri = new URI(filename.trim()); | |||
uri = InternalResourceResolver.cleanURI(uriStr.trim()); | |||
} catch (URISyntaxException e) { | |||
throw new FileNotFoundException("Invalid filename: " | |||
+ filename + " (" + e.getMessage() + ")"); | |||
throw new MalformedURLException("Invalid uri: " + uriStr + " (" + e.getMessage() + ")"); | |||
} | |||
if (LOG.isDebugEnabled()) { | |||
LOG.debug("Opening " + uri); | |||
} | |||
InputStream inputStream = accessor.createInputStream(uri); | |||
return inputStream; | |||
return accessor.createInputStream(uri); | |||
} | |||
/** | |||
@@ -167,7 +164,7 @@ public abstract class CharacterSetBuilder { | |||
* | |||
* @param inputStream the inputstream to close | |||
*/ | |||
protected void closeInputStream(InputStream inputStream) { | |||
private void closeInputStream(InputStream inputStream) { | |||
try { | |||
if (inputStream != null) { | |||
inputStream.close(); | |||
@@ -191,7 +188,7 @@ public abstract class CharacterSetBuilder { | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public CharacterSet buildSBCS(String characterSetName, String codePageName, String encoding, | |||
ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { | |||
AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { | |||
return processFont(characterSetName, codePageName, encoding, CharacterSetType.SINGLE_BYTE, | |||
accessor, eventProducer); | |||
} | |||
@@ -211,7 +208,7 @@ public abstract class CharacterSetBuilder { | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public CharacterSet buildDBCS(String characterSetName, String codePageName, String encoding, | |||
CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer) | |||
CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) | |||
throws IOException { | |||
return processFont(characterSetName, codePageName, encoding, charsetType, accessor, | |||
eventProducer); | |||
@@ -236,7 +233,7 @@ public abstract class CharacterSetBuilder { | |||
} | |||
private CharacterSet processFont(String characterSetName, String codePageName, String encoding, | |||
CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer) | |||
CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) | |||
throws IOException { | |||
// check for cached version of the characterset | |||
String descriptor = characterSetName + "_" + encoding + "_" + codePageName; | |||
@@ -329,7 +326,7 @@ public abstract class CharacterSetBuilder { | |||
* @throws IOException if an I/O exception of some sort has occurred. | |||
*/ | |||
protected Map<String, String> loadCodePage(String codePage, String encoding, | |||
ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { | |||
AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { | |||
// Create the HashMap to store code page information | |||
Map<String, String> codePages = new HashMap<String, String>(); | |||
@@ -337,7 +334,11 @@ public abstract class CharacterSetBuilder { | |||
InputStream inputStream = null; | |||
try { | |||
inputStream = openInputStream(accessor, codePage.trim(), eventProducer); | |||
} catch (IOException e) { | |||
eventProducer.codePageNotFound(this, e); | |||
throw e; | |||
} | |||
try { | |||
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); | |||
byte[] data = structuredFieldReader.getNext(CHARACTER_TABLE_SF); | |||
@@ -367,8 +368,6 @@ public abstract class CharacterSetBuilder { | |||
position++; | |||
} | |||
} | |||
} catch (FileNotFoundException e) { | |||
eventProducer.codePageNotFound(this, e); | |||
} finally { | |||
closeInputStream(inputStream); | |||
} | |||
@@ -383,9 +382,8 @@ public abstract class CharacterSetBuilder { | |||
* @return a class representing the font descriptor | |||
* @throws IOException if an I/O exception of some sort has occurred. | |||
*/ | |||
protected static FontDescriptor processFontDescriptor( | |||
StructuredFieldReader structuredFieldReader) | |||
throws IOException { | |||
private static FontDescriptor processFontDescriptor( | |||
StructuredFieldReader structuredFieldReader) throws IOException { | |||
byte[] fndData = structuredFieldReader.getNext(FONT_DESCRIPTOR_SF); | |||
return new FontDescriptor(fndData); | |||
@@ -399,8 +397,8 @@ public abstract class CharacterSetBuilder { | |||
* @return the FontControl | |||
* @throws IOException if an I/O exception of some sort has occurred. | |||
*/ | |||
protected FontControl processFontControl(StructuredFieldReader structuredFieldReader) | |||
throws IOException { | |||
private FontControl processFontControl(StructuredFieldReader structuredFieldReader) | |||
throws IOException { | |||
byte[] fncData = structuredFieldReader.getNext(FONT_CONTROL_SF); | |||
@@ -431,7 +429,7 @@ public abstract class CharacterSetBuilder { | |||
* @return CharacterSetOrientation array | |||
* @throws IOException if an I/O exception of some sort has occurred. | |||
*/ | |||
protected CharacterSetOrientation[] processFontOrientation( | |||
private CharacterSetOrientation[] processFontOrientation( | |||
StructuredFieldReader structuredFieldReader) throws IOException { | |||
byte[] data = structuredFieldReader.getNext(FONT_ORIENTATION_SF); | |||
@@ -464,7 +462,6 @@ public abstract class CharacterSetBuilder { | |||
} | |||
} | |||
return orientations.toArray(EMPTY_CSO_ARRAY); | |||
} | |||
@@ -480,7 +477,7 @@ public abstract class CharacterSetBuilder { | |||
* font metric values | |||
* @throws IOException if an I/O exception of some sort has occurred. | |||
*/ | |||
protected void processFontPosition(StructuredFieldReader structuredFieldReader, | |||
private void processFontPosition(StructuredFieldReader structuredFieldReader, | |||
CharacterSetOrientation[] characterSetOrientations, double metricNormalizationFactor) | |||
throws IOException { | |||
@@ -537,7 +534,7 @@ public abstract class CharacterSetBuilder { | |||
* font metric values | |||
* @throws IOException if an I/O exception of some sort has occurred. | |||
*/ | |||
protected void processFontIndex(StructuredFieldReader structuredFieldReader, | |||
private void processFontIndex(StructuredFieldReader structuredFieldReader, | |||
CharacterSetOrientation cso, Map<String, String> codepage, | |||
double metricNormalizationFactor) | |||
throws IOException { | |||
@@ -709,22 +706,23 @@ public abstract class CharacterSetBuilder { | |||
return INSTANCE; | |||
} | |||
@Override | |||
protected Map<String, String> loadCodePage(String codePage, String encoding, | |||
ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { | |||
AFPResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { | |||
// Create the HashMap to store code page information | |||
Map<String, String> codePages = new HashMap<String, String>(); | |||
InputStream inputStream = null; | |||
try { | |||
inputStream = openInputStream(accessor, codePage.trim(), eventProducer); | |||
StructuredFieldReader structuredFieldReader | |||
= new StructuredFieldReader(inputStream); | |||
inputStream = super.openInputStream(accessor, codePage.trim(), eventProducer); | |||
} catch (IOException e) { | |||
eventProducer.codePageNotFound(this, e); | |||
throw e; | |||
} | |||
try { | |||
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); | |||
byte[] data; | |||
while ((data = structuredFieldReader.getNext(CHARACTER_TABLE_SF)) != null) { | |||
int position = 0; | |||
byte[] gcgiBytes = new byte[8]; | |||
byte[] charBytes = new byte[2]; | |||
// Read data, ignoring bytes 0 - 2 | |||
@@ -752,12 +750,9 @@ public abstract class CharacterSetBuilder { | |||
} | |||
} | |||
} | |||
} catch (FileNotFoundException e) { | |||
eventProducer.codePageNotFound(this, e); | |||
} finally { | |||
closeInputStream(inputStream); | |||
super.closeInputStream(inputStream); | |||
} | |||
return codePages; | |||
} | |||
@@ -19,13 +19,39 @@ | |||
package org.apache.fop.afp.fonts; | |||
import org.apache.fop.afp.fonts.CharactersetEncoder.DefaultEncoder; | |||
import org.apache.fop.afp.fonts.CharactersetEncoder.EbcdicDoubleByteLineDataEncoder; | |||
/** | |||
* An enumeration of AFP characterset types. | |||
*/ | |||
public enum CharacterSetType { | |||
/** Double byte character sets; these do NOT have the shift-in;shift-out operators */ | |||
DOUBLE_BYTE, | |||
DOUBLE_BYTE { | |||
@Override | |||
CharactersetEncoder getEncoder(String encoding) { | |||
return new DefaultEncoder(encoding, true); | |||
} | |||
}, | |||
/** Double byte character sets; these can have the shift-in;shift-out operators */ | |||
DOUBLE_BYTE_LINE_DATA, | |||
SINGLE_BYTE; | |||
DOUBLE_BYTE_LINE_DATA { | |||
@Override | |||
CharactersetEncoder getEncoder(String encoding) { | |||
return new EbcdicDoubleByteLineDataEncoder(encoding); | |||
} | |||
}, | |||
SINGLE_BYTE { | |||
@Override | |||
CharactersetEncoder getEncoder(String encoding) { | |||
return new DefaultEncoder(encoding, false); | |||
} | |||
}; | |||
/** | |||
* Returns the character-set encoder | |||
* | |||
* @param encoding | |||
* @return | |||
*/ | |||
abstract CharactersetEncoder getEncoder(String encoding); | |||
} |
@@ -87,7 +87,7 @@ public abstract class CharactersetEncoder { | |||
*/ | |||
public static EncodedChars encodeSBCS(CharSequence chars, String encoding) | |||
throws CharacterCodingException { | |||
CharactersetEncoder encoder = newInstance(encoding, CharacterSetType.SINGLE_BYTE); | |||
CharactersetEncoder encoder = CharacterSetType.SINGLE_BYTE.getEncoder(encoding); | |||
return encoder.encode(chars); | |||
} | |||
@@ -97,8 +97,8 @@ public abstract class CharactersetEncoder { | |||
* sequence it will return its EBCDIC code-point, however, the "Shift In - Shift Out" operators | |||
* are removed from the sequence of bytes. These are only used in Line Data. | |||
*/ | |||
private static final class EbcdicDoubleByteLineDataEncoder extends CharactersetEncoder { | |||
private EbcdicDoubleByteLineDataEncoder(String encoding) { | |||
static final class EbcdicDoubleByteLineDataEncoder extends CharactersetEncoder { | |||
EbcdicDoubleByteLineDataEncoder(String encoding) { | |||
super(encoding); | |||
} | |||
@Override | |||
@@ -115,10 +115,10 @@ public abstract class CharactersetEncoder { | |||
* the primary format for most Latin character sets. This can also be used for Unicode double- | |||
* byte character sets (DBCS). | |||
*/ | |||
private static final class DefaultEncoder extends CharactersetEncoder { | |||
static final class DefaultEncoder extends CharactersetEncoder { | |||
private final boolean isDBCS; | |||
private DefaultEncoder(String encoding, boolean isDBCS) { | |||
DefaultEncoder(String encoding, boolean isDBCS) { | |||
super(encoding); | |||
this.isDBCS = isDBCS; | |||
} | |||
@@ -129,24 +129,6 @@ public abstract class CharactersetEncoder { | |||
} | |||
} | |||
/** | |||
* Returns an new instance of a {@link CharactersetEncoder}. | |||
* | |||
* @param encoding the encoding for the underlying character encoder | |||
* @param isEbcdicDBCS whether or not this wraps a double-byte EBCDIC code page. | |||
* @return the CharactersetEncoder | |||
*/ | |||
static CharactersetEncoder newInstance(String encoding, CharacterSetType charsetType) { | |||
switch (charsetType) { | |||
case DOUBLE_BYTE_LINE_DATA: | |||
return new EbcdicDoubleByteLineDataEncoder(encoding); | |||
case DOUBLE_BYTE: | |||
return new DefaultEncoder(encoding, true); | |||
default: | |||
return new DefaultEncoder(encoding, false); | |||
} | |||
} | |||
/** | |||
* A container for encoded character bytes | |||
*/ |
@@ -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} */ |
@@ -20,7 +20,7 @@ | |||
package org.apache.fop.afp.fonts; | |||
import org.apache.fop.afp.AFPEventProducer; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.afp.util.AFPResourceAccessor; | |||
import org.apache.fop.fonts.Typeface; | |||
/** | |||
@@ -42,7 +42,7 @@ public class FopCharacterSet extends CharacterSet { | |||
*/ | |||
public FopCharacterSet(String codePage, String encoding, String name, Typeface charSet, | |||
AFPEventProducer eventProducer) { | |||
super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, (ResourceAccessor) null, | |||
super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, (AFPResourceAccessor) null, | |||
eventProducer); | |||
this.charSet = charSet; | |||
} |
@@ -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 |
@@ -26,16 +26,15 @@ import java.net.URI; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.afp.util.AFPResourceAccessor; | |||
import org.apache.fop.afp.util.AFPResourceUtil; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
/** | |||
* Encapsulates an included resource object that is loaded from an external file. | |||
*/ | |||
public class IncludedResourceObject extends AbstractNamedAFPObject { | |||
private ResourceAccessor resourceAccessor; | |||
private AFPResourceAccessor resourceAccessor; | |||
private URI uri; | |||
/** | |||
@@ -45,7 +44,7 @@ public class IncludedResourceObject extends AbstractNamedAFPObject { | |||
* @param uri the URI of the external file | |||
*/ | |||
public IncludedResourceObject(String name, | |||
ResourceAccessor resourceAccessor, URI uri) { | |||
AFPResourceAccessor resourceAccessor, URI uri) { | |||
super(name); | |||
this.resourceAccessor = resourceAccessor; | |||
this.uri = uri; |
@@ -0,0 +1,76 @@ | |||
/* | |||
* 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.afp.util; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
/** | |||
* Defines an interface through which external resource objects can be accessed. | |||
*/ | |||
public final class AFPResourceAccessor { | |||
private final InternalResourceResolver resourceResolver; | |||
private final String baseURI; | |||
/** | |||
* Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. This | |||
* contructor takes a base URI for resolving font resource URIs. So, if fonts need to be | |||
* accessed, you can set the {@link FontManager}'s base URI instead of the one on the | |||
* {@link org.apache.fop.apps.FopFactory}. | |||
* | |||
* @param InternalResourceResolver resource resolver | |||
* @param baseURI the custom base URI to resolve relative URIs against (may be null) | |||
*/ | |||
public AFPResourceAccessor(InternalResourceResolver resourceResolver, String baseURI) { | |||
this.resourceResolver = resourceResolver; | |||
this.baseURI = baseURI; | |||
} | |||
/** | |||
* Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. | |||
* | |||
* @param InternalResourceResolver resource resolver | |||
*/ | |||
public AFPResourceAccessor(InternalResourceResolver resourceResolver) { | |||
this(resourceResolver, null); | |||
} | |||
private URI getResourceURI(URI uri) { | |||
if (baseURI == null) { | |||
return uri; | |||
} | |||
try { | |||
URI baseURI = InternalResourceResolver.getBaseURI(this.baseURI); | |||
return baseURI.resolve(uri); | |||
} catch (URISyntaxException use) { | |||
return uri; | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
return resourceResolver.getResource(getResourceURI(uri)); | |||
} | |||
} |
@@ -92,13 +92,10 @@ public final class AFPResourceUtil { | |||
throws UnsupportedEncodingException { | |||
//The first 8 bytes of the field data represent the resource name | |||
byte[] nameBytes = new byte[8]; | |||
byte[] fieldData = field.getData(); | |||
if (fieldData.length < 8) { | |||
throw new IllegalArgumentException("Field data does not contain a resource name"); | |||
} | |||
System.arraycopy(fieldData, 0, nameBytes, 0, 8); | |||
return new String(nameBytes, AFPConstants.EBCIDIC_ENCODING); | |||
System.arraycopy(field.getData(), 0, nameBytes, 0, 8); | |||
String asciiName; | |||
asciiName = new String(nameBytes, AFPConstants.EBCIDIC_ENCODING); | |||
return asciiName; | |||
} | |||
/** | |||
@@ -131,13 +128,12 @@ public final class AFPResourceUtil { | |||
public static void copyNamedResource(String name, | |||
final InputStream in, final OutputStream out) throws IOException { | |||
final MODCAParser parser = new MODCAParser(in); | |||
Collection<String> resourceNames = new java.util.HashSet<String>(); | |||
Collection resourceNames = new java.util.HashSet(); | |||
//Find matching "Begin" field | |||
final UnparsedStructuredField fieldBegin; | |||
while (true) { | |||
final UnparsedStructuredField field = parser.readNextStructuredField(); | |||
UnparsedStructuredField field = parser.readNextStructuredField(); | |||
if (field == null) { | |||
throw new IOException("Requested resource '" + name | |||
+ "' not found. Encountered resource names: " + resourceNames); | |||
@@ -146,10 +142,8 @@ public final class AFPResourceUtil { | |||
if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin | |||
continue; //Not a "Begin" field | |||
} | |||
final String resourceName = getResourceName(field); | |||
String resourceName = getResourceName(field); | |||
resourceNames.add(resourceName); | |||
if (resourceName.equals(name)) { | |||
if (LOG.isDebugEnabled()) { | |||
LOG.debug("Start of requested structured field found:\n" | |||
@@ -176,35 +170,45 @@ public final class AFPResourceUtil { | |||
if (wrapInResource) { | |||
ResourceObject resourceObject = new ResourceObject(name) { | |||
protected void writeContent(OutputStream os) throws IOException { | |||
copyNamedStructuredFields(name, fieldBegin, parser, out); | |||
copyStructuredFields(name, fieldBegin, parser, out); | |||
} | |||
}; | |||
resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT); | |||
resourceObject.writeToStream(out); | |||
} else { | |||
copyNamedStructuredFields(name, fieldBegin, parser, out); | |||
copyStructuredFields(name, fieldBegin, parser, out); | |||
} | |||
} | |||
private static void copyNamedStructuredFields(final String name, | |||
UnparsedStructuredField fieldBegin, MODCAParser parser, | |||
OutputStream out) throws IOException { | |||
private static void copyStructuredFields(String name, UnparsedStructuredField fieldBegin, | |||
MODCAParser parser, OutputStream out) throws IOException { | |||
boolean inRequestedResource; | |||
UnparsedStructuredField field = fieldBegin; | |||
//The "Begin" field first | |||
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); | |||
fieldBegin.writeTo(out); | |||
UnparsedStructuredField field; | |||
while (true) { | |||
//Then the rest of the fields until the corresponding "End" field | |||
inRequestedResource = true; | |||
do { | |||
field = parser.readNextStructuredField(); | |||
if (field == null) { | |||
throw new IOException("Ending structured field not found for resource " + name); | |||
break; //Unexpected EOF | |||
} | |||
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); | |||
field.writeTo(out); | |||
if (field.getSfTypeCode() == TYPE_CODE_END | |||
&& fieldBegin.getSfCategoryCode() == field.getSfCategoryCode() | |||
&& name.equals(getResourceName(field))) { | |||
break; | |||
if (field.getSfTypeCode() == TYPE_CODE_END) { | |||
String resourceName = getResourceName(field); | |||
if (resourceName.equals(name)) { | |||
inRequestedResource = false; //Signal end of loop | |||
} | |||
} | |||
field = parser.readNextStructuredField(); | |||
out.write(MODCAParser.CARRIAGE_CONTROL_CHAR); | |||
field.writeTo(out); | |||
} while (inRequestedResource); | |||
if (inRequestedResource) { | |||
throw new IOException("Ending structured field not found for resource " + name); | |||
} | |||
} | |||
} |
@@ -1,87 +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.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 org.apache.fop.apps.FOUserAgent; | |||
/** | |||
* Default implementation of the {@link ResourceAccessor} interface for use inside FOP. | |||
*/ | |||
public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { | |||
private FOUserAgent userAgent; | |||
private String categoryBaseURI; | |||
/** | |||
* Constructor for resource to be accessed via the {@link FOUserAgent}. This contructor | |||
* can take two base URIs: the category base URI is the one to use when differentiating between | |||
* normal resources (ex. images) and font resources. So, if fonts need to be accessed, you can | |||
* set the {@link org.apache.fop.fonts.FontManager}'s base URI instead of the one on the | |||
* {@link org.apache.fop.apps.FopFactory}. | |||
* @param userAgent the FO user agent | |||
* @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; | |||
} | |||
/** {@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); | |||
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()); | |||
} | |||
} | |||
URL url = new URL(src.getSystemId()); | |||
return url.openStream(); | |||
} | |||
} |
@@ -1,76 +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.afp.util; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URL; | |||
/** | |||
* Simple implementation of the {@link ResourceAccessor} interface for access relative to a | |||
* base URI. | |||
*/ | |||
public class SimpleResourceAccessor implements ResourceAccessor { | |||
private URI baseURI; | |||
/** | |||
* Creates a new simple resource accessor. | |||
* @param baseURI the base URI to resolve relative URIs against (may be null) | |||
*/ | |||
public SimpleResourceAccessor(URI baseURI) { | |||
this.baseURI = baseURI; | |||
} | |||
/** | |||
* Creates a new simple resource accessor. | |||
* @param baseDir the base directory to resolve relative filenames against (may be null) | |||
*/ | |||
public SimpleResourceAccessor(File baseDir) { | |||
this(baseDir != null ? baseDir.toURI() : null); | |||
} | |||
/** | |||
* Returns the base URI. | |||
* @return the base URI (or null if no base URI was set) | |||
*/ | |||
public URI getBaseURI() { | |||
return this.baseURI; | |||
} | |||
/** | |||
* Resolve the given URI against the baseURI. | |||
* @param uri the URI to resolve | |||
* @return the resolved URI | |||
*/ | |||
protected URI resolveAgainstBase(URI uri) { | |||
return (getBaseURI() != null ? getBaseURI().resolve(uri) : uri); | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
URI resolved = resolveAgainstBase(uri); | |||
URL url = resolved.toURL(); | |||
return url.openStream(); | |||
} | |||
} |
@@ -17,22 +17,36 @@ | |||
/* $Id$ */ | |||
package org.apache.fop.hyphenation; | |||
package org.apache.fop.apps; | |||
import javax.xml.transform.Source; | |||
import java.net.URI; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.fonts.FontManager; | |||
/** | |||
* <p>This interface is used to resolve relative URIs pointing to hyphenation tree files.</p> | |||
* The environment profile represents the restrictions and allowances that FOP is | |||
*/ | |||
public interface HyphenationTreeResolver { | |||
public interface EnvironmentProfile { | |||
/** | |||
* Returns resource resolver for this environment. | |||
* | |||
* @return the resource resolver | |||
*/ | |||
ResourceResolver getResourceResolver(); | |||
/** | |||
* Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's | |||
* resolve() method is defined to be implicitely available in this case. If the URI cannot | |||
* be resolved, null is returned. | |||
* @param href An href attribute, which may be relative or absolute. | |||
* @return A Source object, or null if the href could not resolved. | |||
* Returns the font manager with restrictions/allowances set for this environment. | |||
* | |||
* @return the font manager | |||
*/ | |||
Source resolve(String href); | |||
FontManager getFontManager(); | |||
/** | |||
* The default base URI used for resolving URIs. | |||
* | |||
* @return the default base URI | |||
*/ | |||
URI getDefaultBaseURI(); | |||
} |
@@ -0,0 +1,113 @@ | |||
/* | |||
* 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.InternalResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
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) { | |||
InternalResourceResolver internalResolver = ResourceResolverFactory.createInternalResourceResolver( | |||
defaultBaseUri, resourceResolver); | |||
return new FontManager(internalResolver, fontDetector, fontCacheManager); | |||
} | |||
} |
@@ -1,376 +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.ByteArrayOutputStream; | |||
import java.io.File; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.net.MalformedURLException; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.net.URL; | |||
import java.net.URLConnection; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.URIResolver; | |||
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.xmlgraphics.util.io.Base64EncodeStream; | |||
import org.apache.xmlgraphics.util.uri.CommonURIResolver; | |||
/** | |||
* Provides FOP specific URI resolution. This is the default URIResolver | |||
* {@link FOUserAgent} will use unless overridden. | |||
* | |||
* @see javax.xml.transform.URIResolver | |||
*/ | |||
public class FOURIResolver implements javax.xml.transform.URIResolver { | |||
// log | |||
private Log log = LogFactory.getLog("FOP"); | |||
/** Common URIResolver */ | |||
private CommonURIResolver commonURIResolver = new CommonURIResolver(); | |||
/** A user settable URI Resolver */ | |||
private URIResolver uriResolver = null; | |||
/** true if exceptions are to be thrown if the URIs cannot be resolved. */ | |||
private boolean throwExceptions = false; | |||
/** | |||
* Checks if the given base URL is acceptable. It also normalizes the URL. | |||
* @param base the base URL to check | |||
* @return the normalized URL | |||
* @throws MalformedURLException if there's a problem with a file URL | |||
*/ | |||
public String checkBaseURL(String base) throws MalformedURLException { | |||
// replace back slash with forward slash to ensure windows file:/// URLS are supported | |||
base = base.replace('\\', '/'); | |||
if (!base.endsWith("/")) { | |||
// The behavior described by RFC 3986 regarding resolution of relative | |||
// references may be misleading for normal users: | |||
// file://path/to/resources + myResource.res -> file://path/to/myResource.res | |||
// file://path/to/resources/ + myResource.res -> file://path/to/resources/myResource.res | |||
// We assume that even when the ending slash is missing, users have the second | |||
// example in mind | |||
base += "/"; | |||
} | |||
File dir = new File(base); | |||
if (dir.isDirectory()) { | |||
return dir.toURI().toASCIIString(); | |||
} else { | |||
URI baseURI; | |||
try { | |||
baseURI = new URI(base); | |||
String scheme = baseURI.getScheme(); | |||
boolean directoryExists = true; | |||
if ("file".equals(scheme)) { | |||
dir = FileUtils.toFile(baseURI.toURL()); | |||
directoryExists = dir.isDirectory(); | |||
} | |||
if (scheme == null || !directoryExists) { | |||
String message = "base " + base + " is not a valid directory"; | |||
if (throwExceptions) { | |||
throw new MalformedURLException(message); | |||
} | |||
log.error(message); | |||
} | |||
return baseURI.toASCIIString(); | |||
} catch (URISyntaxException e) { | |||
//TODO not ideal: our base URLs are actually base URIs. | |||
throw new MalformedURLException(e.getMessage()); | |||
} | |||
} | |||
} | |||
/** | |||
* Default constructor | |||
*/ | |||
public FOURIResolver() { | |||
this(false); | |||
} | |||
/** | |||
* Additional constructor | |||
* | |||
* @param throwExceptions | |||
* true if exceptions are to be thrown if the URIs cannot be | |||
* resolved. | |||
*/ | |||
public FOURIResolver(boolean throwExceptions) { | |||
this.throwExceptions = throwExceptions; | |||
} | |||
/** | |||
* Handles resolve exceptions appropriately. | |||
* | |||
* @param e | |||
* the exception | |||
* @param errorStr | |||
* error string | |||
* @param strict | |||
* strict user config | |||
*/ | |||
private void handleException(Exception e, String errorStr, boolean strict) | |||
throws TransformerException { | |||
if (strict) { | |||
throw new TransformerException(errorStr, e); | |||
} | |||
log.error(e.getMessage()); | |||
} | |||
/** | |||
* Called by the processor through {@link FOUserAgent} when it encounters an | |||
* uri in an external-graphic element. (see also | |||
* {@link javax.xml.transform.URIResolver#resolve(String, String)} This | |||
* resolver will allow URLs without a scheme, i.e. it assumes 'file:' as the | |||
* default scheme. It also allows relative URLs with scheme, e.g. | |||
* file:../../abc.jpg which is not strictly RFC compliant as long as the | |||
* scheme is the same as the scheme of the base URL. If the base URL is null | |||
* a 'file:' URL referencing the current directory is used as the base URL. | |||
* If the method is successful it will return a Source of type | |||
* {@link javax.xml.transform.stream.StreamSource} with its SystemID set to | |||
* the resolved URL used to open the underlying InputStream. | |||
* | |||
* @param href | |||
* An href attribute, which may be relative or absolute. | |||
* @param base | |||
* The base URI against which the first argument will be made | |||
* absolute if the absolute URI is required. | |||
* @return A {@link javax.xml.transform.Source} object, or null if the href | |||
* cannot be resolved. | |||
* @throws javax.xml.transform.TransformerException | |||
* Never thrown by this implementation. | |||
* @see javax.xml.transform.URIResolver#resolve(String, String) | |||
*/ | |||
public Source resolve(String href, String base) throws TransformerException { | |||
Source source = null; | |||
// data URLs can be quite long so evaluate early and don't try to build a File | |||
// (can lead to problems) | |||
source = commonURIResolver.resolve(href, base); | |||
// Custom uri resolution | |||
if (source == null && uriResolver != null) { | |||
source = uriResolver.resolve(href, base); | |||
} | |||
// Fallback to default resolution mechanism | |||
if (source == null) { | |||
URL absoluteURL = null; | |||
int hashPos = href.indexOf('#'); | |||
String fileURL; | |||
String fragment; | |||
if (hashPos >= 0) { | |||
fileURL = href.substring(0, hashPos); | |||
fragment = href.substring(hashPos); | |||
} else { | |||
fileURL = href; | |||
fragment = null; | |||
} | |||
File file = new File(fileURL); | |||
if (file.canRead() && file.isFile()) { | |||
try { | |||
if (fragment != null) { | |||
absoluteURL = new URL(file.toURI().toURL().toExternalForm() + fragment); | |||
} else { | |||
absoluteURL = file.toURI().toURL(); | |||
} | |||
} catch (MalformedURLException mfue) { | |||
handleException(mfue, "Could not convert filename '" + href | |||
+ "' to URL", throwExceptions); | |||
} | |||
} else { | |||
// no base provided | |||
if (base == null) { | |||
// We don't have a valid file protocol based URL | |||
try { | |||
absoluteURL = new URL(href); | |||
} catch (MalformedURLException mue) { | |||
try { | |||
// the above failed, we give it another go in case | |||
// the href contains only a path then file: is | |||
// assumed | |||
absoluteURL = new URL("file:" + href); | |||
} catch (MalformedURLException mfue) { | |||
handleException(mfue, "Error with URL '" + href | |||
+ "'", throwExceptions); | |||
} | |||
} | |||
// try and resolve from context of base | |||
} else { | |||
URL baseURL = null; | |||
try { | |||
baseURL = new URL(base); | |||
} catch (MalformedURLException mfue) { | |||
handleException(mfue, "Error with base URL '" + base | |||
+ "'", throwExceptions); | |||
} | |||
/* | |||
* This piece of code is based on the following statement in | |||
* RFC2396 section 5.2: | |||
* | |||
* 3) If the scheme component is defined, indicating that | |||
* the reference starts with a scheme name, then the | |||
* reference is interpreted as an absolute URI and we are | |||
* done. Otherwise, the reference URI's scheme is inherited | |||
* from the base URI's scheme component. | |||
* | |||
* Due to a loophole in prior specifications [RFC1630], some | |||
* parsers allow the scheme name to be present in a relative | |||
* URI if it is the same as the base URI scheme. | |||
* Unfortunately, this can conflict with the correct parsing | |||
* of non-hierarchical URI. For backwards compatibility, an | |||
* implementation may work around such references by | |||
* removing the scheme if it matches that of the base URI | |||
* and the scheme is known to always use the <hier_part> | |||
* syntax. | |||
* | |||
* The URL class does not implement this work around, so we | |||
* do. | |||
*/ | |||
assert (baseURL != null); | |||
String scheme = baseURL.getProtocol() + ":"; | |||
if (href.startsWith(scheme) && "file:".equals(scheme)) { | |||
href = href.substring(scheme.length()); | |||
int colonPos = href.indexOf(':'); | |||
int slashPos = href.indexOf('/'); | |||
if (slashPos >= 0 && colonPos >= 0 | |||
&& colonPos < slashPos) { | |||
href = "/" + href; // Absolute file URL doesn't | |||
// have a leading slash | |||
} | |||
} | |||
try { | |||
absoluteURL = new URL(baseURL, href); | |||
} catch (MalformedURLException mfue) { | |||
handleException(mfue, "Error with URL; base '" + base | |||
+ "' " + "href '" + href + "'", throwExceptions); | |||
} | |||
} | |||
} | |||
if (absoluteURL != null) { | |||
String effURL = absoluteURL.toExternalForm(); | |||
try { | |||
URLConnection connection = absoluteURL.openConnection(); | |||
connection.setAllowUserInteraction(false); | |||
connection.setDoInput(true); | |||
updateURLConnection(connection, href); | |||
connection.connect(); | |||
return new StreamSource(connection.getInputStream(), effURL); | |||
} catch (FileNotFoundException fnfe) { | |||
// Note: This is on "debug" level since the caller is | |||
// supposed to handle this | |||
log.debug("File not found: " + effURL); | |||
} catch (java.io.IOException ioe) { | |||
log.error("Error with opening URL '" + effURL + "': " | |||
+ ioe.getMessage()); | |||
} | |||
} | |||
} | |||
return source; | |||
} | |||
/** | |||
* This method allows you to set special values on a URLConnection just | |||
* before the connect() method is called. Subclass FOURIResolver and | |||
* override this method to do things like adding the user name and password | |||
* for HTTP basic authentication. | |||
* | |||
* @param connection | |||
* the URLConnection instance | |||
* @param href | |||
* the original URI | |||
*/ | |||
protected void updateURLConnection(URLConnection connection, String href) { | |||
// nop | |||
} | |||
/** | |||
* This is a convenience method for users who want to override | |||
* updateURLConnection for HTTP basic authentication. Simply call it using | |||
* the right username and password. | |||
* | |||
* @param connection | |||
* the URLConnection to set up for HTTP basic authentication | |||
* @param username | |||
* the username | |||
* @param password | |||
* the password | |||
*/ | |||
protected void applyHttpBasicAuthentication(URLConnection connection, | |||
String username, String password) { | |||
String combined = username + ":" + password; | |||
try { | |||
ByteArrayOutputStream baout = new ByteArrayOutputStream(combined | |||
.length() * 2); | |||
Base64EncodeStream base64 = new Base64EncodeStream(baout); | |||
// TODO Not sure what charset/encoding can be used with basic | |||
// authentication | |||
base64.write(combined.getBytes("UTF-8")); | |||
base64.close(); | |||
connection.setRequestProperty("Authorization", "Basic " | |||
+ new String(baout.toByteArray(), "UTF-8")); | |||
} catch (IOException e) { | |||
// won't happen. We're operating in-memory. | |||
throw new RuntimeException( | |||
"Error during base64 encodation of username/password"); | |||
} | |||
} | |||
/** | |||
* Sets the custom 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 resolver | |||
* the new URI resolver | |||
*/ | |||
public void setCustomURIResolver(URIResolver resolver) { | |||
this.uriResolver = resolver; | |||
} | |||
/** | |||
* Returns the custom URI Resolver. | |||
* | |||
* @return the URI Resolver or null, if none is set | |||
*/ | |||
public URIResolver getCustomURIResolver() { | |||
return this.uriResolver; | |||
} | |||
/** | |||
* @param throwExceptions | |||
* Whether or not to throw exceptions on resolution error | |||
*/ | |||
public void setThrowExceptions(boolean throwExceptions) { | |||
this.throwExceptions = throwExceptions; | |||
} | |||
} |
@@ -21,18 +21,22 @@ 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.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; | |||
@@ -41,17 +45,27 @@ 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.InternalResourceResolver; | |||
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.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.RendererConfigOption; | |||
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 +89,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 InternalResourceResolver resourceResolver; | |||
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 +134,7 @@ public class FOUserAgent { | |||
private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { | |||
public ImageContext getParentContext() { | |||
return getFactory(); | |||
return factory; | |||
} | |||
public float getTargetResolution() { | |||
@@ -148,21 +151,59 @@ public class FOUserAgent { | |||
* Main constructor. <b>This constructor should not be called directly. Please use the | |||
* methods from FopFactory to construct FOUserAgent instances!</b> | |||
* @param factory the factory that provides environment-level information | |||
* @param resourceResolver the resolver used to acquire resources | |||
* @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, InternalResourceResolver resourceResolver) { | |||
this.factory = factory; | |||
setBaseURL(factory.getBaseURL()); | |||
this.resourceResolver = resourceResolver; | |||
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 resource resolver. | |||
* | |||
* @return the resource resolver | |||
*/ | |||
public InternalResourceResolver getResourceResolver() { | |||
return resourceResolver; | |||
} | |||
// ---------------------------------------------- rendering-run dependent stuff | |||
@@ -177,7 +218,6 @@ public class FOUserAgent { | |||
setStructureTreeEventHandler(documentHandler.getStructureTreeEventHandler()); | |||
} | |||
this.documentHandlerOverride = documentHandler; | |||
} | |||
/** | |||
@@ -345,48 +385,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 org.apache.fop.fonts.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(RendererConfigOption option) { | |||
return rendererOptions.get(option.getName()); | |||
} | |||
/** | |||
@@ -396,39 +401,20 @@ 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 | |||
*/ | |||
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); | |||
} | |||
} | |||
if (source == null) { | |||
// URI Resolver not configured or returned null, use default resolver from the factory | |||
source = getFactory().resolveURI(href, base); | |||
public StreamSource resolveURI(String uri) { | |||
// TODO: What do we want to do when resources aren't found??? We also need to remove this | |||
// method entirely | |||
try { | |||
// Have to do this so we can resolve data URIs | |||
StreamSource src = new StreamSource(resourceResolver.getResource(uri)); | |||
src.setSystemId(uri); | |||
return src; | |||
} catch (URISyntaxException use) { | |||
return null; | |||
} catch (IOException ioe) { | |||
return null; | |||
} | |||
return source; | |||
} | |||
/** | |||
@@ -497,17 +483,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 org.apache.fop.fonts.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. | |||
@@ -515,12 +490,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(); | |||
} | |||
/** | |||
@@ -531,7 +506,7 @@ public class FOUserAgent { | |||
* @see FopFactory#getPageHeight() | |||
*/ | |||
public String getPageHeight() { | |||
return getFactory().getPageHeight(); | |||
return factory.getPageHeight(); | |||
} | |||
/** | |||
@@ -542,7 +517,7 @@ public class FOUserAgent { | |||
* @see FopFactory#getPageWidth() | |||
*/ | |||
public String getPageWidth() { | |||
return getFactory().getPageWidth(); | |||
return factory.getPageWidth(); | |||
} | |||
/** | |||
@@ -551,7 +526,7 @@ public class FOUserAgent { | |||
* @see FopFactory#validateStrictly() | |||
*/ | |||
public boolean validateStrictly() { | |||
return getFactory().validateStrictly(); | |||
return factory.validateStrictly(); | |||
} | |||
/** | |||
@@ -560,21 +535,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(); | |||
} | |||
/** | |||
@@ -663,12 +638,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; | |||
} | |||
/** | |||
@@ -714,5 +730,69 @@ 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(); | |||
} | |||
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,348 @@ | |||
/* | |||
* 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.Locale; | |||
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.InternalResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
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 resourceResolver 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 resourceResolver) throws SAXException, IOException { | |||
this(fopConfStream, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); | |||
} | |||
/** | |||
* 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, ResourceResolverFactory.createDefaultResourceResolver()); | |||
} | |||
/** | |||
* 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, ResourceResolverFactory.createDefaultResourceResolver()); | |||
} | |||
/** | |||
* Constructor that parses the FOP conf and uses the URI resolver given. | |||
* | |||
* @param fopConfFile the FOP conf file | |||
* @param resourceResolver 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 resourceResolver) | |||
throws SAXException, IOException { | |||
this(new FileInputStream(fopConfFile), | |||
fopConfFile.getAbsoluteFile().getParentFile().toURI(), resourceResolver); | |||
} | |||
private void configure(final URI defaultBaseURI, final ResourceResolver resourceResolver, | |||
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 = InternalResourceResolver.getBaseURI(cfg.getChild("base").getValue(null)); | |||
fopFactoryBuilder.setBaseURI(defaultBaseURI.resolve(confUri)); | |||
} 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(), resourceResolver).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(Locale.getDefault()); | |||
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(Locale.getDefault()); | |||
} | |||
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(Locale.getDefault()).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,19 +21,13 @@ 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; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
@@ -44,13 +38,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.InternalResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
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 +55,49 @@ 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(); | |||
/** The resolver for user-supplied hyphenation patterns */ | |||
private HyphenationTreeResolver hyphResolver = null; | |||
private final ContentHandlerFactoryRegistry contentHandlerFactoryRegistry | |||
= new ContentHandlerFactoryRegistry(); | |||
private ColorSpaceCache colorSpaceCache = null; | |||
private final ColorSpaceCache colorSpaceCache; | |||
/** Image manager for loading and caching image objects */ | |||
private ImageManager imageManager; | |||
private final FopFactoryConfig config; | |||
/** Font manager for font substitution, autodetection and caching **/ | |||
private FontManager fontManager; | |||
private final InternalResourceResolver resolver; | |||
/** Configuration layer used to configure fop */ | |||
private FopFactoryConfigurator config = null; | |||
private final Map<String, RendererConfig> rendererConfig; | |||
/** | |||
* 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.resolver = ResourceResolverFactory.createInternalResourceResolver(config.getBaseURI(), | |||
config.getResourceResolver()); | |||
this.elementMappingRegistry = new ElementMappingRegistry(this); | |||
this.colorSpaceCache = new ColorSpaceCache(resolver); | |||
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 +109,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 +165,12 @@ public class FopFactory implements ImageContext { | |||
* @throws FOPException | |||
*/ | |||
public FOUserAgent newFOUserAgent() { | |||
FOUserAgent userAgent = new FOUserAgent(this); | |||
FOUserAgent userAgent = new FOUserAgent(this, resolver); | |||
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 +184,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 +201,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 +216,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 +235,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 +285,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 +318,32 @@ 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 | |||
*/ | |||
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 | |||
* Returns whether accessibility is enabled. | |||
* @return true if accessibility is enabled | |||
*/ | |||
@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; | |||
} | |||
/** | |||
* 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 | |||
*/ | |||
public void setURIResolver(URIResolver uriResolver) { | |||
foURIResolver.setCustomURIResolver(uriResolver); | |||
boolean isAccessibilityEnabled() { | |||
return config.isAccessibilityEnabled(); | |||
} | |||
/** | |||
* Returns the URI Resolver. | |||
* @return the URI Resolver | |||
* Returns the image manager. | |||
* @return the image manager | |||
*/ | |||
public URIResolver getURIResolver() { | |||
return foURIResolver; | |||
public ImageManager getImageManager() { | |||
return config.getImageManager(); | |||
} | |||
/** | |||
* Returns the FO URI Resolver. | |||
* @return the FO URI Resolver | |||
* Returns the overriding LayoutManagerMaker instance, if any. | |||
* @return the overriding LayoutManagerMaker or null | |||
*/ | |||
public FOURIResolver getFOURIResolver() { | |||
return foURIResolver; | |||
} | |||
/** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ | |||
public HyphenationTreeResolver getHyphenationTreeResolver() { | |||
return this.hyphResolver; | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return config.getLayoutManagerMakerOverride(); | |||
} | |||
/** | |||
* 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; | |||
} | |||
/** | |||
* 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 +351,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 +359,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 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 config.isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
} | |||
/** @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 +377,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 +389,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 +399,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 +409,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 +418,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,81 +436,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; | |||
} | |||
/** | |||
* 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 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 | |||
*/ | |||
public Source resolveURI(String href, String baseUri) { | |||
Source source = null; | |||
try { | |||
source = foURIResolver.resolve(href, baseUri); | |||
} catch (TransformerException e) { | |||
log.error("Attempt to resolve URI '" + href + "' failed: ", e); | |||
} | |||
return source; | |||
return config.getFontManager(); | |||
} | |||
/** | |||
@@ -825,5 +463,4 @@ public class FopFactory implements ImageContext { | |||
public ColorSpaceCache getColorSpaceCache() { | |||
return this.colorSpaceCache; | |||
} | |||
} |
@@ -0,0 +1,648 @@ | |||
/* | |||
* 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 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.ResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
import org.apache.fop.fonts.FontManager; | |||
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, ResourceResolverFactory.createDefaultResourceResolver()); | |||
} | |||
/** | |||
* A builder class for {@link FopFactory} which can be used for setting configuration. | |||
* | |||
* @param defaultBaseURI the default base URI for resolving URIs against | |||
* @param resourceResolver the URI resolver | |||
*/ | |||
public FopFactoryBuilder(URI defaultBaseURI, ResourceResolver resourceResolver) { | |||
this(EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); | |||
} | |||
/** | |||
* 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 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 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 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 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)); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isAccessibilityEnabled() { | |||
return accessibility; | |||
} | |||
/** {@inheritDoc} */ | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return layoutManagerMaker; | |||
} | |||
/** {@inheritDoc} */ | |||
public ResourceResolver getResourceResolver() { | |||
return enviro.getResourceResolver(); | |||
} | |||
/** {@inheritDoc} */ | |||
public URI getBaseURI() { | |||
return baseURI; | |||
} | |||
/** {@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 setBaseURI(URI baseURI); | |||
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 setBaseURI(URI baseURI) { | |||
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 setBaseURI(URI baseURI) { | |||
config.baseURI = baseURI; | |||
} | |||
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,130 @@ | |||
/* | |||
* 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 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.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 getResourceResolver(); | |||
/** | |||
* The base URI from which URIs are resolved against. | |||
* | |||
* @return the base URI | |||
*/ | |||
URI getBaseURI(); | |||
/** @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); | |||
} | |||
} | |||
} |
@@ -32,4 +32,6 @@ public interface MimeConstants extends org.apache.xmlgraphics.util.MimeConstants | |||
String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; | |||
/** Apache FOP's intermediate format XML */ | |||
String MIME_FOP_IF = "application/X-fop-intermediate-format"; | |||
/** Bitmap images */ | |||
String MIME_BITMAP = "image/x-bitmap"; | |||
} |
@@ -0,0 +1,153 @@ | |||
/* | |||
* 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; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.xmlgraphics.util.uri.DataURIResolver; | |||
/** | |||
* This object holds the base URI from which to resolve URIs against as well as the resolver for | |||
* resource acquisition. It also does some URI sanitization of common URI syntactical errors. This | |||
* class takes in a {@link org.apache.fop.apps.io.ResourceResolver} and delegates all relevant | |||
* URIs to it. | |||
*/ | |||
public class InternalResourceResolver { | |||
private final URI baseUri; | |||
private final ResourceResolver resourceResolver; | |||
private final DataURIResolver dataSchemeResolver = new DataURIResolver(); | |||
/** | |||
* @param baseUri the base URI from which to resolve relative URIs | |||
* @param resourceResolver the resolver to delegate to | |||
*/ | |||
InternalResourceResolver(URI baseUri, ResourceResolver resourceResolver) { | |||
this.baseUri = baseUri; | |||
this.resourceResolver = resourceResolver; | |||
} | |||
/** | |||
* Returns the base URI from which to resolve all URIs against. | |||
* | |||
* @return the base URI | |||
*/ | |||
public URI getBaseURI() { | |||
return baseUri; | |||
} | |||
/** | |||
* Retrieve a resource given a URI in String form. This also does some syntactical sanitaion on | |||
* the URI. | |||
* | |||
* @param stringUri the URI in String form | |||
* @return the resource | |||
* @throws IOException if an I/O error occurred | |||
* @throws URISyntaxException if the URI syntax was invalid | |||
*/ | |||
public Resource getResource(String stringUri) throws IOException, URISyntaxException { | |||
if (stringUri.startsWith("data:")) { | |||
return new Resource(resolveDataURI(stringUri)); | |||
} | |||
return getResource(cleanURI(stringUri)); | |||
} | |||
/** | |||
* Retrieve a resource given a URI in String form. | |||
* | |||
* @param uri the resource URI | |||
* @return the resource | |||
* @throws IOException if an I/O error occurred | |||
*/ | |||
public Resource getResource(URI uri) throws IOException { | |||
if (uri.getScheme() != null && uri.getScheme().startsWith("data")) { | |||
return new Resource(resolveDataURI(uri.toASCIIString())); | |||
} | |||
return resourceResolver.getResource(resolveFromBase(uri)); | |||
} | |||
/** | |||
* Returns the OutputStream for a given URI. | |||
* | |||
* @param uri the URI for the inteded stream | |||
* @return the output stream | |||
* @throws IOException if an I/O error occurrred | |||
*/ | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
return resourceResolver.getOutputStream(resolveFromBase(uri)); | |||
} | |||
/** | |||
* Resolves a URI against the base URI. | |||
* | |||
* @param uri the URI that requires resolution | |||
* @return the resolved URI | |||
*/ | |||
public URI resolveFromBase(URI uri) { | |||
return baseUri.resolve(uri); | |||
} | |||
/** | |||
* Performs some sanitation for some of the most common URI syntax mistakes. | |||
* | |||
* @param uriStr the URI in String form | |||
* @return a valid URI | |||
* @throws URISyntaxException if the given String was too erroneous to validate | |||
*/ | |||
public static URI cleanURI(String uriStr) throws URISyntaxException { | |||
// replace back slash with forward slash to ensure windows file:/// URLS are supported | |||
if (uriStr == null) { | |||
return null; | |||
} | |||
String fixedUri = uriStr.replace('\\', '/'); | |||
fixedUri = fixedUri.replace(" ", "%20"); | |||
URI baseURI = new URI(fixedUri); | |||
return baseURI; | |||
} | |||
/** | |||
* Performs some sanitation for some of the most common URI syntax mistakes but returns a | |||
* directory URI rather than a file URI. | |||
* | |||
* @param base the directory URI in String form | |||
* @return the directory URI | |||
* @throws URISyntaxException if the given String was too erroneous to validate | |||
*/ | |||
public static URI getBaseURI(String base) throws URISyntaxException { | |||
String path = base + (base.endsWith("/") ? "" : "/"); | |||
return cleanURI(path); | |||
} | |||
private InputStream resolveDataURI(String dataURI) { | |||
try { | |||
Source src = dataSchemeResolver.resolve(dataURI, ""); | |||
return src == null ? null : ((StreamSource) src).getInputStream(); | |||
} catch (TransformerException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
* 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.OutputStream; | |||
import java.net.URI; | |||
/** | |||
* Implementations of this resource resolver allow FOP users to control the URI resolution | |||
* mechanism. All resource and output stream acquisition goes through this when its implementation | |||
* is given to the {@link org.apache.fop.apps.EnvironmentProfile}. | |||
*/ | |||
public interface ResourceResolver { | |||
/** | |||
* Get a resource given the URI pointing to said resource. | |||
* | |||
* @param uri the resource URI | |||
* @return the resource | |||
* @throws IOException if an I/O error occured during resource acquisition | |||
*/ | |||
Resource getResource(URI uri) throws IOException; | |||
/** | |||
* Gets an output stream of a given URI. | |||
* | |||
* @param uri the output stream URI | |||
* @return the output stream | |||
* @throws IOException if an I/O error occured while creating an output stream | |||
*/ | |||
OutputStream getOutputStream(URI uri) throws IOException; | |||
} |
@@ -0,0 +1,276 @@ | |||
/* | |||
* 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.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
/** | |||
* A factory class for {@link ResourceResolver}s. | |||
*/ | |||
public final class ResourceResolverFactory { | |||
private ResourceResolverFactory() { | |||
} | |||
/** | |||
* Returns the default resource resolver, this is most basic resolver which can be used when | |||
* no there are no I/O or file access restrictions. | |||
* | |||
* @return the default resource resolver | |||
*/ | |||
public static ResourceResolver createDefaultResourceResolver() { | |||
return DefaultResourceResolver.INSTANCE; | |||
} | |||
/** | |||
* A helper merthod that creates an internal resource resolver using the default resover: | |||
* {@link ResourceResolverFactory#createDefaultResourceResolver()}. | |||
* | |||
* @param baseURI the base URI from which to resolve URIs | |||
* @return the default internal resource resolver | |||
*/ | |||
public static InternalResourceResolver createDefaultInternalResourceResolver(URI baseURI) { | |||
return new InternalResourceResolver(baseURI, createDefaultResourceResolver()); | |||
} | |||
/** | |||
* Creates an interal resource resolver given a base URI and a resource resolver. | |||
* | |||
* @param baseURI the base URI from which to resolve URIs | |||
* @param resolver the resource resolver | |||
* @return the internal resource resolver | |||
*/ | |||
public static InternalResourceResolver createInternalResourceResolver(URI baseURI, | |||
ResourceResolver resolver) { | |||
return new InternalResourceResolver(baseURI, resolver); | |||
} | |||
/** | |||
* Creates a temporary-resource-schema aware resource resolver. Temporary resource URIs are | |||
* created by {@link TempResourceURIGenerator}. | |||
* | |||
* @param tempResourceResolver the temporary-resource-schema resolver to use | |||
* @param defaultResourceResolver the default resource resolver to use | |||
* @return the ressource resolver | |||
*/ | |||
public static ResourceResolver createTempAwareResourceResolver( | |||
TempResourceResolver tempResourceResolver, | |||
ResourceResolver defaultResourceResolver) { | |||
return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver); | |||
} | |||
public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder( | |||
ResourceResolver defaultResolver) { | |||
return new SchemaAwareResourceResolverBuilderImpl(defaultResolver); | |||
} | |||
private static final class DefaultResourceResolver implements ResourceResolver { | |||
private static final ResourceResolver INSTANCE = new DefaultResourceResolver(); | |||
private final TempAwareResourceResolver delegate; | |||
private DefaultResourceResolver() { | |||
delegate = new TempAwareResourceResolver(new DefaultTempResourceResolver(), | |||
new NormalResourceResolver()); | |||
} | |||
public Resource getResource(URI uri) throws IOException { | |||
return delegate.getResource(uri); | |||
} | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
return delegate.getOutputStream(uri); | |||
} | |||
} | |||
private static final class TempAwareResourceResolver implements ResourceResolver { | |||
private final TempResourceResolver tempResourceResolver; | |||
private final ResourceResolver defaultResourceResolver; | |||
public TempAwareResourceResolver(TempResourceResolver tempResourceHandler, | |||
ResourceResolver defaultResourceResolver) { | |||
this.tempResourceResolver = tempResourceHandler; | |||
this.defaultResourceResolver = defaultResourceResolver; | |||
} | |||
private static boolean isTempUri(URI uri) { | |||
return TempResourceURIGenerator.isTempUri(uri); | |||
} | |||
public Resource getResource(URI uri) throws IOException { | |||
if (isTempUri(uri)) { | |||
return tempResourceResolver.getResource(uri.getPath()); | |||
} else { | |||
return defaultResourceResolver.getResource(uri); | |||
} | |||
} | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
if (isTempUri(uri)) { | |||
return tempResourceResolver.getOutputStream(uri.getPath()); | |||
} else { | |||
return defaultResourceResolver.getOutputStream(uri); | |||
} | |||
} | |||
} | |||
private static class DefaultTempResourceResolver implements TempResourceResolver { | |||
private static File getTempFile(String path) throws IOException { | |||
File file = new File(System.getProperty("java.io.tmpdir"), path); | |||
file.deleteOnExit(); | |||
return file; | |||
} | |||
public Resource getResource(String id) throws IOException { | |||
return new Resource(getTempFile(id).toURI().toURL().openStream()); | |||
} | |||
public OutputStream getOutputStream(String id) throws IOException { | |||
File file = getTempFile(id); | |||
if (file.createNewFile()) { | |||
return new FileOutputStream(file); | |||
} else { | |||
throw new IOException("Filed to create temporary file: " + id); | |||
} | |||
} | |||
} | |||
private static class NormalResourceResolver implements ResourceResolver { | |||
public Resource getResource(URI uri) throws IOException { | |||
return new Resource(uri.toURL().openStream()); | |||
} | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
return new FileOutputStream(new File(uri)); | |||
} | |||
} | |||
private static final class SchemaAwareResourceResolver implements ResourceResolver { | |||
private final Map<String, ResourceResolver> schemaHandlingResourceResolvers; | |||
private final ResourceResolver defaultResolver; | |||
private SchemaAwareResourceResolver( | |||
Map<String, ResourceResolver> schemaHandlingResourceResolvers, | |||
ResourceResolver defaultResolver) { | |||
this.schemaHandlingResourceResolvers = schemaHandlingResourceResolvers; | |||
this.defaultResolver = defaultResolver; | |||
} | |||
private ResourceResolver getResourceResolverForSchema(URI uri) { | |||
String schema = uri.getScheme(); | |||
if (schemaHandlingResourceResolvers.containsKey(schema)) { | |||
return schemaHandlingResourceResolvers.get(schema); | |||
} else { | |||
return defaultResolver; | |||
} | |||
} | |||
public Resource getResource(URI uri) throws IOException { | |||
return getResourceResolverForSchema(uri).getResource(uri); | |||
} | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
return getResourceResolverForSchema(uri).getOutputStream(uri); | |||
} | |||
} | |||
public interface SchemaAwareResourceResolverBuilder { | |||
void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver); | |||
ResourceResolver build(); | |||
} | |||
private static final class CompletedSchemaAwareResourceResolverBuilder | |||
implements SchemaAwareResourceResolverBuilder { | |||
private static final SchemaAwareResourceResolverBuilder INSTANCE | |||
= new CompletedSchemaAwareResourceResolverBuilder(); | |||
public ResourceResolver build() { | |||
throw new IllegalStateException("Resource resolver already built"); | |||
} | |||
public void registerResourceResolverForSchema(String schema, | |||
ResourceResolver resourceResolver) { | |||
throw new IllegalStateException("Resource resolver already built"); | |||
} | |||
} | |||
private static final class ActiveSchemaAwareResourceResolverBuilder | |||
implements SchemaAwareResourceResolverBuilder { | |||
private final Map<String, ResourceResolver> schemaHandlingResourceResolvers | |||
= new HashMap<String, ResourceResolver>(); | |||
private final ResourceResolver defaultResolver; | |||
private ActiveSchemaAwareResourceResolverBuilder(ResourceResolver defaultResolver) { | |||
this.defaultResolver = defaultResolver; | |||
} | |||
public void registerResourceResolverForSchema(String schema, | |||
ResourceResolver resourceResolver) { | |||
schemaHandlingResourceResolvers.put(schema, resourceResolver); | |||
} | |||
public ResourceResolver build() { | |||
return new SchemaAwareResourceResolver( | |||
Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver); | |||
} | |||
} | |||
private static final class SchemaAwareResourceResolverBuilderImpl | |||
implements SchemaAwareResourceResolverBuilder { | |||
private SchemaAwareResourceResolverBuilder delegate; | |||
private SchemaAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { | |||
this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver); | |||
} | |||
public void registerResourceResolverForSchema(String schema, | |||
ResourceResolver resourceResolver) { | |||
delegate.registerResourceResolverForSchema(schema, resourceResolver); | |||
} | |||
public ResourceResolver build() { | |||
ResourceResolver resourceResolver = delegate.build(); | |||
delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE; | |||
return resourceResolver; | |||
} | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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.OutputStream; | |||
/** | |||
* Implementations of this interface resolve URIs for temporary files used by FOP. The temporary- | |||
* resource URI scheme comes from {@link TempResourceURIGenerator#TMP_SCHEMA}. | |||
*/ | |||
public interface TempResourceResolver { | |||
/** | |||
* Get a temporary-resource given the URI pointing to said resource. | |||
* | |||
* @param uri the resource URI | |||
* @return the resource | |||
* @throws IOException if an I/O error occured during resource acquisition | |||
*/ | |||
Resource getResource(String id) throws IOException; | |||
/** | |||
* Gets an temporary-output stream of a given URI. | |||
* | |||
* @param uri the output stream URI | |||
* @return the output stream | |||
* @throws IOException if an I/O error occured while creating an output stream | |||
*/ | |||
OutputStream getOutputStream(String id) throws IOException; | |||
} |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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. | |||
*/ | |||
package org.apache.fop.apps.io; | |||
import java.net.URI; | |||
import java.util.concurrent.atomic.AtomicLong; | |||
/** | |||
* Creates a URI for any temporary resource used within FOP. | |||
*/ | |||
public final class TempResourceURIGenerator { | |||
public static final String TMP_SCHEMA = "tmp"; | |||
private final String tempURIPrefix; | |||
private final AtomicLong counter; | |||
/** | |||
* @param uriPrefix a prefix used to name the unique URI | |||
*/ | |||
public TempResourceURIGenerator(String uriPrefix) { | |||
counter = new AtomicLong(); | |||
tempURIPrefix = URI.create(TMP_SCHEMA + ":///" + uriPrefix).toASCIIString(); | |||
} | |||
/** | |||
* Generate a unique URI for a temporary resource | |||
* @return the URI | |||
*/ | |||
public URI generate() { | |||
return URI.create(tempURIPrefix + getUniqueId()); | |||
} | |||
private String getUniqueId() { | |||
return Long.toHexString(counter.getAndIncrement()); | |||
} | |||
public static boolean isTempUri(URI uri) { | |||
return TMP_SCHEMA.equals(uri.getScheme()); | |||
} | |||
} |
@@ -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); |
@@ -21,13 +21,12 @@ package org.apache.fop.area; | |||
import java.io.BufferedInputStream; | |||
import java.io.BufferedOutputStream; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.ObjectInputStream; | |||
import java.io.ObjectOutputStream; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
@@ -36,9 +35,9 @@ import org.xml.sax.SAXException; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.ResourceEventProducer; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.io.TempResourceURIGenerator; | |||
import org.apache.fop.fonts.FontInfo; | |||
/** | |||
@@ -49,10 +48,12 @@ import org.apache.fop.fonts.FontInfo; | |||
*/ | |||
public class CachedRenderPagesModel extends RenderPagesModel { | |||
private Map<PageViewport, String> pageMap = new HashMap<PageViewport, String>(); | |||
private Map<PageViewport, URI> pageMap = new HashMap<PageViewport, URI>(); | |||
/** Base directory to save temporary file in, typically points to the user's temp dir. */ | |||
protected File baseDir; | |||
private final URI tempBaseURI; | |||
private static final TempResourceURIGenerator TEMP_URI_GENERATOR | |||
= new TempResourceURIGenerator("cached-pages"); | |||
/** | |||
* Main Constructor | |||
@@ -65,8 +66,7 @@ public class CachedRenderPagesModel extends RenderPagesModel { | |||
public CachedRenderPagesModel (FOUserAgent userAgent, String outputFormat, | |||
FontInfo fontInfo, OutputStream stream) throws FOPException { | |||
super(userAgent, outputFormat, fontInfo, stream); | |||
//TODO: Avoid System.getProperty()? | |||
this.baseDir = new File(System.getProperty("java.io.tmpdir")); | |||
tempBaseURI = TEMP_URI_GENERATOR.generate(); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -78,27 +78,19 @@ public class CachedRenderPagesModel extends RenderPagesModel { | |||
if (pageViewport != newpage) { | |||
try { | |||
// load page from cache | |||
String name = pageMap.get(pageViewport); | |||
File tempFile = new File(baseDir, name); | |||
log.debug("Loading page from: " + tempFile); | |||
ObjectInputStream in = new ObjectInputStream( | |||
new BufferedInputStream( | |||
new FileInputStream(tempFile))); | |||
URI tempURI = pageMap.get(pageViewport); | |||
log.debug("Loading page from: " + tempURI); | |||
InputStream inStream = renderer.getUserAgent().getResourceResolver().getResource(tempURI); | |||
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(inStream)); | |||
try { | |||
pageViewport.loadPage(in); | |||
} finally { | |||
IOUtils.closeQuietly(inStream); | |||
IOUtils.closeQuietly(in); | |||
} | |||
if (!tempFile.delete()) { | |||
ResourceEventProducer eventProducer | |||
= ResourceEventProducer.Provider.get( | |||
renderer.getUserAgent().getEventBroadcaster()); | |||
eventProducer.cannotDeleteTempFile(this, tempFile); | |||
} | |||
pageMap.remove(pageViewport); | |||
} catch (Exception e) { | |||
AreaEventProducer eventProducer | |||
= AreaEventProducer.Provider.get( | |||
AreaEventProducer eventProducer = AreaEventProducer.Provider.get( | |||
renderer.getUserAgent().getEventBroadcaster()); | |||
eventProducer.pageLoadError(this, pageViewport.getPageNumberString(), e); | |||
} | |||
@@ -131,18 +123,17 @@ public class CachedRenderPagesModel extends RenderPagesModel { | |||
// save page to cache | |||
ObjectOutputStream tempstream; | |||
String fname = "fop-page-" + page.getPageIndex() + ".ser"; | |||
File tempFile = new File(baseDir, fname); | |||
tempFile.deleteOnExit(); | |||
tempstream = new ObjectOutputStream(new BufferedOutputStream( | |||
new FileOutputStream(tempFile))); | |||
URI tempURI = tempBaseURI.resolve(fname); | |||
OutputStream outStream = renderer.getUserAgent().getResourceResolver().getOutputStream(tempURI); | |||
tempstream = new ObjectOutputStream(new BufferedOutputStream(outStream)); | |||
try { | |||
page.savePage(tempstream); | |||
} finally { | |||
IOUtils.closeQuietly(tempstream); | |||
} | |||
pageMap.put(page, fname); | |||
pageMap.put(page, tempURI); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Page saved to temporary file: " + tempFile); | |||
log.debug("Page saved to temporary file: " + tempURI); | |||
} | |||
} catch (IOException ioe) { | |||
AreaEventProducer eventProducer |
@@ -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,7 +52,7 @@ 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.pdf.PDFEncryptionOption; | |||
import org.apache.fop.render.print.PagesMode; | |||
import org.apache.fop.render.print.PrintRenderer; | |||
import org.apache.fop.render.xml.XMLRenderer; | |||
@@ -116,12 +117,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 +186,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 +229,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 +290,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 +821,14 @@ public class CommandLineOptions { | |||
} | |||
private PDFEncryptionParams getPDFEncryptionParams() throws FOPException { | |||
PDFEncryptionParams params = (PDFEncryptionParams)renderingOptions.get( | |||
PDFConfigurationConstants.ENCRYPTION_PARAMS); | |||
PDFEncryptionParams params = (PDFEncryptionParams) renderingOptions.get(PDFEncryptionOption.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(PDFEncryptionOption.ENCRYPTION_PARAMS, params); | |||
} | |||
return params; | |||
} | |||
@@ -860,7 +861,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 +869,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 +1028,19 @@ 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); | |||
fopFactoryBuilder.setComplexScriptFeatures(useComplexScriptFeatures); | |||
} | |||
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,7 @@ 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.net.URI; | |||
import org.w3c.dom.Element; | |||
@@ -71,12 +71,10 @@ 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().getResourceResolver().getBaseURI(); | |||
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()); |
@@ -426,7 +426,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.InternalResourceResolver; | |||
//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 resourceResolver the URI resolver for controlling file access | |||
*/ | |||
public CIDFont(InternalResourceResolver resourceResolver) { | |||
super(resourceResolver); | |||
} | |||
// ---- 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.InternalResourceResolver; | |||
/** | |||
@@ -35,27 +37,27 @@ 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 String fontName; | |||
private String fullName; | |||
private Set<String> familyNames; | |||
private String fontSubName; | |||
private URI embedFileURI; | |||
private String embedResourceName; | |||
private final InternalResourceResolver resourceResolver; | |||
private EmbeddingMode embeddingMode = EmbeddingMode.AUTO; | |||
private int capHeight = 0; | |||
private int xHeight = 0; | |||
private int ascender = 0; | |||
private int descender = 0; | |||
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; | |||
@@ -63,6 +65,12 @@ public abstract class CustomFont extends Typeface | |||
private boolean useKerning = true; | |||
private boolean useAdvanced = true; | |||
/** | |||
* @param resourceResolver the URI resource resolver for controlling file access | |||
*/ | |||
public CustomFont(InternalResourceResolver resourceResolver) { | |||
this.resourceResolver = resourceResolver; | |||
} | |||
/** the character map, mapping Unicode ranges to glyph indices. */ | |||
protected CMapSegment[] cmap; | |||
@@ -107,15 +115,16 @@ 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 the embedding mode for this font. | |||
* @return embedding mode | |||
*/ | |||
@@ -124,20 +133,13 @@ public abstract class CustomFont extends Typeface | |||
} | |||
/** | |||
* 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 resourceResolver.getResource(embedFileURI); | |||
} | |||
/** | |||
@@ -335,8 +337,8 @@ public abstract class CustomFont extends Typeface | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public void setEmbedFileName(String path) { | |||
this.embedFileName = path; | |||
public void setEmbedURI(URI path) { | |||
this.embedFileURI = path; | |||
} | |||
/** | |||
@@ -463,14 +465,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.InternalResourceResolver; | |||
/** | |||
* Sets up a set of custom (embedded) fonts | |||
*/ | |||
public class CustomFontCollection implements FontCollection { | |||
private FontResolver fontResolver; | |||
private final List<EmbedFontInfo> embedFontInfoList; | |||
private final InternalResourceResolver 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(InternalResourceResolver fontResolver, | |||
List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { | |||
this.uriResolver = fontResolver; | |||
this.embedFontInfoList = customFonts; | |||
this.useComplexScripts = useComplexScriptFeatures; | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -52,22 +52,14 @@ 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(); |
@@ -0,0 +1,343 @@ | |||
/* | |||
* 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 { | |||
private static final 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()), | |||
fontCfg.getAttribute("embedding-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; | |||
private final String embeddingMode; | |||
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, String embeddingMode) { | |||
this.metrics = metrics; | |||
this.embedUri = embed; | |||
this.subFont = subFont; | |||
this.kerning = kerning; | |||
this.advanced = advanced; | |||
this.encodingMode = encodingMode; | |||
this.embeddingMode = embeddingMode; | |||
} | |||
/** | |||
* 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; | |||
} | |||
public String getEmbeddingMode() { | |||
return embeddingMode; | |||
} | |||
} | |||
} |
@@ -0,0 +1,186 @@ | |||
/* | |||
* 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.InternalResourceResolver; | |||
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 final Log log = LogFactory.getLog(DefaultFontConfigurator.class); | |||
private final FontManager fontManager; | |||
private final InternalResourceResolver resourceResolver; | |||
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.resourceResolver = fontManager.getResourceResolver(); | |||
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>(); | |||
if (fontInfoConfig != null) { | |||
assert fontInfoConfig instanceof DefaultFontConfig; | |||
DefaultFontConfig adobeFontInfoConfig = (DefaultFontConfig) fontInfoConfig; | |||
long start = 0; | |||
if (log.isDebugEnabled()) { | |||
log.debug("Starting font configuration..."); | |||
start = System.currentTimeMillis(); | |||
} | |||
FontAdder fontAdder = new FontAdder(fontManager, resourceResolver, 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 : InternalResourceResolver.cleanURI(metrics); | |||
URI embedUri = InternalResourceResolver.cleanURI(embed); | |||
List<FontTriplet> tripletList = font.getTripletList(); | |||
// no font triplet info | |||
if (tripletList.size() == 0) { | |||
URI fontUri = resourceResolver.resolveFromBase(embedUri); | |||
FontInfoFinder finder = new FontInfoFinder(); | |||
finder.setEventListener(listener); | |||
EmbedFontInfo[] infos = finder.find(fontUri, resourceResolver, fontCache); | |||
return infos[0]; //When subFont is set, only one font is returned | |||
} | |||
EncodingMode encodingMode = EncodingMode.getValue(font.getEncodingMode()); | |||
EmbeddingMode embeddingMode = EmbeddingMode.getValue(font.getEmbeddingMode()); | |||
EmbedFontInfo embedFontInfo = new EmbedFontInfo(metricsUri, font.isKerning(), | |||
font.isAdvanced(), tripletList, embedUri, subFont, encodingMode, embeddingMode); | |||
if (fontCache != null) { | |||
if (!fontCache.containsFont(embedFontInfo)) { | |||
fontCache.addFont(embedFontInfo, resourceResolver); | |||
} | |||
} | |||
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; | |||
/** | |||
@@ -33,62 +34,66 @@ 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 requested embedding mode for this font */ | |||
protected EmbeddingMode embeddingMode = EmbeddingMode.AUTO; | |||
private final EmbeddingMode embeddingMode; | |||
/** 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, | |||
EncodingMode encodingMode, EmbeddingMode embeddingMode) { | |||
this.metricsURI = metricsURI; | |||
this.embedURI = embedURI; | |||
this.kerning = kerning; | |||
this.advanced = advanced; | |||
this.fontTriplets = fontTriplets; | |||
this.subFontName = subFontName; | |||
this.encodingMode = encodingMode; | |||
this.embeddingMode = embeddingMode; | |||
} | |||
/** | |||
* 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; | |||
} | |||
/** | |||
@@ -145,7 +150,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; | |||
@@ -176,28 +181,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; | |||
} | |||
/** | |||
* Sets the embedding mode for this font, currently not supported for Type 1 fonts. | |||
* @param embeddingMode the new embedding mode. | |||
*/ | |||
public void setEmbeddingMode(EmbeddingMode embeddingMode) { | |||
if (embeddingMode == null) { | |||
throw new NullPointerException("embeddingMode must not be null"); | |||
} | |||
this.embeddingMode = embeddingMode; | |||
} | |||
private void readObject(java.io.ObjectInputStream in) | |||
throws IOException, ClassNotFoundException { | |||
in.defaultReadObject(); | |||
@@ -206,7 +189,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.InternalResourceResolver; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
/** | |||
@@ -29,18 +31,19 @@ import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
*/ | |||
public class FontAdder { | |||
private final FontEventListener listener; | |||
private final FontResolver resolver; | |||
private final InternalResourceResolver resourceResolver; | |||
private final FontManager manager; | |||
/** | |||
* Main constructor | |||
* @param manager a font manager | |||
* @param resolver a font resolver | |||
* @param resourceResolver a font resolver | |||
* @param listener a font event handler | |||
*/ | |||
public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) { | |||
public FontAdder(FontManager manager, InternalResourceResolver resourceResolver, | |||
FontEventListener listener) { | |||
this.manager = manager; | |||
this.resolver = resolver; | |||
this.resourceResolver = resourceResolver; | |||
this.listener = listener; | |||
} | |||
@@ -48,14 +51,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(), resourceResolver, 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.InternalResourceResolver; | |||
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, InternalResourceResolver resourceResolver) { | |||
String cacheKey = getCacheKey(fontInfo); | |||
synchronized (changeLock) { | |||
CachedFontFile cachedFontFile; | |||
@@ -329,10 +331,9 @@ 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); | |||
URI fontUri = resourceResolver.resolveFromBase(fontInfo.getEmbedURI()); | |||
File fontFile = new File(fontUri); | |||
long lastModified = fontFile.lastModified(); | |||
cachedFontFile = new CachedFontFile(lastModified); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Font added to cache: " + cacheKey); | |||
@@ -467,8 +468,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,119 @@ | |||
/* | |||
* 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.getResourceResolver().getBaseURI(); | |||
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,328 +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.getValue( | |||
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); | |||
EmbeddingMode embeddingMode = EmbeddingMode.getValue( | |||
fontCfg.getAttribute("embedding-mode", EmbeddingMode.AUTO.toString())); | |||
EmbedFontInfo embedFontInfo | |||
= new EmbedFontInfo(metricsUrl, useKerning, useAdvanced, tripletList, embedUrl, | |||
subFont); | |||
embedFontInfo.setEncodingMode(encodingMode); | |||
embedFontInfo.setEmbeddingMode(embeddingMode); | |||
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.InternalResourceResolver; | |||
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; | |||
/** the FontResolver to use for font URI resolution */ | |||
protected FontResolver resolver; | |||
protected final URI fontFileURI; | |||
/** the resource resolver to use for font URI resolution */ | |||
protected final InternalResourceResolver resourceResolver; | |||
/** the loaded font */ | |||
protected CustomFont returnFont; | |||
@@ -65,56 +60,19 @@ public abstract class FontLoader { | |||
* @param useKerning indicates whether kerning information shall be loaded if available | |||
* @param useAdvanced indicates whether advanced typographic information shall be loaded if | |||
* available | |||
* @param resolver the font resolver used to resolve URIs | |||
* @param resourceResolver 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, InternalResourceResolver resourceResolver) { | |||
this.fontFileURI = fontFileURI; | |||
this.embedded = embedded; | |||
this.useKerning = useKerning; | |||
this.useAdvanced = useAdvanced; | |||
this.resolver = resolver; | |||
this.resourceResolver = resourceResolver; | |||
} | |||
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 embeddingMode the embedding mode | |||
* @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, EmbeddingMode embeddingMode, EncodingMode encodingMode, | |||
FontResolver resolver) throws IOException { | |||
return loadFont(fontFile.toURI().toURL(), subFontName, | |||
embedded, embeddingMode, 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 embeddingMode the embedding mode of the font | |||
* @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, EmbeddingMode embeddingMode, EncodingMode encodingMode, | |||
FontResolver resolver) throws IOException { | |||
return loadFont(fontUrl.toExternalForm(), subFontName, | |||
embedded, embeddingMode, encodingMode, true, true, | |||
resolver); | |||
private static boolean isType1(URI fontURI) { | |||
return fontURI.toASCIIString().toLowerCase().endsWith(".pfb"); | |||
} | |||
/** | |||
@@ -127,14 +85,13 @@ public abstract class FontLoader { | |||
* @param useKerning indicates whether kerning information should be loaded if available | |||
* @param useAdvanced indicates whether advanced typographic information shall be loaded if | |||
* available | |||
* @param resolver the font resolver to use when resolving URIs | |||
* @param resourceResolver the font resolver to use when resolving URIs | |||
* @return the newly loaded font | |||
* @throws IOException In case of an I/O error | |||
*/ | |||
public static CustomFont loadFont(String fontFileURI, String subFontName, | |||
public static CustomFont loadFont(URI fontFileURI, String subFontName, | |||
boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, | |||
boolean useKerning, boolean useAdvanced, FontResolver resolver) throws IOException { | |||
fontFileURI = fontFileURI.trim(); | |||
boolean useKerning, boolean useAdvanced, InternalResourceResolver resourceResolver) throws IOException { | |||
boolean type1 = isType1(fontFileURI); | |||
FontLoader loader; | |||
if (type1) { | |||
@@ -146,49 +103,14 @@ public abstract class FontLoader { | |||
throw new IllegalArgumentException( | |||
"Subset embedding for Type 1 fonts is not supported"); | |||
} | |||
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver); | |||
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resourceResolver); | |||
} else { | |||
loader = new TTFFontLoader(fontFileURI, subFontName, | |||
embedded, embeddingMode, encodingMode, useKerning, useAdvanced, resolver); | |||
loader = new TTFFontLoader(fontFileURI, subFontName, embedded, embeddingMode, | |||
encodingMode, useKerning, useAdvanced, resourceResolver); | |||
} | |||
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.InternalResourceResolver; | |||
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; | |||
/** The resource resolver */ | |||
private InternalResourceResolver resourceResolver; | |||
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 resourceResolver the URI resolver | |||
* @param fontDetector the font detector | |||
* @param fontCacheManager the font cache manager | |||
*/ | |||
public FontManager() { | |||
public FontManager(InternalResourceResolver resourceResolver, FontDetector fontDetector, | |||
FontCacheManager fontCacheManager) { | |||
this.resourceResolver = resourceResolver; | |||
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 resource resolver | |||
* @param resourceResolver resource resolver | |||
*/ | |||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | |||
this.fontBase = fontBase; | |||
public void setResourceResolver(InternalResourceResolver resourceResolver) { | |||
this.resourceResolver = resourceResolver; | |||
} | |||
/** | |||
* Returns the font base URL. | |||
* @return the font base URL (or null if none was set) | |||
*/ | |||
public String getFontBaseURL() { | |||
return this.fontBase; | |||
public InternalResourceResolver getResourceResolver() { | |||
return this.resourceResolver; | |||
} | |||
/** @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,21 @@ public class FontManager { | |||
} | |||
} | |||
} | |||
/** | |||
* Detect fonts from the operating system via FOPs autodetect mechanism. | |||
* | |||
* @param autoDetectFonts if autodetect has been enabled | |||
* @param fontAdder the font adding mechanism | |||
* @param strict whether to enforce strict validation | |||
* @param listener the listener for font related events | |||
* @param fontInfoList a list of font info objects | |||
* @throws FOPException if an exception was thrown auto-detecting fonts | |||
*/ | |||
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,9 @@ import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
import org.apache.fop.fonts.substitute.FontSubstitutions; | |||
import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator; | |||
import org.apache.fop.util.LogUtil; | |||
@@ -45,24 +48,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 resourceResolver; | |||
/** | |||
* 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 resourceResolver the resource resolver | |||
*/ | |||
public FontManagerConfigurator(Configuration cfg, URI baseURI) { | |||
public FontManagerConfigurator(Configuration cfg, URI defaultBaseUri, | |||
ResourceResolver resourceResolver) { | |||
this.cfg = cfg; | |||
this.baseURI = baseURI; | |||
this.defaultBaseUri = defaultBaseUri; | |||
this.resourceResolver = resourceResolver; | |||
} | |||
/** | |||
@@ -75,28 +75,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); | |||
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 = InternalResourceResolver.getBaseURI(cfg.getChild("font-base").getValue( | |||
null)); | |||
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( | |||
defaultBaseUri.resolve(fontBase), resourceResolver)); | |||
} catch (URISyntaxException use) { | |||
LogUtil.handleException(log, use, true); | |||
} | |||
} else { | |||
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( | |||
defaultBaseUri, resourceResolver)); | |||
} | |||
// [GA] permit configuration control over base14 kerning; without this, | |||
@@ -114,7 +115,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 +122,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 +129,6 @@ public class FontManagerConfigurator { | |||
referencedFontsCfg, strict); | |||
fontManager.setReferencedFontsMatcher(matcher); | |||
} | |||
} | |||
} | |||
@@ -159,6 +157,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.InternalResourceResolver; | |||
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 InternalResourceResolver resourceResolver; | |||
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<CMapSegment> bfranges = null; | |||
private List<CMapSegment> 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, InternalResourceResolver resourceResolver) throws FOPException { | |||
this.resourceResolver = resourceResolver; | |||
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} | |||
*/ | |||
@@ -161,45 +153,41 @@ public class FontReader extends DefaultHandler { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public void setDocumentLocator(Locator locator) { | |||
// this.locator = locator; // not used at present | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
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(resourceResolver); | |||
returnFont = multiFont; | |||
isCID = true; | |||
TTFReader.checkMetricsVersion(attributes); | |||
} else if ("TRUETYPE".equals(attributes.getValue("type"))) { | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resourceResolver); | |||
singleFont.setFontType(FontType.TRUETYPE); | |||
returnFont = singleFont; | |||
isCID = false; | |||
TTFReader.checkMetricsVersion(attributes); | |||
} else { | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resourceResolver); | |||
singleFont.setFontType(FontType.TYPE1); | |||
returnFont = singleFont; | |||
isCID = false; | |||
} | |||
} else if ("embed".equals(localName)) { | |||
returnFont.setEmbedFileName(attributes.getValue("file")); | |||
try { | |||
returnFont.setEmbedURI(InternalResourceResolver.cleanURI(attributes.getValue("file"))); | |||
} catch (URISyntaxException e) { | |||
throw new SAXException("URI syntax error in metrics file: " + e.getMessage(), e); | |||
} | |||
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<CMapSegment>(); | |||
} else if ("bf".equals(localName)) { | |||
@@ -208,20 +196,19 @@ public class FontReader extends DefaultHandler { | |||
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"))); | |||
} | |||
} | |||
@@ -319,5 +306,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.InternalResourceResolver; | |||
import org.apache.fop.fonts.base14.Courier; | |||
import org.apache.fop.fonts.base14.CourierBold; | |||
import org.apache.fop.fonts.base14.CourierBoldOblique; | |||
@@ -71,11 +69,11 @@ public final class FontSetup { | |||
* | |||
* @param fontInfo the font info object to set up | |||
* @param embedFontInfoList a list of EmbedFontInfo objects | |||
* @param resolver the font resolver | |||
* @param resourceResolver 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, | |||
InternalResourceResolver resourceResolver, boolean base14Kerning) { | |||
fontInfo.addMetrics("F1", new Helvetica(base14Kerning)); | |||
fontInfo.addMetrics("F2", new HelveticaOblique(base14Kerning)); | |||
fontInfo.addMetrics("F3", new HelveticaBold(base14Kerning)); | |||
@@ -181,7 +179,7 @@ public final class FontSetup { | |||
final int startNum = 15; | |||
/* Add configured fonts */ | |||
addConfiguredFonts(fontInfo, embedFontInfoList, startNum, resolver, base14Kerning); | |||
addConfiguredFonts(fontInfo, embedFontInfoList, startNum, resourceResolver, base14Kerning); | |||
} | |||
/** | |||
@@ -189,21 +187,16 @@ public final class FontSetup { | |||
* @param fontInfo the font info to set up | |||
* @param embedFontInfoList a list of EmbedFontInfo objects | |||
* @param num starting index for internal font numbering | |||
* @param resolver the font resolver | |||
* @param resourceResolver the font resolver | |||
*/ | |||
private static void addConfiguredFonts(FontInfo fontInfo, | |||
List<EmbedFontInfo> embedFontInfoList, int num, FontResolver resolver, | |||
List<EmbedFontInfo> embedFontInfoList, int num, | |||
InternalResourceResolver resourceResolver, | |||
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 resourceResolver != null; | |||
String internalName = null; | |||
@@ -211,7 +204,7 @@ public final class FontSetup { | |||
internalName = "F" + num; | |||
num++; | |||
LazyFont font = new LazyFont(embedFontInfo, resolver); | |||
LazyFont font = new LazyFont(embedFontInfo, resourceResolver, false); | |||
fontInfo.addMetrics(internalName, font); | |||
List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); | |||
@@ -221,32 +214,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 ); | |||
} | |||
} |
@@ -27,6 +27,8 @@ import java.io.Serializable; | |||
*/ | |||
public class FontTriplet implements Comparable<FontTriplet>, Serializable { | |||
public static final FontTriplet DEFAULT_FONT_TRIPLET = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); | |||
/** serial version UID */ | |||
private static final long serialVersionUID = 1168991106658033508L; | |||
@@ -38,14 +40,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 +58,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; | |||
@@ -143,6 +137,5 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable { | |||
*/ | |||
boolean matches(FontTriplet triplet); | |||
} | |||
} | |||
@@ -20,19 +20,17 @@ | |||
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.InternalResourceResolver; | |||
import org.apache.fop.complexscripts.fonts.Positionable; | |||
import org.apache.fop.complexscripts.fonts.Substitutable; | |||
@@ -43,49 +41,50 @@ 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 EmbeddingMode embeddingMode = EmbeddingMode.AUTO; | |||
private boolean embedded = true; | |||
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 EmbeddingMode embeddingMode; | |||
private final String subFontName; | |||
private final boolean embedded; | |||
private final InternalResourceResolver resourceResolver; | |||
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 | |||
* @param resourceResolver 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, InternalResourceResolver resourceResolver, | |||
boolean useComplexScripts) { | |||
this.metricsURI = fontInfo.getMetricsURI(); | |||
this.fontEmbedURI = fontInfo.getEmbedURI(); | |||
this.useKerning = fontInfo.getKerning(); | |||
if ( resolver != null ) { | |||
this.useAdvanced = resolver.isComplexScriptFeaturesEnabled(); | |||
if (resourceResolver != null) { | |||
this.useAdvanced = useComplexScripts; | |||
} else { | |||
this.useAdvanced = fontInfo.getAdvanced(); | |||
} | |||
this.encodingMode = fontInfo.getEncodingMode(); | |||
this.embeddingMode = fontInfo.getEmbeddingMode(); | |||
this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode() | |||
: EncodingMode.AUTO; | |||
this.embeddingMode = fontInfo.getEmbeddingMode() != null ? fontInfo.getEmbeddingMode() | |||
: EmbeddingMode.AUTO; | |||
this.subFontName = fontInfo.getSubFontName(); | |||
this.embedded = fontInfo.isEmbedded(); | |||
this.resolver = resolver; | |||
this.resourceResolver = resourceResolver; | |||
} | |||
/** {@inheritDoc} */ | |||
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('}'); | |||
@@ -95,75 +94,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 = resourceResolver.getResource(metricsURI); | |||
InputSource src = new InputSource(in); | |||
src.setSystemId(metricsURI.toASCIIString()); | |||
reader = new FontReader(src, resourceResolver); | |||
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, subFontName, | |||
embedded, embeddingMode, encodingMode, | |||
useKerning, useAdvanced, resolver); | |||
realFont = FontLoader.loadFont(fontEmbedURI, subFontName, embedded, | |||
embeddingMode, encodingMode, useKerning, useAdvanced, resourceResolver); | |||
} | |||
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.InternalResourceResolver; | |||
import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; | |||
@@ -68,7 +69,8 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
/** | |||
* Default constructor | |||
*/ | |||
public MultiByteFont() { | |||
public MultiByteFont(InternalResourceResolver resourceResolver) { | |||
super(resourceResolver); | |||
subset.setupFirstGlyph(); | |||
setFontType(FontType.TYPE0); | |||
} | |||
@@ -123,7 +125,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
/** {@inheritDoc} */ | |||
public boolean isEmbeddable() { | |||
return !(getEmbedFileName() == null && getEmbedResourceName() == null); | |||
return !(getEmbedFileURI() == null && getEmbedResourceName() == null); | |||
} | |||
public boolean isSubsetEmbedded() { | |||
@@ -553,7 +555,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,7 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.fonts.Glyphs; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; | |||
/** | |||
@@ -53,15 +54,16 @@ public class SingleByteFont extends CustomFont { | |||
private PostScriptVersion ttPostScriptVersion; | |||
/** | |||
* Main constructor. | |||
* @param resourceResolver the URI resolver for controlling file access | |||
*/ | |||
public SingleByteFont() { | |||
public SingleByteFont(InternalResourceResolver resourceResolver) { | |||
super(resourceResolver); | |||
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.Map; | |||
import java.util.Set; | |||
@@ -219,12 +221,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( | |||
@@ -465,7 +472,7 @@ public class TTFReader extends AbstractFontReader { | |||
if (isCid || kpx2.intValue() < 256) { | |||
el2 = doc.createElement("pair"); | |||
el2.setAttribute("kpx2", kpx2.toString()); | |||
Integer val = (Integer)h2.get(kpx2); | |||
Integer val = h2.get(kpx2); | |||
el2.setAttribute("kern", val.toString()); | |||
el.appendChild(el2); | |||
} |
@@ -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.InternalResourceResolver; | |||
import org.apache.fop.fonts.CustomFont; | |||
import org.apache.fop.fonts.EmbedFontInfo; | |||
import org.apache.fop.fonts.EmbeddingMode; | |||
@@ -38,7 +39,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; | |||
@@ -134,26 +134,25 @@ 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, InternalResourceResolver resourceResolver) { | |||
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, | |||
EncodingMode.AUTO, EmbeddingMode.AUTO); | |||
fontInfo.setPostScriptName(customFont.getFontName()); | |||
if (fontCache != null) { | |||
fontCache.addFont(fontInfo); | |||
fontCache.addFont(fontInfo, resourceResolver); | |||
} | |||
return fontInfo; | |||
} | |||
@@ -161,32 +160,31 @@ public class FontInfoFinder { | |||
/** | |||
* Attempts to determine EmbedFontInfo from a given font file. | |||
* | |||
* @param fontURL font URL. Assumed to be local. | |||
* @param resolver font resolver used to resolve font | |||
* @param fontURI the URI of the font resource | |||
* @param resourceResolver 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, InternalResourceResolver resourceResolver, FontCache fontCache) { | |||
URI embedUri = resourceResolver.resolveFromBase(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; | |||
} | |||
@@ -195,19 +193,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 = resourceResolver.getResource(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 { | |||
@@ -222,23 +220,25 @@ public class FontInfoFinder { | |||
log.debug("Loading " + fontName); | |||
} | |||
try { | |||
TTFFontLoader ttfLoader = new TTFFontLoader( | |||
fontFileURL, fontName, true, EmbeddingMode.AUTO, EncodingMode.AUTO, | |||
useKerning, useAdvanced, resolver); | |||
TTFFontLoader ttfLoader = new TTFFontLoader(fontURI, fontName, true, | |||
EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced, | |||
resourceResolver); | |||
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, | |||
resourceResolver); | |||
if (fi != null) { | |||
embedFontInfoList.add(fi); | |||
} | |||
@@ -248,21 +248,22 @@ public class FontInfoFinder { | |||
} else { | |||
// The normal case | |||
try { | |||
customFont = FontLoader.loadFont(fontURL, null, true, EmbeddingMode.AUTO, | |||
EncodingMode.AUTO, resolver); | |||
customFont = FontLoader.loadFont(fontURI, null, true, EmbeddingMode.AUTO, | |||
EncodingMode.AUTO, useKerning, useAdvanced, resourceResolver); | |||
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, resourceResolver); | |||
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; | |||
} | |||
@@ -152,9 +124,9 @@ public class FontFileReader { | |||
final byte buf = read(); | |||
if (buf < 0) { | |||
return (int)(256 + buf); | |||
return (256 + buf); | |||
} else { | |||
return (int)buf; | |||
return buf; | |||
} | |||
} | |||
@@ -178,7 +150,7 @@ public class FontFileReader { | |||
*/ | |||
public final int readTTFUShort() throws IOException { | |||
final int ret = (readTTFUByte() << 8) + readTTFUByte(); | |||
return (int)ret; | |||
return ret; | |||
} | |||
/** |
@@ -19,7 +19,9 @@ | |||
package org.apache.fop.fonts.truetype; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.BitSet; | |||
import java.util.Comparator; | |||
@@ -33,6 +35,7 @@ import java.util.Set; | |||
import java.util.SortedSet; | |||
import java.util.TreeSet; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -1672,7 +1675,7 @@ public class TTFFile { | |||
for (Integer unicodeKey2 : ckpx.keySet()) { | |||
Integer cidKey2 = unicodeToGlyph(unicodeKey2.intValue()); | |||
Integer kern = (Integer)ckpx.get(unicodeKey2); | |||
Integer kern = ckpx.get(unicodeKey2); | |||
Iterator uniMap = mtxTab[cidKey2.intValue()].getUnicodeIndex().listIterator(); | |||
while (uniMap.hasNext()) { | |||
@@ -1838,6 +1841,8 @@ public class TTFFile { | |||
* @throws IOException In case of an I/O problem | |||
*/ | |||
public final List<String> getTTCnames(FontFileReader in) throws IOException { | |||
this.fontFile = in; | |||
List<String> fontNames = new ArrayList<String>(); | |||
String tag = in.readTTFString(4); | |||
@@ -2011,12 +2016,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; | |||
TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); | |||
FontFileReader reader = new FontFileReader(args[0]); | |||
stream = new FileInputStream(args[0]); | |||
FontFileReader reader = new FontFileReader(stream); | |||
String name = null; | |||
if (args.length >= 2) { | |||
@@ -2029,6 +2036,8 @@ public class TTFFile { | |||
} catch (IOException ioe) { | |||
System.err.println("Problem reading font: " + ioe.toString()); | |||
ioe.printStackTrace(System.err); | |||
} finally { | |||
IOUtils.closeQuietly(stream); | |||
} | |||
} | |||
} |
@@ -21,17 +21,18 @@ package org.apache.fop.fonts.truetype; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.fonts.CIDFontType; | |||
import org.apache.fop.fonts.CMapSegment; | |||
import org.apache.fop.fonts.EmbeddingMode; | |||
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; | |||
@@ -53,10 +54,10 @@ public class TTFFontLoader extends FontLoader { | |||
/** | |||
* Default constructor | |||
* @param fontFileURI the URI representing the font file | |||
* @param resolver the FontResolver for font URI resolution | |||
* @param resourceResolver the resource resolver for font URI resolution | |||
*/ | |||
public TTFFontLoader(String fontFileURI, FontResolver resolver) { | |||
this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resolver); | |||
public TTFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) { | |||
this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver); | |||
} | |||
/** | |||
@@ -71,9 +72,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, | |||
boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, | |||
boolean useKerning, boolean useAdvanced, FontResolver resolver) { | |||
public TTFFontLoader(URI fontFileURI, String subFontName, boolean embedded, | |||
EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning, | |||
boolean useAdvanced, InternalResourceResolver resolver) { | |||
super(fontFileURI, embedded, useKerning, useAdvanced, resolver); | |||
this.subFontName = subFontName; | |||
this.encodingMode = encodingMode; | |||
@@ -98,7 +99,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 = resourceResolver.getResource(this.fontFileURI); | |||
try { | |||
TTFFile ttf = new TTFFile(useKerning, useAdvanced); | |||
FontFileReader reader = new FontFileReader(in); | |||
@@ -126,14 +127,13 @@ public class TTFFontLoader extends FontLoader { | |||
} | |||
if (isCid) { | |||
multiFont = new MultiByteFont(); | |||
multiFont = new MultiByteFont(resourceResolver); | |||
returnFont = multiFont; | |||
multiFont.setTTCName(ttcFontName); | |||
} else { | |||
singleFont = new SingleByteFont(); | |||
singleFont = new SingleByteFont(resourceResolver); | |||
returnFont = singleFont; | |||
} | |||
returnFont.setResolver(resolver); | |||
returnFont.setFontName(ttf.getPostScriptName()); | |||
returnFont.setFullName(ttf.getFullName()); | |||
@@ -172,7 +172,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."; |