git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764744 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -358,12 +358,12 @@ list of possible build targets. | |||
</fileset> | |||
</eventResourceGenerator> | |||
<fixcrlf file="${src.java.dir}/org/apache/fop/events/EventFormatter.xml" tab="remove" tablength="2"/> | |||
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/render/afp/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/render/afp/AFPEventProducer.xml"> | |||
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/afp/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml"> | |||
<fileset dir="${src.java.dir}"> | |||
<include name="org/apache/fop/render/afp/**/*.java"/> | |||
</fileset> | |||
</eventResourceGenerator> | |||
<fixcrlf file="${src.java.dir}/org/apache/fop/render/afp/AFPEventProducer.xml" tab="remove" tablength="2"/> | |||
<fixcrlf file="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml" tab="remove" tablength="2"/> | |||
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/render/bitmap/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/render/bitmap/BitmapRendererEventProducer.xml"> | |||
<fileset dir="${src.java.dir}"> | |||
<include name="org/apache/fop/render/bitmap/**/*.java"/> | |||
@@ -608,7 +608,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/*RendererConfigurator**"/> | |||
<include name="org/apache/fop/render/**Configurator**"/> | |||
<include name="org/apache/fop/util/AbstractPaintingState**"/> | |||
<include name="org/apache/fop/pdf/**"/> | |||
</patternset> |
@@ -92,7 +92,7 @@ public class ExampleConcat { | |||
//Create an instance of the target document handler so the IFSerializer | |||
//can use its font setup | |||
IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler( | |||
userAgent, MimeConstants.MIME_PDF + ";mode=painter"); | |||
userAgent, MimeConstants.MIME_PDF); | |||
//Create the IFSerializer to write the intermediate format | |||
IFSerializer ifSerializer = new IFSerializer(); | |||
@@ -150,7 +150,7 @@ public class ExampleConcat { | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Setup target handler | |||
String mime = MimeConstants.MIME_PDF + ";mode=painter"; | |||
String mime = MimeConstants.MIME_PDF; | |||
IFDocumentHandler targetHandler = fopFactory.getRendererFactory().createDocumentHandler( | |||
userAgent, mime); | |||
@@ -73,7 +73,7 @@ public class ExampleStamp { | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Setup target handler | |||
String mime = MimeConstants.MIME_PDF + ";mode=painter"; | |||
String mime = MimeConstants.MIME_PDF; | |||
IFDocumentHandler targetHandler = fopFactory.getRendererFactory().createDocumentHandler( | |||
userAgent, mime); | |||
@@ -151,6 +151,18 @@ | |||
default-page-settings element to specify the two values.</td> | |||
<td>"height" 11 inches, "width" 8.26 inches</td> | |||
</tr> | |||
<tr> | |||
<td>prefer-renderer</td> | |||
<td>boolean (true, false)</td> | |||
<td> | |||
By default, FOP prefers the newer output implementations based on the | |||
<code>IFDocumentHandler</code> interface. If no such implementation can be found for | |||
a given MIME type, it looks for an implementation of the <code>Renderer</code> interface. | |||
If necessary, you can invert the lookup order to prefer the Renderer variant over the | |||
IFDocumentHandler variant by setting this value to true. | |||
</td> | |||
<td>false</td> | |||
</tr> | |||
<tr> | |||
<td>use-cache</td> | |||
<td>boolean (true, false)</td> |
@@ -344,7 +344,7 @@ | |||
</warning> | |||
</section> | |||
<section id="truetype-collections-metrics"> | |||
<title>TrueType Collections Font Metrics</title> | |||
<title>TrueType Collections</title> | |||
<p>TrueType collections (.ttc files) contain more than one font. | |||
To create metrics files for these fonts, you must specify which font in the collection should be generated, by using the "-ttcname" option with the TTFReader.</p> | |||
<p>To get a list of the fonts in a collection, just start the TTFReader as if it were a normal TrueType file (without the -ttcname option). | |||
@@ -356,8 +356,11 @@ | |||
<p> | |||
Alternatively, the individual sub-fonts of a TrueType Collections can be selected | |||
using the "sub-font" attribute on the "font" element. That means that generating | |||
an XML font metrics file for TrueType collections is not necessary anymore. | |||
an XML font metrics file for TrueType collections is not necessary anymore. Example: | |||
</p> | |||
<source><![CDATA[<font embed-url="gulim.ttc" sub-font="GulimChe"> | |||
<font-triplet name="GulimChe" style="normal" weight="normal"/> | |||
</font>]]></source> | |||
</section> | |||
<section id="register"> | |||
<title>Register Fonts with FOP</title> | |||
@@ -542,5 +545,13 @@ | |||
</ul> | |||
<p>Character-by-Character is NOT yet supported!</p> | |||
</section> | |||
<section id="font-list"> | |||
<title>Font List Command-Line Tool</title> | |||
<p> | |||
FOP contains a small command-line tool that lets you generate a list of all configured | |||
fonts. Its class name is: <code>org.apache.fop.tools.fontlist.FontListMain</code>. | |||
Run it with the "-?" parameter to get help for the various options. | |||
</p> | |||
</section> | |||
</body> | |||
</document> |
@@ -451,11 +451,35 @@ out = proc.getOutputStream();]]></source> | |||
</section> | |||
<section id="afp"> | |||
<title>AFP</title> | |||
<warning>The AFP Renderer is a new addition (27-Apr-2006) to the sandbox and as such not yet fully tested or feature complete.</warning> | |||
<p> | |||
The FOP AFP Renderer deals with creating documents conforming to the IBM AFP document architecture | |||
also refered to as MO:DCA (Mixed Object Document Content Architecture). | |||
</p> | |||
<p> | |||
The mapping of XSL-FO elements to the major MO:DCA structures is as follows: | |||
</p> | |||
<table> | |||
<tr> | |||
<th>XSL-FO element</th> | |||
<th>MO:DCA-P object</th> | |||
</tr> | |||
<tr> | |||
<td>fo:root</td> | |||
<td>Document</td> | |||
</tr> | |||
<tr> | |||
<td>fo:page-sequence</td> | |||
<td>Page Group</td> | |||
</tr> | |||
<tr> | |||
<td>fo:simple-page-master</td> | |||
<td>Page</td> | |||
</tr> | |||
</table> | |||
<p> | |||
FOP creates exactly one Document per Printfile with an optional Resource Group at the | |||
beginning. FOP does not create document indices. | |||
</p> | |||
<section id="afp-references"> | |||
<title>References</title> | |||
<ul> | |||
@@ -512,8 +536,8 @@ out = proc.getOutputStream();]]></source> | |||
<source><![CDATA[ <!-- This is an example of mapping actual IBM raster fonts / code pages to a FOP font --> | |||
<font> | |||
<!-- The afp-font element defines the IBM code page, the matching Java encoding and the | |||
path to the font --> | |||
<afp-font type="raster" codepage="T1V10500" encoding="Cp500" path="fonts/ibm"> | |||
base URI for the font --> | |||
<afp-font type="raster" codepage="T1V10500" encoding="Cp500" base-uri="fonts/ibm/"> | |||
<!-- For a raster font a separate element for each font size is required providing | |||
the font size and the corresponding IBM Character set name --> | |||
<afp-raster-font size="7" characterset="C0N20070"/> | |||
@@ -539,15 +563,24 @@ out = proc.getOutputStream();]]></source> | |||
However, the characterset definition is now required within the afp-font element.</p> | |||
<source><![CDATA[ <font> | |||
<afp-font type="outline" codepage="T1V10500" encoding="Cp500" characterset="CZH200 " | |||
path="fonts/ibm" /> | |||
base-uri="file:/fonts/ibm" /> | |||
<font-triplet name="sans-serif" style="normal" weight="normal"/> | |||
<font-triplet name="Helvetica" style="normal" weight="normal"/> | |||
<font-triplet name="any" style="normal" weight="normal"/> | |||
</font> | |||
]]></source> | |||
<p> | |||
If "base-uri" is missing or a relative URI, the fonts are resolved relative to | |||
the font base URI specified in the configuration (or on the FopFactory). | |||
</p> | |||
<note> | |||
Previously, the location of the font files was given by the "path" attribute. This is still | |||
supported for the time being, but you should move to using the more flexible "base-uri" | |||
attribute so you can profit from the power of URI resolvers. | |||
</note> | |||
<p>Experimentation has shown that the font metrics for the FOP built-in Base14 fonts are actually | |||
very similar to some of the IBM outline and raster fonts. In cases were the IBM font files are not | |||
available the path attribute in the afp-font element can be replaced by a base14-font attribute | |||
available the base-uri attribute in the afp-font element can be replaced by a base14-font attribute | |||
giving the name of the matching Base14 font. In this case the AFP Renderer will take the | |||
font metrics from the built-in font.</p> | |||
<source><![CDATA[ <!-- The following are examples of defining outline fonts based on FOP built-in | |||
@@ -687,7 +720,7 @@ out = proc.getOutputStream();]]></source> | |||
xmlns:afp="http://xmlgraphics.apache.org/fop/extensions/afp"> | |||
]]></source> | |||
<section id="afp-page-overlay"> | |||
<title>Page Overlay Extension</title> | |||
<title>Page Overlay (IPO) Extension</title> | |||
<p>The include-page-overlay extension element allows to define on a per simple-page-master basis a page overlay resource. Example:</p> | |||
<source><![CDATA[ | |||
<fo:layout-master-set> | |||
@@ -701,7 +734,7 @@ out = proc.getOutputStream();]]></source> | |||
must be known in the AFP processing environment.</p> | |||
</section> | |||
<section id="afp-page-segment"> | |||
<title>Page Segment Extension</title> | |||
<title>Page Segment (IPS) Extension</title> | |||
<p>The include-page-segment extension element allows to define resource substitution for fo:external-graphics elements. | |||
Example:</p> | |||
<source><![CDATA[ | |||
@@ -724,7 +757,7 @@ out = proc.getOutputStream();]]></source> | |||
</p> | |||
</section> | |||
<section id="afp-tag-logical-element"> | |||
<title>Tag Logical Element Extension</title> | |||
<title>Tag Logical Element (TLE) Extension</title> | |||
<p>The tag-logical-element extension element allows to injects TLEs into the AFP output stream. Example:</p> | |||
<source><![CDATA[ | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" | |||
@@ -735,14 +768,21 @@ out = proc.getOutputStream();]]></source> | |||
<fo:region-body/> | |||
</fo:simple-page-master> | |||
</fo:layout-master-set> | |||
[..] | |||
<fo:page-sequence master-reference="simple"> | |||
<afp:tag-logical-element name="foo" value="bar"/> | |||
<fo:flow flow-name="xsl-region-body"> | |||
[..] | |||
]]></source> | |||
<p>The tag-logical-element extension element can only occur within a simple-page-master. | |||
Multiple tag-logical-element extension elements within a simple-page-master are allowed. | |||
The name and value attributes are mandatory. | |||
<p> | |||
The tag-logical-element extension element can appear within a simple-page-master | |||
(page level) or it can appear as child of page-sequence (page group level). | |||
Multiple tag-logical-element extension elements within a simple-page-master or | |||
page-sequence are allowed. The name and value attributes are mandatory. | |||
</p> | |||
</section> | |||
<section id="afp-no-operation"> | |||
<title>No Operation Extension</title> | |||
<title>No Operation (NOP) Extension</title> | |||
<p>The no-operation extension provides the ability to carry up to 32K of comments or any other type | |||
of unarchitected data into the AFP output stream. Example:</p> | |||
<source><![CDATA[ | |||
@@ -759,6 +799,29 @@ out = proc.getOutputStream();]]></source> | |||
The name attribute is mandatory. | |||
</p> | |||
</section> | |||
<section id="afp-invoke-medium-map"> | |||
<title>Invoke Medium Map (IMM) Extension</title> | |||
<p> | |||
The invoke-medium-map extension allows to generate IMM fields (Invoke Medium Map) in the | |||
generated AFP output. Example: | |||
</p> | |||
<source><![CDATA[ | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" | |||
xmlns:afp="http://xmlgraphics.apache.org/fop/extensions/afp"> | |||
[..] | |||
<fo:page-sequence master-reference="normal"> | |||
<afp:invoke-medium-map name="MYMAP"/> | |||
<fo:flow flow-name="xsl-region-body"> | |||
[..] | |||
]]></source> | |||
<p> | |||
The invoke-medium-map element is allowed as child of fo:page-sequence (page group | |||
level). It is NOT supported on document level (fo:root), yet. FOP also doesn't support | |||
specifying medium maps inside XML (using BMM/EMM). It can only reference an existing | |||
medium map by name. The medium map has to be constructed through different means and | |||
available on the target platform. | |||
</p> | |||
</section> | |||
</section> | |||
<section id="afp-foreign-attributes"> | |||
<title>Foreign Attributes</title> |
@@ -55,6 +55,9 @@ | |||
<xs:element name="page-sequence"> | |||
<xs:complexType> | |||
<xs:sequence> | |||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | |||
<xs:any namespace="##other" processContents="lax"/> | |||
</xs:choice> | |||
<xs:element ref="mf:page" minOccurs="1" maxOccurs="unbounded"/> | |||
</xs:sequence> | |||
<xs:attribute name="id" type="xs:ID"/> |
@@ -91,7 +91,7 @@ which will be used to configure the chosen Forrest skin. | |||
<favicon-url></favicon-url> | |||
<!-- The following used to construct a copyright statement --> | |||
<year>1999-2008</year> | |||
<year>1999-2009</year> | |||
<vendor>The Apache Software Foundation.</vendor> | |||
<copyright-link>http://www.apache.org/licenses/</copyright-link> | |||
@@ -1,2 +1,2 @@ | |||
org.apache.fop.image.loader.batik.ImageLoaderFactorySVG | |||
org.apache.fop.image.loader.batik.ImageLoaderFactoryWMF | |||
org.apache.fop.image.loader.batik.ImageLoaderFactoryWMF |
@@ -37,7 +37,6 @@ 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.ResourceAccessor; | |||
import org.apache.fop.afp.util.SimpleResourceAccessor; | |||
/** | |||
* Manages the creation and storage of document resources | |||
@@ -236,11 +235,11 @@ public class AFPResourceManager { | |||
/** | |||
* Creates an included resource object by loading the contained object from a file. | |||
* @param resourceName the name of the resource | |||
* @param basePath the base path in which to look for the resource files | |||
* @param accessor resource accessor to access the resource with | |||
* @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, String basePath, | |||
public void createIncludedResource(String resourceName, ResourceAccessor accessor, | |||
byte resourceObjectType) throws IOException { | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
URI uri; | |||
@@ -261,9 +260,6 @@ public class AFPResourceManager { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Adding included resource: " + resourceName); | |||
} | |||
//TODO This works with local filenames only. In the long term, this | |||
//should work through FOP's URI resolver. | |||
ResourceAccessor accessor = new SimpleResourceAccessor(basePath); | |||
IncludedResourceObject resourceContent = new IncludedResourceObject( | |||
resourceName, accessor, uri); | |||
@@ -486,10 +486,10 @@ public class DataStream { | |||
* The tag value | |||
*/ | |||
public void createTagLogicalElement(String name, String value) { | |||
if (currentPageGroup != null) { | |||
currentPageGroup.createTagLogicalElement(name, value); | |||
} else { | |||
if (currentPage != null) { | |||
currentPage.createTagLogicalElement(name, value, tleSequence++); | |||
} else { | |||
currentPageGroup.createTagLogicalElement(name, value); | |||
} | |||
} | |||
@@ -67,18 +67,14 @@ public class AFPFontCollection implements FontCollection { | |||
num++; | |||
} | |||
} | |||
if (!fontInfo.hasFont("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)) { | |||
eventProducer.warnMissingDefaultFont(this, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); | |||
} | |||
if (!fontInfo.hasFont("any", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL)) { | |||
eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); | |||
} | |||
if (!fontInfo.hasFont("any", Font.STYLE_NORMAL, Font.WEIGHT_BOLD)) { | |||
eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); | |||
} | |||
if (!fontInfo.hasFont("any", Font.STYLE_ITALIC, Font.WEIGHT_BOLD)) { | |||
eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); | |||
} | |||
checkDefaultFontAvailable(fontInfo, eventProducer, | |||
Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); | |||
checkDefaultFontAvailable(fontInfo, eventProducer, | |||
Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); | |||
checkDefaultFontAvailable(fontInfo, eventProducer, | |||
Font.STYLE_NORMAL, Font.WEIGHT_BOLD); | |||
checkDefaultFontAvailable(fontInfo, eventProducer, | |||
Font.STYLE_ITALIC, Font.WEIGHT_BOLD); | |||
} else { | |||
eventProducer.warnDefaultFontSetup(this); | |||
@@ -89,4 +85,11 @@ public class AFPFontCollection implements FontCollection { | |||
return num; | |||
} | |||
private void checkDefaultFontAvailable(FontInfo fontInfo, AFPEventProducer eventProducer, | |||
String style, int weight) { | |||
if (!fontInfo.hasFont("any", style, weight)) { | |||
eventProducer.warnMissingDefaultFont(this, style, weight); | |||
} | |||
} | |||
} |
@@ -19,21 +19,19 @@ | |||
package org.apache.fop.afp.fonts; | |||
import java.io.File; | |||
import java.io.FileNotFoundException; | |||
import java.io.FilenameFilter; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPConstants; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.afp.util.StructuredFieldReader; | |||
/** | |||
@@ -58,7 +56,7 @@ public final class AFPFontReader { | |||
/** | |||
* Static logging instance | |||
*/ | |||
protected static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp.fonts"); | |||
protected static final Log log = LogFactory.getLog(AFPFontReader.class); | |||
/** | |||
* Template used to convert lists to arrays. | |||
@@ -96,7 +94,7 @@ public final class AFPFontReader { | |||
/** | |||
* The collection of code pages | |||
*/ | |||
private final Map/*<String, Map<String, String>>*/ codePages | |||
private final Map/*<String, Map<String, String>>*/ codePagesCache | |||
= new java.util.HashMap/*<String, Map<String, String>>*/(); | |||
/** | |||
@@ -108,65 +106,16 @@ public final class AFPFontReader { | |||
* | |||
* @throws IOException in the event that an I/O exception of some sort has occurred | |||
*/ | |||
private InputStream openInputStream(String path, String filename) throws IOException { | |||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); | |||
if (classLoader == null) { | |||
classLoader = AFPFontReader.class.getClassLoader(); | |||
} | |||
URL url = classLoader.getResource(path); | |||
if (url == null) { | |||
try { | |||
File file = new File(path); | |||
url = file.toURI().toURL(); | |||
if (url == null) { | |||
String msg = "file not found " + filename + " in classpath: " + path; | |||
log.error(msg); | |||
throw new FileNotFoundException(msg); | |||
} | |||
} catch (MalformedURLException ex) { | |||
String msg = "file not found " + filename + " in classpath: " + path; | |||
log.error(msg); | |||
throw new FileNotFoundException(msg); | |||
} | |||
} | |||
File directory = FileUtils.toFile(url); | |||
if (!directory.canRead()) { | |||
String msg = "Failed to read directory " + url.getPath(); | |||
log.error(msg); | |||
throw new FileNotFoundException(msg); | |||
} | |||
final String filterpattern = filename.trim(); | |||
FilenameFilter filter = new FilenameFilter() { | |||
public boolean accept(File dir, String name) { | |||
return name.startsWith(filterpattern); | |||
} | |||
}; | |||
File[] files = directory.listFiles(filter); | |||
if (files.length < 1) { | |||
String msg = "file search for " + filename + " located " | |||
+ files.length + " files"; | |||
log.error(msg); | |||
throw new FileNotFoundException(msg); | |||
} else if (files.length > 1) { | |||
String msg = "file search for " + filename + " located " | |||
+ files.length + " files"; | |||
log.warn(msg); | |||
} | |||
InputStream inputStream = files[0].toURI().toURL().openStream(); | |||
if (inputStream == null) { | |||
String msg = "AFPFontReader:: getInputStream():: file not found for " + filename; | |||
log.error(msg); | |||
throw new FileNotFoundException(msg); | |||
private InputStream openInputStream(ResourceAccessor accessor, String filename) | |||
throws IOException { | |||
URI uri; | |||
try { | |||
uri = new URI(filename.trim()); | |||
} catch (URISyntaxException e) { | |||
throw new FileNotFoundException("Invalid filename: " | |||
+ filename + " (" + e.getMessage() + ")"); | |||
} | |||
InputStream inputStream = accessor.createInputStream(uri); | |||
return inputStream; | |||
} | |||
@@ -206,13 +155,14 @@ public final class AFPFontReader { | |||
* chracter global identifier. | |||
*/ | |||
String codePageId = new String(characterSet.getCodePage()); | |||
String path = characterSet.getPath(); | |||
ResourceAccessor accessor = characterSet.getResourceAccessor(); | |||
Map/*<String,String>*/ codePage = (Map/*<String,String>*/)codePages.get(codePageId); | |||
Map/*<String,String>*/ codePage | |||
= (Map/*<String,String>*/)codePagesCache.get(codePageId); | |||
if (codePage == null) { | |||
codePage = loadCodePage(codePageId, characterSet.getEncoding(), path); | |||
codePages.put(codePageId, codePage); | |||
codePage = loadCodePage(codePageId, characterSet.getEncoding(), accessor); | |||
codePagesCache.put(codePageId, codePage); | |||
} | |||
/** | |||
@@ -222,7 +172,7 @@ public final class AFPFontReader { | |||
*/ | |||
final String characterSetName = characterSet.getName(); | |||
inputStream = openInputStream(path, characterSetName); | |||
inputStream = openInputStream(accessor, characterSetName); | |||
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); | |||
@@ -246,7 +196,8 @@ public final class AFPFontReader { | |||
} | |||
//process D3AC89 Font Position | |||
processFontPosition(structuredFieldReader, characterSetOrientations, metricNormalizationFactor); | |||
processFontPosition(structuredFieldReader, characterSetOrientations, | |||
metricNormalizationFactor); | |||
//process D38C89 Font Index (per orientation) | |||
for (int i = 0; i < characterSetOrientations.length; i++) { | |||
@@ -274,17 +225,18 @@ public final class AFPFontReader { | |||
* the code page identifier | |||
* @param encoding | |||
* the encoding to use for the character decoding | |||
* @param accessor the resource accessor | |||
* @returns a code page mapping | |||
*/ | |||
private Map/*<String,String>*/ loadCodePage(String codePage, String encoding, | |||
String path) throws IOException { | |||
ResourceAccessor accessor) throws IOException { | |||
// Create the HashMap to store code page information | |||
Map/*<String,String>*/ codePages = new java.util.HashMap/*<String,String>*/(); | |||
InputStream inputStream = null; | |||
try { | |||
inputStream = openInputStream(path, codePage.trim()); | |||
inputStream = openInputStream(accessor, codePage.trim()); | |||
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); | |||
byte[] data = structuredFieldReader.getNext(CHARACTER_TABLE_SF); |
@@ -19,20 +19,25 @@ | |||
package org.apache.fop.afp.fonts; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URI; | |||
import java.nio.ByteBuffer; | |||
import java.nio.CharBuffer; | |||
import java.nio.charset.CharacterCodingException; | |||
import java.nio.charset.Charset; | |||
import java.nio.charset.CharsetEncoder; | |||
import java.nio.charset.CodingErrorAction; | |||
import java.nio.charset.UnsupportedCharsetException; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPConstants; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.afp.util.SimpleResourceAccessor; | |||
import org.apache.fop.afp.util.StringUtils; | |||
/** | |||
@@ -79,7 +84,7 @@ public class CharacterSet { | |||
protected String name; | |||
/** The path to the installed fonts */ | |||
protected String path; | |||
private ResourceAccessor accessor; | |||
/** Indicator as to whether to metrics have been loaded */ | |||
private boolean isMetricsLoaded = false; | |||
@@ -98,8 +103,23 @@ public class CharacterSet { | |||
* @param encoding the encoding of the font | |||
* @param name the character set name | |||
* @param path the path to the installed afp fonts | |||
* @deprecated Please use {@link #CharacterSet(String, String, String, URI)} instead. | |||
*/ | |||
public CharacterSet(String codePage, String encoding, String name, String path) { | |||
this(codePage, encoding, name, | |||
new SimpleResourceAccessor(path != null ? new File(path) : null)); | |||
} | |||
/** | |||
* Constructor for the CharacterSetMetric object, the character set is used | |||
* to load the font information from the actual AFP font. | |||
* | |||
* @param codePage the code page identifier | |||
* @param encoding the encoding of the font | |||
* @param name the character set name | |||
* @param accessor the resource accessor to load resource with | |||
*/ | |||
public CharacterSet(String codePage, String encoding, String name, ResourceAccessor accessor) { | |||
if (name.length() > MAX_NAME_LEN) { | |||
String msg = "Character set name '" + name + "' must be a maximum of " | |||
+ MAX_NAME_LEN + " characters"; | |||
@@ -114,9 +134,15 @@ public class CharacterSet { | |||
} | |||
this.codePage = codePage; | |||
this.encoding = encoding; | |||
this.encoder = Charset.forName(encoding).newEncoder(); | |||
this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); | |||
this.path = path; | |||
try { | |||
this.encoder = Charset.forName(encoding).newEncoder(); | |||
this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); | |||
} catch (UnsupportedCharsetException uce) { | |||
//No nio-capable encoder available | |||
//This may happen with "Cp500" on Sun Java 1.4.2 | |||
this.encoder = null; | |||
} | |||
this.accessor = accessor; | |||
this.characterSetOrientations = new java.util.HashMap(4); | |||
} | |||
@@ -195,12 +221,11 @@ public class CharacterSet { | |||
} | |||
/** | |||
* Returns the path where the font resources are installed | |||
* | |||
* @return the path where the font resources are installed | |||
* Returns the resource accessor to load the font resources with. | |||
* @return the resource accessor to load the font resources with | |||
*/ | |||
public String getPath() { | |||
return path; | |||
public ResourceAccessor getResourceAccessor() { | |||
return this.accessor; | |||
} | |||
/** | |||
@@ -321,7 +346,12 @@ public class CharacterSet { | |||
* @return true if the character is in the character set | |||
*/ | |||
public boolean hasChar(char c) { | |||
return encoder.canEncode(c); | |||
if (encoder != null) { | |||
return encoder.canEncode(c); | |||
} else { | |||
//Sun Java 1.4.2 compatibility | |||
return true; | |||
} | |||
} | |||
/** | |||
@@ -331,14 +361,26 @@ public class CharacterSet { | |||
* @throws CharacterCodingException if the encoding operation fails | |||
*/ | |||
public byte[] encodeChars(CharSequence chars) throws CharacterCodingException { | |||
ByteBuffer bb = encoder.encode(CharBuffer.wrap(chars)); | |||
if (bb.hasArray()) { | |||
return bb.array(); | |||
if (encoder != null) { | |||
ByteBuffer bb = encoder.encode(CharBuffer.wrap(chars)); | |||
if (bb.hasArray()) { | |||
return bb.array(); | |||
} else { | |||
bb.rewind(); | |||
byte[] bytes = new byte[bb.remaining()]; | |||
bb.get(bytes); | |||
return bytes; | |||
} | |||
} else { | |||
bb.rewind(); | |||
byte[] bytes = new byte[bb.remaining()]; | |||
bb.get(bytes); | |||
return bytes; | |||
//Sun Java 1.4.2 compatibility | |||
byte[] bytes; | |||
try { | |||
bytes = chars.toString().getBytes(this.encoding); | |||
return bytes; | |||
} catch (UnsupportedEncodingException uee) { | |||
throw new UnsupportedOperationException( | |||
"Unsupported encoding: " + uee.getMessage()); | |||
} | |||
} | |||
} | |||
@@ -19,6 +19,7 @@ | |||
package org.apache.fop.afp.fonts; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.fonts.Typeface; | |||
/** | |||
@@ -43,7 +44,7 @@ public class FopCharacterSet extends CharacterSet { | |||
String name, | |||
Typeface charSet) { | |||
super(codePage, encoding, name, null); | |||
super(codePage, encoding, name, (ResourceAccessor)null); | |||
this.charSet = charSet; | |||
} | |||
@@ -19,42 +19,68 @@ | |||
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; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.fonts.FontManager; | |||
/** | |||
* Default implementation of the {@link ResourceAccessor} interface for use inside FOP. | |||
*/ | |||
public class DefaultFOPResourceAccessor implements ResourceAccessor { | |||
public class DefaultFOPResourceAccessor extends SimpleResourceAccessor { | |||
private FOUserAgent userAgent; | |||
private String categoryBaseURI; | |||
/** | |||
* Main constructor. | |||
* 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 FontManager}'s base URI instead of the one on the {@link 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) { | |||
public DefaultFOPResourceAccessor(FOUserAgent userAgent, String categoryBaseURI, URI baseURI) { | |||
super(baseURI); | |||
this.userAgent = userAgent; | |||
this.categoryBaseURI = categoryBaseURI; | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
Source src = userAgent.resolveURI(uri.toASCIIString()); | |||
//Step 1: resolve against local base URI --> URI | |||
URI resolved = resolveAgainstBase(uri); | |||
//Step 2: resolve against the user agent --> stream | |||
Source src; | |||
src = userAgent.resolveURI(resolved.toASCIIString(), this.categoryBaseURI); | |||
if (src == null) { | |||
return null; | |||
throw new FileNotFoundException("Resource not found: " + uri.toASCIIString()); | |||
} else if (src instanceof StreamSource) { | |||
StreamSource ss = (StreamSource)src; | |||
InputStream in = ss.getInputStream(); | |||
return in; | |||
} else { | |||
return null; | |||
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(); | |||
} | |||
} |
@@ -26,7 +26,8 @@ import java.net.URI; | |||
import java.net.URL; | |||
/** | |||
* Simple implementation of the {@link ResourceAccessor} interface for access via files. | |||
* Simple implementation of the {@link ResourceAccessor} interface for access relative to a | |||
* base URI. | |||
*/ | |||
public class SimpleResourceAccessor implements ResourceAccessor { | |||
@@ -34,23 +35,40 @@ public class SimpleResourceAccessor implements ResourceAccessor { | |||
/** | |||
* Creates a new simple resource accessor. | |||
* @param basePath the base path to resolve relative URIs to | |||
* @param baseURI the base URI to resolve relative URIs against (may be null) | |||
*/ | |||
public SimpleResourceAccessor(File basePath) { | |||
this.baseURI = basePath.toURI(); | |||
public SimpleResourceAccessor(URI baseURI) { | |||
this.baseURI = baseURI; | |||
} | |||
/** | |||
* Creates a new simple resource accessor. | |||
* @param basePath the base path to resolve relative URIs to | |||
* @param baseDir the base directory to resolve relative filenames against (may be null) | |||
*/ | |||
public SimpleResourceAccessor(String basePath) { | |||
this(new File(basePath)); | |||
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 = this.baseURI.resolve(uri); | |||
URI resolved = resolveAgainstBase(uri); | |||
URL url = resolved.toURL(); | |||
return url.openStream(); | |||
} |
@@ -24,6 +24,8 @@ 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; | |||
@@ -32,8 +34,10 @@ 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; | |||
@@ -74,15 +78,31 @@ public class FOURIResolver implements javax.xml.transform.URIResolver { | |||
base += "/"; | |||
} | |||
File dir = new File(base); | |||
try { | |||
base = (dir.isDirectory() ? dir.toURI().toURL() : new URL(base)).toExternalForm(); | |||
} catch (MalformedURLException mfue) { | |||
if (throwExceptions) { | |||
throw mfue; | |||
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()); | |||
} | |||
log.error(mfue.getMessage()); | |||
} | |||
return base; | |||
} | |||
/** |
@@ -21,6 +21,7 @@ package org.apache.fop.apps; | |||
// Java | |||
import java.io.File; | |||
import java.net.MalformedURLException; | |||
import java.util.Date; | |||
import java.util.Map; | |||
@@ -43,6 +44,7 @@ import org.apache.fop.events.EventListener; | |||
import org.apache.fop.events.FOPEventListenerProxy; | |||
import org.apache.fop.events.LoggingEventListener; | |||
import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.RendererFactory; | |||
import org.apache.fop.render.XMLHandlerRegistry; | |||
@@ -84,9 +86,6 @@ public class FOUserAgent { | |||
*/ | |||
private String base = null; | |||
/** The base URL for all font URL resolutions. */ | |||
private String fontBase = null; | |||
/** A user settable URI Resolver */ | |||
private URIResolver uriResolver = null; | |||
@@ -97,6 +96,7 @@ public class FOUserAgent { | |||
private Renderer rendererOverride = null; | |||
private FOEventHandler foEventHandlerOverride = null; | |||
private boolean locatorEnabled = true; // true by default (for error messages). | |||
private boolean conserveMemoryPolicy = false; | |||
private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster(); | |||
//TODO Verify that a byte array is the best solution here | |||
@@ -154,7 +154,6 @@ public class FOUserAgent { | |||
} | |||
this.factory = factory; | |||
setBaseURL(factory.getBaseURL()); | |||
setFontBaseURL(factory.getFontManager().getFontBaseURL()); | |||
setTargetResolution(factory.getTargetResolution()); | |||
if (this.getRendererOptions().get("accessibility") == null) { | |||
this.rendererOptions.put("accessibility", Boolean.FALSE); | |||
@@ -351,11 +350,16 @@ public class FOUserAgent { | |||
} | |||
/** | |||
* sets font base URL | |||
* Sets font base URL. | |||
* @param fontBaseUrl font base URL | |||
* @deprecated Use {@link FontManager#setFontBaseURL(String)} instead. | |||
*/ | |||
public void setFontBaseURL(String fontBaseUrl) { | |||
this.fontBase = fontBaseUrl; | |||
try { | |||
getFactory().getFontManager().setFontBaseURL(fontBaseUrl); | |||
} catch (MalformedURLException e) { | |||
throw new IllegalArgumentException(e.getMessage()); | |||
} | |||
} | |||
/** | |||
@@ -490,8 +494,13 @@ public class FOUserAgent { | |||
// ---------------------------------------------- environment-level stuff | |||
// (convenience access to FopFactory methods) | |||
/** @return the font base URL */ | |||
/** | |||
* Returns the font base URL. | |||
* @return the font base URL | |||
* @deprecated Use {@link FontManager#getFontBaseURL()} instead. This method is not used by FOP. | |||
*/ | |||
public String getFontBaseURL() { | |||
String fontBase = getFactory().getFontManager().getFontBaseURL(); | |||
return fontBase != null ? fontBase : getBaseURL(); | |||
} | |||
@@ -622,6 +631,24 @@ public class FOUserAgent { | |||
} | |||
/** | |||
* Check whether memory-conservation is enabled. | |||
* | |||
* @return true if FOP is to conserve as much as possible | |||
*/ | |||
public boolean isConserveMemoryPolicyEnabled() { | |||
return this.conserveMemoryPolicy; | |||
} | |||
/** | |||
* Control whether memory-conservation should be enabled | |||
* | |||
* @param conserveMemoryPolicy the cachingEnabled to set | |||
*/ | |||
public void setConserveMemoryPolicy(boolean conserveMemoryPolicy) { | |||
this.conserveMemoryPolicy = conserveMemoryPolicy; | |||
} | |||
/** | |||
* Check if accessibility is enabled. | |||
* @return true if accessibility is enabled |
@@ -278,9 +278,11 @@ public class FopFactory implements ImageContext { | |||
*/ | |||
public Fop newFop(FOUserAgent userAgent) throws FOPException { | |||
if (userAgent.getRendererOverride() == null | |||
&& userAgent.getFOEventHandlerOverride() == null) { | |||
throw new IllegalStateException("Either the overriding renderer or the overriding" | |||
+ " FOEventHandler must be set when this factory method is used!"); | |||
&& userAgent.getFOEventHandlerOverride() == null | |||
&& userAgent.getDocumentHandlerOverride() == null) { | |||
throw new IllegalStateException("An overriding renderer," | |||
+ " FOEventHandler or IFDocumentHandler must be set on the user agent" | |||
+ " when this factory method is used!"); | |||
} | |||
return newFop(null, userAgent); | |||
} |
@@ -61,6 +61,8 @@ public class FopFactoryConfigurator { | |||
/** Defines the default target resolution (72dpi) for FOP */ | |||
public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi | |||
private static final String PREFER_RENDERER = "prefer-renderer"; | |||
/** logger instance */ | |||
private final Log log = LogFactory.getLog(FopFactoryConfigurator.class); | |||
@@ -182,6 +184,16 @@ public class FopFactoryConfigurator { | |||
} | |||
} | |||
// 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 font manager | |||
FontManager fontManager = factory.getFontManager(); | |||
FontManagerConfigurator fontManagerConfigurator = new FontManagerConfigurator(cfg); |
@@ -124,7 +124,11 @@ public class AreaTreeHandler extends FOEventHandler { | |||
*/ | |||
protected void setupModel(FOUserAgent userAgent, String outputFormat, | |||
OutputStream stream) throws FOPException { | |||
this.model = new RenderPagesModel(userAgent, outputFormat, fontInfo, stream); | |||
if (userAgent.isConserveMemoryPolicyEnabled()) { | |||
this.model = new CachedRenderPagesModel(userAgent, outputFormat, fontInfo, stream); | |||
} else { | |||
this.model = new RenderPagesModel(userAgent, outputFormat, fontInfo, stream); | |||
} | |||
} | |||
/** | |||
@@ -442,7 +446,6 @@ public class AreaTreeHandler extends FOEventHandler { | |||
/** | |||
* Default constructor | |||
* @param areaTreeHandler area tree handler | |||
*/ | |||
protected Statistics() { | |||
this.runtime = Runtime.getRuntime(); |
@@ -21,6 +21,8 @@ package org.apache.fop.area; | |||
import java.awt.Color; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.nio.CharBuffer; | |||
import java.util.List; | |||
import java.util.Map; | |||
@@ -41,6 +43,7 @@ import org.w3c.dom.Document; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.Locator; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
@@ -48,6 +51,7 @@ import org.xml.sax.helpers.DefaultHandler; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.image.loader.ImageException; | |||
import org.apache.xmlgraphics.image.loader.ImageInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.ImageSessionContext; | |||
@@ -68,6 +72,7 @@ import org.apache.fop.area.inline.SpaceArea; | |||
import org.apache.fop.area.inline.TextArea; | |||
import org.apache.fop.area.inline.Viewport; | |||
import org.apache.fop.area.inline.WordArea; | |||
import org.apache.fop.events.ResourceEventProducer; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.ElementMappingRegistry; | |||
import org.apache.fop.fo.expr.PropertyException; | |||
@@ -149,6 +154,7 @@ public class AreaTreeParser { | |||
private Stack delegateStack = new Stack(); | |||
private ContentHandler delegate; | |||
private DOMImplementation domImplementation; | |||
private Locator locator; | |||
public Handler(AreaTreeModel treeModel, FOUserAgent userAgent, | |||
@@ -223,6 +229,15 @@ public class AreaTreeParser { | |||
return (Viewport)findAreaType(Viewport.class); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setDocumentLocator(Locator locator) { | |||
this.locator = locator; | |||
} | |||
private Locator getLocator() { | |||
return this.locator; | |||
} | |||
/** {@inheritDoc} */ | |||
public void startElement(String uri, String localName, String qName, Attributes attributes) | |||
throws SAXException { | |||
@@ -356,6 +371,7 @@ public class AreaTreeParser { | |||
pageSequence.setLanguage(lang); | |||
String country = attributes.getValue("country"); | |||
pageSequence.setCountry(country); | |||
transferForeignObjects(attributes, pageSequence); | |||
areaStack.push(pageSequence); | |||
} | |||
} | |||
@@ -970,9 +986,16 @@ public class AreaTreeParser { | |||
this.currentPageViewport.addExtensionAttachment(attachment); | |||
} | |||
} else { | |||
Object o = areaStack.peek(); | |||
if (o instanceof AreaTreeObject && obj instanceof ExtensionAttachment) { | |||
AreaTreeObject ato = (AreaTreeObject)o; | |||
ExtensionAttachment attachment = (ExtensionAttachment)obj; | |||
ato.addExtensionAttachment(attachment); | |||
} else { | |||
log.warn("Don't know how to handle externally generated object: " + obj); | |||
} | |||
} | |||
} | |||
private void setAreaAttributes(Attributes attributes, Area area) { | |||
area.setIPD(Integer.parseInt(attributes.getValue("ipd"))); | |||
@@ -1048,8 +1071,21 @@ public class AreaTreeParser { | |||
= userAgent.getImageSessionContext(); | |||
ImageInfo info = manager.getImageInfo(uri, sessionContext); | |||
bkg.setImageInfo(info); | |||
} catch (Exception e) { | |||
log.error("Background image not available: " + uri, e); | |||
} catch (ImageException e) { | |||
ResourceEventProducer eventProducer | |||
= ResourceEventProducer.Provider.get( | |||
this.userAgent.getEventBroadcaster()); | |||
eventProducer.imageError(this, uri, e, getLocator()); | |||
} catch (FileNotFoundException fnfe) { | |||
ResourceEventProducer eventProducer | |||
= ResourceEventProducer.Provider.get( | |||
this.userAgent.getEventBroadcaster()); | |||
eventProducer.imageNotFound(this, uri, fnfe, getLocator()); | |||
} catch (IOException ioe) { | |||
ResourceEventProducer eventProducer | |||
= ResourceEventProducer.Provider.get( | |||
this.userAgent.getEventBroadcaster()); | |||
eventProducer.imageIOError(this, uri, ioe, getLocator()); | |||
} | |||
String repeat = attributes.getValue("bkg-repeat"); |
@@ -129,7 +129,7 @@ public class CachedRenderPagesModel extends RenderPagesModel { | |||
try { | |||
// save page to cache | |||
ObjectOutputStream tempstream; | |||
String fname = "fop-page-" + page.toString() + ".ser"; | |||
String fname = "fop-page-" + page.getPageIndex() + ".ser"; | |||
File tempFile = new File(baseDir, fname); | |||
tempFile.deleteOnExit(); | |||
tempstream = new ObjectOutputStream(new BufferedOutputStream( |
@@ -24,7 +24,7 @@ import java.util.List; | |||
/** | |||
* Represents a page sequence in the area tree. | |||
*/ | |||
public class PageSequence { | |||
public class PageSequence extends AreaTreeObject { | |||
private List pages = new java.util.ArrayList(); | |||
private LineArea title; |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.area.inline; | |||
import java.io.Serializable; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.LineArea; | |||
import org.apache.fop.area.Trait; | |||
@@ -35,7 +37,7 @@ public class InlineArea extends Area { | |||
* that can be used in order to re-compute adjustments when a | |||
* page-number or a page-number-citation is resolved | |||
*/ | |||
protected class InlineAdjustingInfo { | |||
protected class InlineAdjustingInfo implements Serializable { | |||
/** stretch of the inline area */ | |||
protected int availableStretch; | |||
/** shrink of the inline area */ |
@@ -110,6 +110,8 @@ public class CommandLineOptions { | |||
private Map renderingOptions = new java.util.HashMap(); | |||
/* target resolution (for the user agent) */ | |||
private int targetResolution = 0; | |||
/* control memory-conservation policy */ | |||
private boolean conserveMemoryPolicy = false; | |||
private FopFactory factory = FopFactory.newInstance(); | |||
private FOUserAgent foUserAgent; | |||
@@ -168,6 +170,7 @@ public class CommandLineOptions { | |||
} | |||
addXSLTParameter("fop-output-format", getOutputFormat()); | |||
addXSLTParameter("fop-version", Version.getVersion()); | |||
foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy); | |||
} else { | |||
return false; | |||
} | |||
@@ -268,6 +271,8 @@ public class CommandLineOptions { | |||
setLogOption("debug", "debug"); | |||
} else if (args[i].equals("-r")) { | |||
factory.setStrictValidation(false); | |||
} else if (args[i].equals("-conserve")) { | |||
conserveMemoryPolicy = true; | |||
} else if (args[i].equals("-dpi")) { | |||
i = i + parseResolution(args, i); | |||
} else if (args[i].equals("-q") || args[i].equals("--quiet")) { | |||
@@ -1134,6 +1139,8 @@ public class CommandLineOptions { | |||
+ " -a enables accessibility features (Tagged PDF etc., default off)\n" | |||
+ " -pdfprofile prof PDF file will be generated with the specified profile\n" | |||
+ " (Examples for prof: PDF/A-1b or PDF/X-3:2003)\n\n" | |||
+ " -conserve Enable memory-conservation policy (trades memory-consumption for disk I/O)" | |||
+ " (Note: currently only influences whether the area tree is serialized.)" | |||
+ " [INPUT] \n" | |||
+ " infile xsl:fo input file (the same as the next) \n" | |||
+ " (use '-' for infile to pipe input from stdin)\n" |
@@ -24,6 +24,8 @@ | |||
<message key="rule.childOfDeclarations">The element must be a child of fo:declarations.</message> | |||
<message key="rule.childOfSPMorDeclarations">The element must be a child of fo:declarations or fo:simple-page-master.</message> | |||
<message key="rule.childOfInstreamForeignObjectorExternalGraphic">The element must be a child of fo:instream-foreign-object or fo:external-graphic.</message> | |||
<message key="rule.childOfPageSequence">The element must be a child of fo:page-sequence.</message> | |||
<message key="rule.childOfPageSequenceOrSPM">The element must be a child of fo:page-sequence or fo:simple-page-master.</message> | |||
<message key="rule.wrapperInvalidChildForParent">An fo:wrapper is only permitted to have children that would be permitted for its parent.</message> | |||
<message key="org.apache.fop.fo.FOValidationEventProducer.tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message> | |||
<message key="org.apache.fop.fo.FOValidationEventProducer.nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message> |
@@ -784,27 +784,27 @@ public interface Constants { | |||
// compound property constants | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_BLOCK_PROGRESSION_DIRECTION = 1 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_CONDITIONALITY = 2 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_INLINE_PROGRESSION_DIRECTION = 3 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_LENGTH = 4 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_MAXIMUM = 5 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_MINIMUM = 6 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_OPTIMUM = 7 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_PRECEDENCE = 8 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_WITHIN_COLUMN = 9 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_WITHIN_LINE = 10 << COMPOUND_SHIFT; | |||
/** Property constant for compund property */ | |||
/** Property constant for compound property */ | |||
int CP_WITHIN_PAGE = 11 << COMPOUND_SHIFT; | |||
// Enumeration constants |
@@ -73,6 +73,7 @@ public class Leader extends InlineLevel { | |||
leaderLength = pList.get(PR_LEADER_LENGTH).getLengthRange(); | |||
leaderPattern = pList.get(PR_LEADER_PATTERN).getEnum(); | |||
leaderPatternWidth = pList.get(PR_LEADER_PATTERN_WIDTH).getLength(); | |||
ruleThickness = pList.get(PR_RULE_THICKNESS).getLength(); | |||
switch(leaderPattern) { | |||
case EN_SPACE: | |||
// use Space | |||
@@ -81,7 +82,6 @@ public class Leader extends InlineLevel { | |||
// the following properties only apply | |||
// for leader-pattern = "rule" | |||
ruleStyle = pList.get(PR_RULE_STYLE).getEnum(); | |||
ruleThickness = pList.get(PR_RULE_THICKNESS).getLength(); | |||
break; | |||
case EN_DOTS: | |||
break; |
@@ -48,7 +48,7 @@ public class PageSequence extends AbstractPageSequence { | |||
// the set of flows includes StaticContent flows also | |||
/** Map of flows to their flow name (flow-name, Flow) */ | |||
private Map flowMap; | |||
private Map/*<String, Flow>*/ flowMap; | |||
/** | |||
* The currentSimplePageMaster is either the page master for the | |||
@@ -96,18 +96,18 @@ public class PageSequence extends AbstractPageSequence { | |||
/** {@inheritDoc} */ | |||
protected void startOfNode() throws FOPException { | |||
super.startOfNode(); | |||
flowMap = new java.util.HashMap(); | |||
flowMap = new java.util.HashMap/*<String, Flow>*/(); | |||
this.simplePageMaster = getRoot().getLayoutMasterSet().getSimplePageMaster(masterReference); | |||
if (this.simplePageMaster == null) { | |||
this.simplePageMaster | |||
= getRoot().getLayoutMasterSet().getSimplePageMaster(masterReference); | |||
if (simplePageMaster == null) { | |||
this.pageSequenceMaster | |||
= getRoot().getLayoutMasterSet().getPageSequenceMaster(masterReference); | |||
if (this.pageSequenceMaster == null) { | |||
= getRoot().getLayoutMasterSet().getPageSequenceMaster(masterReference); | |||
if (pageSequenceMaster == null) { | |||
getFOValidationEventProducer().masterNotFound(this, getName(), | |||
masterReference, getLocator()); | |||
} | |||
} | |||
getFOEventHandler().startPageSequence(this); | |||
} | |||
@@ -170,7 +170,7 @@ public class PageSequence extends AbstractPageSequence { | |||
flowMap.put(((StaticContent)child).getFlowName(), child); | |||
break; | |||
default: | |||
assert false; | |||
super.addChildNode(child); | |||
} | |||
} | |||
@@ -26,6 +26,7 @@ import org.xml.sax.Locator; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.datatypes.FODimension; | |||
import org.apache.fop.datatypes.Numeric; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.PropertyList; | |||
@@ -130,6 +131,24 @@ public abstract class Region extends FObj { | |||
|| name.equals("xsl-footnote-separator")); | |||
} | |||
/** | |||
* Get the page-width context | |||
* @param lengthBase the lengthBase to use for resolving percentages | |||
* @return context for the width of the page-reference-area | |||
*/ | |||
protected PercentBaseContext getPageWidthContext(int lengthBase) { | |||
return layoutMaster.getPageWidthContext(lengthBase); | |||
} | |||
/** | |||
* Get the page-width context | |||
* @param lengthBase the lengthBase to use for resolving percentages | |||
* @return context for the width of the page-reference-area | |||
*/ | |||
protected PercentBaseContext getPageHeightContext(int lengthBase) { | |||
return layoutMaster.getPageHeightContext(lengthBase); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean generatesReferenceAreas() { | |||
return true; |
@@ -26,7 +26,7 @@ import java.awt.Rectangle; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.datatypes.FODimension; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.datatypes.SimplePercentBaseContext; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
/** | |||
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_region-after"> | |||
@@ -48,25 +48,9 @@ public class RegionAfter extends RegionBA { | |||
/* Special rules apply to resolving extent as values are resolved relative | |||
* to the page size and reference orientation. | |||
*/ | |||
SimplePercentBaseContext pageWidthContext; | |||
SimplePercentBaseContext pageHeightContext; | |||
if (spm.getReferenceOrientation() % 180 == 0) { | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageWidth().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageHeight().getValue()); | |||
} else { | |||
// invert width and height since top left are rotated by 90 (cl or ccl) | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageHeight().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageWidth().getValue()); | |||
} | |||
SimplePercentBaseContext neighbourContext; | |||
PercentBaseContext pageWidthContext = getPageWidthContext(LengthBase.CUSTOM_BASE); | |||
PercentBaseContext pageHeightContext = getPageHeightContext(LengthBase.CUSTOM_BASE); | |||
PercentBaseContext neighbourContext; | |||
Rectangle vpRect; | |||
if (spm.getWritingMode() == EN_LR_TB || spm.getWritingMode() == EN_RL_TB) { | |||
neighbourContext = pageWidthContext; |
@@ -27,7 +27,7 @@ import org.apache.fop.datatypes.FODimension; | |||
import org.apache.fop.datatypes.Length; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.datatypes.Numeric; | |||
import org.apache.fop.datatypes.SimplePercentBaseContext; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.PropertyList; | |||
import org.apache.fop.fo.properties.CommonMarginBlock; | |||
@@ -106,24 +106,8 @@ public class RegionBody extends Region { | |||
* Also the values are resolved relative to the page size | |||
* and reference orientation. | |||
*/ | |||
SimplePercentBaseContext pageWidthContext; | |||
SimplePercentBaseContext pageHeightContext; | |||
if (spm.getReferenceOrientation() % 180 == 0) { | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CONTAINING_BLOCK_WIDTH, | |||
spm.getPageWidth().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CONTAINING_BLOCK_WIDTH, | |||
spm.getPageHeight().getValue()); | |||
} else { | |||
// invert width and height since top left are rotated by 90 (cl or ccl) | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CONTAINING_BLOCK_WIDTH, | |||
spm.getPageHeight().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CONTAINING_BLOCK_WIDTH, | |||
spm.getPageWidth().getValue()); | |||
} | |||
PercentBaseContext pageWidthContext = getPageWidthContext(LengthBase.CONTAINING_BLOCK_WIDTH); | |||
PercentBaseContext pageHeightContext = getPageHeightContext(LengthBase.CONTAINING_BLOCK_WIDTH); | |||
int start; | |||
int end; |
@@ -26,7 +26,7 @@ import java.awt.Rectangle; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.datatypes.FODimension; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.datatypes.SimplePercentBaseContext; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
/** | |||
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_region-end"> | |||
@@ -48,25 +48,9 @@ public class RegionEnd extends RegionSE { | |||
/* Special rules apply to resolving extent as values are resolved relative | |||
* to the page size and reference orientation. | |||
*/ | |||
SimplePercentBaseContext pageWidthContext; | |||
SimplePercentBaseContext pageHeightContext; | |||
if (spm.getReferenceOrientation() % 180 == 0) { | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageWidth().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageHeight().getValue()); | |||
} else { | |||
// invert width and height since top left are rotated by 90 (cl or ccl) | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageHeight().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageWidth().getValue()); | |||
} | |||
SimplePercentBaseContext neighbourContext; | |||
PercentBaseContext pageWidthContext = getPageWidthContext(LengthBase.CUSTOM_BASE); | |||
PercentBaseContext pageHeightContext = getPageHeightContext(LengthBase.CUSTOM_BASE); | |||
PercentBaseContext neighbourContext; | |||
Rectangle vpRect; | |||
if (spm.getWritingMode() == EN_LR_TB || spm.getWritingMode() == EN_RL_TB) { | |||
neighbourContext = pageHeightContext; |
@@ -26,7 +26,7 @@ import java.awt.Rectangle; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.datatypes.FODimension; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.datatypes.SimplePercentBaseContext; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
/** | |||
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_region-start"> | |||
@@ -48,25 +48,9 @@ public class RegionStart extends RegionSE { | |||
/* Special rules apply to resolving extent as values are resolved relative | |||
* to the page size and reference orientation. | |||
*/ | |||
SimplePercentBaseContext pageWidthContext; | |||
SimplePercentBaseContext pageHeightContext; | |||
if (spm.getReferenceOrientation() % 180 == 0) { | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageWidth().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageHeight().getValue()); | |||
} else { | |||
// invert width and height since top left are rotated by 90 (cl or ccl) | |||
pageWidthContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageHeight().getValue()); | |||
pageHeightContext = new SimplePercentBaseContext(null, | |||
LengthBase.CUSTOM_BASE, | |||
spm.getPageWidth().getValue()); | |||
} | |||
SimplePercentBaseContext neighbourContext; | |||
PercentBaseContext pageWidthContext = getPageWidthContext(LengthBase.CUSTOM_BASE); | |||
PercentBaseContext pageHeightContext = getPageHeightContext(LengthBase.CUSTOM_BASE); | |||
PercentBaseContext neighbourContext; | |||
Rectangle vpRect; | |||
if (spm.getWritingMode() == EN_LR_TB || spm.getWritingMode() == EN_RL_TB) { | |||
neighbourContext = pageHeightContext; |
@@ -29,6 +29,8 @@ import org.xml.sax.Locator; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.datatypes.Length; | |||
import org.apache.fop.datatypes.Numeric; | |||
import org.apache.fop.datatypes.SimplePercentBaseContext; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.PropertyList; | |||
@@ -194,6 +196,44 @@ public class SimplePageMaster extends FObj { | |||
regions.put(key, region); | |||
} | |||
/** | |||
* Gets the context for the width of the page-reference-area, | |||
* taking into account the reference-orientation. | |||
* | |||
* @param lengthBase the lengthBase to use to resolve percentages | |||
* @return context for the width of the page-reference-area | |||
*/ | |||
protected final PercentBaseContext getPageWidthContext(int lengthBase) { | |||
return (this.referenceOrientation.getValue() % 180 == 0) | |||
? new SimplePercentBaseContext( | |||
null, | |||
lengthBase, | |||
this.getPageWidth().getValue()) | |||
: new SimplePercentBaseContext( | |||
null, | |||
lengthBase, | |||
this.getPageHeight().getValue()); | |||
} | |||
/** | |||
* Gets the context for the height of the page-reference-area, | |||
* taking into account the reference-orientation. | |||
* | |||
* @param lengthBase the lengthBase to use to resolve percentages | |||
* @return the context for the height of the page-reference-area | |||
*/ | |||
protected final PercentBaseContext getPageHeightContext(int lengthBase) { | |||
return (this.referenceOrientation.getValue() % 180 == 0) | |||
? new SimplePercentBaseContext( | |||
null, | |||
lengthBase, | |||
this.getPageHeight().getValue()) | |||
: new SimplePercentBaseContext( | |||
null, | |||
lengthBase, | |||
this.getPageWidth().getValue()); | |||
} | |||
/** | |||
* Returns the region for a given region class. | |||
* @param regionId Constants ID of the FO representing the region |
@@ -650,6 +650,78 @@ public class CommonBorderPaddingBackground { | |||
|| borderInfo[START] != null || borderInfo[END] != null); | |||
} | |||
/** | |||
* Returns the "background-color" property. | |||
* @return the "background-color" property. | |||
*/ | |||
public Color getBackgroundColor() { | |||
return backgroundColor; | |||
} | |||
/** | |||
* Returns the "background-attachment" property. | |||
* @return the "background-attachment" property. | |||
*/ | |||
public int getBackgroundAttachment() { | |||
return backgroundAttachment; | |||
} | |||
/** | |||
* Returns the "background-image" property. | |||
* @return the "background-image" property. | |||
*/ | |||
public String getBackgroundImage() { | |||
return backgroundImage; | |||
} | |||
/** | |||
* Returns the "background-repeat" property. | |||
* @return the "background-repeat" property. | |||
*/ | |||
public int getBackgroundRepeat() { | |||
return backgroundRepeat; | |||
} | |||
/** | |||
* Returns the "background-position-horizontal" property. | |||
* @return the "background-position-horizontal" property. | |||
*/ | |||
public Length getBackgroundPositionHorizontal() { | |||
return backgroundPositionHorizontal; | |||
} | |||
/** | |||
* Returns the "background-position-vertical" property. | |||
* @return the "background-position-vertical" property. | |||
*/ | |||
public Length getBackgroundPositionVertical() { | |||
return backgroundPositionVertical; | |||
} | |||
/** | |||
* Returns the background image info | |||
* @return the background image info | |||
*/ | |||
public ImageInfo getBackgroundImageInfo() { | |||
return backgroundImageInfo; | |||
} | |||
/** | |||
* Returns the border info | |||
* @return the border info | |||
*/ | |||
public BorderInfo[] getBorderInfo() { | |||
return borderInfo; | |||
} | |||
/** | |||
* Returns the padding | |||
* @return the padding | |||
*/ | |||
public CondLengthProperty[] getPadding() { | |||
return padding; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean equals(Object obj) { | |||
if (this == obj) { |
@@ -170,6 +170,16 @@ public final class CommonFont { | |||
return fontWeight.getEnum(); | |||
} | |||
/** @return the "font-size" property. */ | |||
public Length getFontSize() { | |||
return fontSize; | |||
} | |||
/** @return the "font-size-adjust" property. */ | |||
public Numeric getFontSizeAdjust() { | |||
return fontSizeAdjust; | |||
} | |||
/** | |||
* Create and return an array of <code>FontTriplets</code> based on | |||
* the properties stored in the instance variables. |
@@ -0,0 +1,72 @@ | |||
/* | |||
* 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.net.URL; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
/** | |||
* Adds a list of fonts to a given font info list | |||
*/ | |||
public class FontAdder { | |||
private FontEventListener listener; | |||
private FontResolver resolver; | |||
private FontManager manager; | |||
/** | |||
* Main constructor | |||
* @param manager a font manager | |||
* @param resolver a font resolver | |||
* @param listener a font event handler | |||
*/ | |||
public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) { | |||
this.manager = manager; | |||
this.resolver = resolver; | |||
this.listener = listener; | |||
} | |||
/** | |||
* Iterates over font url list adding to font info list | |||
* @param fontURLList font file list | |||
* @param fontInfoList a configured font info list | |||
*/ | |||
public void add(List/*<URL>*/ fontURLList, List/*<EmbedFontInfo>*/ fontInfoList) { | |||
FontCache cache = manager.getFontCache(); | |||
FontInfoFinder finder = new FontInfoFinder(); | |||
finder.setEventListener(listener); | |||
for (Iterator iter = fontURLList.iterator(); iter.hasNext();) { | |||
URL fontUrl = (URL)iter.next(); | |||
EmbedFontInfo[] embedFontInfos = finder.find(fontUrl, resolver, cache); | |||
if (embedFontInfos == null) { | |||
continue; | |||
} | |||
for (int i = 0, c = embedFontInfos.length; i < c; i++) { | |||
EmbedFontInfo fontInfo = embedFontInfos[i]; | |||
if (fontInfo != null) { | |||
fontInfoList.add(fontInfo); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,101 @@ | |||
/* | |||
* 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.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.fop.apps.FOPException; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.util.LogUtil; | |||
import org.apache.xmlgraphics.util.ClasspathResource; | |||
/** | |||
* Detector of operating system and classpath fonts | |||
*/ | |||
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 FontManager fontManager; | |||
private FontAdder fontAdder; | |||
private boolean strict; | |||
/** | |||
* 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. | |||
*/ | |||
public FontDetector(FontManager manager, FontAdder adder, boolean strict) { | |||
this.fontManager = manager; | |||
this.fontAdder = adder; | |||
this.strict = strict; | |||
} | |||
/** | |||
* 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(); | |||
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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,313 @@ | |||
/* | |||
* 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 Log log = LogFactory.getLog(FontInfoConfigurator.class); | |||
private Configuration cfg; | |||
private FontManager fontManager; | |||
private FontResolver fontResolver; | |||
private FontEventListener listener; | |||
private 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 fonts = cfg.getChild("fonts", false); | |||
if (fonts != 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 = (fonts.getChild("auto-detect", false) != null); | |||
if (autodetectFonts) { | |||
FontDetector fontDetector = new FontDetector(fontManager, fontAdder, strict); | |||
fontDetector.detect(fontInfoList); | |||
} | |||
// Add configured directories to FontInfo | |||
addDirectories(fonts, fontAdder, fontInfoList); | |||
// Add configured fonts to FontInfo | |||
FontCache fontCache = fontManager.getFontCache(); | |||
addFonts(fonts, fontCache, fontInfoList); | |||
// Update referenced fonts (fonts which are not to be embedded) | |||
fontManager.updateReferencedFonts(fontInfoList); | |||
// Update font cache if it has changed | |||
if (fontCache != null && fontCache.hasChanged()) { | |||
fontCache.save(); | |||
} | |||
if (log.isDebugEnabled()) { | |||
log.debug("Finished font configuration in " | |||
+ (System.currentTimeMillis() - start) + "ms"); | |||
} | |||
} | |||
} | |||
private void addDirectories(Configuration fontsCfg, | |||
FontAdder fontAdder, List/*<URL>*/ 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); | |||
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; | |||
try { | |||
fontUrl = fontFile.toURI().toURL(); | |||
} catch (MalformedURLException e) { | |||
// Should never happen | |||
log.debug("Malformed Url: " + e.getMessage()); | |||
return null; | |||
} | |||
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); | |||
EncodingMode encodingMode = EncodingMode.valueOf( | |||
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); | |||
EmbedFontInfo embedFontInfo | |||
= new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont); | |||
embedFontInfo.setEncodingMode(encodingMode); | |||
if (fontCache != null) { | |||
if (!fontCache.containsFont(embedFontInfo)) { | |||
fontCache.addFont(embedFontInfo); | |||
} | |||
} | |||
if (log.isDebugEnabled()) { | |||
String embedFile = embedFontInfo.getEmbedFile(); | |||
log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") | |||
+ "metric file " + embedFontInfo.getMetricsFile()); | |||
for (int j = 0; j < tripletList.size(); ++j) { | |||
FontTriplet triplet = (FontTriplet) 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; | |||
} | |||
} |
@@ -20,6 +20,8 @@ | |||
package org.apache.fop.fonts; | |||
import java.net.MalformedURLException; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
@@ -186,4 +188,27 @@ public class FontManager { | |||
public Matcher getReferencedFontsMatcher() { | |||
return this.referencedFontsMatcher; | |||
} | |||
/** | |||
* Updates the referenced font list | |||
* @param fontInfoList a font info list | |||
*/ | |||
public void updateReferencedFonts(List fontInfoList) { | |||
Matcher matcher = getReferencedFontsMatcher(); | |||
if (matcher == null) { | |||
return; //No referenced fonts | |||
} | |||
Iterator iter = fontInfoList.iterator(); | |||
while (iter.hasNext()) { | |||
EmbedFontInfo fontInfo = (EmbedFontInfo)iter.next(); | |||
Iterator triplets = fontInfo.getFontTriplets().iterator(); | |||
while (triplets.hasNext()) { | |||
FontTriplet triplet = (FontTriplet)triplets.next(); | |||
if (matcher.matches(triplet)) { | |||
fontInfo.setEmbedded(false); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -130,7 +130,7 @@ public class FontFileFinder extends DirectoryWalker implements FontFinder { | |||
* @throws IOException io exception | |||
* {@inheritDoc} | |||
*/ | |||
public List find() throws IOException { | |||
public List/*<URL>*/ find() throws IOException { | |||
final FontFinder fontDirFinder; | |||
final String osName = System.getProperty("os.name"); | |||
if (osName.startsWith("Windows")) { | |||
@@ -142,8 +142,8 @@ public class FontFileFinder extends DirectoryWalker implements FontFinder { | |||
fontDirFinder = new UnixFontDirFinder(); | |||
} | |||
} | |||
List fontDirs = fontDirFinder.find(); | |||
List results = new java.util.ArrayList(); | |||
List/*<URL>*/ fontDirs = fontDirFinder.find(); | |||
List/*<URL>*/ results = new java.util.ArrayList/*<URL>*/(); | |||
for (Iterator iter = fontDirs.iterator(); iter.hasNext();) { | |||
final File dir = (File)iter.next(); | |||
super.walk(dir, results); |
@@ -37,6 +37,6 @@ public interface FontFinder { | |||
* @throws IOException | |||
* In case of an I/O problem | |||
*/ | |||
List find() throws IOException; | |||
List/*<URL>*/ find() throws IOException; | |||
} |
@@ -26,7 +26,9 @@ import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.AreaTreeObject; | |||
import org.apache.fop.area.PageViewport; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.FONode; | |||
@@ -266,8 +268,10 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
childLMs = new java.util.ArrayList(10); | |||
} | |||
childLMs.add(lm); | |||
log.trace(this.getClass().getName() | |||
+ ": Adding child LM " + lm.getClass().getName()); | |||
if (log.isTraceEnabled()) { | |||
log.trace(this.getClass().getName() | |||
+ ": Adding child LM " + lm.getClass().getName()); | |||
} | |||
} | |||
/** | |||
@@ -300,6 +304,13 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
return pos; | |||
} | |||
private void verifyNonNullPosition(Position pos) { | |||
if (pos == null || pos.getIndex() < 0) { | |||
throw new IllegalArgumentException( | |||
"Only non-null Positions with an index can be checked"); | |||
} | |||
} | |||
/** | |||
* Indicates whether the given Position is the first area-generating Position of this LM. | |||
* @param pos the Position (must be one with a position index) | |||
@@ -307,9 +318,7 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
*/ | |||
public boolean isFirst(Position pos) { | |||
//log.trace("isFirst() smallestPosNumberChecked=" + smallestPosNumberChecked + " " + pos); | |||
if (pos == null || pos.getIndex() < 0) { | |||
throw new IllegalArgumentException("Only non-null Positions with an index can be checked"); | |||
} | |||
verifyNonNullPosition(pos); | |||
if (pos.getIndex() == this.smallestPosNumberChecked) { | |||
return true; | |||
} else if (pos.getIndex() < this.smallestPosNumberChecked) { | |||
@@ -326,10 +335,7 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
* @return True if it is the last Position | |||
*/ | |||
public boolean isLast(Position pos) { | |||
//log.trace("isLast() lastGenPos=" + lastGeneratedPosition + " " + pos); | |||
if (pos == null || pos.getIndex() < 0) { | |||
throw new IllegalArgumentException("Only non-null Positions with an index can be checked"); | |||
} | |||
verifyNonNullPosition(pos); | |||
return (pos.getIndex() == this.lastGeneratedPosition | |||
&& isFinished()); | |||
} | |||
@@ -338,11 +344,31 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
* Transfers foreign attributes from the formatting object to the area. | |||
* @param targetArea the area to set the attributes on | |||
*/ | |||
protected void transferForeignAttributes(Area targetArea) { | |||
protected void transferForeignAttributes(AreaTreeObject targetArea) { | |||
Map atts = fobj.getForeignAttributes(); | |||
targetArea.setForeignAttributes(atts); | |||
} | |||
/** | |||
* Transfers extension attachments from the formatting object to the area. | |||
* @param targetArea the area to set the extensions on | |||
*/ | |||
protected void transferExtensionAttachments(AreaTreeObject targetArea) { | |||
if (fobj.hasExtensionAttachments()) { | |||
targetArea.setExtensionAttachments(fobj.getExtensionAttachments()); | |||
} | |||
} | |||
/** | |||
* Transfers extensions (foreign attributes and extension attachments) from | |||
* the formatting object to the area. | |||
* @param targetArea the area to set the extensions on | |||
*/ | |||
protected void transferExtensions(AreaTreeObject targetArea) { | |||
transferForeignAttributes(targetArea); | |||
transferExtensionAttachments(targetArea); | |||
} | |||
/** | |||
* Registers the FO's markers on the current PageViewport | |||
* |
@@ -167,6 +167,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
addChildToArea(childArea, getCurrentArea()); | |||
} | |||
/** {@inheritDoc} */ | |||
protected void notifyEndOfLayout() { | |||
super.notifyEndOfLayout(); | |||
// Free memory of the area tree | |||
//this.parentArea = null; | |||
} | |||
/** | |||
* Force current area to be added to parent area. | |||
*/ | |||
@@ -340,18 +347,19 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
return returnList; | |||
} else { | |||
if (prevLM != null) { | |||
// there is a block handled by prevLM | |||
// before the one handled by curLM | |||
addInBetweenBreak(contentList, context, childLC); | |||
} | |||
if (returnedList == null || returnedList.isEmpty()) { | |||
//Avoid NoSuchElementException below (happens with empty blocks) | |||
continue; | |||
} | |||
if (prevLM != null | |||
&& !ElementListUtils.startsWithForcedBreak(returnedList)) { | |||
// there is a block handled by prevLM before the one | |||
// handled by curLM, and the one handled | |||
// by the current LM does not begin with a break | |||
addInBetweenBreak(contentList, context, childLC); | |||
} | |||
contentList.addAll(returnedList); | |||
if (((ListElement) ListUtil.getLast(returnedList)) | |||
.isForcedBreak()) { | |||
if (ElementListUtils.endsWithForcedBreak(returnedList)) { | |||
// a descendant of this block has break-after | |||
if (curLM.isFinished() && !hasNextChildLM()) { | |||
forcedBreakAfterLast = (BreakElement) ListUtil | |||
@@ -486,7 +494,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
// ? "penalty" : (lastElement.isGlue() ? "glue" : "box" ))); | |||
/*LF*/ //log.debug(" position e' " + lastElement.getPosition().getClass().getName()); | |||
/*LF*/ //log.debug(" " + (bpUnit > 0 ? "unit" : "")); | |||
Position innerPosition = ((NonLeafPosition) lastElement.getPosition()).getPosition(); | |||
Position innerPosition = lastElement.getPosition().getPosition(); | |||
if (innerPosition == null && lastElement.isGlue()) { | |||
// this adjustment applies to space-before or space-after of this block | |||
@@ -536,7 +544,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
/*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> chiamata passata"); | |||
return ((BlockLevelLayoutManager)storedPenalty.getLayoutManager()) | |||
.negotiateBPDAdjustment(storedPenalty.getW(), | |||
(KnuthElement)storedPenalty); | |||
storedPenalty); | |||
} else { | |||
// the original penalty has width = 0 | |||
// the adjustment involves only the spaces before and after | |||
@@ -787,12 +795,12 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
returnList.add(new KnuthGlue(0, 0, 0, | |||
SPACE_AFTER_ADJUSTMENT, | |||
new NonLeafPosition(this, null), | |||
(!spaceAfterIsConditional) ? false : true)); | |||
spaceAfterIsConditional)); | |||
} else { | |||
returnList.add(new KnuthGlue(adjustedSpaceAfter, 0, 0, | |||
SPACE_AFTER_ADJUSTMENT, | |||
new NonLeafPosition(this, null), | |||
(!spaceAfterIsConditional) ? false : true)); | |||
spaceAfterIsConditional)); | |||
} | |||
if (!spaceAfterIsConditional) { | |||
returnList.add(new KnuthBox(0, | |||
@@ -1201,8 +1209,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
totalLength.add(new MinOptMax(element.getW())); | |||
//log.debug("box " + element.getW()); | |||
} else if (element.isGlue()) { | |||
totalLength.min -= ((KnuthGlue) element).getZ(); | |||
totalLength.max += ((KnuthGlue) element).getY(); | |||
totalLength.min -= element.getZ(); | |||
totalLength.max += element.getY(); | |||
//leafValue = ((LeafPosition) element.getPosition()).getLeafPos(); | |||
//log.debug("glue " + element.getW() + " + " | |||
// + ((KnuthGlue) element).getY() + " - " + ((KnuthGlue) element).getZ()); | |||
@@ -1239,10 +1247,10 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
lengthAfterBreak.subtract(new MinOptMax(element.getW())); | |||
bPrevIsBox = true; | |||
} else if (element.isGlue()) { | |||
lengthBeforeBreak.min -= ((KnuthGlue) element).getZ(); | |||
lengthAfterBreak.min += ((KnuthGlue) element).getZ(); | |||
lengthBeforeBreak.max += ((KnuthGlue) element).getY(); | |||
lengthAfterBreak.max -= ((KnuthGlue) element).getY(); | |||
lengthBeforeBreak.min -= element.getZ(); | |||
lengthAfterBreak.min += element.getZ(); | |||
lengthBeforeBreak.max += element.getY(); | |||
lengthAfterBreak.max -= element.getY(); | |||
bPrevIsBox = false; | |||
} else { | |||
lengthBeforeBreak.add(new MinOptMax(element.getW())); | |||
@@ -1250,7 +1258,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
} | |||
// create the new elements | |||
if (element.isPenalty() && ((KnuthPenalty) element).getP() < KnuthElement.INFINITE | |||
if (element.isPenalty() && element.getP() < KnuthElement.INFINITE | |||
|| element.isGlue() && bPrevIsBox | |||
|| !oldListIterator.hasNext()) { | |||
// suppress elements after the breaking point | |||
@@ -1260,8 +1268,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
iStepsForward++; | |||
if (el.isGlue()) { | |||
// suppressed glue | |||
lengthAfterBreak.min += ((KnuthGlue) el).getZ(); | |||
lengthAfterBreak.max -= ((KnuthGlue) el).getY(); | |||
lengthAfterBreak.min += el.getZ(); | |||
lengthAfterBreak.max -= el.getY(); | |||
} else if (el.isPenalty()) { | |||
// suppressed penalty, do nothing | |||
} else { | |||
@@ -1281,8 +1289,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
for (int i = 0; i < iStepsForward; i++) { | |||
KnuthElement el = (KnuthElement) oldListIterator.previous(); | |||
if (el.isGlue()) { | |||
lengthAfterBreak.min -= ((KnuthGlue) el).getZ(); | |||
lengthAfterBreak.max += ((KnuthGlue) el).getY(); | |||
lengthAfterBreak.min -= el.getZ(); | |||
lengthAfterBreak.max += el.getY(); | |||
} | |||
} | |||
@@ -193,6 +193,15 @@ public final class ElementListUtils { | |||
return last.isForcedBreak(); | |||
} | |||
/** | |||
* Indicates whether the given element list starts with a forced break. | |||
* @param elems the element list | |||
* @return true if the list starts with a forced break | |||
*/ | |||
public static boolean startsWithForcedBreak(List elems) { | |||
return !elems.isEmpty() && ((ListElement) elems.get(0)).isForcedBreak(); | |||
} | |||
/** | |||
* Indicates whether the given element list ends with a penalty with a non-infinite penalty | |||
* value. | |||
@@ -229,4 +238,4 @@ public final class ElementListUtils { | |||
return prevBreak; | |||
} | |||
} | |||
} |
@@ -105,7 +105,9 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan | |||
Dimension intrinsicSize = info.getSize().getDimensionMpt(); | |||
ImageLayout layout = new ImageLayout(getExternalDocument(), this, intrinsicSize); | |||
areaTreeHandler.getAreaTreeModel().startPageSequence(new PageSequence(null)); | |||
PageSequence pageSequence = new PageSequence(null); | |||
transferExtensions(pageSequence); | |||
areaTreeHandler.getAreaTreeModel().startPageSequence(pageSequence); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Starting layout"); | |||
} |
@@ -88,8 +88,8 @@ public class FlowLayoutManager extends BlockStackingLayoutManager | |||
.getDisableColumnBalancing(); | |||
} else if (curLM instanceof BlockContainerLayoutManager) { | |||
span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan(); | |||
disableColumnBalancing = ((BlockContainerLayoutManager) curLM) | |||
.getBlockContainerFO().getDisableColumnBalancing(); | |||
disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO() | |||
.getDisableColumnBalancing(); | |||
} | |||
int currentSpan = context.getCurrentSpan(); | |||
@@ -130,24 +130,23 @@ public class FlowLayoutManager extends BlockStackingLayoutManager | |||
returnList.addAll(returnedList); | |||
SpaceResolver.resolveElementList(returnList); | |||
return returnList; | |||
} else { | |||
if (returnList.size() > 0) { | |||
} else if (returnedList.size() > 0) { | |||
if (returnList.size() > 0 | |||
&& !ElementListUtils.startsWithForcedBreak(returnedList)) { | |||
addInBetweenBreak(returnList, context, childLC); | |||
} | |||
if (returnedList.size() > 0) { | |||
returnList.addAll(returnedList); | |||
if (ElementListUtils.endsWithForcedBreak(returnList)) { | |||
if (curLM.isFinished() && !hasNextChildLM()) { | |||
//If the layout manager is finished at this point, the pending | |||
//marks become irrelevant. | |||
childLC.clearPendingMarks(); | |||
//setFinished(true); | |||
break; | |||
} | |||
// a descendant of this flow has break-after | |||
SpaceResolver.resolveElementList(returnList); | |||
return returnList; | |||
returnList.addAll(returnedList); | |||
if (ElementListUtils.endsWithForcedBreak(returnList)) { | |||
if (curLM.isFinished() && !hasNextChildLM()) { | |||
//If the layout manager is finished at this point, the pending | |||
//marks become irrelevant. | |||
childLC.clearPendingMarks(); | |||
//setFinished(true); | |||
break; | |||
} | |||
// a descendant of this flow has break-after | |||
SpaceResolver.resolveElementList(returnList); | |||
return returnList; | |||
} | |||
} | |||
@@ -273,7 +273,8 @@ public class PageBreaker extends AbstractBreaker { | |||
//Get page break from which we restart | |||
PageBreakPosition pbp = (PageBreakPosition) | |||
alg.getPageBreaks().get(restartPoint - 1); | |||
newStartPos = pbp.getLeafPos(); | |||
//Set starting position to the first element *after* the page-break | |||
newStartPos = pbp.getLeafPos() + 1; | |||
//Handle page break right here to avoid any side-effects | |||
if (newStartPos > 0) { | |||
handleBreakTrait(Constants.EN_PAGE); | |||
@@ -306,16 +307,15 @@ public class PageBreaker extends AbstractBreaker { | |||
1, true, BreakingAlgorithm.ALL_BREAKS); | |||
AbstractBreaker.log.debug("restart: iOptPageCount= " + iOptPageCount | |||
+ " pageBreaks.size()= " + algRestart.getPageBreaks().size()); | |||
//Make sure we only add the areas we haven't added already | |||
effectiveList.ignoreAtStart = newStartPos; | |||
boolean replaceLastPage | |||
= iOptPageCount <= pslm.getCurrentPV().getBodyRegion().getColumnCount(); | |||
if (replaceLastPage) { | |||
//Replace last page | |||
pslm.setCurrentPage(pageProvider.getPage(false, currentPageNum)); | |||
//Make sure we only add the areas we haven't added already | |||
effectiveList.ignoreAtStart = newStartPos; | |||
addAreas(algRestart, iOptPageCount, originalList, effectiveList); | |||
} else { | |||
effectiveList.ignoreAtStart = newStartPos; | |||
addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList); | |||
//Add blank last page | |||
pageProvider.setLastPageIndex(currentPageNum + 1); | |||
@@ -430,8 +430,8 @@ public class PageBreaker extends AbstractBreaker { | |||
childLC); | |||
} | |||
// set the offset from the top margin | |||
Footnote parentArea = (Footnote) pslm.getCurrentPV().getBodyRegion().getFootnote(); | |||
int topOffset = (int) pslm.getCurrentPV().getBodyRegion().getBPD() - parentArea.getBPD(); | |||
Footnote parentArea = pslm.getCurrentPV().getBodyRegion().getFootnote(); | |||
int topOffset = pslm.getCurrentPV().getBodyRegion().getBPD() - parentArea.getBPD(); | |||
if (separatorArea != null) { | |||
topOffset -= separatorArea.getBPD(); | |||
} | |||
@@ -451,7 +451,7 @@ public class PageBreaker extends AbstractBreaker { | |||
/** {@inheritDoc} */ | |||
protected void observeElementList(List elementList) { | |||
ElementListObserver.observe(elementList, "breaker", | |||
((PageSequence)pslm.getFObj()).getId()); | |||
pslm.getFObj().getId()); | |||
} | |||
/** |
@@ -92,6 +92,7 @@ public class PageSequenceLayoutManager extends AbstractPageSequenceLayoutManager | |||
AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel(); | |||
org.apache.fop.area.PageSequence pageSequenceAreaObject | |||
= new org.apache.fop.area.PageSequence(title); | |||
transferExtensions(pageSequenceAreaObject); | |||
pageSequenceAreaObject.setLanguage(getPageSequence().getLanguage()); | |||
pageSequenceAreaObject.setCountry(getPageSequence().getCountry()); | |||
areaTreeModel.startPageSequence(pageSequenceAreaObject); |
@@ -121,16 +121,15 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
= new org.apache.fop.area.inline.Leader(); | |||
leader.setRuleStyle(fobj.getRuleStyle()); | |||
leader.setRuleThickness(fobj.getRuleThickness().getValue(this)); | |||
leader.setBPD(fobj.getRuleThickness().getValue(this)); | |||
leaderArea = leader; | |||
} else { | |||
leaderArea = new Space(); | |||
leaderArea.setBPD(1); | |||
} | |||
leaderArea.setBPD(fobj.getRuleThickness().getValue(this)); | |||
leaderArea.addTrait(Trait.COLOR, fobj.getColor()); | |||
} else if (fobj.getLeaderPattern() == EN_SPACE) { | |||
leaderArea = new Space(); | |||
leaderArea.setBPD(1); | |||
leaderArea.setBPD(fobj.getRuleThickness().getValue(this)); | |||
} else if (fobj.getLeaderPattern() == EN_DOTS) { | |||
TextArea t = new TextArea(); | |||
char dot = '.'; // userAgent.getLeaderDotCharacter(); | |||
@@ -198,7 +197,7 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager { | |||
} else { | |||
//Content collapsed to nothing, so use a space | |||
leaderArea = new Space(); | |||
leaderArea.setBPD(1); | |||
leaderArea.setBPD(fobj.getRuleThickness().getValue(this)); | |||
} | |||
} | |||
TraitSetter.setProducerID(leaderArea, fobj.getId()); |
@@ -201,8 +201,6 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
p.setP(0); | |||
} | |||
notifyEndOfLayout(); | |||
setFinished(true); | |||
return returnList; | |||
} | |||
@@ -427,6 +425,8 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
flush(); | |||
curBlockArea = null; | |||
notifyEndOfLayout(); | |||
} | |||
/** Adds background areas for the column, body and row, if any. */ |
@@ -33,9 +33,8 @@ public abstract class AbstractPDFFontStream extends AbstractPDFStream { | |||
} | |||
/** {@inheritDoc} */ | |||
protected void setupFilterList() { | |||
addDefaultFilter(PDFFilterList.FONT_FILTER); | |||
super.setupFilterList(); | |||
protected String getDefaultFilterName() { | |||
return PDFFilterList.FONT_FILTER; | |||
} | |||
} |
@@ -47,21 +47,23 @@ public abstract class AbstractPDFStream extends PDFDictionary { | |||
* from outside. | |||
*/ | |||
protected void setupFilterList() { | |||
addDefaultFilter(PDFFilterList.DEFAULT_FILTER); | |||
if (!getFilterList().isInitialized()) { | |||
getFilterList().addDefaultFilters( | |||
getDocumentSafely().getFilterMap(), | |||
getDefaultFilterName()); | |||
} | |||
prepareImplicitFilters(); | |||
getDocument().applyEncryption(this); | |||
} | |||
/** | |||
* Adds the default filter to the filter list if the filter list hasn't been initialized, yet. | |||
* @param filterName the name of the default filter to use | |||
* Returns the name of a suitable filter for this PDF object. | |||
* | |||
* @return the default filter | |||
* @see PDFFilterList | |||
*/ | |||
protected void addDefaultFilter(String filterName) { | |||
if (!getFilterList().isInitialized()) { | |||
getFilterList().addDefaultFilters( | |||
getDocumentSafely().getFilterMap(), | |||
filterName); | |||
} | |||
protected String getDefaultFilterName() { | |||
return PDFFilterList.DEFAULT_FILTER; | |||
} | |||
/** |
@@ -159,14 +159,11 @@ public class PDFImageXObject extends PDFXObject { | |||
} | |||
/** | |||
* This sets up the default filters for XObjects. It uses the PDFImage | |||
* instance to determine what default filters to apply. | |||
* {@inheritDoc} | |||
* This class uses the PDFImage instance to determine the default filter. | |||
*/ | |||
protected void setupFilterList() { | |||
addDefaultFilter(pdfimage.getFilterHint()); | |||
super.setupFilterList(); | |||
protected String getDefaultFilterName() { | |||
return pdfimage.getFilterHint(); | |||
} | |||
} |
@@ -59,9 +59,8 @@ public class PDFMetadata extends PDFStream { | |||
} | |||
/** {@inheritDoc} */ | |||
protected void setupFilterList() { | |||
addDefaultFilter(PDFFilterList.METADATA_FILTER); | |||
super.setupFilterList(); | |||
protected String getDefaultFilterName() { | |||
return PDFFilterList.METADATA_FILTER; | |||
} | |||
/** |
@@ -0,0 +1,89 @@ | |||
/* | |||
* 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.render; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
* An abstract configurator | |||
*/ | |||
public abstract class AbstractConfigurator { | |||
/** logger instance */ | |||
protected static Log log = LogFactory.getLog(AbstractConfigurator.class); | |||
private static final String MIME = "mime"; | |||
/** fop factory configuration */ | |||
protected FOUserAgent userAgent = null; | |||
/** | |||
* Default constructor | |||
* @param userAgent user agent | |||
*/ | |||
public AbstractConfigurator(FOUserAgent userAgent) { | |||
super(); | |||
this.userAgent = userAgent; | |||
} | |||
/** | |||
* Returns the configuration subtree for a specific renderer. | |||
* @param mimeType the MIME type of the renderer | |||
* @return the requested configuration subtree, null if there's no configuration | |||
*/ | |||
protected Configuration getConfig(String mimeType) { | |||
Configuration cfg = userAgent.getFactory().getUserConfig(); | |||
if (cfg == null) { | |||
if (log.isDebugEnabled()) { | |||
log.debug("userconfig is null"); | |||
} | |||
return null; | |||
} | |||
Configuration userConfig = null; | |||
String type = getType(); | |||
Configuration[] cfgs | |||
= cfg.getChild(type + "s").getChildren(type); | |||
for (int i = 0; i < cfgs.length; ++i) { | |||
Configuration child = cfgs[i]; | |||
try { | |||
if (child.getAttribute(MIME).equals(mimeType)) { | |||
userConfig = child; | |||
break; | |||
} | |||
} catch (ConfigurationException e) { | |||
// silently pass over configurations without mime type | |||
} | |||
} | |||
log.debug((userConfig == null ? "No u" : "U") | |||
+ "ser configuration found for MIME type " + mimeType); | |||
return userConfig; | |||
} | |||
/** | |||
* Returns the configurator type | |||
* @return the configurator type | |||
*/ | |||
public abstract String getType(); | |||
} |
@@ -29,8 +29,11 @@ import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.w3c.dom.Document; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.area.Area; | |||
@@ -66,7 +69,6 @@ import org.apache.fop.area.inline.WordArea; | |||
import org.apache.fop.events.ResourceEventProducer; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.w3c.dom.Document; | |||
/** | |||
* Abstract base class for all renderers. The Abstract renderer does all the | |||
@@ -648,7 +650,6 @@ public abstract class AbstractRenderer | |||
* @param space the space to render | |||
*/ | |||
protected void renderInlineSpace(Space space) { | |||
space.setBPD(0); | |||
renderInlineAreaBackAndBorders(space); | |||
// an inline space moves the inline progression position | |||
// for the current block by the width or height of the space | |||
@@ -830,15 +831,6 @@ public abstract class AbstractRenderer | |||
} | |||
} | |||
/** | |||
* Get the MIME type of the renderer. | |||
* | |||
* @return The MIME type of the renderer | |||
*/ | |||
public String getMimeType() { | |||
return null; | |||
} | |||
/** | |||
* Converts a millipoint-based transformation matrix to points. | |||
* @param at a millipoint-based transformation matrix |
@@ -20,9 +20,6 @@ | |||
package org.apache.fop.render; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
@@ -30,21 +27,16 @@ import org.apache.fop.apps.FOUserAgent; | |||
* Abstract base classes for renderer-related configurator classes. This class basically just | |||
* provides an accessor to the specific renderer configuration object. | |||
*/ | |||
public abstract class AbstractRendererConfigurator { | |||
/** logger instance */ | |||
protected static Log log = LogFactory.getLog(AbstractRendererConfigurator.class); | |||
/** fop factory configuration */ | |||
protected FOUserAgent userAgent = null; | |||
public abstract class AbstractRendererConfigurator extends AbstractConfigurator { | |||
private static final String TYPE = "renderer"; | |||
/** | |||
* Default constructor | |||
* @param userAgent user agent | |||
*/ | |||
public AbstractRendererConfigurator(FOUserAgent userAgent) { | |||
super(); | |||
this.userAgent = userAgent; | |||
super(userAgent); | |||
} | |||
/** | |||
@@ -53,16 +45,8 @@ public abstract class AbstractRendererConfigurator { | |||
* @return the requested configuration subtree, null if there's no configuration | |||
*/ | |||
protected Configuration getRendererConfig(Renderer renderer) { | |||
String mimeType = renderer.getMimeType(); | |||
if (mimeType == null) { | |||
if (log.isInfoEnabled()) { | |||
log.info("renderer mimeType is null"); | |||
return super.getConfig(renderer.getMimeType()); | |||
} | |||
return null; | |||
} | |||
return getRendererConfig(mimeType); | |||
} | |||
/** | |||
* Returns the configuration subtree for a specific renderer. | |||
@@ -70,31 +54,14 @@ public abstract class AbstractRendererConfigurator { | |||
* @return the requested configuration subtree, null if there's no configuration | |||
*/ | |||
protected Configuration getRendererConfig(String mimeType) { | |||
Configuration cfg = userAgent.getFactory().getUserConfig(); | |||
if (cfg == null) { | |||
if (log.isDebugEnabled()) { | |||
log.debug("userconfig is null"); | |||
return super.getConfig(mimeType); | |||
} | |||
return null; | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public String getType() { | |||
return TYPE; | |||
} | |||
Configuration userRendererConfig = null; | |||
Configuration[] cfgs | |||
= cfg.getChild("renderers").getChildren("renderer"); | |||
for (int i = 0; i < cfgs.length; ++i) { | |||
Configuration child = cfgs[i]; | |||
try { | |||
if (child.getAttribute("mime").equals(mimeType)) { | |||
userRendererConfig = child; | |||
break; | |||
} | |||
} catch (ConfigurationException e) { | |||
// silently pass over configurations without mime type | |||
} | |||
} | |||
log.debug((userRendererConfig == null ? "No u" : "U") | |||
+ "ser configuration found for MIME type " + mimeType); | |||
return userRendererConfig; | |||
} | |||
} |
@@ -41,7 +41,7 @@ public class DefaultFontResolver implements FontResolver { | |||
/** {@inheritDoc} */ | |||
public Source resolve(String href) { | |||
return userAgent.resolveURI(href, userAgent.getFontBaseURL()); | |||
return userAgent.resolveURI(href, userAgent.getFactory().getFontManager().getFontBaseURL()); | |||
} | |||
} |
@@ -19,46 +19,26 @@ | |||
package org.apache.fop.render; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.Iterator; | |||
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.FileUtils; | |||
import org.apache.commons.io.IOUtils; | |||
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.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.fonts.CustomFontCollection; | |||
import org.apache.fop.fonts.EmbedFontInfo; | |||
import org.apache.fop.fonts.EncodingMode; | |||
import org.apache.fop.fonts.FontCache; | |||
import org.apache.fop.fonts.FontCollection; | |||
import org.apache.fop.fonts.FontEventAdapter; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontInfoConfigurator; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.fonts.FontUtil; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
import org.apache.fop.fonts.base14.Base14FontCollection; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* Base Print renderer configurator (mostly handles font configuration) | |||
@@ -95,7 +75,7 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
FontEventListener listener = new FontEventAdapter( | |||
renderer.getUserAgent().getEventBroadcaster()); | |||
List embedFontInfoList = buildFontList(cfg, fontResolver, listener); | |||
List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontList(cfg, fontResolver, listener); | |||
printRenderer.addFontList(embedFontInfoList); | |||
} | |||
@@ -107,7 +87,7 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
* @return the list of {@code EmbedFontInfo} objects | |||
* @throws FOPException if an error occurs while processing the configuration | |||
*/ | |||
protected List buildFontList(Configuration cfg, FontResolver fontResolver, | |||
protected List/*<EmbedFontInfo>*/ buildFontList(Configuration cfg, FontResolver fontResolver, | |||
FontEventListener listener) throws FOPException { | |||
FopFactory factory = userAgent.getFactory(); | |||
FontManager fontManager = factory.getFontManager(); | |||
@@ -117,346 +97,15 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
} | |||
boolean strict = factory.validateUserConfigStrictly(); | |||
FontCache fontCache = fontManager.getFontCache(); | |||
List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg, | |||
fontResolver, strict, fontManager, listener); | |||
if (fontCache != null && fontCache.hasChanged()) { | |||
fontCache.save(); | |||
} | |||
return embedFontInfoList; | |||
} | |||
/** | |||
* Builds a list of EmbedFontInfo objects for use with the setup() method. | |||
* | |||
* @param cfg Configuration object | |||
* @param fontResolver the FontResolver to use | |||
* @param strict true if an Exception should be thrown if an error is found. | |||
* @param fontManager the font manager | |||
* @param listener a font event listener | |||
* @return a List of EmbedFontInfo objects. | |||
* @throws FOPException If an error occurs while processing the configuration | |||
*/ | |||
public static List/*<EmbedFontInfo>*/ buildFontListFromConfiguration(Configuration cfg, | |||
FontResolver fontResolver, | |||
boolean strict, FontManager fontManager, | |||
FontEventListener listener) throws FOPException { | |||
FontCache fontCache = fontManager.getFontCache(); | |||
String fontBaseURL = fontManager.getFontBaseURL(); | |||
List/*<EmbedFontInfo>*/ fontInfoList | |||
= new java.util.ArrayList/*<EmbedFontInfo>*/(); | |||
Configuration fonts = cfg.getChild("fonts", false); | |||
if (fonts != null) { | |||
long start = 0; | |||
if (log.isDebugEnabled()) { | |||
log.debug("Starting font configuration..."); | |||
start = System.currentTimeMillis(); | |||
} | |||
// native o/s search (autodetect) configuration | |||
boolean autodetectFonts = (fonts.getChild("auto-detect", false) != null); | |||
if (autodetectFonts) { | |||
// search in font base if it is defined and | |||
// is a directory but don't recurse | |||
FontFileFinder fontFileFinder = new FontFileFinder(); | |||
if (fontBaseURL != null) { | |||
try { | |||
File fontBase = FileUtils.toFile(new URL(fontBaseURL)); | |||
if (fontBase != null) { | |||
//Can only use the font base URL if it's a file URL | |||
addFontInfoListFromFileList( | |||
fontFileFinder.find(fontBase.getAbsolutePath()), | |||
fontInfoList, | |||
fontResolver, | |||
fontCache, | |||
listener | |||
); | |||
} | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// native o/s font directory finder | |||
try { | |||
addFontInfoListFromFileList( | |||
fontFileFinder.find(), | |||
fontInfoList, | |||
fontResolver, | |||
fontCache, | |||
listener | |||
); | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
// load fonts from classpath | |||
addFontInfoListFromFileList(ClasspathResource.getInstance() | |||
.listResourcesOfMimeType("application/x-font"), | |||
fontInfoList, fontResolver, fontCache, listener); | |||
addFontInfoListFromFileList( | |||
ClasspathResource.getInstance() | |||
.listResourcesOfMimeType( | |||
"application/x-font-truetype"), | |||
fontInfoList, fontResolver, fontCache, listener); | |||
} | |||
// directory (multiple font) configuration | |||
Configuration[] directories = fonts.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; | |||
} | |||
FontFileFinder fontFileFinder = new FontFileFinder(recursive ? -1 : 1); | |||
try { | |||
addFontInfoListFromFileList( | |||
fontFileFinder.find(directory), | |||
fontInfoList, | |||
fontResolver, | |||
fontCache, | |||
listener | |||
); | |||
} catch (IOException e) { | |||
LogUtil.handleException(log, e, strict); | |||
} | |||
} | |||
// font file (singular) configuration | |||
Configuration[] font = fonts.getChildren("font"); | |||
for (int i = 0; i < font.length; i++) { | |||
EmbedFontInfo embedFontInfo = getFontInfoFromConfiguration( | |||
font[i], fontResolver, strict, fontCache, listener); | |||
if (embedFontInfo != null) { | |||
fontInfoList.add(embedFontInfo); | |||
} | |||
} | |||
// Update referenced fonts (fonts which are not to be embedded) | |||
updateReferencedFonts(fontInfoList, fontManager.getReferencedFontsMatcher()); | |||
if (log.isDebugEnabled()) { | |||
log.debug("Finished font configuration in " | |||
+ (System.currentTimeMillis() - start) + "ms"); | |||
} | |||
} | |||
//Read font configuration | |||
FontInfoConfigurator fontInfoConfigurator | |||
= new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); | |||
List/*<EmbedFontInfo>*/ fontInfoList = new java.util.ArrayList/*<EmbedFontInfo>*/(); | |||
fontInfoConfigurator.configure(fontInfoList); | |||
return fontInfoList; | |||
} | |||
private static void updateReferencedFonts(List fontInfoList, FontTriplet.Matcher matcher) { | |||
if (matcher == null) { | |||
return; //No referenced fonts | |||
} | |||
Iterator iter = fontInfoList.iterator(); | |||
while (iter.hasNext()) { | |||
EmbedFontInfo fontInfo = (EmbedFontInfo)iter.next(); | |||
Iterator triplets = fontInfo.getFontTriplets().iterator(); | |||
while (triplets.hasNext()) { | |||
FontTriplet triplet = (FontTriplet)triplets.next(); | |||
if (matcher.matches(triplet)) { | |||
fontInfo.setEmbedded(false); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Iterates over font file list adding font info to list | |||
* @param fontFileList font file list | |||
* @param embedFontInfoList a configured font info list | |||
* @param resolver font resolver | |||
*/ | |||
private static void addFontInfoListFromFileList( | |||
List fontFileList, List/*<EmbedFontInfo>*/ embedFontInfoList, | |||
FontResolver resolver, FontCache fontCache, FontEventListener listener) { | |||
for (Iterator iter = fontFileList.iterator(); iter.hasNext();) { | |||
URL fontUrl = (URL)iter.next(); | |||
// parse font to ascertain font info | |||
FontInfoFinder finder = new FontInfoFinder(); | |||
finder.setEventListener(listener); | |||
//EmbedFontInfo fontInfo = finder.find(fontUrl, resolver, fontCache); | |||
//List<EmbedFontInfo> embedFontInfoList = finder.find(fontUrl, resolver, fontCache); | |||
EmbedFontInfo[] embedFontInfos = finder.find(fontUrl, resolver, fontCache); | |||
if (embedFontInfos == null) { | |||
continue; | |||
} | |||
for (int i = 0, c = embedFontInfos.length; i < c; i++) { | |||
EmbedFontInfo fontInfo = embedFontInfos[i]; | |||
if (fontInfo != null) { | |||
embedFontInfoList.add(fontInfo); | |||
} | |||
} | |||
} | |||
} | |||
private static void closeSource(Source src) { | |||
if (src instanceof StreamSource) { | |||
StreamSource streamSource = (StreamSource)src; | |||
IOUtils.closeQuietly(streamSource.getInputStream()); | |||
IOUtils.closeQuietly(streamSource.getReader()); | |||
} | |||
} | |||
/** | |||
* Creates a new FontTriplet given a triple Configuration | |||
* | |||
* @param tripletCfg a triplet configuration | |||
* @param strict use strict validation | |||
* @return a font triplet font key | |||
* @throws FOPException thrown if a FOP exception occurs | |||
*/ | |||
private static FontTriplet getFontTripletFromConfiguration( | |||
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 a font info from a font node Configuration definition | |||
* | |||
* @param fontCfg Configuration object (font node) | |||
* @param fontResolver font resolver used to resolve font | |||
* @param strict validate configuration strictly | |||
* @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 | |||
*/ | |||
private static EmbedFontInfo getFontInfoFromConfiguration( | |||
Configuration fontCfg, FontResolver fontResolver, boolean strict, | |||
FontCache fontCache, FontEventListener listener) | |||
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; | |||
try { | |||
fontUrl = fontFile.toURI().toURL(); | |||
} catch (MalformedURLException e) { | |||
// Should never happen | |||
log.debug("Malformed Url: " + e.getMessage()); | |||
return null; | |||
} | |||
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 = getFontTripletFromConfiguration(tripletCfg[j], strict); | |||
tripletList.add(fontTriplet); | |||
} | |||
boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); | |||
EncodingMode encodingMode = EncodingMode.valueOf( | |||
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); | |||
EmbedFontInfo embedFontInfo | |||
= new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont); | |||
embedFontInfo.setEncodingMode(encodingMode); | |||
if (fontCache != null) { | |||
if (!fontCache.containsFont(embedFontInfo)) { | |||
fontCache.addFont(embedFontInfo); | |||
} | |||
} | |||
if (log.isDebugEnabled()) { | |||
String embedFile = embedFontInfo.getEmbedFile(); | |||
log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") | |||
+ "metric file " + embedFontInfo.getMetricsFile()); | |||
for (int j = 0; j < tripletList.size(); ++j) { | |||
FontTriplet triplet = (FontTriplet) tripletList.get(j); | |||
log.debug(" Font triplet " | |||
+ triplet.getName() + ", " | |||
+ triplet.getStyle() + ", " | |||
+ triplet.getWeight()); | |||
} | |||
} | |||
return embedFontInfo; | |||
} | |||
// ---=== IFDocumentHandler configuration ===--- | |||
/** {@inheritDoc} */ | |||
@@ -485,5 +134,4 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
new FontCollection[fontCollections.size()])); | |||
documentHandler.setFontInfo(fontInfo); | |||
} | |||
} |
@@ -51,6 +51,8 @@ public class RendererFactory { | |||
private Map eventHandlerMakerMapping = new java.util.HashMap(); | |||
private Map documentHandlerMakerMapping = new java.util.HashMap(); | |||
private boolean rendererPreferred = false; | |||
/** | |||
* Main constructor. | |||
*/ | |||
@@ -60,6 +62,26 @@ public class RendererFactory { | |||
discoverDocumentHandlers(); | |||
} | |||
/** | |||
* Controls whether a {@link Renderer} is preferred over a {@link IFDocumentHandler} if | |||
* both are available for the same MIME type. | |||
* @param value true to prefer the {@link Renderer}, | |||
* false to prefer the {@link IFDocumentHandler}. | |||
*/ | |||
public void setRendererPreferred(boolean value) { | |||
this.rendererPreferred = value; | |||
} | |||
/** | |||
* Indicates whether a {@link Renderer} is preferred over a {@link IFDocumentHandler} if | |||
* both are available for the same MIME type. | |||
* @return true if the {@link Renderer} is preferred, | |||
* false if the {@link IFDocumentHandler} is preferred. | |||
*/ | |||
public boolean isRendererPreferred() { | |||
return this.rendererPreferred; | |||
} | |||
/** | |||
* Add a new RendererMaker. If another maker has already been registered for a | |||
* particular MIME type, this call overwrites the existing one. | |||
@@ -236,27 +258,54 @@ public class RendererFactory { | |||
} else if (userAgent.getRendererOverride() != null) { | |||
return userAgent.getRendererOverride(); | |||
} else { | |||
AbstractRendererMaker maker = getRendererMaker(outputFormat); | |||
if (maker != null) { | |||
Renderer rend = maker.makeRenderer(userAgent); | |||
rend.setUserAgent(userAgent); | |||
RendererConfigurator configurator = maker.getConfigurator(userAgent); | |||
if (configurator != null) { | |||
configurator.configure(rend); | |||
Renderer renderer; | |||
if (isRendererPreferred()) { | |||
//Try renderer first | |||
renderer = tryRendererMaker(userAgent, outputFormat); | |||
if (renderer == null) { | |||
renderer = tryIFDocumentHandlerMaker(userAgent, outputFormat); | |||
} | |||
return rend; | |||
} else { | |||
AbstractIFDocumentHandlerMaker documentHandlerMaker | |||
= getDocumentHandlerMaker(outputFormat); | |||
if (documentHandlerMaker != null) { | |||
IFDocumentHandler documentHandler = createDocumentHandler( | |||
userAgent, outputFormat); | |||
return createRendererForDocumentHandler(documentHandler); | |||
} else { | |||
throw new UnsupportedOperationException( | |||
"No renderer for the requested format available: " + outputFormat); | |||
//Try document handler first | |||
renderer = tryIFDocumentHandlerMaker(userAgent, outputFormat); | |||
if (renderer == null) { | |||
renderer = tryRendererMaker(userAgent, outputFormat); | |||
} | |||
} | |||
if (renderer == null) { | |||
throw new UnsupportedOperationException( | |||
"No renderer for the requested format available: " + outputFormat); | |||
} | |||
return renderer; | |||
} | |||
} | |||
private Renderer tryIFDocumentHandlerMaker(FOUserAgent userAgent, String outputFormat) | |||
throws FOPException { | |||
AbstractIFDocumentHandlerMaker documentHandlerMaker | |||
= getDocumentHandlerMaker(outputFormat); | |||
if (documentHandlerMaker != null) { | |||
IFDocumentHandler documentHandler = createDocumentHandler( | |||
userAgent, outputFormat); | |||
return createRendererForDocumentHandler(documentHandler); | |||
} else { | |||
return null; | |||
} | |||
} | |||
private Renderer tryRendererMaker(FOUserAgent userAgent, String outputFormat) | |||
throws FOPException { | |||
AbstractRendererMaker maker = getRendererMaker(outputFormat); | |||
if (maker != null) { | |||
Renderer rend = maker.makeRenderer(userAgent); | |||
rend.setUserAgent(userAgent); | |||
RendererConfigurator configurator = maker.getConfigurator(userAgent); | |||
if (configurator != null) { | |||
configurator.configure(rend); | |||
} | |||
return rend; | |||
} else { | |||
return null; | |||
} | |||
} | |||
@@ -327,6 +376,9 @@ public class RendererFactory { | |||
*/ | |||
public IFDocumentHandler createDocumentHandler(FOUserAgent userAgent, String outputFormat) | |||
throws FOPException { | |||
if (userAgent.getDocumentHandlerOverride() != null) { | |||
return userAgent.getDocumentHandlerOverride(); | |||
} | |||
AbstractIFDocumentHandlerMaker maker = getDocumentHandlerMaker(outputFormat); | |||
if (maker == null) { | |||
throw new UnsupportedOperationException( |
@@ -38,9 +38,9 @@ import org.apache.fop.fonts.FontEventAdapter; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | |||
import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap; | |||
import org.apache.fop.render.afp.extensions.AFPPageSetup; | |||
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFPainter; | |||
@@ -70,7 +70,11 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
private Map/*<String,String>*/pageSegmentMap | |||
= new java.util.HashMap/*<String,String>*/(); | |||
private boolean inPageHeader; | |||
private static final int LOC_ELSEWHERE = 0; | |||
private static final int LOC_FOLLOWING_PAGE_SEQUENCE = 1; | |||
private static final int LOC_IN_PAGE_HEADER = 2; | |||
private int location = LOC_ELSEWHERE; | |||
/** | |||
* Default constructor. | |||
@@ -91,11 +95,6 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
return MimeConstants.MIME_AFP; | |||
} | |||
/** {@inheritDoc} */ | |||
public void setContext(IFContext context) { | |||
super.setContext(context); | |||
} | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandlerConfigurator getConfigurator() { | |||
return new AFPRendererConfigurator(getUserAgent()); | |||
@@ -164,6 +163,7 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
} catch (IOException ioe) { | |||
throw new IFException("I/O error in startPageSequence()", ioe); | |||
} | |||
this.location = LOC_FOLLOWING_PAGE_SEQUENCE; | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -186,6 +186,7 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
/** {@inheritDoc} */ | |||
public void startPage(int index, String name, String pageMasterName, Dimension size) | |||
throws IFException { | |||
this.location = LOC_ELSEWHERE; | |||
paintingState.clear(); | |||
pageSegmentMap.clear(); | |||
@@ -208,12 +209,12 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
/** {@inheritDoc} */ | |||
public void startPageHeader() throws IFException { | |||
super.startPageHeader(); | |||
this.inPageHeader = true; | |||
this.location = LOC_IN_PAGE_HEADER; | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageHeader() throws IFException { | |||
this.inPageHeader = false; | |||
this.location = LOC_ELSEWHERE; | |||
super.endPageHeader(); | |||
} | |||
@@ -244,30 +245,49 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
public void handleExtensionObject(Object extension) throws IFException { | |||
if (extension instanceof AFPPageSetup) { | |||
AFPPageSetup aps = (AFPPageSetup)extension; | |||
if (!inPageHeader) { | |||
throw new IFException( | |||
"AFP page setup extension encountered outside the page header: " + aps, null); | |||
} | |||
String element = aps.getElementName(); | |||
if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) { | |||
String overlay = aps.getName(); | |||
if (overlay != null) { | |||
dataStream.createIncludePageOverlay(overlay); | |||
if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(element)) { | |||
if (this.location != LOC_IN_PAGE_HEADER | |||
&& this.location != LOC_FOLLOWING_PAGE_SEQUENCE) { | |||
throw new IFException( | |||
"TLE extension must be in the page header or between page-sequence" | |||
+ " and the first page: " + aps, null); | |||
} | |||
} else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(element)) { | |||
String name = aps.getName(); | |||
String source = aps.getValue(); | |||
pageSegmentMap.put(source, name); | |||
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(element)) { | |||
String name = aps.getName(); | |||
String value = aps.getValue(); | |||
dataStream.createTagLogicalElement(name, value); | |||
} else if (AFPElementMapping.NO_OPERATION.equals(element)) { | |||
String content = aps.getContent(); | |||
if (content != null) { | |||
dataStream.createNoOperation(content); | |||
} else { | |||
if (this.location != LOC_IN_PAGE_HEADER) { | |||
throw new IFException( | |||
"AFP page setup extension encountered outside the page header: " + aps, null); | |||
} | |||
if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) { | |||
String overlay = aps.getName(); | |||
if (overlay != null) { | |||
dataStream.createIncludePageOverlay(overlay); | |||
} | |||
} else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(element)) { | |||
String name = aps.getName(); | |||
String source = aps.getValue(); | |||
pageSegmentMap.put(source, name); | |||
} else if (AFPElementMapping.NO_OPERATION.equals(element)) { | |||
String content = aps.getContent(); | |||
if (content != null) { | |||
dataStream.createNoOperation(content); | |||
} | |||
} | |||
} | |||
} else if (extension instanceof AFPInvokeMediumMap) { | |||
if (this.location != LOC_FOLLOWING_PAGE_SEQUENCE) { | |||
throw new IFException( | |||
"AFP IMM extension must be between page-sequence and the first page: " | |||
+ extension, null); | |||
} | |||
AFPInvokeMediumMap imm = (AFPInvokeMediumMap)extension; | |||
String mediumMap = imm.getName(); | |||
if (mediumMap != null) { | |||
dataStream.createInvokeMediumMap(mediumMap); | |||
} | |||
} | |||
} | |||
@@ -30,9 +30,8 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
*/ | |||
public class AFPDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { | |||
//TODO Revert to normal MIME after stabilization! | |||
private static final String[] MIMES = new String[] | |||
{MimeConstants.MIME_AFP + ";mode=painter"}; | |||
{MimeConstants.MIME_AFP}; | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { |
@@ -49,6 +49,7 @@ import org.apache.fop.afp.modca.PresentationTextObject; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.afp.ptoca.PtocaBuilder; | |||
import org.apache.fop.afp.ptoca.PtocaProducer; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.fonts.Font; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontTriplet; | |||
@@ -342,12 +343,13 @@ public class AFPPainter extends AbstractIFPainter { | |||
try { | |||
//Embed fonts (char sets and code pages) | |||
//TODO This should be moved to a place where it has less performance impact | |||
if (charSet.getPath() != null) { | |||
if (charSet.getResourceAccessor() != null) { | |||
ResourceAccessor accessor = charSet.getResourceAccessor(); | |||
documentHandler.getResourceManager().createIncludedResource( | |||
charSet.getName(), charSet.getPath(), | |||
charSet.getName(), accessor, | |||
ResourceObject.TYPE_FONT_CHARACTER_SET); | |||
documentHandler.getResourceManager().createIncludedResource( | |||
charSet.getCodePage(), charSet.getPath(), | |||
charSet.getCodePage(), accessor, | |||
ResourceObject.TYPE_CODE_PAGE); | |||
} | |||
} catch (IOException ioe) { |
@@ -63,8 +63,8 @@ import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.area.CTM; | |||
import org.apache.fop.area.LineArea; | |||
import org.apache.fop.area.OffDocumentItem; | |||
import org.apache.fop.area.PageSequence; | |||
import org.apache.fop.area.PageViewport; | |||
import org.apache.fop.area.Trait; | |||
import org.apache.fop.area.inline.Image; | |||
@@ -80,6 +80,7 @@ import org.apache.fop.render.AbstractPathOrientedRenderer; | |||
import org.apache.fop.render.Graphics2DAdapter; | |||
import org.apache.fop.render.RendererContext; | |||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | |||
import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap; | |||
import org.apache.fop.render.afp.extensions.AFPPageSetup; | |||
/** | |||
@@ -213,12 +214,31 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageSequence(LineArea seqTitle) { | |||
public void startPageSequence(PageSequence pageSequence) { | |||
super.startPageSequence(pageSequence); | |||
try { | |||
dataStream.startPageGroup(); | |||
} catch (IOException e) { | |||
log.error(e.getMessage()); | |||
} | |||
if (pageSequence.hasExtensionAttachments()) { | |||
for (Iterator iter = pageSequence.getExtensionAttachments().iterator(); | |||
iter.hasNext();) { | |||
ExtensionAttachment attachment = (ExtensionAttachment)iter.next(); | |||
if (attachment instanceof AFPInvokeMediumMap) { | |||
AFPInvokeMediumMap imm = (AFPInvokeMediumMap)attachment; | |||
String mediumMap = imm.getName(); | |||
if (mediumMap != null) { | |||
dataStream.createInvokeMediumMap(mediumMap); | |||
} | |||
} else if (attachment instanceof AFPPageSetup) { | |||
AFPPageSetup aps = (AFPPageSetup)attachment; | |||
String name = aps.getName(); | |||
String value = aps.getValue(); | |||
dataStream.createTagLogicalElement(name, value); | |||
} | |||
} | |||
} | |||
} | |||
/** {@inheritDoc} */ |
@@ -20,6 +20,8 @@ | |||
package org.apache.fop.render.afp; | |||
import java.io.File; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.List; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
@@ -33,6 +35,8 @@ import org.apache.fop.afp.fonts.CharacterSet; | |||
import org.apache.fop.afp.fonts.FopCharacterSet; | |||
import org.apache.fop.afp.fonts.OutlineFont; | |||
import org.apache.fop.afp.fonts.RasterFont; | |||
import org.apache.fop.afp.util.DefaultFOPResourceAccessor; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fonts.FontCollection; | |||
@@ -85,7 +89,29 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
log.error("Mandatory font configuration element '<afp-font...' is missing"); | |||
return null; | |||
} | |||
String path = afpFontCfg.getAttribute("path", fontPath); | |||
URI baseURI = null; | |||
String uri = afpFontCfg.getAttribute("base-uri", fontPath); | |||
if (uri == null) { | |||
//Fallback for old attribute which only supports local filenames | |||
String path = afpFontCfg.getAttribute("path", fontPath); | |||
if (path != null) { | |||
File f = new File(path); | |||
baseURI = f.toURI(); | |||
} | |||
} else { | |||
try { | |||
baseURI = new URI(uri); | |||
} catch (URISyntaxException e) { | |||
log.error("Invalid URI: " + e.getMessage()); | |||
return null; | |||
} | |||
} | |||
ResourceAccessor accessor = new DefaultFOPResourceAccessor( | |||
this.userAgent, | |||
this.userAgent.getFactory().getFontManager().getFontBaseURL(), | |||
baseURI); | |||
String type = afpFontCfg.getAttribute("type"); | |||
if (type == null) { | |||
log.error("Mandatory afp-font configuration attribute 'type=' is missing"); | |||
@@ -147,7 +173,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
} | |||
} else { | |||
font.addCharacterSet(size, new CharacterSet( | |||
codepage, encoding, characterset, path)); | |||
codepage, encoding, characterset, accessor)); | |||
} | |||
} | |||
return new AFPFontInfo(font, tripletList); | |||
@@ -180,7 +206,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator | |||
log.error(msg); | |||
} | |||
} else { | |||
characterSet = new CharacterSet(codepage, encoding, characterset, path); | |||
characterSet = new CharacterSet(codepage, encoding, characterset, accessor); | |||
} | |||
// Create a new font object | |||
OutlineFont font = new OutlineFont(name, characterSet); |
@@ -33,12 +33,6 @@ import org.apache.fop.fo.FONode; | |||
*/ | |||
public class AFPElementMapping extends ElementMapping { | |||
/** page element */ | |||
public static final String PAGE = "page"; | |||
/** page group element */ | |||
// public static final String PAGE_GROUP = "page-group"; | |||
/** tag logical element */ | |||
public static final String TAG_LOGICAL_ELEMENT = "tag-logical-element"; | |||
@@ -51,8 +45,8 @@ public class AFPElementMapping extends ElementMapping { | |||
/** NOP */ | |||
public static final String NO_OPERATION = "no-operation"; | |||
/** resource information (name, level, dest) */ | |||
// public static final String RESOURCE_INFO = "resource-info"; | |||
/** IMM: Invoke Medium Map (on fo:page-sequence) */ | |||
public static final String INVOKE_MEDIUM_MAP = "invoke-medium-map"; | |||
/** | |||
* The namespace used for AFP extensions | |||
@@ -77,11 +71,6 @@ public class AFPElementMapping extends ElementMapping { | |||
if (foObjs == null) { | |||
super.foObjs = new java.util.HashMap(); | |||
foObjs.put(PAGE, new AFPPageSetupMaker()); | |||
// foObjs.put( | |||
// PAGE_GROUP, | |||
// new AFPPageGroupMaker() | |||
// ); | |||
foObjs.put( | |||
TAG_LOGICAL_ELEMENT, | |||
new AFPTagLogicalElementMaker()); | |||
@@ -94,51 +83,40 @@ public class AFPElementMapping extends ElementMapping { | |||
foObjs.put( | |||
NO_OPERATION, | |||
new AFPNoOperationMaker()); | |||
// foObjs.put( | |||
// RESOURCE_INFO, | |||
// new AFPResourceInfoMaker()); | |||
} | |||
} | |||
static class AFPPageSetupMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPPageSetupElement(parent); | |||
foObjs.put( | |||
INVOKE_MEDIUM_MAP, | |||
new AFPInvokeMediumMapMaker()); | |||
} | |||
} | |||
static class AFPIncludePageOverlayMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPElement(parent, INCLUDE_PAGE_OVERLAY); | |||
return new AFPPageSetupElement(parent, INCLUDE_PAGE_OVERLAY); | |||
} | |||
} | |||
static class AFPIncludePageSegmentMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPElement(parent, INCLUDE_PAGE_SEGMENT); | |||
return new AFPPageSetupElement(parent, INCLUDE_PAGE_SEGMENT); | |||
} | |||
} | |||
static class AFPTagLogicalElementMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPElement(parent, TAG_LOGICAL_ELEMENT); | |||
return new AFPPageSetupElement(parent, TAG_LOGICAL_ELEMENT); | |||
} | |||
} | |||
static class AFPNoOperationMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPElement(parent, NO_OPERATION); | |||
return new AFPPageSetupElement(parent, NO_OPERATION); | |||
} | |||
} | |||
static class AFPInvokeMediumMapMaker extends ElementMapping.Maker { | |||
public FONode make(FONode parent) { | |||
return new AFPInvokeMediumMapElement(parent); | |||
} | |||
} | |||
// static class AFPResourceInfoMaker extends ElementMapping.Maker { | |||
// public FONode make(FONode parent) { | |||
// return new AFPResourceInfoElement(parent); | |||
// } | |||
// } | |||
// static class AFPPageGroupMaker extends ElementMapping.Maker { | |||
// public FONode make(FONode parent) { | |||
// return new AFPElement(parent, PAGE_GROUP); | |||
// } | |||
// } | |||
} |
@@ -5,9 +5,9 @@ | |||
* 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. | |||
@@ -21,45 +21,37 @@ package org.apache.fop.render.afp.extensions; | |||
import java.io.Serializable; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
import org.apache.xmlgraphics.util.XMLizable; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
/** | |||
* This is the pass-through value object for the AFP extension. | |||
*/ | |||
public abstract class AFPExtensionAttachment | |||
implements ExtensionAttachment, Serializable, XMLizable { | |||
private static final long serialVersionUID = 7190606822558332901L; | |||
/** The category URI for this extension attachment. */ | |||
public static final String CATEGORY = "apache:fop:extensions:afp"; | |||
/** name attribute */ | |||
protected static final String ATT_NAME = "name"; | |||
/** | |||
* the extension element name | |||
*/ | |||
protected String elementName; | |||
/** | |||
* the extension content | |||
*/ | |||
protected String content; | |||
/** | |||
* the extension name attribute | |||
*/ | |||
protected String name; | |||
/** | |||
* the extension value attribute | |||
*/ | |||
protected String value; | |||
/** | |||
* Default constructor. | |||
* | |||
* | |||
* @param elementName the name of the afp extension attachment, may be null | |||
*/ | |||
public AFPExtensionAttachment(String elementName) { | |||
@@ -91,65 +83,9 @@ public abstract class AFPExtensionAttachment | |||
this.name = name; | |||
} | |||
/** | |||
* @return the value | |||
*/ | |||
public String getValue() { | |||
return value; | |||
} | |||
/** | |||
* Sets the value | |||
* @param source The value name to set. | |||
*/ | |||
public void setValue(String source) { | |||
this.value = source; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getCategory() { | |||
return CATEGORY; | |||
} | |||
/** | |||
* @return the data | |||
*/ | |||
public String getContent() { | |||
return content; | |||
} | |||
/** | |||
* Sets the data | |||
* @param content The byte data to set. | |||
*/ | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
/** | |||
* name attribute | |||
*/ | |||
protected static final String ATT_NAME = "name"; | |||
/** | |||
* value attribute | |||
*/ | |||
protected static final String ATT_VALUE = "value"; | |||
/** {@inheritDoc} */ | |||
public void toSAX(ContentHandler handler) throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
if (name != null && name.length() > 0) { | |||
atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); | |||
} | |||
if (value != null && value.length() > 0) { | |||
atts.addAttribute(null, ATT_VALUE, ATT_VALUE, "CDATA", value); | |||
} | |||
handler.startElement(CATEGORY, elementName, elementName, atts); | |||
if (content != null && content.length() > 0) { | |||
char[] chars = content.toCharArray(); | |||
handler.characters(chars, 0, chars.length); | |||
} | |||
handler.endElement(CATEGORY, elementName, elementName); | |||
} | |||
} |
@@ -19,13 +19,15 @@ | |||
package org.apache.fop.render.afp.extensions; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.util.ContentHandlerFactory; | |||
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
/** | |||
* ContentHandler (parser) for restoring AFPExtension objects from XML. | |||
@@ -39,7 +41,7 @@ public class AFPExtensionHandler extends DefaultHandler | |||
private StringBuffer content = new StringBuffer(); | |||
private Attributes lastAttributes; | |||
private AFPPageSetup returnedObject; | |||
private AFPExtensionAttachment returnedObject; | |||
private ObjectBuiltListener listener; | |||
/** {@inheritDoc} */ | |||
@@ -53,8 +55,7 @@ public class AFPExtensionHandler extends DefaultHandler | |||
|| localName.equals(AFPElementMapping.TAG_LOGICAL_ELEMENT) | |||
|| localName.equals(AFPElementMapping.INCLUDE_PAGE_OVERLAY) | |||
|| localName.equals(AFPElementMapping.INCLUDE_PAGE_SEGMENT) | |||
|| localName.equals(AFPElementMapping.PAGE) | |||
/*|| localName.equals(AFPElementMapping.PAGE_GROUP)*/) { | |||
|| localName.equals(AFPElementMapping.INVOKE_MEDIUM_MAP)) { | |||
//handled in endElement | |||
} else { | |||
handled = false; | |||
@@ -74,17 +75,24 @@ public class AFPExtensionHandler extends DefaultHandler | |||
/** {@inheritDoc} */ | |||
public void endElement(String uri, String localName, String qName) throws SAXException { | |||
if (AFPPageSetup.CATEGORY.equals(uri)) { | |||
this.returnedObject = new AFPPageSetup(localName); | |||
AFPPageSetup pageSetupExtn = null; | |||
if (localName.equals(AFPElementMapping.INVOKE_MEDIUM_MAP)) { | |||
this.returnedObject = new AFPInvokeMediumMap(); | |||
} | |||
else { | |||
pageSetupExtn = new AFPPageSetup(localName); | |||
this.returnedObject = pageSetupExtn; | |||
} | |||
String name = lastAttributes.getValue("name"); | |||
if (name != null) { | |||
returnedObject.setName(name); | |||
} | |||
String value = lastAttributes.getValue("value"); | |||
if (value != null) { | |||
returnedObject.setValue(value); | |||
if (value != null && pageSetupExtn != null) { | |||
pageSetupExtn.setValue(value); | |||
} | |||
if (content.length() > 0) { | |||
returnedObject.setContent(content.toString()); | |||
if (content.length() > 0 && pageSetupExtn != null) { | |||
pageSetupExtn.setContent(content.toString()); | |||
content.setLength(0); //Reset text buffer (see characters()) | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* 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.render.afp.extensions; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
/** | |||
* This is the pass-through value object for the AFP extension. | |||
*/ | |||
public class AFPInvokeMediumMap extends AFPExtensionAttachment { | |||
private static final long serialVersionUID = -7493160084509249309L; | |||
/** | |||
* Default constructor. | |||
*/ | |||
public AFPInvokeMediumMap() { | |||
super(AFPElementMapping.INVOKE_MEDIUM_MAP); | |||
} | |||
/** {@inheritDoc} */ | |||
public void toSAX(ContentHandler handler) throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
if (name != null && name.length() > 0) { | |||
atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); | |||
} | |||
handler.startElement(CATEGORY, elementName, elementName, atts); | |||
handler.endElement(CATEGORY, elementName, elementName); | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
return "AFPInvokeMediumMap(name=" + getName() + ")"; | |||
} | |||
} |
@@ -22,37 +22,34 @@ package org.apache.fop.render.afp.extensions; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.ValidationException; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
/** | |||
* This class extends the org.apache.fop.extensions.ExtensionObj class. The | |||
* object faciliates extraction of elements from formatted objects based on | |||
* the static list as defined in the AFPElementMapping implementation. | |||
* <p/> | |||
* This class represents an AFP-specific extension element to embed Invoke Medium Map (IMM) | |||
* fields at the beginning of a page group. The element is optional and expected as a direct child | |||
* of an fo:page-sequence. | |||
*/ | |||
public class AFPElement extends AbstractAFPExtensionObject { | |||
public class AFPInvokeMediumMapElement extends AbstractAFPExtensionObject { | |||
/** | |||
* Constructs an AFP object (called by Maker). | |||
* | |||
* Constructs the AFP extension object (called by Maker). | |||
* @param parent the parent formatting object | |||
* @param name the name of the afp element | |||
*/ | |||
public AFPElement(FONode parent, String name) { | |||
super(parent, name); | |||
public AFPInvokeMediumMapElement(FONode parent) { | |||
super(parent, AFPElementMapping.INVOKE_MEDIUM_MAP); | |||
} | |||
/** {@inheritDoc} */ | |||
protected void startOfNode() throws FOPException { | |||
super.startOfNode(); | |||
if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) { | |||
throw new ValidationException(getName() + " must be a child of fo:simple-page-master."); | |||
if (parent.getNameId() != Constants.FO_PAGE_SEQUENCE) { | |||
invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), | |||
"rule.childOfPageSequence"); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
/** {@inheritDoc} */ | |||
protected ExtensionAttachment instantiateExtensionAttachment() { | |||
return new AFPPageSetup(getLocalName()); | |||
return new AFPInvokeMediumMap(); | |||
} | |||
} |
@@ -19,11 +19,28 @@ | |||
package org.apache.fop.render.afp.extensions; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
/** | |||
* This is the pass-through value object for the AFP extension. | |||
*/ | |||
public class AFPPageSetup extends AFPExtensionAttachment { | |||
/** value attribute */ | |||
protected static final String ATT_VALUE = "value"; | |||
/** | |||
* the extension content | |||
*/ | |||
protected String content; | |||
/** | |||
* the extension value attribute | |||
*/ | |||
protected String value; | |||
/** | |||
* Default constructor. | |||
* | |||
@@ -36,8 +53,55 @@ public class AFPPageSetup extends AFPExtensionAttachment { | |||
private static final long serialVersionUID = -549941295384013190L; | |||
/** | |||
* {@inheritDoc} | |||
* Returns the value of the extension. | |||
* @return the value | |||
*/ | |||
public String getValue() { | |||
return value; | |||
} | |||
/** | |||
* Sets the value | |||
* @param source The value name to set. | |||
*/ | |||
public void setValue(String source) { | |||
this.value = source; | |||
} | |||
/** | |||
* Returns the content of the extension. | |||
* @return the data | |||
*/ | |||
public String getContent() { | |||
return content; | |||
} | |||
/** | |||
* Sets the data | |||
* @param content The byte data to set. | |||
*/ | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
/** {@inheritDoc} */ | |||
public void toSAX(ContentHandler handler) throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
if (name != null && name.length() > 0) { | |||
atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); | |||
} | |||
if (value != null && value.length() > 0) { | |||
atts.addAttribute(null, ATT_VALUE, ATT_VALUE, "CDATA", value); | |||
} | |||
handler.startElement(CATEGORY, elementName, elementName, atts); | |||
if (content != null && content.length() > 0) { | |||
char[] chars = content.toCharArray(); | |||
handler.characters(chars, 0, chars.length); | |||
} | |||
handler.endElement(CATEGORY, elementName, elementName); | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
return "AFPPageSetup(element-name=" + getElementName() | |||
+ " name=" + getName() + " value=" + getValue() + ")"; |
@@ -19,37 +19,91 @@ | |||
package org.apache.fop.render.afp.extensions; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.Locator; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.ValidationException; | |||
import org.apache.fop.fo.PropertyList; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
/** | |||
* Extension element for afp:ps-page-setup-code. | |||
* This class extends the org.apache.fop.extensions.ExtensionObj class. The | |||
* object faciliates extraction of elements from formatted objects based on | |||
* the static list as defined in the AFPElementMapping implementation. | |||
* <p/> | |||
*/ | |||
public class AFPPageSetupElement extends AbstractAFPExtensionObject { | |||
/** | |||
* Main constructor | |||
* @param parent parent FO node | |||
* Constructs an AFP object (called by Maker). | |||
* | |||
* @param parent the parent formatting object | |||
* @param name the name of the afp element | |||
*/ | |||
public AFPPageSetupElement(FONode parent) { | |||
super(parent, "page"); | |||
public AFPPageSetupElement(FONode parent, String name) { | |||
super(parent, name); | |||
} | |||
private AFPPageSetup getPageSetupAttachment() { | |||
return (AFPPageSetup)getExtensionAttachment(); | |||
} | |||
/** {@inheritDoc} */ | |||
protected void startOfNode() throws FOPException { | |||
super.startOfNode(); | |||
if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) { | |||
throw new ValidationException(getName() + " must be a child of fo:simple-page-master."); | |||
if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(getLocalName())) { | |||
if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER | |||
&& parent.getNameId() != Constants.FO_PAGE_SEQUENCE) { | |||
invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), | |||
"rule.childOfPageSequenceOrSPM"); | |||
} | |||
} else { | |||
if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) { | |||
invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), | |||
"rule.childOfSPM"); | |||
} | |||
} | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
protected void characters(char[] data, int start, int length, | |||
PropertyList pList, Locator locator) throws FOPException { | |||
StringBuffer sb = new StringBuffer(); | |||
AFPPageSetup pageSetup = getPageSetupAttachment(); | |||
if (pageSetup.getContent() != null) { | |||
sb.append(pageSetup.getContent()); | |||
} | |||
sb.append(data, start, length); | |||
pageSetup.setContent(sb.toString()); | |||
} | |||
/** {@inheritDoc} */ | |||
public void processNode(String elementName, Locator locator, | |||
Attributes attlist, PropertyList propertyList) | |||
throws FOPException { | |||
super.processNode(elementName, locator, attlist, propertyList); | |||
AFPPageSetup pageSetup = getPageSetupAttachment(); | |||
if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(elementName)) { | |||
String attr = attlist.getValue("src"); | |||
if (attr != null && attr.length() > 0) { | |||
pageSetup.setValue(attr); | |||
} else { | |||
throw new FOPException(elementName + " must have a src attribute."); | |||
} | |||
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(elementName)) { | |||
String attr = attlist.getValue("value"); | |||
if (attr != null && attr.length() > 0) { | |||
pageSetup.setValue(attr); | |||
} else { | |||
throw new FOPException(elementName + " must have a value attribute."); | |||
} | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
protected ExtensionAttachment instantiateExtensionAttachment() { | |||
return new AFPPageSetup(this.name); | |||
return new AFPPageSetup(getLocalName()); | |||
} | |||
} |
@@ -54,9 +54,7 @@ public abstract class AbstractAFPExtensionObject extends FONode { | |||
this.name = name; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
protected void validateChildNode(Locator loc, String nsURI, String localName) | |||
throws ValidationException { | |||
if (FO_URI.equals(nsURI)) { | |||
@@ -64,32 +62,17 @@ public abstract class AbstractAFPExtensionObject extends FONode { | |||
} | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
protected void characters(char[] data, int start, int length, | |||
PropertyList pList, Locator locator) throws FOPException { | |||
((AFPExtensionAttachment)getExtensionAttachment()).setContent( | |||
new String(data, start, length)); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public String getNamespaceURI() { | |||
return AFPElementMapping.NAMESPACE; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public String getNormalNamespacePrefix() { | |||
return AFPElementMapping.NAMESPACE_PREFIX; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public void processNode(String elementName, Locator locator, | |||
Attributes attlist, PropertyList propertyList) | |||
throws FOPException { | |||
@@ -100,26 +83,9 @@ public abstract class AbstractAFPExtensionObject extends FONode { | |||
} else { | |||
throw new FOPException(elementName + " must have a name attribute."); | |||
} | |||
if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(elementName)) { | |||
attr = attlist.getValue("src"); | |||
if (attr != null && attr.length() > 0) { | |||
extensionAttachment.setValue(attr); | |||
} else { | |||
throw new FOPException(elementName + " must have a src attribute."); | |||
} | |||
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(elementName)) { | |||
attr = attlist.getValue("value"); | |||
if (attr != null && attr.length() > 0) { | |||
extensionAttachment.setValue(attr); | |||
} else { | |||
throw new FOPException(elementName + " must have a value attribute."); | |||
} | |||
} | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
protected void endOfNode() throws FOPException { | |||
super.endOfNode(); | |||
} | |||
@@ -130,9 +96,7 @@ public abstract class AbstractAFPExtensionObject extends FONode { | |||
*/ | |||
protected abstract ExtensionAttachment instantiateExtensionAttachment(); | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public ExtensionAttachment getExtensionAttachment() { | |||
if (extensionAttachment == null) { | |||
this.extensionAttachment = (AFPExtensionAttachment)instantiateExtensionAttachment(); | |||
@@ -140,9 +104,7 @@ public abstract class AbstractAFPExtensionObject extends FONode { | |||
return this.extensionAttachment; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public String getLocalName() { | |||
return name; | |||
} |
@@ -30,8 +30,7 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
*/ | |||
public class TIFFDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { | |||
//TODO Revert to normal MIME after stabilization! | |||
private static final String[] MIMES = new String[] {MimeConstants.MIME_TIFF + ";mode=painter"}; | |||
private static final String[] MIMES = new String[] {MimeConstants.MIME_TIFF}; | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { |
@@ -30,8 +30,7 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
*/ | |||
public class PCLDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { | |||
//TODO Revert to normal MIME after stabilization! | |||
private static final String[] MIMES = new String[] {MimeConstants.MIME_PCL + ";mode=painter"}; | |||
private static final String[] MIMES = new String[] {MimeConstants.MIME_PCL}; | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { |
@@ -279,6 +279,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { | |||
pdfDoc.outputTrailer(this.outputStream); | |||
} | |||
this.pdfDoc = null; | |||
pdfResources = null; | |||
this.generator = null; | |||
currentContext = null; |
@@ -30,8 +30,7 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
*/ | |||
public class PDFDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { | |||
//TODO Revert to normal MIME after stabilization! | |||
private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF + ";mode=painter"}; | |||
private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF}; | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { |
@@ -29,6 +29,7 @@ import java.util.Map; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.area.PageViewport; | |||
import org.apache.fop.render.java2d.Java2DRenderer; | |||
@@ -75,6 +76,11 @@ public class PageableRenderer extends Java2DRenderer implements Pageable { | |||
public PageableRenderer() { | |||
} | |||
/** {@inheritDoc} */ | |||
public String getMimeType() { | |||
return MimeConstants.MIME_FOP_PRINT; | |||
} | |||
/** {@inheritDoc} */ | |||
public void setUserAgent(FOUserAgent agent) { | |||
super.setUserAgent(agent); |
@@ -30,9 +30,8 @@ import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
*/ | |||
public class PSDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { | |||
//TODO Revert to normal MIME after stabilization! | |||
private static final String[] MIMES = new String[] | |||
{MimeConstants.MIME_POSTSCRIPT + ";mode=painter"}; | |||
{MimeConstants.MIME_POSTSCRIPT}; | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { |
@@ -438,7 +438,9 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
if (pageSequence.getCountry() != null) { | |||
addAttribute("country", pageSequence.getCountry()); | |||
} | |||
transferForeignObjects(pageSequence); | |||
startElement("pageSequence", atts); | |||
handleExtensionAttachments(pageSequence.getExtensionAttachments()); | |||
LineArea seqTitle = pageSequence.getTitle(); | |||
if (seqTitle != null) { | |||
startElement("title"); |
@@ -25,12 +25,13 @@ import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontInfoConfigurator; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.FontSetup; | |||
import org.apache.fop.pdf.PDFDocument; | |||
import org.apache.fop.render.PrintRendererConfigurator; | |||
import org.apache.fop.render.pdf.PDFRendererConfigurator; | |||
/** | |||
@@ -61,15 +62,19 @@ public class PDFDocumentGraphics2DConfigurator { | |||
//TODO Make use of fontBaseURL, font substitution and referencing configuration | |||
//Requires a change to the expected configuration layout | |||
List/*<EmbedFontInfo>*/ embedFontInfoList | |||
= PrintRendererConfigurator.buildFontListFromConfiguration( | |||
cfg, fontResolver, false, fontManager, null); | |||
//TODO Wire in the FontEventListener | |||
final FontEventListener listener = null; | |||
final boolean strict = false; | |||
FontInfoConfigurator fontInfoConfigurator | |||
= new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict); | |||
List/*<EmbedFontInfo>*/ fontInfoList = new java.util.ArrayList/*<EmbedFontInfo>*/(); | |||
fontInfoConfigurator.configure(fontInfoList); | |||
if (fontManager.useCache()) { | |||
fontManager.getFontCache().save(); | |||
} | |||
FontInfo fontInfo = new FontInfo(); | |||
FontSetup.setup(fontInfo, embedFontInfoList, fontResolver); | |||
FontSetup.setup(fontInfo, fontInfoList, fontResolver); | |||
graphics.setFontInfo(fontInfo); | |||
} catch (FOPException e) { | |||
throw new ConfigurationException("Error while setting up fonts", e); |
@@ -59,6 +59,15 @@ import org.apache.batik.ext.awt.RadialGradientPaint; | |||
import org.apache.batik.ext.awt.RenderingHintsKeyExt; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.batik.gvt.PatternPaint; | |||
import org.apache.xmlgraphics.image.loader.ImageInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageSize; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRendered; | |||
import org.apache.xmlgraphics.java2d.AbstractGraphics2D; | |||
import org.apache.xmlgraphics.java2d.GraphicContext; | |||
import org.apache.fop.fonts.Font; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontSetup; | |||
@@ -83,13 +92,6 @@ import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter; | |||
import org.apache.fop.render.pdf.ImageRawJPEGAdapter; | |||
import org.apache.fop.render.pdf.ImageRenderedAdapter; | |||
import org.apache.fop.util.ColorExt; | |||
import org.apache.xmlgraphics.image.loader.ImageInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageSize; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRendered; | |||
import org.apache.xmlgraphics.java2d.AbstractGraphics2D; | |||
import org.apache.xmlgraphics.java2d.GraphicContext; | |||
/** | |||
* PDF Graphics 2D. | |||
@@ -741,13 +743,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
throw new PDFConformanceException( | |||
"PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK."); | |||
} | |||
float[] cComps = c.getColorComponents(new float[3]); | |||
double[] cmyk = new double[3]; | |||
for (int i = 0; i < 3; i++) { | |||
// convert the float elements to doubles for pdf | |||
cmyk[i] = cComps[i]; | |||
} | |||
PDFColor currentColour = new PDFColor(cmyk[0], cmyk[1], cmyk[2], cmyk[3]); | |||
PDFColor currentColour = new PDFColor(c); | |||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||
} else if (c.getColorSpace().getType() | |||
== ColorSpace.TYPE_2CLR) { |
@@ -0,0 +1,115 @@ | |||
/* | |||
* 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.tools.fontlist; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.SortedMap; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontMetrics; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
/** | |||
* Generates a list of available fonts. | |||
*/ | |||
public class FontListGenerator { | |||
/** | |||
* List all fonts configured for a particular output format (identified by MIME type). | |||
* The sorted map returned looks like this: | |||
* <code>SortedMap<String/font-family, List<{@link FontSpec}>></code> | |||
* @param fopFactory the FOP factory (already configured) | |||
* @param mime the MIME type identified the selected output format | |||
* @param listener a font event listener to catch any font-related errors while listing fonts | |||
* @return the map of font families | |||
* @throws FOPException if an error occurs setting up the fonts | |||
*/ | |||
public SortedMap listFonts(FopFactory fopFactory, String mime, FontEventListener listener) | |||
throws FOPException { | |||
FontInfo fontInfo = setupFonts(fopFactory, mime, listener); | |||
SortedMap fontFamilies = buildFamilyMap(fontInfo); | |||
return fontFamilies; | |||
} | |||
private FontInfo setupFonts(FopFactory fopFactory, String mime, FontEventListener listener) | |||
throws FOPException { | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//The document handler is only instantiated to get access to its configurator! | |||
IFDocumentHandler documentHandler | |||
= fopFactory.getRendererFactory().createDocumentHandler(userAgent, mime); | |||
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); | |||
FontInfo fontInfo = new FontInfo(); | |||
configurator.setupFontInfo(documentHandler, fontInfo); | |||
return fontInfo; | |||
} | |||
private SortedMap buildFamilyMap(FontInfo fontInfo) { | |||
Map fonts = fontInfo.getFonts(); | |||
Set keyBag = new java.util.HashSet(fonts.keySet()); | |||
Map keys = new java.util.HashMap(); | |||
SortedMap fontFamilies = new java.util.TreeMap(); | |||
//SortedMap<String/font-family, List<FontSpec>> | |||
Iterator iter = fontInfo.getFontTriplets().entrySet().iterator(); | |||
while (iter.hasNext()) { | |||
Map.Entry entry = (Map.Entry)iter.next(); | |||
FontTriplet triplet = (FontTriplet)entry.getKey(); | |||
String key = (String)entry.getValue(); | |||
FontSpec container; | |||
if (keyBag.contains(key)) { | |||
keyBag.remove(key); | |||
FontMetrics metrics = (FontMetrics)fonts.get(key); | |||
container = new FontSpec(key, metrics); | |||
container.addFamilyNames(metrics.getFamilyNames()); | |||
keys.put(key, container); | |||
String firstFamilyName = (String)container.getFamilyNames().first(); | |||
List containers = (List)fontFamilies.get(firstFamilyName); | |||
if (containers == null) { | |||
containers = new java.util.ArrayList(); | |||
fontFamilies.put(firstFamilyName, containers); | |||
} | |||
containers.add(container); | |||
Collections.sort(containers); | |||
} else { | |||
container = (FontSpec)keys.get(key); | |||
} | |||
container.addTriplet(triplet); | |||
} | |||
return fontFamilies; | |||
} | |||
} |
@@ -0,0 +1,305 @@ | |||
/* | |||
* 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.tools.fontlist; | |||
import java.io.File; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.io.PrintStream; | |||
import java.net.URL; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.SortedMap; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerConfigurationException; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.sax.SAXTransformerFactory; | |||
import javax.xml.transform.sax.TransformerHandler; | |||
import javax.xml.transform.stream.StreamResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.apache.commons.io.FilenameUtils; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.Version; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.util.GenerationHelperContentHandler; | |||
/** | |||
* Command-line application to list available fonts and to optionally produce sample pages | |||
* with those fonts. | |||
*/ | |||
public final class FontListMain { | |||
private static final int GENERATE_CONSOLE = 0; | |||
private static final int GENERATE_XML = 1; | |||
private static final int GENERATE_FO = 2; | |||
private static final int GENERATE_RENDERED = 3; | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private File configFile; | |||
private File outputFile; | |||
private String configMime = MimeConstants.MIME_PDF; | |||
private String outputMime; | |||
private int mode = GENERATE_CONSOLE; | |||
private String singleFamilyFilter; | |||
private FontListMain() throws SAXException, IOException { | |||
} | |||
private void prepare() throws SAXException, IOException { | |||
if (this.configFile != null) { | |||
fopFactory.setUserConfig(this.configFile); | |||
} | |||
} | |||
private ContentHandler getFOPContentHandler(OutputStream out) throws FOPException { | |||
Fop fop = fopFactory.newFop(this.outputMime, out); | |||
return fop.getDefaultHandler(); | |||
} | |||
private void generateXML(SortedMap fontFamilies, File outFile, String singleFamily) | |||
throws TransformerConfigurationException, SAXException, IOException { | |||
SAXTransformerFactory tFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); | |||
TransformerHandler handler; | |||
if (this.mode == GENERATE_XML) { | |||
handler = tFactory.newTransformerHandler(); | |||
} else { | |||
URL url = getClass().getResource("fonts2fo.xsl"); | |||
if (url == null) { | |||
throw new FileNotFoundException("Did not find resource: fonts2fo.xsl"); | |||
} | |||
handler = tFactory.newTransformerHandler(new StreamSource(url.toExternalForm())); | |||
} | |||
if (singleFamily != null) { | |||
Transformer transformer = handler.getTransformer(); | |||
transformer.setParameter("single-family", singleFamily); | |||
} | |||
OutputStream out = new java.io.FileOutputStream(outFile); | |||
out = new java.io.BufferedOutputStream(out); | |||
if (this.mode == GENERATE_RENDERED) { | |||
handler.setResult(new SAXResult(getFOPContentHandler(out))); | |||
} else { | |||
handler.setResult(new StreamResult(out)); | |||
} | |||
try { | |||
GenerationHelperContentHandler helper = new GenerationHelperContentHandler( | |||
handler, null); | |||
FontListSerializer serializer = new FontListSerializer(); | |||
serializer.generateSAX(fontFamilies, singleFamily, helper); | |||
} finally { | |||
IOUtils.closeQuietly(out); | |||
} | |||
} | |||
private void generate() throws Exception { | |||
prepare(); | |||
FontEventListener listener = new FontEventListener() { | |||
public void fontLoadingErrorAtAutoDetection(Object source, | |||
String fontURL, Exception e) { | |||
System.err.println("Could not load " + fontURL | |||
+ " (" + e.getLocalizedMessage() + ")"); | |||
} | |||
public void fontSubstituted(Object source, | |||
FontTriplet requested, FontTriplet effective) { | |||
//ignore | |||
} | |||
public void glyphNotAvailable(Object source, char ch, String fontName) { | |||
//ignore | |||
} | |||
}; | |||
FontListGenerator listGenerator = new FontListGenerator(); | |||
SortedMap fontFamilies = listGenerator.listFonts(fopFactory, configMime, listener); | |||
if (this.mode == GENERATE_CONSOLE) { | |||
writeToConsole(fontFamilies); | |||
} else { | |||
writeOutput(fontFamilies); | |||
} | |||
} | |||
private void writeToConsole(SortedMap fontFamilies) | |||
throws TransformerConfigurationException, SAXException, IOException { | |||
Iterator iter = fontFamilies.entrySet().iterator(); | |||
while (iter.hasNext()) { | |||
Map.Entry entry = (Map.Entry)iter.next(); | |||
String firstFamilyName = (String)entry.getKey(); | |||
System.out.println(firstFamilyName + ":"); | |||
List list = (List)entry.getValue(); | |||
Iterator fonts = list.iterator(); | |||
while (fonts.hasNext()) { | |||
FontSpec f = (FontSpec)fonts.next(); | |||
System.out.println(" " + f.getKey() + " " + f.getFamilyNames()); | |||
Iterator triplets = f.getTriplets().iterator(); | |||
while (triplets.hasNext()) { | |||
FontTriplet triplet = (FontTriplet)triplets.next(); | |||
System.out.println(" " + triplet.toString()); | |||
} | |||
} | |||
} | |||
} | |||
private void writeOutput(SortedMap fontFamilies) | |||
throws TransformerConfigurationException, SAXException, IOException { | |||
if (this.outputFile.isDirectory()) { | |||
System.out.println("Creating one file for each family..."); | |||
Iterator iter = fontFamilies.entrySet().iterator(); | |||
while (iter.hasNext()) { | |||
Map.Entry entry = (Map.Entry)iter.next(); | |||
String familyName = (String)entry.getKey(); | |||
System.out.println("Creating output file for " + familyName + "..."); | |||
String filename; | |||
switch(this.mode) { | |||
case GENERATE_RENDERED: | |||
filename = familyName + ".pdf"; | |||
break; | |||
case GENERATE_FO: | |||
filename = familyName + ".fo"; | |||
break; | |||
case GENERATE_XML: | |||
filename = familyName + ".xml"; | |||
break; | |||
default: | |||
throw new IllegalStateException("Unsupported mode"); | |||
} | |||
File outFile = new File(this.outputFile, filename); | |||
generateXML(fontFamilies, outFile, familyName); | |||
} | |||
} else { | |||
System.out.println("Creating output file..."); | |||
generateXML(fontFamilies, this.outputFile, this.singleFamilyFilter); | |||
} | |||
System.out.println(this.outputFile + " written."); | |||
} | |||
private static void printVersion() { | |||
System.out.println("Apache FOP " + Version.getVersion() | |||
+ " - http://xmlgraphics.apache.org/fop/\n"); | |||
} | |||
private static void printHelp() { | |||
printVersion(); | |||
String className = FontListMain.class.getName(); | |||
PrintStream out = System.out; | |||
out.println("USAGE"); | |||
out.println(" java [vmargs] " + className | |||
+ " [-c <config-file>] [-f <mime>] [[output-dir|output-file] [font-family]]"); | |||
out.println(); | |||
out.println("PARAMETERS"); | |||
out.println(" config-file: an optional FOP configuration file"); | |||
out.println(" mime: The MIME type of the output format for which to"); | |||
out.println(" create the font list (defaults to application/pdf)"); | |||
out.println(" output-dir: Creates one sample PDF per font-family"); | |||
out.println(" output-file: writes the list as file (valid file extensions: xml, fo, pdf)"); | |||
out.println(" font-family: filters to a single font family"); | |||
out.println(); | |||
out.println("EXAMPLE"); | |||
out.println(" java [vmargs] " + className | |||
+ " -c userconfig.xml all-fonts.pdf"); | |||
out.println(" --> this generates a single PDF containing a sample"); | |||
out.println(" of all configured fonts."); | |||
out.println(" java [vmargs] " + className | |||
+ " -c userconfig.xml"); | |||
out.println(" --> this prints all configured fonts to the console."); | |||
out.println(); | |||
} | |||
private void parseArguments(String[] args) { | |||
if (args.length > 0) { | |||
int idx = 0; | |||
if ("--help".equals(args[idx]) || "-?".equals(args[idx]) || "-h".equals(args[idx])) { | |||
printHelp(); | |||
System.exit(0); | |||
} | |||
if (idx < args.length - 1 && "-c".equals(args[idx])) { | |||
String filename = args[idx + 1]; | |||
this.configFile = new File(filename); | |||
idx += 2; | |||
} | |||
if (idx < args.length - 1 && "-f".equals(args[idx])) { | |||
this.configMime = args[idx + 1]; | |||
idx += 2; | |||
} | |||
if (idx < args.length) { | |||
String name = args[idx]; | |||
this.outputFile = new File(name); | |||
if (this.outputFile.isDirectory()) { | |||
this.mode = GENERATE_RENDERED; | |||
this.outputMime = MimeConstants.MIME_PDF; | |||
} else if (FilenameUtils.getExtension(name).equalsIgnoreCase("pdf")) { | |||
this.mode = GENERATE_RENDERED; | |||
this.outputMime = MimeConstants.MIME_PDF; | |||
} else if (FilenameUtils.getExtension(name).equalsIgnoreCase("fo")) { | |||
this.mode = GENERATE_FO; | |||
} else if (FilenameUtils.getExtension(name).equalsIgnoreCase("xml")) { | |||
this.mode = GENERATE_XML; | |||
} else { | |||
throw new IllegalArgumentException( | |||
"Operating mode for the output file cannot be determined" | |||
+ " or is unsupported: " + name); | |||
} | |||
idx++; | |||
} | |||
if (idx < args.length) { | |||
this.singleFamilyFilter = args[idx]; | |||
} | |||
} else { | |||
System.out.println("use --help or -? for usage information."); | |||
} | |||
} | |||
/** | |||
* The command-line interface. | |||
* @param args the command-line arguments | |||
*/ | |||
public static void main(String[] args) { | |||
try { | |||
FontListMain app = new FontListMain(); | |||
app.parseArguments(args); | |||
app.generate(); | |||
} catch (Throwable t) { | |||
printHelp(); | |||
t.printStackTrace(); | |||
System.exit(-1); | |||
} | |||
} | |||
} |
@@ -0,0 +1,142 @@ | |||
/* | |||
* 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.tools.fontlist; | |||
import java.util.Collection; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.SortedMap; | |||
import java.util.regex.Pattern; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.util.GenerationHelperContentHandler; | |||
/** | |||
* Turns the font list into SAX events. | |||
*/ | |||
public class FontListSerializer { | |||
private static final String FONTS = "fonts"; | |||
private static final String FAMILY = "family"; | |||
private static final String FONT = "font"; | |||
private static final String TRIPLETS = "triplets"; | |||
private static final String TRIPLET = "triplet"; | |||
private static final String NAME = "name"; | |||
private static final String STRIPPED_NAME = "stripped-name"; | |||
private static final String TYPE = "type"; | |||
private static final String KEY = "key"; | |||
private static final String STYLE = "style"; | |||
private static final String WEIGHT = "weight"; | |||
private static final String CDATA = "CDATA"; | |||
/** | |||
* Generates SAX events from the font damily map. | |||
* @param fontFamilies the font families | |||
* @param handler the target SAX handler | |||
* @throws SAXException if an XML-related exception occurs | |||
*/ | |||
public void generateSAX(SortedMap fontFamilies, | |||
GenerationHelperContentHandler handler) throws SAXException { | |||
generateSAX(fontFamilies, null, handler); | |||
} | |||
/** | |||
* Generates SAX events from the font damily map. | |||
* @param fontFamilies the font families | |||
* @param singleFamily if not null, the output will be filtered so only this single font family | |||
* will be used | |||
* @param handler the target SAX handler | |||
* @throws SAXException if an XML-related exception occurs | |||
*/ | |||
public void generateSAX(SortedMap fontFamilies, String singleFamily, | |||
GenerationHelperContentHandler handler) throws SAXException { | |||
handler.startDocument(); | |||
AttributesImpl atts = new AttributesImpl(); | |||
handler.startElement(FONTS, atts); | |||
Iterator iter = fontFamilies.entrySet().iterator(); | |||
while (iter.hasNext()) { | |||
Map.Entry entry = (Map.Entry)iter.next(); | |||
String familyName = (String)entry.getKey(); | |||
if (singleFamily != null && familyName != singleFamily) { | |||
continue; | |||
} | |||
atts.clear(); | |||
atts.addAttribute(null, NAME, NAME, CDATA, familyName); | |||
atts.addAttribute(null, STRIPPED_NAME, STRIPPED_NAME, CDATA, | |||
stripQuotes(familyName)); | |||
handler.startElement(FAMILY, atts); | |||
List containers = (List)entry.getValue(); | |||
generateXMLForFontContainers(handler, containers); | |||
handler.endElement(FAMILY); | |||
} | |||
handler.endElement(FONTS); | |||
handler.endDocument(); | |||
} | |||
private final Pattern quotePattern = Pattern.compile("'"); | |||
private String stripQuotes(String name) { | |||
return quotePattern.matcher(name).replaceAll(""); | |||
} | |||
private void generateXMLForFontContainers(GenerationHelperContentHandler handler, | |||
List containers) throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
Iterator fontIter = containers.iterator(); | |||
while (fontIter.hasNext()) { | |||
FontSpec cont = (FontSpec)fontIter.next(); | |||
atts.clear(); | |||
atts.addAttribute(null, KEY, KEY, CDATA, cont.getKey()); | |||
atts.addAttribute(null, TYPE, TYPE, CDATA, | |||
cont.getFontMetrics().getFontType().getName()); | |||
handler.startElement(FONT, atts); | |||
generateXMLForTriplets(handler, cont.getTriplets()); | |||
handler.endElement(FONT); | |||
} | |||
} | |||
private void generateXMLForTriplets(GenerationHelperContentHandler handler, Collection triplets) | |||
throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
atts.clear(); | |||
handler.startElement(TRIPLETS, atts); | |||
Iterator iter = triplets.iterator(); | |||
while (iter.hasNext()) { | |||
FontTriplet triplet = (FontTriplet)iter.next(); | |||
atts.clear(); | |||
atts.addAttribute(null, NAME, NAME, CDATA, triplet.getName()); | |||
atts.addAttribute(null, STYLE, STYLE, CDATA, triplet.getStyle()); | |||
atts.addAttribute(null, WEIGHT, WEIGHT, CDATA, | |||
Integer.toString(triplet.getWeight())); | |||
handler.element(TRIPLET, atts); | |||
} | |||
handler.endElement(TRIPLETS); | |||
} | |||
} |
@@ -0,0 +1,103 @@ | |||
/* | |||
* 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.tools.fontlist; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.SortedSet; | |||
import org.apache.fop.fonts.FontMetrics; | |||
import org.apache.fop.fonts.FontTriplet; | |||
/** | |||
* Represents a font with information on how it can be used from XSL-FO. | |||
*/ | |||
public class FontSpec implements Comparable { | |||
private String key; | |||
private FontMetrics metrics; | |||
private SortedSet familyNames = new java.util.TreeSet(); | |||
private Collection triplets = new java.util.TreeSet(); | |||
/** | |||
* Creates a new font spec. | |||
* @param key the internal font key | |||
* @param metrics the font metrics | |||
*/ | |||
public FontSpec(String key, FontMetrics metrics) { | |||
this.key = key; | |||
this.metrics = metrics; | |||
} | |||
/** | |||
* Adds font family names. | |||
* @param names the names | |||
*/ | |||
public void addFamilyNames(Collection names) { | |||
this.familyNames.addAll(names); | |||
} | |||
/** | |||
* Adds a font triplet. | |||
* @param triplet the font triplet | |||
*/ | |||
public void addTriplet(FontTriplet triplet) { | |||
this.triplets.add(triplet); | |||
} | |||
/** | |||
* Returns the font family names. | |||
* @return the font family names | |||
*/ | |||
public SortedSet getFamilyNames() { | |||
return Collections.unmodifiableSortedSet(this.familyNames); | |||
} | |||
/** | |||
* Returns the font triplets. | |||
* @return the font triplets | |||
*/ | |||
public Collection getTriplets() { | |||
return Collections.unmodifiableCollection(this.triplets); | |||
} | |||
/** | |||
* Returns the internal font key. | |||
* @return the internal font key | |||
*/ | |||
public String getKey() { | |||
return this.key; | |||
} | |||
/** | |||
* Returns the font metrics. | |||
* @return the font metrics | |||
*/ | |||
public FontMetrics getFontMetrics() { | |||
return this.metrics; | |||
} | |||
/** {@inheritDoc} */ | |||
public int compareTo(Object o) { | |||
FontSpec other = (FontSpec)o; | |||
return metrics.getFullName().compareTo(other.metrics.getFullName()); | |||
} | |||
} |
@@ -0,0 +1,200 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- | |||
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$ --> | |||
<xsl:stylesheet version="1.0" | |||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | |||
xmlns:fo="http://www.w3.org/1999/XSL/Format" | |||
xmlns:svg="http://www.w3.org/2000/svg"> | |||
<xsl:output method="xml" indent="yes"/> | |||
<xsl:param name="single-family" select="''"/> | |||
<xsl:template match="fonts"> | |||
<fo:root font-family="sans-serif" font-size="10pt"> | |||
<!-- defines the layout master --> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" | |||
margin="1.5cm"> | |||
<fo:region-body/> | |||
</fo:simple-page-master> | |||
</fo:layout-master-set> | |||
<!-- starts actual layout --> | |||
<xsl:choose> | |||
<xsl:when test="string-length($single-family) > 0"> | |||
<xsl:apply-templates select="family[@name = $single-family]"/> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<xsl:call-template name="bookmarks"/> | |||
<xsl:call-template name="toc"/> | |||
<xsl:apply-templates/> | |||
</xsl:otherwise> | |||
</xsl:choose> | |||
</fo:root> | |||
</xsl:template> | |||
<xsl:template name="bookmarks"> | |||
<fo:bookmark-tree> | |||
<fo:bookmark internal-destination="toc"> | |||
<fo:bookmark-title>Table of Contents</fo:bookmark-title> | |||
</fo:bookmark> | |||
<xsl:apply-templates mode="bookmark"/> | |||
</fo:bookmark-tree> | |||
</xsl:template> | |||
<xsl:template name="toc"> | |||
<fo:page-sequence master-reference="A4" id="toc"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block> | |||
<fo:block font-size="14pt" font-weight="bold" space-after="1em">FOP Font List</fo:block> | |||
<fo:block space-after="0.5em">The number of font families: <xsl:value-of select="count(family)"/></fo:block> | |||
</fo:block> | |||
<xsl:if test="count(family) > 0"> | |||
<fo:list-block provisional-distance-between-starts="1.6em" | |||
provisional-label-separation="0.5em"> | |||
<xsl:apply-templates mode="toc"/> | |||
</fo:list-block> | |||
</xsl:if> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</xsl:template> | |||
<xsl:template match="family" mode="bookmark"> | |||
<fo:bookmark internal-destination="{generate-id()}"> | |||
<fo:bookmark-title> | |||
<xsl:value-of select="@name"/> | |||
</fo:bookmark-title> | |||
</fo:bookmark> | |||
</xsl:template> | |||
<xsl:template match="family" mode="toc"> | |||
<fo:list-item> | |||
<fo:list-item-label start-indent="2mm" end-indent="label-end()"> | |||
<fo:block hyphenation-character="−" font-family="Symbol">•</fo:block> | |||
</fo:list-item-label> | |||
<fo:list-item-body start-indent="body-start()"> | |||
<fo:block> | |||
<fo:basic-link internal-destination="{generate-id()}"> | |||
<xsl:value-of select="@name"/> | |||
</fo:basic-link> | |||
</fo:block> | |||
</fo:list-item-body> | |||
</fo:list-item> | |||
</xsl:template> | |||
<xsl:template match="family"> | |||
<fo:page-sequence master-reference="A4" id="{generate-id()}"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block> | |||
<fo:block font-size="14pt" font-weight="bold" space-after="0.5em" border-bottom="solid 0.5mm"> | |||
<xsl:value-of select="@name"/> | |||
</fo:block> | |||
<fo:block> | |||
<fo:block font-weight="bold">Fonts:</fo:block> | |||
<xsl:apply-templates/> | |||
</fo:block> | |||
</fo:block> | |||
<xsl:call-template name="weight-sample"> | |||
<xsl:with-param name="font-family" select="@stripped-name"/> | |||
</xsl:call-template> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</xsl:template> | |||
<xsl:template name="weight-sample"> | |||
<xsl:param name="font-family" select="'sans-serif'"/> | |||
<fo:block border="solid 0.25mm" start-indent="0.25mm" end-indent="0.25mm" | |||
space-before="0.5em" | |||
keep-together.within-column="always"> | |||
<fo:block font-size="8pt" | |||
background-color="black" color="white" | |||
padding="0mm 1mm" start-indent="1.25mm" end-indent="1.25mm"> | |||
Weight Sample: font-family="<xsl:value-of select="$font-family"/>" font-weight="100..900"</fo:block> | |||
<fo:block padding="1mm 1mm" start-indent="1.25mm" end-indent="1.25mm"> | |||
<xsl:attribute name="font-family"> | |||
<xsl:value-of select="$font-family"/> | |||
</xsl:attribute> | |||
<fo:block font-weight="100">100: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="200">200: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="300">300: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="400">400: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="500">500: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="600">600: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="700">700: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="800">800: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block font-weight="900">900: The quick brown fox jumps over the lazy dog</fo:block> | |||
<fo:block> | |||
<fo:instream-foreign-object> | |||
<svg xmlns="http://www.w3.org/2000/svg" width="16cm" height="108pt"> | |||
<g font-family="sans-serif" font-weight="bold" font-size="80pt" | |||
transform="translate(30, 100) rotate(-15)"> | |||
<text fill="lightgray">SVG</text> | |||
</g> | |||
<g font-size="10pt"> | |||
<xsl:attribute name="font-family"> | |||
'<xsl:value-of select="$font-family"/>' | |||
</xsl:attribute> | |||
<text x="0" y="10"> | |||
<tspan x="0" dy="0" font-weight="100">100: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="200">200: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="300">300: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="400">400: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="500">500: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="600">600: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="700">700: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="800">800: The quick brown fox jumps over the lazy dog</tspan> | |||
<tspan x="0" dy="12" font-weight="900">900: The quick brown fox jumps over the lazy dog</tspan> | |||
</text> | |||
</g> | |||
</svg> | |||
</fo:instream-foreign-object> | |||
</fo:block> | |||
</fo:block> | |||
</fo:block> | |||
</xsl:template> | |||
<xsl:template match="font"> | |||
<fo:block>Internal key: <xsl:value-of select="@key"/></fo:block> | |||
<fo:block border="solid 0.25mm" start-indent="0.25mm" end-indent="0.25mm"> | |||
<fo:block font-size="8pt" | |||
background-color="black" color="white" | |||
padding="0mm 1mm" start-indent="1.25mm" end-indent="1.25mm"> | |||
Sample:</fo:block> | |||
<fo:block font-family="{triplets/triplet[1]/@name}" | |||
font-style="{triplets/triplet[1]/@style}" | |||
font-weight="{triplets/triplet[1]/@weight}" | |||
font-size="14pt" padding="1mm" start-indent="1.25mm" end-indent="1.25mm"> | |||
The quick brown fox jumps over the lazy dog. | |||
</fo:block> | |||
</fo:block> | |||
<fo:block start-indent="5mm"> | |||
<fo:block>Accessible by:</fo:block> | |||
<fo:block start-indent="10mm"> | |||
<xsl:apply-templates select="triplets/triplet"/> | |||
</fo:block> | |||
</fo:block> | |||
</xsl:template> | |||
<xsl:template match="triplet"> | |||
<fo:block color="gray"> | |||
font-family=<fo:inline color="black">"<xsl:value-of select="@name"/>"</fo:inline> | |||
font-style=<fo:inline color="black"><xsl:value-of select="@style"/>"</fo:inline> | |||
font-weight=<fo:inline color="black"><xsl:value-of select="@weight"/>"</fo:inline> | |||
</fo:block> | |||
</xsl:template> | |||
</xsl:stylesheet> |
@@ -61,6 +61,46 @@ | |||
<action context="Renderers" dev="JM" type="add" fixes-bug="46705" due-to="Jost Klopfstein"> | |||
Added basic accessibility and Tagged PDF support. | |||
</action> | |||
<action context="Renderers" dev="JM" type="fix"> | |||
Fixed a bug that left the PrintRenderer unconfigured even if a configuration was | |||
specified for "application/X-fop-print". | |||
</action> | |||
<action context="Renderers" dev="JM" type="fix" fixes-bug="46882" due-to="Yegor Kozlov"> | |||
Fixed the handling of CMYK colors in PDFGraphics2D. | |||
</action> | |||
<action context="Layout" dev="AD" type="fix" fixes-bug="46489"> | |||
Fixed a bug when combining a forced break with a "last" page-master. The restart | |||
of the algorithm would start at the index of the penalty corresponding to the last | |||
page-break. This has been changed to the index of the first element after the last | |||
page-break. | |||
</action> | |||
<action context="Fonts" dev="JM" type="add"> | |||
Added a command-line tool to list all configured fonts | |||
(org.apache.fop.tools.fontlist.FontListMain). | |||
</action> | |||
<action context="Code" dev="AD" type="add" fixes-bug="46828" due-to="Dario Laera"> | |||
Added the possibility to use CachedRenderPagesModel, to conserve memory in case | |||
of large documents with a lot of cross-references (area tree will be serialized to | |||
disk to avoid keeping it entirely in memory). | |||
</action> | |||
<action context="Fonts" dev="JM" type="add"> | |||
AFP Fonts: Added support for full URI resolution on configured AFP fonts. | |||
</action> | |||
<action context="Renderers" dev="JM" type="add"> | |||
AFP Output: Tag Logical Element (TLE) is now also allowed on fo:page-sequence | |||
(page group level). | |||
</action> | |||
<action context="Layout" dev="JM" type="fix"> | |||
Fixed BPD trait and border painting for leaders with leader-pattern="space" | |||
(and similar cases). | |||
</action> | |||
<action context="Renderers" dev="JM" type="add"> | |||
AFP Output: Added support for Invoke Medium Map (IMM). | |||
</action> | |||
<action context="Renderers" dev="JM" type="add"> | |||
Introduced a new, additional intermediate format optimized for performance. Please see | |||
the intermediate format documentation for details. | |||
</action> | |||
<action context="Fonts" dev="JM" type="fix" fixes-bug="46686" due-to="Alok Singh"> | |||
Use temporary directory for the font cache if the user home directory is not | |||
write-accessible. | |||
@@ -74,11 +114,11 @@ | |||
code. | |||
</action> | |||
<action context="Code" dev="VH" type="fix" fixes-bug="46638"> | |||
MinOptMaxUtil.toMinOptMax was converting LengthRangeProperty objects into illegal MinOptMax | |||
MinOptMaxUtil.toMinOptMax was converting LengthRangeProperty objects into illegal MinOptMax | |||
objects (in some cases opt could be inferior to min). | |||
</action> | |||
<action context="Layout" dev="VH" type="add" fixes-bug="46315" due-to="Georg Datterl"> | |||
Added extension to disable column balancing before blocks spanning the whole page, in | |||
Added extension to disable column balancing before blocks spanning the whole page, in | |||
multiple-column documents. | |||
</action> | |||
<action context="Renderers" dev="JM" type="add"> |
@@ -25,6 +25,7 @@ import junit.framework.TestSuite; | |||
import org.apache.fop.fonts.TrueTypeAnsiTestCase; | |||
import org.apache.fop.image.loader.batik.ImageLoaderTestCase; | |||
import org.apache.fop.image.loader.batik.ImagePreloaderTestCase; | |||
import org.apache.fop.intermediate.IFMimickingTestCase; | |||
import org.apache.fop.render.pdf.PDFAConformanceTestCase; | |||
import org.apache.fop.render.pdf.PDFCMapTestCase; | |||
import org.apache.fop.render.pdf.PDFEncodingTestCase; | |||
@@ -54,6 +55,7 @@ public class StandardTestSuite { | |||
suite.addTest(RichTextFormatTestSuite.suite()); | |||
suite.addTest(new TestSuite(ImageLoaderTestCase.class)); | |||
suite.addTest(new TestSuite(ImagePreloaderTestCase.class)); | |||
suite.addTest(new TestSuite(IFMimickingTestCase.class)); | |||
//$JUnit-END$ | |||
return suite; | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* 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.config; | |||
import java.net.MalformedURLException; | |||
import junit.framework.TestCase; | |||
import org.apache.fop.apps.FOURIResolver; | |||
/** | |||
* This tests some aspects of the {@link FOURIResolver} class. | |||
*/ | |||
public class FOURIResolverTestCase extends TestCase { | |||
/** | |||
* Checks the {@link FOURIResolver#checkBaseURL(String)} method. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testCheckBaseURI() throws Exception { | |||
FOURIResolver resolver = new FOURIResolver(true); | |||
System.out.println(resolver.checkBaseURL("./test/config")); | |||
System.out.println(resolver.checkBaseURL("file:test/config")); | |||
System.out.println(resolver.checkBaseURL("fantasy:myconfig")); | |||
try { | |||
resolver.checkBaseURL("./doesnotexist"); | |||
fail("Expected an exception for a inexistent base directory"); | |||
} catch (MalformedURLException mfue) { | |||
//expected | |||
} | |||
try { | |||
resolver.checkBaseURL("file:doesnotexist"); | |||
fail("Expected an exception for a inexistent base URI"); | |||
} catch (MalformedURLException mfue) { | |||
//expected | |||
} | |||
} | |||
} |
@@ -20,7 +20,7 @@ | |||
package org.apache.fop.config; | |||
/* | |||
* this font base does not exist and a relative font path is used | |||
* This font base does not exist and a relative font path is used. | |||
*/ | |||
public class FontBaseBadTestCase extends BaseDestructiveUserConfigTestCase { | |||
@@ -28,14 +28,7 @@ public class FontBaseBadTestCase extends BaseDestructiveUserConfigTestCase { | |||
super(name); | |||
} | |||
public void testUserConfig() throws Exception { | |||
// Override this method from the super-class and do nothing as this test doesn't pass ATM | |||
// TODO re-enable later | |||
} | |||
/** | |||
* @see org.apache.fop.config.BaseUserConfigTestCase#getUserConfigFilename() | |||
*/ | |||
/** {@inheritDoc} */ | |||
public String getUserConfigFilename() { | |||
return "test_fontbase_bad.xconf"; | |||
} |
@@ -0,0 +1,149 @@ | |||
/* | |||
* 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.intermediate; | |||
import java.io.File; | |||
import javax.xml.transform.ErrorListener; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.dom.DOMResult; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import junit.framework.TestCase; | |||
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.apps.MimeConstants; | |||
import org.apache.fop.events.Event; | |||
import org.apache.fop.events.EventFormatter; | |||
import org.apache.fop.events.EventListener; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFSerializer; | |||
/** | |||
* This test checks the correct mimicking of a different output format. | |||
*/ | |||
public class IFMimickingTestCase extends TestCase { | |||
private FopFactory fopFactory; | |||
/** {@inheritDoc} */ | |||
protected void setUp() throws Exception { | |||
super.setUp(); | |||
fopFactory = FopFactory.newInstance(); | |||
File configFile = new File("test/test-no-xml-metrics.xconf"); | |||
fopFactory.setUserConfig(configFile); | |||
} | |||
/** | |||
* Tests IF document handler mimicking with PDF output. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testMimickingPDF() throws Exception { | |||
doTestMimicking(MimeConstants.MIME_PDF); | |||
} | |||
/** | |||
* Tests IF document handler mimicking with PostScript output. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testMimickingPS() throws Exception { | |||
doTestMimicking(MimeConstants.MIME_POSTSCRIPT); | |||
} | |||
/** | |||
* Tests IF document handler mimicking with TIFF output. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testMimickingTIFF() throws Exception { | |||
doTestMimicking(MimeConstants.MIME_TIFF); | |||
} | |||
private void doTestMimicking(String mime) throws FOPException, IFException, | |||
TransformerException { | |||
//Set up XMLRenderer to render to a DOM | |||
DOMResult domResult = new DOMResult(); | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
userAgent.getEventBroadcaster().addEventListener(new EventListener() { | |||
public void processEvent(Event event) { | |||
if (event.getEventGroupID().equals("org.apache.fop.fonts.FontEventAdapter")) { | |||
fail("There must be no font-related event! Got: " | |||
+ EventFormatter.format(event)); | |||
} | |||
} | |||
}); | |||
//Create an instance of the target renderer so the XMLRenderer can use its font setup | |||
IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler( | |||
userAgent, mime); | |||
//Setup painter | |||
IFSerializer serializer = new IFSerializer(); | |||
serializer.setContext(new IFContext(userAgent)); | |||
serializer.mimicDocumentHandler(targetHandler); | |||
serializer.setResult(domResult); | |||
userAgent.setDocumentHandlerOverride(serializer); | |||
Fop fop = fopFactory.newFop(userAgent); | |||
//minimal-pdf-a.fo uses the Gladiator font so is an ideal FO file for this test: | |||
StreamSource src = new StreamSource(new File("test/xml/pdf-a/minimal-pdf-a.fo")); | |||
TransformerFactory tFactory = TransformerFactory.newInstance(); | |||
Transformer transformer = tFactory.newTransformer(); | |||
setErrorListener(transformer); | |||
transformer.transform(src, new SAXResult(fop.getDefaultHandler())); | |||
} | |||
/** | |||
* Sets an error listener which doesn't swallow errors like Xalan's default one. | |||
* @param transformer the transformer to set the error listener on | |||
*/ | |||
protected void setErrorListener(Transformer transformer) { | |||
transformer.setErrorListener(new ErrorListener() { | |||
public void error(TransformerException exception) throws TransformerException { | |||
throw exception; | |||
} | |||
public void fatalError(TransformerException exception) throws TransformerException { | |||
throw exception; | |||
} | |||
public void warning(TransformerException exception) throws TransformerException { | |||
//ignore | |||
} | |||
}); | |||
} | |||
} |
@@ -88,7 +88,7 @@ public class IFParserTestCase extends AbstractIntermediateTestCase { | |||
/** {@inheritDoc} */ | |||
protected String getTargetMIME() { | |||
return MimeConstants.MIME_PDF + ";mode=painter"; | |||
return MimeConstants.MIME_PDF; | |||
} | |||
/** {@inheritDoc} */ |
@@ -48,12 +48,14 @@ import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.events.model.EventSeverity; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.layoutengine.EvalCheck; | |||
import org.apache.fop.layoutengine.TrueCheck; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFRenderer; | |||
import org.apache.fop.render.intermediate.IFSerializer; | |||
import org.apache.fop.util.ConsoleEventListenerForTests; | |||
import org.apache.fop.util.DelegatingContentHandler; | |||
/** | |||
@@ -106,9 +108,12 @@ public class IFTester { | |||
} | |||
} | |||
private Document createIF(Document areaTreeXML) throws TransformerException { | |||
private Document createIF(File testFile, Document areaTreeXML) throws TransformerException { | |||
try { | |||
FOUserAgent ua = fopFactory.newFOUserAgent(); | |||
ua.setBaseURL(testFile.getParentFile().toURI().toURL().toExternalForm()); | |||
ua.getEventBroadcaster().addEventListener( | |||
new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN)); | |||
IFRenderer ifRenderer = new IFRenderer(); | |||
ifRenderer.setUserAgent(ua); | |||
@@ -160,7 +165,7 @@ public class IFTester { | |||
*/ | |||
public void doIFChecks(File testFile, Element checksRoot, Document areaTreeXML) | |||
throws TransformerException { | |||
Document ifDocument = createIF(areaTreeXML); | |||
Document ifDocument = createIF(testFile, areaTreeXML); | |||
if (this.backupDir != null) { | |||
Transformer transformer = tfactory.newTransformer(); | |||
Source src = new DOMSource(ifDocument); |
@@ -0,0 +1,159 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.render; | |||
import junit.framework.TestCase; | |||
import org.apache.commons.io.output.NullOutputStream; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.area.AreaTreeHandler; | |||
import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFRenderer; | |||
import org.apache.fop.render.pdf.PDFDocumentHandler; | |||
import org.apache.fop.render.pdf.PDFRenderer; | |||
import org.apache.fop.render.rtf.RTFHandler; | |||
/** | |||
* Tests for {@link RendererFactory}. | |||
*/ | |||
public class RendererFactoryTest extends TestCase { | |||
public void testDocumentHandlerLevel() throws Exception { | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
RendererFactory factory = fopFactory.getRendererFactory(); | |||
FOUserAgent ua; | |||
IFDocumentHandler handler; | |||
IFDocumentHandler overrideHandler; | |||
ua = fopFactory.newFOUserAgent(); | |||
handler = factory.createDocumentHandler(ua, MimeConstants.MIME_PDF); | |||
assertTrue(handler instanceof PDFDocumentHandler); | |||
ua = fopFactory.newFOUserAgent(); | |||
overrideHandler = new PDFDocumentHandler(); | |||
overrideHandler.setContext(new IFContext(ua)); | |||
ua.setDocumentHandlerOverride(overrideHandler); | |||
handler = factory.createDocumentHandler(ua, null); | |||
assertTrue(handler == overrideHandler); | |||
ua = fopFactory.newFOUserAgent(); | |||
try { | |||
handler = factory.createDocumentHandler(ua, "invalid/format"); | |||
fail("Expected UnsupportedOperationException"); | |||
} catch (UnsupportedOperationException uoe) { | |||
//expected | |||
} | |||
} | |||
public void testRendererLevel() throws Exception { | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
RendererFactory factory = fopFactory.getRendererFactory(); | |||
FOUserAgent ua; | |||
Renderer renderer; | |||
Renderer overrideRenderer; | |||
ua = fopFactory.newFOUserAgent(); | |||
renderer = factory.createRenderer(ua, MimeConstants.MIME_PDF); | |||
assertTrue(renderer instanceof IFRenderer); | |||
factory.setRendererPreferred(true); //Test legacy setting | |||
ua = fopFactory.newFOUserAgent(); | |||
renderer = factory.createRenderer(ua, MimeConstants.MIME_PDF); | |||
assertTrue(renderer instanceof PDFRenderer); | |||
ua = fopFactory.newFOUserAgent(); | |||
renderer = factory.createRenderer(ua, MimeConstants.MIME_FOP_IF); | |||
assertTrue(renderer instanceof IFRenderer); | |||
factory.setRendererPreferred(false); | |||
ua = fopFactory.newFOUserAgent(); | |||
overrideRenderer = new PDFRenderer(); | |||
overrideRenderer.setUserAgent(ua); | |||
ua.setRendererOverride(overrideRenderer); | |||
renderer = factory.createRenderer(ua, null); | |||
assertTrue(renderer == overrideRenderer); | |||
ua = fopFactory.newFOUserAgent(); | |||
IFDocumentHandler overrideHandler; | |||
overrideHandler = new PDFDocumentHandler(); | |||
overrideHandler.setContext(new IFContext(ua)); | |||
ua.setDocumentHandlerOverride(overrideHandler); | |||
renderer = factory.createRenderer(ua, null); | |||
assertTrue(renderer instanceof IFRenderer); | |||
ua = fopFactory.newFOUserAgent(); | |||
try { | |||
renderer = factory.createRenderer(ua, "invalid/format"); | |||
fail("Expected UnsupportedOperationException"); | |||
} catch (UnsupportedOperationException uoe) { | |||
//expected | |||
} | |||
} | |||
public void testFOEventHandlerLevel() throws Exception { | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
RendererFactory factory = fopFactory.getRendererFactory(); | |||
FOUserAgent ua; | |||
FOEventHandler foEventHandler; | |||
FOEventHandler overrideFOEventHandler; | |||
ua = fopFactory.newFOUserAgent(); | |||
foEventHandler = factory.createFOEventHandler( | |||
ua, MimeConstants.MIME_PDF, new NullOutputStream()); | |||
assertTrue(foEventHandler instanceof AreaTreeHandler); | |||
ua = fopFactory.newFOUserAgent(); | |||
foEventHandler = factory.createFOEventHandler( | |||
ua, MimeConstants.MIME_RTF, new NullOutputStream()); | |||
assertTrue(foEventHandler instanceof RTFHandler); | |||
ua = fopFactory.newFOUserAgent(); | |||
try { | |||
foEventHandler = factory.createFOEventHandler( | |||
ua, "invalid/format", new NullOutputStream()); | |||
fail("Expected UnsupportedOperationException"); | |||
} catch (UnsupportedOperationException uoe) { | |||
//expected | |||
} | |||
ua = fopFactory.newFOUserAgent(); | |||
try { | |||
foEventHandler = factory.createFOEventHandler( | |||
ua, MimeConstants.MIME_PDF, null); | |||
fail("Expected FOPException because of missing OutputStream"); | |||
} catch (FOPException fe) { | |||
//expected | |||
} | |||
ua = fopFactory.newFOUserAgent(); | |||
overrideFOEventHandler = new RTFHandler(ua, new NullOutputStream()); | |||
ua.setFOEventHandlerOverride(overrideFOEventHandler); | |||
foEventHandler = factory.createFOEventHandler( | |||
ua, null, null); | |||
assertTrue(foEventHandler == overrideFOEventHandler); | |||
} | |||
} |