Browse Source

Merge from Trunk revisions 744927 - 763662.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764744 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Jeremias Maerki 15 years ago
parent
commit
b6a655ca97
100 changed files with 3078 additions and 1068 deletions
  1. 3
    3
      build.xml
  2. 2
    2
      examples/embedding/java/embedding/intermediate/ExampleConcat.java
  3. 1
    1
      examples/embedding/java/embedding/intermediate/ExampleStamp.java
  4. 12
    0
      src/documentation/content/xdocs/trunk/configuration.xml
  5. 13
    2
      src/documentation/content/xdocs/trunk/fonts.xml
  6. 75
    12
      src/documentation/content/xdocs/trunk/output.xml
  7. 3
    0
      src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd
  8. 1
    1
      src/documentation/skinconf.xml
  9. 1
    1
      src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory
  10. 2
    6
      src/java/org/apache/fop/afp/AFPResourceManager.java
  11. 3
    3
      src/java/org/apache/fop/afp/DataStream.java
  12. 15
    12
      src/java/org/apache/fop/afp/fonts/AFPFontCollection.java
  13. 25
    73
      src/java/org/apache/fop/afp/fonts/AFPFontReader.java
  14. 59
    17
      src/java/org/apache/fop/afp/fonts/CharacterSet.java
  15. 2
    1
      src/java/org/apache/fop/afp/fonts/FopCharacterSet.java
  16. 34
    8
      src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java
  17. 26
    8
      src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java
  18. 27
    7
      src/java/org/apache/fop/apps/FOURIResolver.java
  19. 34
    7
      src/java/org/apache/fop/apps/FOUserAgent.java
  20. 5
    3
      src/java/org/apache/fop/apps/FopFactory.java
  21. 12
    0
      src/java/org/apache/fop/apps/FopFactoryConfigurator.java
  22. 5
    2
      src/java/org/apache/fop/area/AreaTreeHandler.java
  23. 38
    2
      src/java/org/apache/fop/area/AreaTreeParser.java
  24. 1
    1
      src/java/org/apache/fop/area/CachedRenderPagesModel.java
  25. 1
    1
      src/java/org/apache/fop/area/PageSequence.java
  26. 3
    1
      src/java/org/apache/fop/area/inline/InlineArea.java
  27. 7
    0
      src/java/org/apache/fop/cli/CommandLineOptions.java
  28. 2
    0
      src/java/org/apache/fop/events/EventFormatter.xml
  29. 11
    11
      src/java/org/apache/fop/fo/Constants.java
  30. 1
    1
      src/java/org/apache/fop/fo/flow/Leader.java
  31. 8
    8
      src/java/org/apache/fop/fo/pagination/PageSequence.java
  32. 19
    0
      src/java/org/apache/fop/fo/pagination/Region.java
  33. 4
    20
      src/java/org/apache/fop/fo/pagination/RegionAfter.java
  34. 3
    19
      src/java/org/apache/fop/fo/pagination/RegionBody.java
  35. 4
    20
      src/java/org/apache/fop/fo/pagination/RegionEnd.java
  36. 4
    20
      src/java/org/apache/fop/fo/pagination/RegionStart.java
  37. 40
    0
      src/java/org/apache/fop/fo/pagination/SimplePageMaster.java
  38. 72
    0
      src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
  39. 10
    0
      src/java/org/apache/fop/fo/properties/CommonFont.java
  40. 72
    0
      src/java/org/apache/fop/fonts/FontAdder.java
  41. 101
    0
      src/java/org/apache/fop/fonts/FontDetector.java
  42. 313
    0
      src/java/org/apache/fop/fonts/FontInfoConfigurator.java
  43. 25
    0
      src/java/org/apache/fop/fonts/FontManager.java
  44. 3
    3
      src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java
  45. 1
    1
      src/java/org/apache/fop/fonts/autodetect/FontFinder.java
  46. 36
    10
      src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
  47. 30
    22
      src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  48. 10
    1
      src/java/org/apache/fop/layoutmgr/ElementListUtils.java
  49. 3
    1
      src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
  50. 16
    17
      src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  51. 7
    7
      src/java/org/apache/fop/layoutmgr/PageBreaker.java
  52. 1
    0
      src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
  53. 3
    4
      src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java
  54. 2
    2
      src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
  55. 2
    3
      src/java/org/apache/fop/pdf/AbstractPDFFontStream.java
  56. 11
    9
      src/java/org/apache/fop/pdf/AbstractPDFStream.java
  57. 3
    6
      src/java/org/apache/fop/pdf/PDFImageXObject.java
  58. 2
    3
      src/java/org/apache/fop/pdf/PDFMetadata.java
  59. 89
    0
      src/java/org/apache/fop/render/AbstractConfigurator.java
  60. 3
    11
      src/java/org/apache/fop/render/AbstractRenderer.java
  61. 12
    45
      src/java/org/apache/fop/render/AbstractRendererConfigurator.java
  62. 1
    1
      src/java/org/apache/fop/render/DefaultFontResolver.java
  63. 8
    360
      src/java/org/apache/fop/render/PrintRendererConfigurator.java
  64. 69
    17
      src/java/org/apache/fop/render/RendererFactory.java
  65. 46
    26
      src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
  66. 1
    2
      src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java
  67. 5
    3
      src/java/org/apache/fop/render/afp/AFPPainter.java
  68. 22
    2
      src/java/org/apache/fop/render/afp/AFPRenderer.java
  69. 29
    3
      src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
  70. 15
    37
      src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java
  71. 9
    73
      src/java/org/apache/fop/render/afp/extensions/AFPExtensionAttachment.java
  72. 19
    11
      src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
  73. 54
    0
      src/java/org/apache/fop/render/afp/extensions/AFPInvokeMediumMap.java
  74. 12
    15
      src/java/org/apache/fop/render/afp/extensions/AFPInvokeMediumMapElement.java
  75. 65
    1
      src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java
  76. 66
    12
      src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
  77. 8
    46
      src/java/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java
  78. 1
    2
      src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java
  79. 1
    2
      src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java
  80. 1
    0
      src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
  81. 1
    2
      src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java
  82. 6
    0
      src/java/org/apache/fop/render/print/PageableRenderer.java
  83. 1
    2
      src/java/org/apache/fop/render/ps/PSDocumentHandlerMaker.java
  84. 2
    0
      src/java/org/apache/fop/render/xml/XMLRenderer.java
  85. 10
    5
      src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java
  86. 10
    14
      src/java/org/apache/fop/svg/PDFGraphics2D.java
  87. 115
    0
      src/java/org/apache/fop/tools/fontlist/FontListGenerator.java
  88. 305
    0
      src/java/org/apache/fop/tools/fontlist/FontListMain.java
  89. 142
    0
      src/java/org/apache/fop/tools/fontlist/FontListSerializer.java
  90. 103
    0
      src/java/org/apache/fop/tools/fontlist/FontSpec.java
  91. 200
    0
      src/java/org/apache/fop/tools/fontlist/fonts2fo.xsl
  92. 42
    2
      status.xml
  93. 2
    0
      test/java/org/apache/fop/StandardTestSuite.java
  94. 56
    0
      test/java/org/apache/fop/config/FOURIResolverTestCase.java
  95. 2
    9
      test/java/org/apache/fop/config/FontBaseBadTestCase.java
  96. 149
    0
      test/java/org/apache/fop/intermediate/IFMimickingTestCase.java
  97. 1
    1
      test/java/org/apache/fop/intermediate/IFParserTestCase.java
  98. 7
    2
      test/java/org/apache/fop/intermediate/IFTester.java
  99. 159
    0
      test/java/org/apache/fop/render/RendererFactoryTest.java
  100. 0
    0
      test/java/org/apache/fop/threading/FOPTestbed.java

+ 3
- 3
build.xml View File

@@ -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>

+ 2
- 2
examples/embedding/java/embedding/intermediate/ExampleConcat.java View File

@@ -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);


+ 1
- 1
examples/embedding/java/embedding/intermediate/ExampleStamp.java View File

@@ -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);


+ 12
- 0
src/documentation/content/xdocs/trunk/configuration.xml View File

@@ -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>

+ 13
- 2
src/documentation/content/xdocs/trunk/fonts.xml View File

@@ -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>

+ 75
- 12
src/documentation/content/xdocs/trunk/output.xml View File

@@ -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>

+ 3
- 0
src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd View File

@@ -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"/>

+ 1
- 1
src/documentation/skinconf.xml View File

@@ -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
- 1
src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory View File

@@ -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

+ 2
- 6
src/java/org/apache/fop/afp/AFPResourceManager.java View File

@@ -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);


+ 3
- 3
src/java/org/apache/fop/afp/DataStream.java View File

@@ -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);
}
}


+ 15
- 12
src/java/org/apache/fop/afp/fonts/AFPFontCollection.java View File

@@ -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);
}
}

}

+ 25
- 73
src/java/org/apache/fop/afp/fonts/AFPFontReader.java View File

@@ -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);

+ 59
- 17
src/java/org/apache/fop/afp/fonts/CharacterSet.java View File

@@ -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());
}
}
}


+ 2
- 1
src/java/org/apache/fop/afp/fonts/FopCharacterSet.java View File

@@ -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;
}


+ 34
- 8
src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java View File

@@ -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
- 8
src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java View File

@@ -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();
}

+ 27
- 7
src/java/org/apache/fop/apps/FOURIResolver.java View File

@@ -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;
}

/**

+ 34
- 7
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -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

+ 5
- 3
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -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);
}

+ 12
- 0
src/java/org/apache/fop/apps/FopFactoryConfigurator.java View File

@@ -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);

+ 5
- 2
src/java/org/apache/fop/area/AreaTreeHandler.java View File

@@ -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();

+ 38
- 2
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -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");

+ 1
- 1
src/java/org/apache/fop/area/CachedRenderPagesModel.java View File

@@ -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(

+ 1
- 1
src/java/org/apache/fop/area/PageSequence.java View File

@@ -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;

+ 3
- 1
src/java/org/apache/fop/area/inline/InlineArea.java View File

@@ -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 */

+ 7
- 0
src/java/org/apache/fop/cli/CommandLineOptions.java View File

@@ -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"

+ 2
- 0
src/java/org/apache/fop/events/EventFormatter.xml View File

@@ -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>

+ 11
- 11
src/java/org/apache/fop/fo/Constants.java View File

@@ -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

+ 1
- 1
src/java/org/apache/fop/fo/flow/Leader.java View File

@@ -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;

+ 8
- 8
src/java/org/apache/fop/fo/pagination/PageSequence.java View File

@@ -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);
}
}


+ 19
- 0
src/java/org/apache/fop/fo/pagination/Region.java View File

@@ -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;

+ 4
- 20
src/java/org/apache/fop/fo/pagination/RegionAfter.java View File

@@ -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;

+ 3
- 19
src/java/org/apache/fop/fo/pagination/RegionBody.java View File

@@ -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;

+ 4
- 20
src/java/org/apache/fop/fo/pagination/RegionEnd.java View File

@@ -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;

+ 4
- 20
src/java/org/apache/fop/fo/pagination/RegionStart.java View File

@@ -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;

+ 40
- 0
src/java/org/apache/fop/fo/pagination/SimplePageMaster.java View File

@@ -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

+ 72
- 0
src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java View File

@@ -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) {

+ 10
- 0
src/java/org/apache/fop/fo/properties/CommonFont.java View File

@@ -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.

+ 72
- 0
src/java/org/apache/fop/fonts/FontAdder.java View File

@@ -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);
}
}
}
}
}

+ 101
- 0
src/java/org/apache/fop/fonts/FontDetector.java View File

@@ -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);
}
}
}

+ 313
- 0
src/java/org/apache/fop/fonts/FontInfoConfigurator.java View File

@@ -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;
}

}

+ 25
- 0
src/java/org/apache/fop/fonts/FontManager.java View File

@@ -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;
}
}
}
}
}

+ 3
- 3
src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java View File

@@ -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);

+ 1
- 1
src/java/org/apache/fop/fonts/autodetect/FontFinder.java View File

@@ -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;

}

+ 36
- 10
src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java View File

@@ -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
*

+ 30
- 22
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -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();
}
}


+ 10
- 1
src/java/org/apache/fop/layoutmgr/ElementListUtils.java View File

@@ -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;
}

}
}

+ 3
- 1
src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java View File

@@ -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");
}

+ 16
- 17
src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java View File

@@ -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;
}
}


+ 7
- 7
src/java/org/apache/fop/layoutmgr/PageBreaker.java View File

@@ -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());
}

/**

+ 1
- 0
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java View File

@@ -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);

+ 3
- 4
src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java View File

@@ -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());

+ 2
- 2
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java View File

@@ -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. */

+ 2
- 3
src/java/org/apache/fop/pdf/AbstractPDFFontStream.java View File

@@ -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;
}

}

+ 11
- 9
src/java/org/apache/fop/pdf/AbstractPDFStream.java View File

@@ -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;
}

/**

+ 3
- 6
src/java/org/apache/fop/pdf/PDFImageXObject.java View File

@@ -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();
}


}

+ 2
- 3
src/java/org/apache/fop/pdf/PDFMetadata.java View File

@@ -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;
}

/**

+ 89
- 0
src/java/org/apache/fop/render/AbstractConfigurator.java View File

@@ -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();
}

+ 3
- 11
src/java/org/apache/fop/render/AbstractRenderer.java View File

@@ -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

+ 12
- 45
src/java/org/apache/fop/render/AbstractRendererConfigurator.java View File

@@ -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;
}
}

+ 1
- 1
src/java/org/apache/fop/render/DefaultFontResolver.java View File

@@ -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());
}

}

+ 8
- 360
src/java/org/apache/fop/render/PrintRendererConfigurator.java View File

@@ -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);
}

}

+ 69
- 17
src/java/org/apache/fop/render/RendererFactory.java View File

@@ -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(

+ 46
- 26
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

@@ -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);
}
}
}


+ 1
- 2
src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java View File

@@ -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) {

+ 5
- 3
src/java/org/apache/fop/render/afp/AFPPainter.java View File

@@ -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) {

+ 22
- 2
src/java/org/apache/fop/render/afp/AFPRenderer.java View File

@@ -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} */

+ 29
- 3
src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java View File

@@ -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);

+ 15
- 37
src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java View File

@@ -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);
// }
// }
}

+ 9
- 73
src/java/org/apache/fop/render/afp/extensions/AFPExtensionAttachment.java View File

@@ -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
- 11
src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java View File

@@ -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())
}
}

+ 54
- 0
src/java/org/apache/fop/render/afp/extensions/AFPInvokeMediumMap.java View File

@@ -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() + ")";
}
}

src/java/org/apache/fop/render/afp/extensions/AFPElement.java → src/java/org/apache/fop/render/afp/extensions/AFPInvokeMediumMapElement.java View File

@@ -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();
}
}

+ 65
- 1
src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java View File

@@ -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() + ")";

+ 66
- 12
src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java View File

@@ -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());
}
}

+ 8
- 46
src/java/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java View File

@@ -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;
}

+ 1
- 2
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandlerMaker.java View File

@@ -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) {

+ 1
- 2
src/java/org/apache/fop/render/pcl/PCLDocumentHandlerMaker.java View File

@@ -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) {

+ 1
- 0
src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java View File

@@ -279,6 +279,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
pdfDoc.outputTrailer(this.outputStream);
}
this.pdfDoc = null;

pdfResources = null;
this.generator = null;
currentContext = null;

+ 1
- 2
src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java View File

@@ -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) {

+ 6
- 0
src/java/org/apache/fop/render/print/PageableRenderer.java View File

@@ -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);

+ 1
- 2
src/java/org/apache/fop/render/ps/PSDocumentHandlerMaker.java View File

@@ -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) {

+ 2
- 0
src/java/org/apache/fop/render/xml/XMLRenderer.java View File

@@ -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");

+ 10
- 5
src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java View File

@@ -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);

+ 10
- 14
src/java/org/apache/fop/svg/PDFGraphics2D.java View File

@@ -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) {

+ 115
- 0
src/java/org/apache/fop/tools/fontlist/FontListGenerator.java View File

@@ -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&lt;String/font-family, List&lt;{@link FontSpec}&gt;&gt;</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;
}

}

+ 305
- 0
src/java/org/apache/fop/tools/fontlist/FontListMain.java View File

@@ -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);
}
}

}

+ 142
- 0
src/java/org/apache/fop/tools/fontlist/FontListSerializer.java View File

@@ -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);
}

}

+ 103
- 0
src/java/org/apache/fop/tools/fontlist/FontSpec.java View File

@@ -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());
}

}

+ 200
- 0
src/java/org/apache/fop/tools/fontlist/fonts2fo.xsl View File

@@ -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) &gt; 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="&#x2212;" font-family="Symbol">&#x2022;</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>

+ 42
- 2
status.xml View File

@@ -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">

+ 2
- 0
test/java/org/apache/fop/StandardTestSuite.java View File

@@ -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;
}

+ 56
- 0
test/java/org/apache/fop/config/FOURIResolverTestCase.java View File

@@ -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
}
}

}

+ 2
- 9
test/java/org/apache/fop/config/FontBaseBadTestCase.java View File

@@ -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";
}

+ 149
- 0
test/java/org/apache/fop/intermediate/IFMimickingTestCase.java View File

@@ -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
}

});
}

}

+ 1
- 1
test/java/org/apache/fop/intermediate/IFParserTestCase.java View File

@@ -88,7 +88,7 @@ public class IFParserTestCase extends AbstractIntermediateTestCase {

/** {@inheritDoc} */
protected String getTargetMIME() {
return MimeConstants.MIME_PDF + ";mode=painter";
return MimeConstants.MIME_PDF;
}

/** {@inheritDoc} */

+ 7
- 2
test/java/org/apache/fop/intermediate/IFTester.java View File

@@ -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);

+ 159
- 0
test/java/org/apache/fop/render/RendererFactoryTest.java View File

@@ -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);
}

}

+ 0
- 0
test/java/org/apache/fop/threading/FOPTestbed.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save