Browse Source

Merged feature branch https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign (603620-746655) into Trunk.

This adds a new intermediate format to FOP. Please see the documentation for details.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@746664 13f79535-47bb-0310-9956-ffa450edef68
pull/37/head
Jeremias Maerki 15 years ago
parent
commit
2370a1d7ba
100 changed files with 5454 additions and 1209 deletions
  1. 42
    25
      build.xml
  2. 219
    0
      examples/embedding/java/embedding/atxml/ExampleConcat.java
  3. 143
    0
      examples/embedding/java/embedding/atxml/ExampleStamp.java
  4. 44
    35
      examples/embedding/java/embedding/intermediate/ExampleConcat.java
  5. 31
    27
      examples/embedding/java/embedding/intermediate/ExampleStamp.java
  6. 49
    0
      examples/embedding/xml/xslt/ifstamp.xsl
  7. 22
    10
      examples/plan/src/org/apache/fop/plan/PreloaderPlan.java
  8. 9
    6
      examples/plan/src/org/apache/fop/plan/SimplePlanDrawer.java
  9. BIN
      lib/xmlgraphics-commons-1.4svn.jar
  10. 218
    33
      src/documentation/content/xdocs/trunk/intermediate.xml
  11. 12
    10
      src/documentation/intermediate-format-ng/example1.xml
  12. 54
    35
      src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
  13. 28
    2
      src/documentation/intermediate-format-ng/fop-intermediate-format-ng-datatypes.xsd
  14. 124
    0
      src/documentation/intermediate-format-ng/fop-intermediate-format-ng-nav.xsd
  15. 30
    68
      src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd
  16. BIN
      src/documentation/resources/images/if-architecture-overview.png
  17. 973
    0
      src/documentation/resources/images/svg/if-architecture-overview.svg
  18. 20
    0
      src/java/META-INF/services/org.apache.fop.render.ImageHandler
  19. 1
    1
      src/java/META-INF/services/org.apache.fop.render.Renderer
  20. 6
    0
      src/java/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler
  21. 1
    0
      src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter
  22. 39
    2
      src/java/org/apache/fop/afp/AFPGraphics2D.java
  23. 35
    1
      src/java/org/apache/fop/afp/AFPPaintingState.java
  24. 94
    33
      src/java/org/apache/fop/afp/AFPResourceManager.java
  25. 1
    21
      src/java/org/apache/fop/afp/DataStream.java
  26. 5
    6
      src/java/org/apache/fop/afp/fonts/AFPFont.java
  27. 40
    0
      src/java/org/apache/fop/afp/fonts/CharacterSet.java
  28. 12
    23
      src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
  29. 6
    0
      src/java/org/apache/fop/afp/fonts/OutlineFont.java
  30. 5
    0
      src/java/org/apache/fop/afp/fonts/RasterFont.java
  31. 3
    4
      src/java/org/apache/fop/afp/modca/AbstractPageObject.java
  32. 8
    7
      src/java/org/apache/fop/afp/modca/GraphicsObject.java
  33. 63
    0
      src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
  34. 21
    454
      src/java/org/apache/fop/afp/modca/PresentationTextData.java
  35. 45
    15
      src/java/org/apache/fop/afp/modca/PresentationTextObject.java
  36. 76
    0
      src/java/org/apache/fop/afp/ptoca/LineDataInfoProducer.java
  37. 389
    0
      src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
  38. 69
    0
      src/java/org/apache/fop/afp/ptoca/PtocaConstants.java
  39. 39
    0
      src/java/org/apache/fop/afp/ptoca/PtocaProducer.java
  40. 62
    0
      src/java/org/apache/fop/afp/ptoca/TextDataInfoProducer.java
  41. 23
    0
      src/java/org/apache/fop/afp/ptoca/package.html
  42. 6
    4
      src/java/org/apache/fop/afp/svg/AFPImageElementBridge.java
  43. 36
    28
      src/java/org/apache/fop/afp/svg/AFPTextHandler.java
  44. 8
    0
      src/java/org/apache/fop/afp/svg/AFPTextPainter.java
  45. 60
    0
      src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java
  46. 40
    0
      src/java/org/apache/fop/afp/util/ResourceAccessor.java
  47. 58
    0
      src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java
  48. 38
    0
      src/java/org/apache/fop/apps/FOUserAgent.java
  49. 10
    0
      src/java/org/apache/fop/apps/FopFactory.java
  50. 2
    1
      src/java/org/apache/fop/apps/MimeConstants.java
  51. 58
    75
      src/java/org/apache/fop/area/AreaTreeParser.java
  52. 10
    4
      src/java/org/apache/fop/area/Page.java
  53. 0
    12
      src/java/org/apache/fop/area/RegionReference.java
  54. 3
    2
      src/java/org/apache/fop/cli/AreaTreeInputHandler.java
  55. 113
    21
      src/java/org/apache/fop/cli/CommandLineOptions.java
  56. 83
    0
      src/java/org/apache/fop/cli/IFInputHandler.java
  57. 6
    6
      src/java/org/apache/fop/fo/XMLObj.java
  58. 19
    7
      src/java/org/apache/fop/fonts/FontLoader.java
  59. 1
    1
      src/java/org/apache/fop/fonts/LazyFont.java
  60. 1
    1
      src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
  61. 8
    4
      src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
  62. 10
    5
      src/java/org/apache/fop/fonts/type1/Type1FontLoader.java
  63. 36
    0
      src/java/org/apache/fop/image/loader/batik/BatikImageFlavors.java
  64. 94
    0
      src/java/org/apache/fop/image/loader/batik/ImageConverterG2D2SVG.java
  65. 1
    2
      src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
  66. 3
    37
      src/java/org/apache/fop/pdf/PDFNumber.java
  67. 52
    23
      src/java/org/apache/fop/pdf/PDFPaintingState.java
  68. 26
    4
      src/java/org/apache/fop/pdf/PDFReference.java
  69. 9
    1
      src/java/org/apache/fop/pdf/PDFTextUtil.java
  70. 12
    4
      src/java/org/apache/fop/pdf/PDFUri.java
  71. 2
    11
      src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
  72. 141
    0
      src/java/org/apache/fop/render/AbstractImageHandlerGraphics2D.java
  73. 13
    12
      src/java/org/apache/fop/render/AbstractImageHandlerRegistry.java
  74. 2
    1
      src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
  75. 32
    1
      src/java/org/apache/fop/render/AbstractRenderer.java
  76. 2
    1
      src/java/org/apache/fop/render/AbstractRendererConfigurator.java
  77. 86
    0
      src/java/org/apache/fop/render/AbstractRenderingContext.java
  78. 1
    1
      src/java/org/apache/fop/render/Graphics2DImagePainter.java
  79. 4
    4
      src/java/org/apache/fop/render/ImageAdapter.java
  80. 27
    15
      src/java/org/apache/fop/render/ImageHandler.java
  81. 50
    0
      src/java/org/apache/fop/render/ImageHandlerBase.java
  82. 177
    0
      src/java/org/apache/fop/render/ImageHandlerRegistry.java
  83. 64
    0
      src/java/org/apache/fop/render/ImageHandlerUtil.java
  84. 12
    8
      src/java/org/apache/fop/render/PrintRenderer.java
  85. 53
    4
      src/java/org/apache/fop/render/PrintRendererConfigurator.java
  86. 2
    1
      src/java/org/apache/fop/render/Renderer.java
  87. 0
    8
      src/java/org/apache/fop/render/RendererContext.java
  88. 163
    23
      src/java/org/apache/fop/render/RendererFactory.java
  89. 71
    0
      src/java/org/apache/fop/render/RenderingContext.java
  90. 81
    0
      src/java/org/apache/fop/render/afp/AFPCustomizable.java
  91. 321
    0
      src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
  92. 54
    0
      src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.java
  93. 1
    0
      src/java/org/apache/fop/render/afp/AFPEventProducer.xml
  94. 13
    12
      src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java
  95. 47
    18
      src/java/org/apache/fop/render/afp/AFPImageHandler.java
  96. 67
    7
      src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java
  97. 24
    10
      src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java
  98. 16
    1
      src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java
  99. 64
    11
      src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
  100. 0
    0
      src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java

+ 42
- 25
build.xml View File

@@ -592,11 +592,7 @@ list of possible build targets.
<include name="org/apache/fop/area/AreaTreeControl*"/>
<include name="org/apache/fop/svg/**"/>
<include name="org/apache/fop/fonts/**"/>
<include name="org/apache/fop/image/FopImag*.class"/>
<include name="org/apache/fop/image/Jpeg*"/>
<include name="org/apache/fop/image/EPS*"/>
<include name="org/apache/fop/image/Abstract*"/>
<include name="org/apache/fop/image/analyser/*.class"/>
<include name="org/apache/fop/image/loader/batik/BatikImageFlavors*.class"/>
<include name="org/apache/fop/util/CMYKColorSpace*.class"/>
<include name="org/apache/fop/util/Color*.class"/>
<include name="org/apache/fop/util/ASCII*.class"/>
@@ -604,12 +600,14 @@ list of possible build targets.
<include name="org/apache/fop/util/SubInputStream.class"/>
<include name="org/apache/fop/util/Finalizable.class"/>
<include name="org/apache/fop/util/CharUtilities.class"/>
<include name="org/apache/fop/util/DecimalFormatCache*.class"/>
</patternset>
<!-- PDF transcoder -->
<patternset>
<include name="org/apache/fop/render/pdf/**"/>
<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/util/AbstractPaintingState**"/>
<include name="org/apache/fop/pdf/**"/>
@@ -897,25 +895,44 @@ list of possible build targets.
<test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${junit.reports.dir}" outfile="TEST-FO-tree"/>
</junit>
</target>
<target name="junit-intermediate-format" depends="junit-compile, junit-layout" description="Runs FOP's intermediate format JUnit tests" if="xmlunit.present">
<echo message="Running intermediate format tests"/>
<junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/>
<sysproperty key="fop.layoutengine.testset" value="standard"/>
<formatter type="brief" usefile="false"/>
<formatter type="plain" usefile="true"/>
<formatter type="xml" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-tools-classpath"/>
<fileset dir="build">
<include name="fop.jar"/>
</fileset>
</classpath>
<test name="org.apache.fop.intermediate.IntermediateFormatTestSuite" todir="${junit.reports.dir}" outfile="TEST-intermediate-format"/>
</junit>
<macrodef name="junit-run">
<attribute name="title"/>
<element name="tests"/>
<sequential>
<echo message="Running @{title} tests..."/>
<junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/>
<formatter type="brief" usefile="false"/>
<formatter type="plain" usefile="true"/>
<formatter type="xml" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-tools-classpath"/>
<fileset dir="build">
<include name="fop.jar"/>
</fileset>
</classpath>
<tests/>
</junit>
</sequential>
</macrodef>
<target name="junit-area-tree-xml-format" depends="junit-compile" description="Runs FOP's area tree XML format JUnit tests" if="xmlunit.present">
<junit-run title="area tree XML format">
<tests>
<sysproperty key="fop.layoutengine.testset" value="standard"/>
<test name="org.apache.fop.intermediate.AreaTreeXMLFormatTestSuite" todir="${junit.reports.dir}" outfile="TEST-area-tree-xml-format"/>
</tests>
</junit-run>
</target>
<target name="junit-intermediate-format" depends="junit-compile" description="Runs FOP's intermediate format JUnit tests" if="xmlunit.present">
<junit-run title="intermediate format">
<tests>
<sysproperty key="fop.layoutengine.testset" value="standard"/>
<test name="org.apache.fop.intermediate.IntermediateFormatTestSuite" todir="${junit.reports.dir}" outfile="TEST-intermediate-format"/>
</tests>
</junit-run>
</target>
<target name="junit-text-linebreak" depends="junit-compile" description="Runs FOP's JUnit unicode linebreak tests" if="junit.present">
<echo message="Running tests for Unicode UAX#14 support"/>
@@ -936,7 +953,7 @@ list of possible build targets.
</junit>
</target>
<target name="junit-reduced" depends="junit-userconfig, junit-basic, junit-transcoder, junit-text-linebreak, junit-fotree"/>
<target name="junit-full" depends="junit-reduced, junit-layout, junit-intermediate-format"/>
<target name="junit-full" depends="junit-reduced, junit-layout, junit-area-tree-xml-format, junit-intermediate-format"/>
<target name="junit" depends="junit-full" description="Runs all of FOP's JUnit tests" if="junit.present">
<fail><condition><or><isset property="fop.junit.error"/><isset property="fop.junit.failure"/><not><isset property="hyphenation.present"/></not></or></condition>
NOTE:

+ 219
- 0
examples/embedding/java/embedding/atxml/ExampleConcat.java View File

@@ -0,0 +1,219 @@
/*
* 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 embedding.atxml;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.SAXException;

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.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.xml.XMLRenderer;

import embedding.ExampleObj2XML;
import embedding.model.ProjectMember;
import embedding.model.ProjectTeam;

/**
* Example for the area tree XML format that demonstrates the concatenation of two documents
* rendered to the area tree XML format. A single PDF file is generated from the two area tree
* files.
*/
public class ExampleConcat {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();

/**
* Creates a sample ProjectTeam instance for this demo.
* @return ProjectTeam the newly created ProjectTeam instance
*/
public static ProjectTeam createAnotherProjectTeam() {
ProjectTeam team = new ProjectTeam();
team.setProjectName("The Dynamic Duo");
team.addMember(new ProjectMember(
"Batman", "lead", "batman@heroes.org"));
team.addMember(new ProjectMember(
"Robin", "aid", "robin@heroes.org"));
return team;
}

/**
* Converts an XSL-FO document to an area tree XML file.
* @param src the source file
* @param xslt the stylesheet file
* @param areaTreeFile the target area tree XML file
* @throws IOException In case of an I/O problem
* @throws FOPException In case of a FOP problem
* @throws TransformerException In case of a XSL transformation problem
*/
public void convertToAreaTreeXML(Source src, Source xslt, File areaTreeFile)
throws IOException, FOPException, TransformerException {

//Create a user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Create an instance of the target renderer so the XMLRenderer can use its font setup
Renderer targetRenderer = userAgent.getRendererFactory().createRenderer(
userAgent, MimeConstants.MIME_PDF);

//Create the XMLRenderer to create the area tree XML
XMLRenderer xmlRenderer = new XMLRenderer();
xmlRenderer.setUserAgent(userAgent);

//Tell the XMLRenderer to mimic the target renderer
xmlRenderer.mimicRenderer(targetRenderer);

//Make sure the prepared XMLRenderer is used
userAgent.setRendererOverride(xmlRenderer);

// Setup output
OutputStream out = new java.io.FileOutputStream(areaTreeFile);
out = new java.io.BufferedOutputStream(out);
try {
// Construct fop (the MIME type here is unimportant due to the override
// on the user agent)
Fop fop = fopFactory.newFop(null, userAgent, out);

// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer;
if (xslt != null) {
transformer = factory.newTransformer(xslt);
} else {
transformer = factory.newTransformer();
}

// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());

// Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}
}

/**
* Concatenates an array of area tree XML files to a single PDF file.
* @param files the array of area tree XML files
* @param pdffile the target PDF file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
* @throws SAXException In case of an XML-related problem
*/
public void concatToPDF(File[] files, File pdffile)
throws IOException, TransformerException, SAXException {
// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {
//Setup fonts and user agent
FontInfo fontInfo = new FontInfo();
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Construct the AreaTreeModel that will received the individual pages
AreaTreeModel treeModel = new RenderPagesModel(userAgent,
MimeConstants.MIME_PDF, fontInfo, out);

//Iterate over all area tree files
AreaTreeParser parser = new AreaTreeParser();
for (int i = 0; i < files.length; i++) {
Source src = new StreamSource(files[i]);
parser.parse(src, treeModel, userAgent);
}

//Signal the end of the processing. The renderer can finalize the target document.
treeModel.endDocument();
} finally {
out.close();
}
}

/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleConcat\n");

//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();

//Setup output file
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File[] files = new File[] {
new File(outDir, "team1.at.xml"),
new File(outDir, "team2.at.xml")};
File pdffile = new File(outDir, "ResultConcat.pdf");
for (int i = 0; i < files.length; i++) {
System.out.println("Area Tree XML file " + (i + 1) + ": "
+ files[i].getCanonicalPath());
}
System.out.println("PDF Output File: " + pdffile.getCanonicalPath());
System.out.println();


ProjectTeam team1 = ExampleObj2XML.createSampleProjectTeam();
ProjectTeam team2 = createAnotherProjectTeam();

ExampleConcat app = new ExampleConcat();

//Create area tree XML files
app.convertToAreaTreeXML(
team1.getSourceForProjectTeam(),
new StreamSource(xsltfile), files[0]);
app.convertToAreaTreeXML(
team2.getSourceForProjectTeam(),
new StreamSource(xsltfile), files[1]);

//Concatenate the individual area tree files to one document
app.concatToPDF(files, pdffile);

System.out.println("Success!");

} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}

}

+ 143
- 0
examples/embedding/java/embedding/atxml/ExampleStamp.java View File

@@ -0,0 +1,143 @@
/*
* 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 embedding.atxml;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.SAXException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.fonts.FontInfo;

import embedding.ExampleObj2XML;
import embedding.model.ProjectTeam;

/**
* Example for the area tree XML format that demonstrates the stamping of a document with some
* kind of watermark. The resulting document is then rendered to a PDF file.
*/
public class ExampleStamp {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();

/**
* Stamps an area tree XML file and renders it to a PDF file.
* @param atfile the area tree XML file
* @param stampSheet the stylesheet that does the stamping
* @param pdffile the target PDF file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
* @throws SAXException In case of an XML-related problem
*/
public void stampToPDF(File atfile, File stampSheet, File pdffile)
throws IOException, TransformerException, SAXException {
// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {
//Setup fonts and user agent
FontInfo fontInfo = new FontInfo();
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Construct the AreaTreeModel that will received the individual pages
AreaTreeModel treeModel = new RenderPagesModel(userAgent,
MimeConstants.MIME_PDF, fontInfo, out);

//Iterate over all area tree files
AreaTreeParser parser = new AreaTreeParser();
Source src = new StreamSource(atfile);
Source xslt = new StreamSource(stampSheet);

//Setup Transformer for XSLT processing
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(xslt);

//Send XSLT result to AreaTreeParser
SAXResult res = new SAXResult(parser.getContentHandler(treeModel, userAgent));

//Start XSLT transformation and area tree parsing
transformer.transform(src, res);

//Signal the end of the processing. The renderer can finalize the target document.
treeModel.endDocument();
} finally {
out.close();
}
}

/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleConcat\n");

//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();

//Setup output file
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File atfile = new File(outDir, "team.at.xml");
File stampxsltfile = new File(baseDir, "xml/xslt/atstamp.xsl");
File pdffile = new File(outDir, "ResultStamped.pdf");
System.out.println("Area Tree XML file : " + atfile.getCanonicalPath());
System.out.println("Stamp XSLT: " + stampxsltfile.getCanonicalPath());
System.out.println("PDF Output File: " + pdffile.getCanonicalPath());
System.out.println();

ProjectTeam team1 = ExampleObj2XML.createSampleProjectTeam();

//Create area tree XML file
ExampleConcat concatapp = new ExampleConcat();
concatapp.convertToAreaTreeXML(
team1.getSourceForProjectTeam(),
new StreamSource(xsltfile), atfile);

//Stamp document and produce a PDF from the area tree XML format
ExampleStamp app = new ExampleStamp();
app.stampToPDF(atfile, stampxsltfile, pdffile);

System.out.println("Success!");

} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}

}

+ 44
- 35
examples/embedding/java/embedding/intermediate/ExampleConcat.java View File

@@ -29,20 +29,22 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.SAXException;

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.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.xml.XMLRenderer;
import org.xml.sax.SAXException;
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;
import org.apache.fop.render.intermediate.IFUtil;
import org.apache.fop.render.intermediate.util.IFConcatenator;

import embedding.ExampleObj2XML;
import embedding.model.ProjectMember;
@@ -50,7 +52,7 @@ import embedding.model.ProjectTeam;

/**
* Example for the intermediate format that demonstrates the concatenation of two documents
* renderered to the intermediate format. A single PDF file is generated from the two intermediate
* rendered to the intermediate format. A single PDF file is generated from the two intermediate
* files.
*/
public class ExampleConcat {
@@ -76,7 +78,7 @@ public class ExampleConcat {
* Converts an XSL-FO document to an intermediate file.
* @param src the source file
* @param xslt the stylesheet file
* @param intermediate the target intermediate file (area tree XML)
* @param intermediate the target intermediate file
* @throws IOException In case of an I/O problem
* @throws FOPException In case of a FOP problem
* @throws TransformerException In case of a XSL transformation problem
@@ -87,25 +89,26 @@ public class ExampleConcat {
//Create a user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Create an instance of the target renderer so the XMLRenderer can use its font setup
Renderer targetRenderer = userAgent.getRendererFactory().createRenderer(
userAgent, MimeConstants.MIME_PDF);
//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");

//Create the XMLRenderer to create the intermediate format (area tree XML)
XMLRenderer xmlRenderer = new XMLRenderer();
xmlRenderer.setUserAgent(userAgent);
//Create the IFSerializer to write the intermediate format
IFSerializer ifSerializer = new IFSerializer();
ifSerializer.setContext(new IFContext(userAgent));

//Tell the XMLRenderer to mimic the target renderer
xmlRenderer.mimicRenderer(targetRenderer);
//Tell the IFSerializer to mimic the target format
ifSerializer.mimicDocumentHandler(targetHandler);

//Make sure the prepared XMLRenderer is used
userAgent.setRendererOverride(xmlRenderer);
//Make sure the prepared document handler is used
userAgent.setDocumentHandlerOverride(ifSerializer);

// Setup output
OutputStream out = new java.io.FileOutputStream(intermediate);
out = new java.io.BufferedOutputStream(out);
try {
// Construct fop (the MIME type here is unimportant due to the override
// Construct FOP (the MIME type here is unimportant due to the override
// on the user agent)
Fop fop = fopFactory.newFop(null, userAgent, out);

@@ -130,35 +133,41 @@ public class ExampleConcat {

/**
* Concatenates an array of intermediate files to a single PDF file.
* @param files the array of intermediate files (area tree XML)
* @param files the array of intermediate files
* @param pdffile the target PDF file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
* @throws SAXException In case of an XML-related problem
* @throws IFException if there was an IF-related error while creating the output file
*/
public void concatToPDF(File[] files, File pdffile)
throws IOException, TransformerException, SAXException {
throws IOException, TransformerException, SAXException, IFException {
// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {
//Setup fonts and user agent
FontInfo fontInfo = new FontInfo();
//Setup user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Construct the AreaTreeModel that will received the individual pages
AreaTreeModel treeModel = new RenderPagesModel(userAgent,
MimeConstants.MIME_PDF, fontInfo, out);
//Setup target handler
String mime = MimeConstants.MIME_PDF + ";mode=painter";
IFDocumentHandler targetHandler = fopFactory.getRendererFactory().createDocumentHandler(
userAgent, mime);

//Setup fonts
IFUtil.setupFonts(targetHandler);
targetHandler.setResult(new StreamResult(pdffile));

IFConcatenator concatenator = new IFConcatenator(targetHandler, null);

//Iterate over all intermediate files
AreaTreeParser parser = new AreaTreeParser();
for (int i = 0; i < files.length; i++) {
Source src = new StreamSource(files[i]);
parser.parse(src, treeModel, userAgent);
concatenator.appendDocument(src);
}

//Signal the end of the processing. The renderer can finalize the target document.
treeModel.endDocument();
//Signal the end of the processing so the target file can be finalized properly.
concatenator.finish();
} finally {
out.close();
}
@@ -170,7 +179,7 @@ public class ExampleConcat {
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleConcat\n");
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n");

//Setup directories
File baseDir = new File(".");
@@ -180,9 +189,9 @@ public class ExampleConcat {
//Setup output file
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File[] files = new File[] {
new File(outDir, "team1.at.xml"),
new File(outDir, "team2.at.xml")};
File pdffile = new File(outDir, "ResultConcat.pdf");
new File(outDir, "team1.if.xml"),
new File(outDir, "team2.if.xml")};
File pdffile = new File(outDir, "ResultIFConcat.pdf");
for (int i = 0; i < files.length; i++) {
System.out.println("Intermediate file " + (i + 1) + ": "
+ files[i].getCanonicalPath());

+ 31
- 27
examples/embedding/java/embedding/intermediate/ExampleStamp.java View File

@@ -28,16 +28,18 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.SAXException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.fonts.FontInfo;
import org.xml.sax.SAXException;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFParser;
import org.apache.fop.render.intermediate.IFUtil;

import embedding.ExampleObj2XML;
import embedding.model.ProjectTeam;
@@ -53,30 +55,35 @@ public class ExampleStamp {

/**
* Stamps an intermediate file and renders it to a PDF file.
* @param atfile the intermediate file (area tree XML)
* @param iffile the intermediate file (area tree XML)
* @param stampSheet the stylesheet that does the stamping
* @param pdffile the target PDF file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
* @throws SAXException In case of an XML-related problem
* @throws IFException if there was an IF-related error while creating the output file
*/
public void stampToPDF(File atfile, File stampSheet, File pdffile)
throws IOException, TransformerException, SAXException {
public void stampToPDF(File iffile, File stampSheet, File pdffile)
throws IOException, TransformerException, SAXException, IFException {
// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {
//Setup fonts and user agent
FontInfo fontInfo = new FontInfo();
//user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Construct the AreaTreeModel that will received the individual pages
AreaTreeModel treeModel = new RenderPagesModel(userAgent,
MimeConstants.MIME_PDF, fontInfo, out);
//Setup target handler
String mime = MimeConstants.MIME_PDF + ";mode=painter";
IFDocumentHandler targetHandler = fopFactory.getRendererFactory().createDocumentHandler(
userAgent, mime);

//Iterate over all intermediate files
AreaTreeParser parser = new AreaTreeParser();
Source src = new StreamSource(atfile);
//Setup fonts
IFUtil.setupFonts(targetHandler);
targetHandler.setResult(new StreamResult(pdffile));

IFParser parser = new IFParser();

Source src = new StreamSource(iffile);
Source xslt = new StreamSource(stampSheet);

//Setup Transformer for XSLT processing
@@ -84,13 +91,10 @@ public class ExampleStamp {
Transformer transformer = tFactory.newTransformer(xslt);

//Send XSLT result to AreaTreeParser
SAXResult res = new SAXResult(parser.getContentHandler(treeModel, userAgent));
SAXResult res = new SAXResult(parser.getContentHandler(targetHandler, userAgent));

//Start XSLT transformation and area tree parsing
transformer.transform(src, res);

//Signal the end of the processing. The renderer can finalize the target document.
treeModel.endDocument();
} finally {
out.close();
}
@@ -102,7 +106,7 @@ public class ExampleStamp {
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleConcat\n");
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n");

//Setup directories
File baseDir = new File(".");
@@ -111,10 +115,10 @@ public class ExampleStamp {

//Setup output file
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File atfile = new File(outDir, "team.at.xml");
File stampxsltfile = new File(baseDir, "xml/xslt/atstamp.xsl");
File pdffile = new File(outDir, "ResultStamped.pdf");
System.out.println("Intermediate file : " + atfile.getCanonicalPath());
File iffile = new File(outDir, "team.if.xml");
File stampxsltfile = new File(baseDir, "xml/xslt/ifstamp.xsl");
File pdffile = new File(outDir, "ResultIFStamped.pdf");
System.out.println("Intermediate file : " + iffile.getCanonicalPath());
System.out.println("Stamp XSLT: " + stampxsltfile.getCanonicalPath());
System.out.println("PDF Output File: " + pdffile.getCanonicalPath());
System.out.println();
@@ -125,11 +129,11 @@ public class ExampleStamp {
ExampleConcat concatapp = new ExampleConcat();
concatapp.convertToIntermediate(
team1.getSourceForProjectTeam(),
new StreamSource(xsltfile), atfile);
new StreamSource(xsltfile), iffile);

//Stamp document and produce a PDF from the intermediate format
ExampleStamp app = new ExampleStamp();
app.stampToPDF(atfile, stampxsltfile, pdffile);
app.stampToPDF(iffile, stampxsltfile, pdffile);

System.out.println("Success!");


+ 49
- 0
examples/embedding/xml/xslt/ifstamp.xsl View File

@@ -0,0 +1,49 @@
<?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:if="http://xmlgraphics.apache.org/fop/intermediate">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<!-- ========================= -->
<!-- stamping... -->
<!-- ========================= -->
<xsl:template match="if:content">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<!-- Stamp a big "SPECIMEN" text over the whole page using an area tree fragment inserted at the right place... -->
<if:g transform="translate(100000, 750000) rotate(-55)">
<if:font family="sans-serif" style="normal" weight="400" variant="normal" size="160000"
color="#dfdfdf"/>
<if:text xml:space="preserve" x="0" y="0">SPECIMEN</if:text>
</if:g>
<!-- Note: The free transformation above will not work with AFP output. In such a case,
using an embedded SVG graphic is better. -->
<xsl:apply-templates select="child::*"/>
</xsl:copy>
</xsl:template>
<!-- ========================= -->
<!-- identity transformation -->
<!-- ========================= -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

+ 22
- 10
examples/plan/src/org/apache/fop/plan/PreloaderPlan.java View File

@@ -22,6 +22,7 @@ package org.apache.fop.plan;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
@@ -43,6 +44,7 @@ import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;

import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.UnclosableInputStream;

/**
@@ -71,21 +73,16 @@ public class PreloaderPlan extends AbstractImagePreloader {

InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
try {
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
Source source = new StreamSource(in);
DOMResult res = new DOMResult();
transformer.transform(source, res);

//Have to render the plan to know its size
PlanRenderer pr = new PlanRenderer();
Document planDoc = (Document)res.getNode();
Document planDoc = getDocument(in);
Element rootEl = planDoc.getDocumentElement();
if (!PlanElementMapping.NAMESPACE.equals(rootEl.getNamespaceURI())) {
if (!PlanElementMapping.NAMESPACE.equals(
rootEl.getNamespaceURI())) {
in.reset();
return null;
}

//Have to render the plan to know its size
PlanRenderer pr = new PlanRenderer();
Document svgDoc = pr.createSVGDocument(planDoc);
float width = pr.getWidth();
float height = pr.getHeight();
@@ -119,4 +116,19 @@ public class PreloaderPlan extends AbstractImagePreloader {
}
}

private Document getDocument(InputStream in) throws TransformerException {
TransformerFactory tFactory = TransformerFactory.newInstance();
//Custom error listener to minimize output to console
ErrorListener errorListener = new DefaultErrorListener(log);
tFactory.setErrorListener(errorListener);
Transformer transformer = tFactory.newTransformer();
transformer.setErrorListener(errorListener);
Source source = new StreamSource(in);
DOMResult res = new DOMResult();
transformer.transform(source, res);

Document doc = (Document)res.getNode();
return doc;
}

}

+ 9
- 6
examples/plan/src/org/apache/fop/plan/SimplePlanDrawer.java View File

@@ -29,6 +29,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.apache.batik.dom.svg.SVGDOMImplementation;

import org.apache.fop.svg.SVGUtilities;

/**
@@ -83,13 +84,15 @@ public class SimplePlanDrawer implements PlanDrawer {

String title = "";

DOMImplementation impl =
SVGDOMImplementation.getDOMImplementation();
DOMImplementation impl
= SVGDOMImplementation.getDOMImplementation();
Document doc = impl.createDocument(SVG_NAMESPACE, "svg", null);

Element svgRoot = doc.getDocumentElement();
svgRoot.setAttributeNS(null, "width", "" + width);
svgRoot.setAttributeNS(null, "height", "" + height);
svgRoot.setAttributeNS(null, "width", Float.toString(width));
svgRoot.setAttributeNS(null, "height", Float.toString(height));
svgRoot.setAttributeNS(null, "viewBox",
"0 0 " + Float.toString(width) + " " + Float.toString(height));
svgRoot.setAttributeNS(null, "style",
"font-size:" + 8
+ ";font-family:"
@@ -99,8 +102,8 @@ public class SimplePlanDrawer implements PlanDrawer {
java.awt.Font.PLAIN, (int)fontSize);

if (bord) {
Element border =
SVGUtilities.createRect(doc, 0, 0, width, height);
Element border
= SVGUtilities.createRect(doc, 0, 0, width, height);
border.setAttributeNS(null, "style", "stroke:black;fill:none");
svgRoot.appendChild(border);
}

BIN
lib/xmlgraphics-commons-1.4svn.jar View File


+ 218
- 33
src/documentation/content/xdocs/trunk/intermediate.xml View File

@@ -24,16 +24,25 @@
</header>
<body>
<note>
Please note that the intermediate format is an <strong>advanced feature</strong> and can be ignored by most
users of Apache FOP.
Please note that the intermediate formats described here are
<strong>advanced features</strong> and can be ignored by most users of Apache FOP.
</note>
<section id="introduction">
<title>Introduction</title>
<p>
The intermediate format (IF) is a proprietary XML format that represents the area tree
generated by the layout engine. The area tree is conceptually defined in the
Apache FOP now provides two different so-called intermediate formats. The first one
(let's call it the area tree XML format) is basically a 1:1 XML representation of FOP's
area tree as generated by the layout engine. The area tree is conceptually defined in the
<a href="http://www.w3.org/TR/2001/REC-xsl-20011015/slice1.html#section-N742-Formatting">XSL-FO specification in chapter 1.1.2</a>.
The IF can be generated through the area tree XML Renderer (the XMLRenderer).
Even though the area tree is mentioned in the XSL-FO specification, this part is not
standardized. Therefore, the area tree XML format is a FOP-proprietary XML file format.
The area tree XML can be generated through the area tree XML Renderer (the XMLRenderer).
</p>
<p>
The second intermediate format (which we shall name exactly like this: the intermediate
format)
is a recent addition which tries to meet a slightly different set of goals. It is highly
optimized for speed.
</p>
<p>
The intermediate format can be used to generate intermediate documents that are modified
@@ -43,31 +52,74 @@
to a single output file.
</p>
</section>
<section id="which-if">
<title>Which Intermediate Format to choose?</title>
<p>
Both formats have their use cases, so the choice you will make will depend on your
particular situation. Here is a list of strengths and use cases for both formats:
</p>
<section id="strengths-at">
<title>Area Tree XML (AT XML)</title>
<ul>
<li>1:1 representation of FOP's area tree in XML.</li>
<li>Contains more structure information than the new intermediate format.</li>
<li>Used in FOP's layout engine test suite for regression testing.</li>
</ul>
</section>
<section id="strengths-if">
<title>Intermediate Format (IF)</title>
<ul>
<li>Highly optimized for speed.</li>
<li>Smaller XML files.</li>
<li>Easier to post-process.</li>
<li>XML Schema is available.</li>
<li>
Recommended for use cases where documents are formatted concurrently and later
concatenated to a single print job.
</li>
</ul>
</section>
<p>
More technical information about the two formats can be found on the
<a href="http://wiki.apache.org/xmlgraphics-fop/AreaTreeIntermediateXml/NewDesign">FOP Wiki</a>.
</p>
</section>
<section id="architecture">
<title>Architectural Overview</title>
<figure src="images/if-architecture-overview.png"
alt="Diagram with an architectural overview over the intermediate formats"/>
</section>
<section id="usage">
<title>Usage of the Intermediate Format</title>
<title>Usage of the Area Tree XML format (AT XML)</title>
<p>
As already mentioned, the area tree XML format is generated by using the
<strong>XMLRenderer</strong> (MIME type: <strong>application/X-fop-areatree</strong>).
So, you basically set the right MIME type for the output format and process your FO files
as if you would create a PDF file.
</p>
<p>
As already mentioned, the IF is generated by using the <strong>XMLRenderer</strong> (MIME type:
<strong>application/X-fop-areatree</strong>). So, you basically set the right MIME type for
the output format and process your FO files as if you would create a PDF file. However, there
is an important detail to consider: The various Renderers don't all use the same font sources.
To be able to create the right area tree for the ultimate output file, you need to create
the IF file using the right font setup. This is achieved by telling the XMLRenderer to mimic
another renderer. This is done by calling the XMLRenderer's mimicRenderer() method with an
instance of the ultimate target renderer as the single parameter. This has a consequence: An
IF file rendered with the Java2DRenderer may not look as expected when it was actually generated
for the PDF renderer. For renderers that use the same font setup, this restriction does not
apply (PDF and PS, for example). Generating the intermediate format file is the first step.
However, there is an important detail to consider: The
various Renderers don't all use the same font sources. To be able to create the right
area tree for the ultimate output format, you need to create the area tree XML file using
the right font setup. This is achieved by telling the XMLRenderer to mimic another
renderer. This is done by calling the XMLRenderer's mimicRenderer() method with an
instance of the ultimate target renderer as the single parameter. This has a consequence:
An area tree XML file rendered with the Java2DRenderer may not look as expected when it
was actually generated for the PDF renderer. For renderers that use the same font setup,
this restriction does not apply (PDF and PS, for example). Generating the area tree XML
format file is the first step.
</p>
<p>
The second step is to reparse the IF file using the <strong>AreaTreeParser</strong> which is
found in the org.apache.fop.area package. The pages retrieved from the IF file are added to an
AreaTreeModel instance from where they are normally rendered using one of the available Renderer
implementations. You can find examples for the IF processing in the
<a href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/"><code>examples/embedding</code></a>
directory in the FOP distribution
The second step is to reparse the file using the <strong>AreaTreeParser</strong> which is
found in the org.apache.fop.area package. The pages retrieved from the area tree XML file
are added to an AreaTreeModel instance from where they are normally rendered using one of
the available Renderer implementations. You can find examples for the area tree XML
processing in the
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/"><code>examples/embedding</code></a>
directory in the FOP distribution.
</p>
<p>
The basic pattern to parse the IF format looks like this:
The basic pattern to parse the area tree XML format looks like this:
</p>
<source><![CDATA[
FopFactory fopFactory = FopFactory.newInstance();
@@ -84,7 +136,7 @@ try {
AreaTreeModel treeModel = new RenderPagesModel(userAgent,
MimeConstants.MIME_PDF, fontInfo, out);
//Parse the IF file into the area tree
//Parse the area tree file into the area tree
AreaTreeParser parser = new AreaTreeParser();
Source src = new StreamSource(myIFFile);
parser.parse(src, treeModel, userAgent);
@@ -95,7 +147,7 @@ try {
out.close();
}]]></source>
<p>
This example simply reads an IF file and renders it to a PDF file. Please note, that in normal
This example simply reads an area tree file and renders it to a PDF file. Please note, that in normal
FOP operation you're shielded from having to instantiate the FontInfo object yourself. This
is normally a task of the AreaTreeHandler which is not present in this scenario. The same
applies to the AreaTreeModel instance, in this case an instance of a subclass called
@@ -105,7 +157,7 @@ try {
is now finished.
</p>
<p>
The intermediate format can also be used from the <a href="running.html#standalone-start">command-line</a>
The area tree XML format can also be used from the <a href="running.html#standalone-start">command-line</a>
by using the "-atin" parameter for specifying the area tree XML as input file. You can also
specify a "mimic renderer" by inserting a MIME type between "-at" and the output file.
</p>
@@ -113,8 +165,8 @@ try {
<title>Concatenating Documents</title>
<p>
This initial example is obviously not very useful. It would be faster to create the PDF file
directly. As the <a href="http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/ExampleConcat.java">ExampleConcat.java</a>
example shows you can easily parse multiple IF files in a row and add the parsed pages to the
directly. As the <a href="http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/examples/embedding/java/embedding/atxml/ExampleConcat.java">ExampleConcat.java</a>
example shows you can easily parse multiple area tree files in a row and add the parsed pages to the
same AreaTreeModel instance which essentially concatenates all the input document to one single
output document.
</p>
@@ -122,18 +174,22 @@ try {
<section id="modifying">
<title>Modifying Documents</title>
<p>
One of the most important use cases for the intermediate format is obviously modifying the area
One of the most important use cases for this format is obviously modifying the area
tree XML before finally rendering it to the target format. You can easily use XSLT to process
the IF file according to your needs. Please note, that we will currently not formally describe
the intermediate format. You need to have a good understanding its structure so you don't
the AT XML file according to your needs. Please note, that we will currently not formally describe
the area tree XML format. You need to have a good understanding its structure so you don't
create any non-parseable files. We may add an XML Schema and more detailed documentation at a
later time. You're invited to help us with that.
</p>
<note>
The area tree XML format is sensitive to changes in whitespace. If you're not careful,
the modified file may not render correctly.
</note>
</section>
<section id="advanced">
<title>Advanced Use</title>
<p>
The generation of the intermediate format as well as it parsing process has been designed to allow
The generation of the area tree format as well as it parsing process has been designed to allow
for maximum flexibility and optimization. Please note that you can call <code>setTransformerHandler()</code> on
XMLRenderer to give the XMLRenderer your own TransformerHandler instance in case you would like to
do custom serialization (to a W3C DOM, for example) and/or to directly modify the area tree using
@@ -142,5 +198,134 @@ try {
</p>
</section>
</section>
<section id="usage-if">
<title>Usage of the Intermediate Format (IF)</title>
<p>
The Intermediate Format (IF) is generated by the <strong>IFSerializer</strong>
(MIME type: <strong>application/X-fop-intermediate-format</strong>).
So, you basically set the right MIME type for the output format and process your FO files
as if you would create a PDF file.
</p>
<p>
The IFSerializer is an implementation of the <strong>IFDocumentHandler</strong> and
<strong>IFPainter</strong> interfaces. The <strong>IFRenderer</strong> class is responsible
for converting FOP's area tree into calls against these two interfaces.
</p>
<ul>
<li>
IFDocumentHandler: This interface is used on the document-level and defines the
overall structure of the Intermediate Format.
</li>
<li>
IFPainter: This interface is used to generate graphical page content like text, images
and borders.
</li>
</ul>
<p>
As with the AT XML, there is an important detail to consider: The various output
implementations don't all use the same font sources. To be able
to create the right IF for the ultimate output file, you need to create the IF file using
the right font setup. This is achieved by telling the IFRenderer (responsible for
converting the area tree into calls to the IFDocumentHandler and IFPainter interfaces)
to mimic another renderer. This is done by calling the IFSerializer's
mimicDocumentHandler() method with an instance of the ultimate target document handler
as the single parameter. This has a consequence: An IF file rendered with the
Java2DDocumentHandler may not look as expected when it was actually generated for the PDF
implementation. For implementations that use the same font setup,
this restriction does not apply (PDF and PS, for example). Generating the Intermediate
Format file is the first step.
</p>
<p>
The second step is to reparse the file using the <strong>IFParser</strong> which is
found in the org.apache.fop.render.intermediate package. The IFParser simply takes an
IFDocumentHandler instance against which it generates the appropriate calls. The IFParser
is implemented as a SAX ContentHandler so you're free to choose the method for
post-processing the IF file(s). You can use XSLT or write SAX- or DOM-based code to
manipulate the contents. You can find examples for the Intermediate Format
processing in the
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/"><code>examples/embedding</code></a>
directory in the FOP distribution.
</p>
<p>
The basic pattern to parse the intermediate format looks like this:
</p>
<source><![CDATA[
FopFactory fopFactory = FopFactory.newInstance();
// Setup output
OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {
//Setup user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent();

//Create IFDocumentHandler instance
IFDocumentHandler targetHandler;
String mime = MimeConstants.MIME_PDF;
targetHandler = fopFactory.getRendererFactory().createDocumentHandler(
userAgent, mime);

//Setup fonts
IFUtil.setupFonts(targetHandler);
//Tell the target handler where to write the PDF to
targetHandler.setResult(new StreamResult(pdffile));

//Parse the IF file
IFParser parser = new IFParser();
Source src = new StreamSource(myIFFile);
parser.parse(src, targetHandler, userAgent);
} finally {
out.close();
}]]></source>
<p>
This example simply reads an intermediate file and renders it to a PDF file. Here
IFParser.parse() is used, but you can also just get a SAX ContentHandler by using the
IFParser.getContentHandler() method.
</p>
<section id="concat-if">
<title>Concatenating Documents</title>
<p>
This initial example is obviously not very useful. It would be faster to create the PDF file
directly (without the intermediate step). As the
<a href="http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/ExampleConcat.java">ExampleConcat.java</a>
example shows you can easily parse multiple intermediate files in a row and use the
IFConcatenator class to concatenate page sequences from multiple source files to a single
output file. This particular example does the concatenation on the level of the
IFDocumentHandler interface. You could also do this in XSLT or using SAX on the XML level.
Whatever suits your process best.
</p>
</section>
<section id="modifying-if">
<title>Modifying Documents</title>
<p>
One of the most important use cases for this format is obviously modifying the
intermediate format before finally rendering it to the target format. You can easily use
XSLT to process the IF file according to your needs.
</p>
<p>
There is an XML Schema (located under
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/documentation/intermediate-format-ng/">src/documentation/intermediate-format-ng</a>)
that helps you verify that your modified content is correct.
</p>
<p>
For certain output formats there's a caveat: Formats like AFP and PCL do not support
arbitrary transformations on the IF's "viewport" and "g" elements. Possible are
only rotations in 90 degree steps and translations.
</p>
</section>
<section id="advanced-if">
<title>Advanced Use</title>
<p>
The generation of the intermediate format as well as it parsing process has been
designed to allow for maximum flexibility and optimization. So rather than just passing
in a StreamResult to IFSerializer's setResult() method, you can also use a SAXResult
or a DOMResult. And as you've already seen , the IFParser on the other side allows you
to retrieve a ContentHandler instance where you can manually send SAX events to
start the parsing process (see <code>getContentHandler()</code>).
</p>
</section>
</section>
</body>
</document>

+ 12
- 10
src/documentation/intermediate-format-ng/example1.xml View File

@@ -19,7 +19,8 @@
<document xmlns="http://xmlgraphics.apache.org/fop/intermediate"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlgraphics.apache.org/fop/intermediate fop-intermediate-format-ng.xsd"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation">
<header>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
@@ -44,7 +45,7 @@
</header>
<page-sequence id="ps1">
<page index="1" name="1">
<page index="0" name="1" width="595275" height="841889">
<page-header>
<ps:ps-setup-code xmlns:ps="apache:fop:extensions:postscript">%FOPTestPSSetupCode: General
setup code here!</ps:ps-setup-code>
@@ -52,20 +53,21 @@
<content>
<!-- Note: this is not actual content that is supposed to make any sense.
It is merely to give you an idea what the content can look like. -->
<box transform="translate(5000, 6000)" width="18000" height="10000">
<viewport transform="translate(5000, 6000)" width="18000" height="10000">
<font family="Helvetica" style="normal" weight="400" variant="normal" size="12000"
color="black"/>
<text x="1233 1241 1247 1253 1264" y="803">Hello</text>
<draw-rect x="1233" y="1200" width="20000" height="20000" fill="yellow" stroke="none"/>
<box transform="translate(1233, 1200)" width="20000" height="20000" clip="true">
<text x="1233" y="803">Hello</text>
<rect x="1233" y="1200" width="20000" height="20000" fill="yellow"/>
<viewport transform="translate(1233, 1200)" width="20000" height="20000" clip-rect="0 0 20000 20000">
<image xlink:href="myimage.svg" x="0" y="0" width="20000" height="20000"/>
</box>
</box>
</viewport>
</viewport>
</content>
<page-trailer>
<target x="1233" y="803" name="toc"/>
<target x="1233" y="1200" name="chapter1"/>
<nav:goto-xy id="toc" page-index="0" x="1233" y="803"/>
<nav:goto-xy id="chapter1" page-index="0" x="1233" y="1200"/>
</page-trailer>
</page>
</page-sequence>
<trailer/>
</document>

+ 54
- 35
src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd View File

@@ -20,15 +20,26 @@
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate"
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate">
<xs:include schemaLocation="fop-intermediate-format-ng-datatypes.xsd"/>
<xs:import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<xs:complexType name="contentType">
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="box">
<xs:element name="viewport">
<xs:complexType>
<xs:complexContent>
<xs:extension base="mf:contentType">
<xs:attribute name="transform" type="xs:string"/>
<xs:attributeGroup ref="mf:sizeAtts"/>
<xs:attribute name="clip" type="xs:boolean" default="false"/>
<xs:attribute name="clip-rect" type="mf:rectangleType"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="g">
<xs:complexType>
<xs:complexContent>
<xs:extension base="mf:contentType">
<xs:attribute name="transform" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
@@ -40,7 +51,7 @@
<xs:attribute name="variant" type="mf:fontVariantType"/>
<xs:attribute name="weight" type="mf:fontWeightType"/>
<xs:attribute name="stretch" type="mf:fontStretchType"/>
<xs:attribute name="size" type="xs:positiveInteger"/>
<xs:attribute name="size" type="mf:lengthType"/>
<xs:attribute name="color" type="mf:colorType"/>
</xs:complexType>
</xs:element>
@@ -48,50 +59,49 @@
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="x" use="required">
<xs:simpleType>
<xs:list itemType="xs:integer"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="y" use="required">
<xs:attribute name="x" use="required" type="mf:lengthType"/>
<xs:attribute name="y" use="required" type="mf:lengthType"/>
<xs:attribute name="letter-spacing" type="mf:lengthType"/>
<xs:attribute name="word-spacing" type="mf:lengthType"/>
<xs:attribute name="dx">
<xs:simpleType>
<xs:list itemType="xs:integer"/>
<xs:list itemType="mf:lengthType"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute ref="xml:space"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="clip-path">
<xs:complexType>
<xs:attribute name="d" type="mf:pathDataType" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="draw-path">
<xs:element name="clip-rect">
<xs:complexType>
<xs:attribute name="d" type="mf:pathDataType" use="required"/>
<xs:attributeGroup ref="mf:fillStrokeAtts"/>
<xs:attributeGroup ref="mf:rectAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="clip-rect">
<xs:element name="rect">
<xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/>
<xs:attributeGroup ref="mf:fillAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="draw-rect">
<xs:element name="line">
<xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/>
<xs:attributeGroup ref="mf:fillStrokeAtts"/>
<xs:attribute name="x1" use="required" type="mf:lengthType"/>
<xs:attribute name="y1" use="required" type="mf:lengthType"/>
<xs:attribute name="x2" use="required" type="mf:lengthType"/>
<xs:attribute name="y2" use="required" type="mf:lengthType"/>
<xs:attribute name="color" use="required" type="mf:colorType"/>
<xs:attribute name="stroke-width" use="required" type="mf:lengthType"/>
<xs:attribute name="style" use="required" type="mf:ruleStyle"/>
</xs:complexType>
</xs:element>
<xs:element name="draw-border-line">
<xs:element name="border-rect">
<xs:complexType>
<xs:attribute name="x1" type="xs:integer" use="required"/>
<xs:attribute name="y1" type="xs:integer" use="required"/>
<xs:attribute name="x2" type="xs:integer" use="required"/>
<xs:attribute name="y2" type="xs:integer" use="required"/>
<xs:attribute name="width" type="xs:integer" use="required"/>
<xs:attribute name="style" type="mf:borderStyle" default="solid"/>
<xs:attributeGroup ref="mf:rectAtts"/>
<xs:attribute name="start" type="mf:borderDef"/>
<xs:attribute name="end" type="mf:borderDef"/>
<xs:attribute name="before" type="mf:borderDef"/>
<xs:attribute name="after" type="mf:borderDef"/>
</xs:complexType>
</xs:element>
<xs:element name="image">
@@ -100,7 +110,7 @@
<xs:extension base="xs:anyType">
<!-- Either use element content with any namespace or xlink:href -->
<xs:attributeGroup ref="mf:rectAtts"/>
<xs:anyAttribute namespace="http://www.w3.org/1999/xlink" processContents="skip"/>
<xs:attributeGroup ref="mf:foreignAtts"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
@@ -108,16 +118,25 @@
</xs:choice>
</xs:complexType>
<xs:attributeGroup name="sizeAtts">
<xs:attribute name="width" type="xs:positiveInteger" use="required"/>
<xs:attribute name="height" type="xs:positiveInteger" use="required"/>
<xs:attribute name="width" type="mf:lengthType" use="required"/>
<xs:attribute name="height" type="mf:lengthType" use="required"/>
</xs:attributeGroup>
<xs:attributeGroup name="posAtts">
<xs:attribute name="x" type="mf:lengthType" default="0"/>
<xs:attribute name="y" type="mf:lengthType" default="0"/>
</xs:attributeGroup>
<xs:attributeGroup name="rectAtts">
<xs:attribute name="x" type="xs:integer" default="0"/>
<xs:attribute name="y" type="xs:integer" default="0"/>
<xs:attributeGroup ref="mf:posAtts"/>
<xs:attributeGroup ref="mf:sizeAtts"/>
</xs:attributeGroup>
<xs:attributeGroup name="fillStrokeAtts">
<xs:attributeGroup name="fillAtts">
<xs:attribute name="fill" type="xs:string" default="none"/>
</xs:attributeGroup>
<!--xs:attributeGroup name="fillStrokeAtts">
<xs:attribute name="fill" type="xs:string" default="none"/>
<xs:attribute name="stroke" type="xs:string" default="none"/>
</xs:attributeGroup-->
<xs:attributeGroup name="foreignAtts">
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:attributeGroup>
</xs:schema>

+ 28
- 2
src/documentation/intermediate-format-ng/fop-intermediate-format-ng-datatypes.xsd View File

@@ -22,8 +22,8 @@
<xs:simpleType name="colorType">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="pathDataType">
<xs:restriction base="xs:string"/>
<xs:simpleType name="lengthType">
<xs:restriction base="xs:int"/>
</xs:simpleType>
<xs:simpleType name="fontStyleType">
<xs:restriction base="xs:string">
@@ -77,4 +77,30 @@
<xs:enumeration value="outset"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ruleStyle">
<xs:restriction base="xs:string">
<xs:enumeration value="solid"/>
<xs:enumeration value="dotted"/>
<xs:enumeration value="dashed"/>
<xs:enumeration value="double"/>
<xs:enumeration value="groove"/>
<xs:enumeration value="ridge"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="borderDef">
<xs:restriction base="xs:string">
<!-- TODO refine me: \w+ will not be good enough for CMYK color, for example
<xs:pattern value="\((solid|dotted|dashed|double|groove|ridge|inset|outset),\w+,\d+(,collapse-(inner|outer))?"/>
-->
<xs:pattern value="\((solid|dotted|dashed|double|groove|ridge|inset|outset),.+)"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="lengthListType">
<xs:list itemType="mf:lengthType"/>
</xs:simpleType>
<xs:simpleType name="rectangleType">
<xs:restriction base="mf:lengthListType">
<xs:length value="4"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

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

@@ -0,0 +1,124 @@
<?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$ -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate/document-navigation"
xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation"
xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
<xs:import schemaLocation="fop-intermediate-format-ng-datatypes.xsd"
namespace="http://xmlgraphics.apache.org/fop/intermediate"/>
<xs:element name="bookmark-tree">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element ref="nav:bookmark"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="bookmark">
<xs:complexType>
<xs:complexContent>
<xs:extension base="nav:actionType">
<xs:sequence>
<xs:element ref="nav:bookmark" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="title" type="xs:string"/>
<xs:attribute name="starting-state">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="show"/>
<xs:enumeration value="hide"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<!-- Not yet implemented:
<xs:attribute name="color" type="if:colorType"/>
<xs:attribute name="font-style">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="normal"/>
<xs:enumeration value="italic"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="font-weight">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="normal"/>
<xs:enumeration value="bold"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
-->
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="link">
<xs:complexType>
<xs:complexContent>
<xs:extension base="nav:actionType">
<xs:attribute name="rect" type="if:rectangleType"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="actionType">
<xs:choice>
<xs:element ref="nav:goto-uri"/>
<xs:element ref="nav:goto-xy"/>
</xs:choice>
</xs:complexType>
<xs:element name="goto-uri">
<xs:complexType>
<xs:attributeGroup ref="nav:idAtts"/>
<xs:attribute name="uri" type="xs:anyURI" use="required"/>
<xs:attribute name="show-destination" use="optional" default="replace">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="new"/>
<xs:enumeration value="replace"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="goto-xy">
<xs:complexType>
<xs:attributeGroup ref="nav:refDef"/>
<xs:attribute name="page-index" type="xs:int"/>
<xs:attributeGroup ref="nav:posAtts"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="posAtts">
<xs:attribute name="x" type="if:lengthType" default="0"/>
<xs:attribute name="y" type="if:lengthType" default="0"/>
</xs:attributeGroup>
<xs:attributeGroup name="idAtts">
<xs:attribute name="id" type="xs:NCName"/>
</xs:attributeGroup>
<xs:attributeGroup name="refDef">
<xs:attributeGroup ref="nav:idAtts"/>
<xs:attribute name="idref" type="xs:NCName"/>
</xs:attributeGroup>
</xs:schema>

+ 30
- 68
src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd View File

@@ -18,111 +18,73 @@
<!-- $Id$ -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate"
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate">
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate"
xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation">
<xs:import namespace="http://xmlgraphics.apache.org/fop/intermediate/document-navigation"
schemaLocation="fop-intermediate-format-ng-nav.xsd"/>
<xs:import namespace="adobe:ns:meta/" schemaLocation="xmp-metadata.xsd"/>
<xs:import namespace="http://xmlgraphics.apache.org/fop/intermediate/document-navigation"
schemaLocation="fop-intermediate-format-ng-nav.xsd"/>
<xs:include schemaLocation="fop-intermediate-format-ng-datatypes.xsd"/>
<xs:include schemaLocation="fop-intermediate-format-ng-content.xsd"/>
<xs:element name="document">
<xs:complexType>
<xs:sequence>
<xs:element ref="mf:header"/>
<xs:element ref="mf:page-sequence"/>
<xs:element ref="mf:page-sequence" minOccurs="1" maxOccurs="unbounded"/>
<xs:element ref="mf:trailer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="header">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="x:xmpmeta" xmlns:x="adobe:ns:meta/"/>
<xs:element ref="mf:bookmark-tree"/>
<!--xs:element ref="x:xmpmeta" xmlns:x="adobe:ns:meta/"/-->
<xs:any namespace="##other" processContents="lax"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="bookmark-tree">
<xs:element name="trailer">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element ref="mf:bookmark"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="bookmark">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="bookmark-title">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="color" type="mf:colorType"/>
<xs:attribute name="font-style">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="normal"/>
<xs:enumeration value="italic"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="font-weight">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="normal"/>
<xs:enumeration value="bold"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element ref="mf:bookmark" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="external-destination" type="xs:anyURI"/>
<xs:attribute name="internal-destination" type="xs:NCName">
</xs:attribute>
<xs:attribute name="starting-state">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="show"/>
<xs:enumeration value="hide"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<!--xs:element ref="nav:bookmark-tree"/-->
<xs:any namespace="##other" processContents="lax"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="page-sequence">
<xs:complexType>
<xs:sequence>
<xs:element ref="mf:page"/>
<xs:element ref="mf:page" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID"/>
<xs:attributeGroup ref="mf:foreignAtts"/>
</xs:complexType>
</xs:element>
<xs:element name="page">
<xs:complexType>
<xs:sequence>
<xs:element name="page-header">
<xs:complexType>
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:any processContents="skip"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="page-header" type="mf:anyContent"/>
<xs:element name="content" type="mf:contentType"/>
<xs:element name="page-trailer" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="target" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="x" use="required" type="xs:integer"/>
<xs:attribute name="y" use="required" type="xs:integer"/>
<xs:attribute name="name" use="required" type="xs:ID"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="nav:link"/>
<xs:element ref="nav:goto-xy"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="index" type="xs:nonNegativeInteger" use="required"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="page-master-name" type="xs:string"/>
<xs:attributeGroup ref="mf:sizeAtts"/>
<xs:attributeGroup ref="mf:foreignAtts"/>
</xs:complexType>
</xs:element>
<xs:complexType name="anyContent">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any namespace="##other" processContents="lax"/>
</xs:choice>
</xs:complexType>
</xs:schema>

BIN
src/documentation/resources/images/if-architecture-overview.png View File


+ 973
- 0
src/documentation/resources/images/svg/if-architecture-overview.svg View File

@@ -0,0 +1,973 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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$ -->
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docbase="C:\Dev\FOP\main\docs"
sodipodi:docname="if-architecture-overview.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective129" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3213"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.5311603"
inkscape:cx="520.07452"
inkscape:cy="881.552"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
grid_units="mm"
gridtolerance="10000"
guidetolerance="10000"
showguides="true"
inkscape:guide-bbox="true"
inkscape:grid-points="true"
inkscape:window-width="1280"
inkscape:window-height="975"
inkscape:window-x="1280"
inkscape:window-y="22">
<inkscape:grid
id="GridFromPre046Settings"
type="xygrid"
originx="0px"
originy="0px"
spacingx="1mm"
spacingy="1mm"
color="#0000ff"
empcolor="#0000ff"
opacity="0.2"
empopacity="0.4"
empspacing="2" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g2901"
transform="translate(85.03936,43.01968)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
ry="0"
y="95.664871"
x="177.66095"
height="20.883432"
width="49.615047"
id="rect1872"
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.99119538;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text1874"
y="110.58022"
x="202.47726"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
y="110.58022"
x="202.47726"
id="tspan1876"
sodipodi:role="line">fo:root</tspan></text>
<rect
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:1.59498918;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect1878"
width="133.05069"
height="20.164854"
x="254.84074"
y="81.793541"
ry="0" />
<text
sodipodi:linespacing="125%"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="321.37488"
y="95.186516"
id="text1880"><tspan
sodipodi:role="line"
id="tspan1882"
x="321.37488"
y="95.186516"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans">fo:layout-master-set</tspan></text>
<rect
ry="0"
y="110.14"
x="254.84074"
height="20.164854"
width="133.05069"
id="rect1884"
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:1.59498918;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
id="text1886"
y="123.53297"
x="321.37488"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"
sodipodi:linespacing="125%"><tspan
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
y="123.53297"
x="321.37488"
id="tspan1888"
sodipodi:role="line">fo:page-sequence</tspan></text>
<path
inkscape:connection-end="#rect1878"
inkscape:connection-start="#rect1872"
inkscape:connector-type="polyline"
id="path1890"
d="M 227.7716,103.0781 L 254.04326,99.933702"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connection-end="#rect1884"
inkscape:connection-start="#rect1872"
inkscape:connector-type="polyline"
id="path1892"
d="M 227.7716,109.11064 L 254.04326,112.22968"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.74172068;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2889"
width="27.604736"
height="21.018122"
x="425.56772"
y="88.953514"
ry="0" />
<rect
ry="0"
y="116.79997"
x="425.56772"
height="21.018122"
width="27.604736"
id="rect2891"
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.74172068;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.74172068;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2893"
width="27.604736"
height="21.018122"
x="425.56772"
y="145.14642"
ry="0" />
<path
inkscape:connection-end="#rect2889"
inkscape:connection-start="#rect1884"
inkscape:connector-type="polyline"
id="path2895"
d="M 383.21018,109.3425 L 425.19686,101.956"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connection-end="#rect2891"
inkscape:connection-start="#rect1884"
inkscape:connector-type="polyline"
id="path2897"
d="M 388.68893,124.26543 L 425.19686,126.45787"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connection-end="#rect2893"
inkscape:connection-start="#rect1884"
inkscape:connector-type="polyline"
id="path2899"
d="M 357.59989,131.10235 L 425.19686,151.39969"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g2998"
transform="translate(219.685,121.0872)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<g
id="g2843">
<rect
ry="0"
y="195.09483"
x="128.27205"
height="20.448639"
width="104.87323"
id="rect1911"
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:1.42598891;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text1913"
y="208.6297"
x="181.22136"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
y="208.6297"
x="181.22136"
id="tspan1915"
sodipodi:role="line">AreaTreeModel</tspan></text>
</g>
<g
transform="translate(-21.25984,4.782451e-6)"
id="g2848">
<rect
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:1.42598891;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2831"
width="104.87322"
height="20.448639"
x="270.00433"
y="194.98007"
ry="0" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="322.17142"
y="208.40947"
id="text2833"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan2835"
x="322.17142"
y="208.40947"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans">PageSequence</tspan></text>
</g>
<g
id="g2943">
<rect
ry="0"
y="194.72183"
x="368.95871"
height="20.965132"
width="41.610195"
id="rect2837"
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.909495;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text2839"
y="208.33037"
x="389.49426"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
y="208.33037"
x="389.49426"
id="tspan2841"
sodipodi:role="line">Page</tspan></text>
</g>
<path
inkscape:connection-end="#g2848"
inkscape:connection-start="#g2843"
inkscape:connector-type="polyline"
id="path2858"
d="M 233.85827,205.26852 L 248.0315,205.25502"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connection-start="#g2848"
inkscape:connector-type="polyline"
id="path2860"
d="M 354.33071,205.2044 L 368.50396,205.2044"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
ry="0"
y="187.55232"
x="439.74191"
height="21.130945"
width="27.602772"
id="rect2937"
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.74368227;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.74368227;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2939"
width="27.602772"
height="21.130945"
x="439.74191"
y="215.89877"
ry="0" />
<rect
ry="0"
y="244.24522"
x="439.74191"
height="21.130945"
width="27.602772"
id="rect2941"
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.74368227;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
inkscape:connection-end="#rect2937"
inkscape:connection-start="#g2943"
inkscape:connector-type="polyline"
id="path2948"
d="M 411.02365,202.8422 L 439.37007,199.6926"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connection-end="#rect2939"
inkscape:connection-start="#g2943"
inkscape:connector-type="polyline"
id="path2950"
d="M 411.02365,212.29102 L 439.37007,221.73983"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connection-end="#rect2941"
inkscape:connection-start="#g2943"
inkscape:connector-type="polyline"
id="path2952"
d="M 403.82606,216.14171 L 439.48105,243.87338"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g3253"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.24847627;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2996"
width="132.39719"
height="40.27121"
x="50.730537"
y="68.447052"
ry="0" />
<text
sodipodi:linespacing="125%"
id="text3020"
y="93.801895"
x="116.34612"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="93.801895"
x="116.34612"
id="tspan3022"
sodipodi:role="line">FOTreeBuilder</tspan></text>
</g>
<g
id="g3247"
transform="translate(141.7323,12.20033)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
ry="0"
y="217.29221"
x="50.756805"
height="42.191582"
width="132.34465"
id="rect3031"
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="116.88812"
y="233.50031"
id="text3033"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3035"
x="116.88812"
y="233.50031">AreaTreeHandler</tspan><tspan
id="tspan3040"
sodipodi:role="line"
x="116.88812"
y="251.00031">(Layout Engine)</tspan></text>
</g>
<rect
style="fill:#ae9cf1;fill-opacity:1;stroke:black;stroke-width:1.77165354;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3045"
width="110.05285"
height="20.705212"
x="262.48203"
y="39.253674"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<text
sodipodi:linespacing="125%"
id="text3047"
y="53.974442"
x="317.62564"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
y="53.974442"
x="317.62564"
id="tspan3049"
sodipodi:role="line">SAX Stream</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
d="M 248.0315,53.149584 L 191.33858,74.409427"
id="path3059"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
id="path3241"
d="M 191.43839,109.27294 L 255.09931,138.99007"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
sodipodi:nodetypes="cc"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
id="path3243"
d="M 261.55988,166.75554 L 245.20176,224.44681"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
sodipodi:nodetypes="cc"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 250.3891,277.42379 L 338.12078,314.94766"
id="path3245"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 255.46357,165.63116 L 168.19427,225.27411"
id="path3258"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<text
xml:space="preserve"
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="257.95044"
y="195.39291"
id="text3260"
sodipodi:linespacing="125%"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
sodipodi:role="line"
id="tspan3262"
x="257.95044"
y="195.39291">Interface:</tspan><tspan
sodipodi:role="line"
x="257.95044"
y="207.89291"
id="tspan3264">FOEventHandler</tspan></text>
<g
id="g3282"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3268"
width="132.34465"
height="42.191582"
x="50.756802"
y="229.49254"
ry="0" />
<text
sodipodi:linespacing="125%"
id="text3270"
y="255.80757"
x="116.24895"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="255.80757"
x="116.24895"
sodipodi:role="line"
id="tspan3274">RTFHandler</tspan></text>
</g>
<g
id="g3294"
transform="translate(14.40538,-35.26891)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<path
sodipodi:nodetypes="ccccc"
id="rect3287"
d="M 63.383779,357.70983 L 127.3269,357.70983 L 127.3269,421.65409 C 118.19217,394.73019 81.653243,418.2886 63.383779,401.46117 L 63.383779,357.70983 z "
style="fill:#f8ffb7;fill-opacity:1;stroke:black;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
id="text3290"
y="382.34586"
x="83.824089"
style="font-size:12px;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="382.34586"
x="83.824089"
id="tspan3292"
sodipodi:role="line">RTF</tspan></text>
</g>
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 113.38583,279.92124 L 113.38583,315.35431"
id="path3299"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<g
id="g3390"
transform="translate(89.82496,0)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3303"
width="132.34465"
height="42.191582"
x="242.0954"
y="427.91769"
ry="0" />
<text
sodipodi:linespacing="125%"
id="text3305"
y="454.23273"
x="308.06607"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="454.23273"
x="308.06607"
sodipodi:role="line"
id="tspan3309">XMLRenderer</tspan></text>
</g>
<g
id="g3395"
transform="translate(89.82496,0)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
ry="0"
y="428.74014"
x="389.76379"
height="42.191582"
width="132.34465"
id="rect3317"
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="455.73447"
y="455.05518"
id="text3319"
sodipodi:linespacing="125%"><tspan
id="tspan3321"
sodipodi:role="line"
x="455.73447"
y="455.05518">IFRenderer</tspan></text>
</g>
<path
id="path3331"
d="M 545.66929,478.34643 L 481.88976,627.16533"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
sodipodi:nodetypes="cc"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
id="path3333"
d="M 418.11024,343.70077 L 503.14961,421.65352"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
sodipodi:nodetypes="cc"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 396.85039,343.70077 L 389.76378,421.65352"
id="path3335"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<g
id="g3371"
transform="translate(89.82496,0)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<path
sodipodi:nodetypes="ccccc"
id="path3339"
d="M 276.8687,520.21064 L 340.81182,520.21064 L 340.81182,584.1549 C 331.67709,557.231 295.13816,580.78941 276.8687,563.96198 L 276.8687,520.21064 z "
style="fill:#f8ffb7;fill-opacity:1;stroke:black;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text3341"
y="542.12598"
x="310.29745"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="542.12598"
x="310.29745"
id="tspan3343"
sodipodi:role="line">Area Tree</tspan><tspan
y="557.12598"
x="310.29745"
sodipodi:role="line"
id="tspan3345">XML</tspan></text>
</g>
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 394.54937,478.34643 L 394.54937,513.7795"
id="path3369"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<g
id="g3385"
transform="translate(89.82496,0)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
ry="0"
y="428.74014"
x="80.253777"
height="42.191582"
width="132.34465"
id="rect3379"
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="146.22444"
y="455.05518"
id="text3381"
sodipodi:linespacing="125%"><tspan
id="tspan3383"
sodipodi:role="line"
x="146.22444"
y="455.05518">AreaTreeParser</tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 394.54937,577.55903 C 394.54937,655.51179 233.85827,612.9921 233.85827,478.34643"
id="path3402"
sodipodi:nodetypes="cc"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
sodipodi:nodetypes="cc"
id="path3404"
d="M 233.85827,421.65352 C 233.85827,357.87399 276.37795,329.52754 340.15748,329.52754"
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<text
sodipodi:linespacing="125%"
id="text3406"
y="379.13385"
x="474.80316"
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
y="379.13385"
x="474.80316"
id="tspan3408"
sodipodi:role="line">Interface:</tspan><tspan
id="tspan3410"
y="391.63385"
x="474.80316"
sodipodi:role="line">Renderer</tspan></text>
<g
id="g3498"
transform="translate(-89.635853,104.63778)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<path
sodipodi:nodetypes="ccccc"
id="path3483"
d="M 651.31418,542.61673 L 715.2573,542.61673 L 715.2573,606.56099 C 706.12257,579.63709 669.58364,603.1955 651.31418,586.36807 L 651.31418,542.61673 z"
style="fill:#f8ffb7;fill-opacity:1;stroke:#000000;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text3485"
y="572.13385"
x="683.05139"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="572.13385"
x="683.05139"
id="tspan3487"
sodipodi:role="line">IF</tspan></text>
</g>
<text
xml:space="preserve"
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="602.36218"
y="627.16534"
id="text3489"
sodipodi:linespacing="125%"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
sodipodi:role="line"
id="tspan3491"
x="602.36218"
y="627.16534">Interface:</tspan><tspan
sodipodi:role="line"
x="602.36218"
y="639.66534"
id="tspan3493">ContentHandler (SAX)</tspan></text>
<g
id="g2555">
<rect
style="fill:#f1de9c;fill-opacity:1;stroke:#000000;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3505"
width="132.34465"
height="42.191582"
x="552.75592"
y="740.55115"
ry="0" />
<text
sodipodi:linespacing="125%"
id="text3507"
y="766.86621"
x="618.24805"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="766.86621"
x="618.24805"
sodipodi:role="line"
id="tspan3509">IFParser</tspan></text>
</g>
<text
sodipodi:linespacing="125%"
id="text3520"
y="522.43549"
x="590.3725"
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
y="522.43549"
x="590.3725"
id="tspan3522"
sodipodi:role="line">Interfaces:</tspan><tspan
id="tspan3524"
y="534.93549"
x="590.3725"
sodipodi:role="line">IFDocumentHandler/</tspan><tspan
y="547.43549"
x="590.3725"
sodipodi:role="line"
id="tspan2551">IFPainter</tspan></text>
<g
id="g2536">
<g
id="g3323"
transform="translate(353.51182,368.6681)">
<path
sodipodi:nodetypes="ccccc"
id="path3325"
d="M 63.383779,357.70983 L 127.3269,357.70983 L 127.3269,421.65409 C 118.19217,394.73019 81.653243,418.2886 63.383779,401.46117 L 63.383779,357.70983 z"
style="fill:#f8ffb7;fill-opacity:1;stroke:#000000;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
id="text3327"
y="382.34586"
x="83.824089"
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="382.34586"
x="83.824089"
id="tspan3329"
sodipodi:role="line">PDF</tspan></text>
</g>
<g
id="g2530">
<rect
style="fill:#f1de9c;fill-opacity:1;stroke:#000000;stroke-width:2.58850002;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3514"
width="168.63074"
height="41.904087"
x="364.55179"
y="635.05115"
ry="0" />
<text
sodipodi:linespacing="125%"
id="text3516"
y="652.47241"
x="448.18698"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="652.47241"
x="448.18698"
sodipodi:role="line"
id="tspan3518">PDFDocumentHandler/</tspan><tspan
y="669.97241"
x="448.18698"
sodipodi:role="line"
id="tspan2528">PDFPainter</tspan></text>
</g>
<path
id="path3526"
d="M 448.84954,684.51367 L 448.84954,719.94674"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
sodipodi:nodetypes="cc" />
</g>
<path
id="path3528"
d="M 595.27559,620.07872 L 595.27559,641.33856"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
sodipodi:nodetypes="cc"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
sodipodi:nodetypes="czszc"
id="path3530"
d="M 595.27559,790.15746 C 595.27559,811.4173 680.31495,811.4173 701.5748,790.15746 C 722.83465,768.89762 722.83465,708.6614 722.83465,641.33856 C 722.83465,566.92911 722.83465,520.86612 701.5748,499.60628 C 680.31496,478.34643 616.53543,471.25982 588.18898,513.77951"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<g
id="g3317"
transform="translate(-11.872214,-169.75063)"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008">
<rect
ry="0"
y="740.55115"
x="566.92914"
height="42.191582"
width="132.34465"
id="rect3308"
style="fill:#f1de9c;fill-opacity:1;stroke:#000000;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="632.42126"
y="766.86621"
id="text3310"
sodipodi:linespacing="125%"><tspan
id="tspan3312"
sodipodi:role="line"
x="632.42126"
y="766.86621">IFSerializer</tspan></text>
</g>
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 545.66929,478.34643 L 595.27559,563.3858"
id="path3322"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1"
d="M 595.27559,705.11809 L 595.27559,733.46454"
id="path3324"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008" />
<text
sodipodi:linespacing="125%"
id="text3326"
y="719.29132"
x="602.36218"
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
y="719.29132"
x="602.36218"
id="tspan3328"
sodipodi:role="line">Interface:</tspan><tspan
id="tspan3330"
y="731.79132"
x="602.36218"
sodipodi:role="line">ContentHandler (SAX)</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="560.98297"
y="812.41168"
id="text3332"
sodipodi:linespacing="125%"
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png"
inkscape:export-xdpi="95.985008"
inkscape:export-ydpi="95.985008"><tspan
sodipodi:role="line"
id="tspan3334"
x="560.98297"
y="812.41168">Interfaces:</tspan><tspan
sodipodi:role="line"
x="560.98297"
y="824.91168"
id="tspan3336">IFDocumentHandler/</tspan><tspan
sodipodi:role="line"
x="560.98297"
y="824.91168"
id="tspan2553">IFPainter</tspan></text>
</g>
</svg>

+ 20
- 0
src/java/META-INF/services/org.apache.fop.render.ImageHandler View File

@@ -0,0 +1,20 @@
org.apache.fop.render.pdf.PDFImageHandlerGraphics2D
org.apache.fop.render.pdf.PDFImageHandlerRenderedImage
org.apache.fop.render.pdf.PDFImageHandlerRawJPEG
org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax
org.apache.fop.render.pdf.PDFImageHandlerSVG
org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage
org.apache.fop.render.java2d.Java2DImageHandlerGraphics2D
org.apache.fop.render.pcl.PCLImageHandlerRenderedImage
org.apache.fop.render.pcl.PCLImageHandlerGraphics2D
org.apache.fop.render.ps.PSImageHandlerRenderedImage
org.apache.fop.render.ps.PSImageHandlerEPS
org.apache.fop.render.ps.PSImageHandlerRawCCITTFax
org.apache.fop.render.ps.PSImageHandlerRawJPEG
org.apache.fop.render.ps.PSImageHandlerGraphics2D
org.apache.fop.render.ps.PSImageHandlerSVG
org.apache.fop.render.afp.AFPImageHandlerRenderedImage
org.apache.fop.render.afp.AFPImageHandlerGraphics2D
org.apache.fop.render.afp.AFPImageHandlerRawStream
org.apache.fop.render.afp.AFPImageHandlerRawCCITTFax
org.apache.fop.render.afp.AFPImageHandlerSVG

+ 1
- 1
src/java/META-INF/services/org.apache.fop.render.Renderer View File

@@ -7,4 +7,4 @@ org.apache.fop.render.xml.XMLRendererMaker
org.apache.fop.render.awt.AWTRendererMaker
org.apache.fop.render.print.PrintRendererMaker
org.apache.fop.render.afp.AFPRendererMaker
org.apache.fop.render.pcl.PCLRendererMaker
org.apache.fop.render.pcl.PCLRendererMaker

+ 6
- 0
src/java/META-INF/services/org.apache.fop.render.intermediate.IFDocumentHandler View File

@@ -0,0 +1,6 @@
org.apache.fop.render.pdf.PDFDocumentHandlerMaker
org.apache.fop.render.pcl.PCLDocumentHandlerMaker
org.apache.fop.render.bitmap.TIFFDocumentHandlerMaker
org.apache.fop.render.ps.PSDocumentHandlerMaker
org.apache.fop.render.afp.AFPDocumentHandlerMaker
org.apache.fop.render.intermediate.IFSerializerMaker

+ 1
- 0
src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter View File

@@ -1,2 +1,3 @@
org.apache.fop.image.loader.batik.ImageConverterSVG2G2D
org.apache.fop.image.loader.batik.ImageConverterG2D2SVG
org.apache.fop.image.loader.batik.ImageConverterWMF2G2D

+ 39
- 2
src/java/org/apache/fop/afp/AFPGraphics2D.java View File

@@ -57,6 +57,7 @@ import org.apache.xmlgraphics.java2d.StrokingTextHandler;
import org.apache.xmlgraphics.java2d.TextHandler;
import org.apache.xmlgraphics.ps.ImageEncodingHelper;
import org.apache.xmlgraphics.util.MimeConstants;
import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.afp.goca.GraphicsSetLineType;
import org.apache.fop.afp.modca.GraphicsObject;
@@ -236,6 +237,32 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand
this.gc = gc;
}

private int getResolution() {
return this.paintingState.getResolution();
}

/**
* Converts a length value to an absolute value.
* Please note that this only uses the "ScaleY" factor, so this will result
* in a bad value should "ScaleX" and "ScaleY" be different.
* @param length the length
* @return the absolute length
*/
public double convertToAbsoluteLength(double length) {
AffineTransform current = getTransform();
double mult = getResolution() / (double)UnitConv.IN2PT;
double factor = -current.getScaleY() / mult;
return length * factor;
}

/** IBM's AFP Workbench paints lines that are wider than expected. We correct manually. */
private static final double GUESSED_WIDTH_CORRECTION = 1.7;

private static final double SPEC_NORMAL_LINE_WIDTH = UnitConv.in2pt(0.01); //"approx" 0.01 inch
private static final double NORMAL_LINE_WIDTH
= SPEC_NORMAL_LINE_WIDTH * GUESSED_WIDTH_CORRECTION;


/**
* Apply the stroke to the AFP graphics object.
* This takes the java stroke and outputs the appropriate settings
@@ -249,7 +276,17 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand

// set line width
float lineWidth = basicStroke.getLineWidth();
graphicsObj.setLineWidth(Math.round(lineWidth / 2));
if (false) {
//Old approach. Retained until verified problems with 1440 resolution
graphicsObj.setLineWidth(Math.round(lineWidth / 2));
} else {
double absoluteLineWidth = lineWidth * Math.abs(getTransform().getScaleY());
double multiplier = absoluteLineWidth / NORMAL_LINE_WIDTH;
graphicsObj.setLineWidth((int)Math.round(multiplier));
//TODO Use GSFLW instead of GSLW for higher accuracy?
}

//No line join, miter limit and end cap support in GOCA. :-(

// set line type/style (note: this is an approximation at best!)
float[] dashArray = basicStroke.getDashArray();
@@ -689,7 +726,7 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand
/** {@inheritDoc} */
public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image,
float x, float y, float width, float height) {
log.debug("NYI: addNativeImage() "+ "image=" + image
log.debug("NYI: addNativeImage() " + "image=" + image
+ ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height);
}


+ 35
- 1
src/java/org/apache/fop/afp/AFPPaintingState.java View File

@@ -19,8 +19,11 @@

package org.apache.fop.afp;

import java.awt.Point;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.fonts.AFPPageFonts;
import org.apache.fop.util.AbstractPaintingState;

@@ -53,7 +56,7 @@ implements Cloneable {
private int resolution = 240; // 240 dpi

/** the current page */
private AFPPagePaintingState pagePaintingState = new AFPPagePaintingState();
private transient AFPPagePaintingState pagePaintingState = new AFPPagePaintingState();

// /** reference orientation */
// private int orientation = 0;
@@ -313,6 +316,37 @@ implements Cloneable {
return this.unitConv;
}

/**
* Returns a point on the current page, taking the current painting state into account.
*
* @param x the X-coordinate
* @param y the Y-coordinate
* @return a point on the current page
*/
public Point getPoint(int x, int y) {
Point p = new Point();
int rotation = getRotation();
switch (rotation) {
case 90:
p.x = y;
p.y = getPageWidth() - x;
break;
case 180:
p.x = getPageWidth() - x;
p.y = getPageHeight() - y;
break;
case 270:
p.x = getPageHeight() - y;
p.y = x;
break;
default:
p.x = x;
p.y = y;
break;
}
return p;
}

/** {@inheritDoc} */
public Object clone() {
AFPPaintingState paintingState = (AFPPaintingState)super.clone();

+ 94
- 33
src/java/org/apache/fop/afp/AFPResourceManager.java View File

@@ -21,19 +21,32 @@ package org.apache.fop.afp;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.modca.AbstractNamedAFPObject;
import org.apache.fop.afp.modca.AbstractPageObject;
import org.apache.fop.afp.modca.IncludeObject;
import org.apache.fop.afp.modca.IncludedResourceObject;
import org.apache.fop.afp.modca.PageSegment;
import org.apache.fop.afp.modca.Registry;
import org.apache.fop.afp.modca.ResourceGroup;
import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.afp.util.ResourceAccessor;
import org.apache.fop.afp.util.SimpleResourceAccessor;

/**
* Manages the creation and storage of document resources
*/
public class AFPResourceManager {

/** logging instance */
private static Log log = LogFactory.getLog(AFPResourceManager.class);

/** The AFP datastream (document tree) */
private DataStream dataStream;

@@ -47,8 +60,8 @@ public class AFPResourceManager {
/** Maintain a reference count of instream objects for referencing purposes */
private int instreamObjectCount = 0;

/** a mapping of resourceInfo --> names of includable objects */
private final Map/*<AFPResourceInfo,String>*/ includableObjectsMap
/** a mapping of resourceInfo --> include name */
private final Map/*<AFPResourceInfo,String>*/ includeNameMap
= new java.util.HashMap()/*<AFPResourceInfo,String>*/;

private Map pageSegmentMap = new java.util.HashMap();
@@ -120,7 +133,7 @@ public class AFPResourceManager {
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
updateResourceInfoUri(resourceInfo);

String objectName = (String)includableObjectsMap.get(resourceInfo);
String objectName = (String)includeNameMap.get(resourceInfo);
if (objectName != null) {
// an existing data resource so reference it by adding an include to the current page
includeObject(dataObjectInfo, objectName);
@@ -156,35 +169,35 @@ public class AFPResourceManager {
useInclude &= resourceGroup != null;
if (useInclude) {

boolean usePageSegment = dataObjectInfo.isCreatePageSegment();

// if it is to reside within a resource group at print-file or external level
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) {
if (usePageSegment) {
String pageSegmentName = "S10" + namedObj.getName().substring(3);
namedObj.setName(pageSegmentName);
PageSegment seg = new PageSegment(pageSegmentName);
seg.addObject(namedObj);
namedObj = seg;
}
boolean usePageSegment = dataObjectInfo.isCreatePageSegment();

// wrap newly created data object in a resource object
namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType);
// if it is to reside within a resource group at print-file or external level
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) {
if (usePageSegment) {
String pageSegmentName = "S10" + namedObj.getName().substring(3);
namedObj.setName(pageSegmentName);
PageSegment seg = new PageSegment(pageSegmentName);
seg.addObject(namedObj);
namedObj = seg;
}

// add data object into its resource group destination
resourceGroup.addObject(namedObj);
// wrap newly created data object in a resource object
namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType);
}

// create the include object
objectName = namedObj.getName();
if (usePageSegment) {
includePageSegment(dataObjectInfo, objectName);
pageSegmentMap.put(resourceInfo, objectName);
} else {
includeObject(dataObjectInfo, objectName);
// record mapping of resource info to data object resource name
includableObjectsMap.put(resourceInfo, objectName);
}
// add data object into its resource group destination
resourceGroup.addObject(namedObj);

// create the include object
objectName = namedObj.getName();
if (usePageSegment) {
includePageSegment(dataObjectInfo, objectName);
pageSegmentMap.put(resourceInfo, objectName);
} else {
includeObject(dataObjectInfo, objectName);
// record mapping of resource info to data object resource name
includeNameMap.put(resourceInfo, objectName);
}

} else {
// not to be included so inline data object directly into the current page
@@ -206,10 +219,10 @@ public class AFPResourceManager {

private void includeObject(AFPDataObjectInfo dataObjectInfo,
String objectName) {
IncludeObject includeObject
= dataObjectFactory.createInclude(objectName, dataObjectInfo);
dataStream.getCurrentPage().addObject(includeObject);
}
IncludeObject includeObject
= dataObjectFactory.createInclude(objectName, dataObjectInfo);
dataStream.getCurrentPage().addObject(includeObject);
}

private void includePageSegment(AFPDataObjectInfo dataObjectInfo,
String pageSegmentName) {
@@ -220,6 +233,53 @@ public class AFPResourceManager {
currentPage.createIncludePageSegment(pageSegmentName, x, y, createHardPageSegments);
}

/**
* 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 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,
byte resourceObjectType) throws IOException {
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE);
URI uri;
try {
uri = new URI(resourceName.trim());
} catch (URISyntaxException e) {
throw new IOException("Could not create URI from resource name: " + resourceName
+ " (" + e.getMessage() + ")");
}

AFPResourceInfo resourceInfo = new AFPResourceInfo();
resourceInfo.setLevel(resourceLevel);
resourceInfo.setName(resourceName);
resourceInfo.setUri(uri.toASCIIString());

String objectName = (String)includeNameMap.get(resourceInfo);
if (objectName == null) {
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);

ResourceObject resourceObject = factory.createResource(resourceName);
resourceObject.setDataObject(resourceContent);
resourceObject.setType(resourceObjectType);

ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
resourceGroup.addObject(resourceObject);
// record mapping of resource info to data object resource name
includeNameMap.put(resourceInfo, resourceName);
} else {
//skip, already created
}
}

/**
* Sets resource level defaults. The existing defaults over merged with the ones passed in
* as parameter.
@@ -236,4 +296,5 @@ public class AFPResourceManager {
public AFPResourceLevelDefaults getResourceLevelDefaults() {
return this.resourceLevelDefaults;
}
}

}

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

@@ -340,27 +340,7 @@ public class DataStream {
* @return a point on the current page
*/
private Point getPoint(int x, int y) {
Point p = new Point();
int rotation = paintingState.getRotation();
switch (rotation) {
case 90:
p.x = y;
p.y = currentPage.getWidth() - x;
break;
case 180:
p.x = currentPage.getWidth() - x;
p.y = currentPage.getHeight() - y;
break;
case 270:
p.x = currentPage.getHeight() - y;
p.y = x;
break;
default:
p.x = x;
p.y = y;
break;
}
return p;
return paintingState.getPoint(x, y);
}

/**

+ 5
- 6
src/java/org/apache/fop/afp/fonts/AFPFont.java View File

@@ -97,13 +97,12 @@ public abstract class AFPFont extends Typeface {
*/
public abstract CharacterSet getCharacterSet(int size);

/**
* Determines whether this font contains a particular character/glyph.
* @param c character to check
* @return True if the character is supported, False otherwise
/**
* Indicates if this font may be embedded.
* @return True, if embedding is possible/permitted
*/
public boolean hasChar(char c) {
return true;
public boolean isEmbeddable() {
return false; //TODO Complete AFP font embedding
}

/** {@inheritDoc} */

+ 40
- 0
src/java/org/apache/fop/afp/fonts/CharacterSet.java View File

@@ -21,10 +21,17 @@ package org.apache.fop.afp.fonts;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.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.StringUtils;

@@ -65,6 +72,9 @@ public class CharacterSet {
/** The encoding used for the code page */
protected String encoding;

/** The charset encoder corresponding to this encoding */
private CharsetEncoder encoder;

/** The character set relating to the font */
protected String name;

@@ -104,6 +114,8 @@ public class CharacterSet {
}
this.codePage = codePage;
this.encoding = encoding;
this.encoder = Charset.forName(encoding).newEncoder();
this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
this.path = path;

this.characterSetOrientations = new java.util.HashMap(4);
@@ -303,6 +315,33 @@ public class CharacterSet {
return c;
}

/**
* Indicates whether the given char in the character set.
* @param c the character to check
* @return true if the character is in the character set
*/
public boolean hasChar(char c) {
return encoder.canEncode(c);
}

/**
* Encodes a character sequence to a byte array.
* @param chars the characters
* @return the encoded characters
* @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();
} else {
bb.rewind();
byte[] bytes = new byte[bb.remaining()];
bb.get(bytes);
return bytes;
}
}

/**
* Map a Unicode character to a code point in the font.
* The code tables are already converted to Unicode therefore
@@ -312,6 +351,7 @@ public class CharacterSet {
* @return the mapped character
*/
public char mapChar(char c) {
//TODO This is not strictly correct but we'll let it be for the moment
return c;
}


+ 12
- 23
src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java View File

@@ -40,16 +40,6 @@ package org.apache.fop.afp.fonts;
*/
public class CharacterSetOrientation {

/**
* The code page to which the character set relates
*/
private String codePage;

/**
* The encoding used for the code page
*/
private String encoding;

/**
* The ascender height for the character set
*/
@@ -66,9 +56,9 @@ public class CharacterSetOrientation {
private int capHeight;

/**
* The characters in the charcater set
* The character widths in the character set
*/
private int[] chars = new int[256];
private int[] charsWidths = new int[256];

/**
* The height of lowercase letters
@@ -166,8 +156,8 @@ public class CharacterSetOrientation {
* @return the widths of all characters
*/
public int[] getWidths() {
int arr[] = new int[(getLastChar() - getFirstChar()) + 1];
System.arraycopy(chars, getFirstChar(), arr, 0, (getLastChar() - getFirstChar()) + 1);
int[] arr = new int[(getLastChar() - getFirstChar()) + 1];
System.arraycopy(charsWidths, getFirstChar(), arr, 0, (getLastChar() - getFirstChar()) + 1);
return arr;
}

@@ -187,11 +177,11 @@ public class CharacterSetOrientation {
* @return the widths of the character
*/
public int getWidth(int characterIndex) {
if (characterIndex >= chars.length) {
if (characterIndex >= charsWidths.length) {
throw new IllegalArgumentException("Invalid character index: "
+ characterIndex + ", maximum is " + (chars.length - 1));
+ characterIndex + ", maximum is " + (charsWidths.length - 1));
}
return chars[characterIndex];
return charsWidths[characterIndex];
}

/**
@@ -253,14 +243,13 @@ public class CharacterSetOrientation {
* @param width the widths of the character
*/
public void setWidth(int character, int width) {

if (character >= chars.length) {
if (character >= charsWidths.length) {
// Increase the size of the array if necessary
int arr[] = new int[(character - firstChar) + 1];
System.arraycopy(chars, 0, arr, 0, chars.length);
chars = arr;
int[] arr = new int[(character - firstChar) + 1];
System.arraycopy(charsWidths, 0, arr, 0, charsWidths.length);
charsWidths = arr;
}
chars[character] = width;
charsWidths[character] = width;

}


+ 6
- 0
src/java/org/apache/fop/afp/fonts/OutlineFont.java View File

@@ -166,6 +166,11 @@ public class OutlineFont extends AFPFont {
return getWidths(1000);
}

/** {@inheritDoc} */
public boolean hasChar(char c) {
return charSet.hasChar(c);
}

/**
* Map a Unicode character to a code point in the font.
* @param c character to map
@@ -179,4 +184,5 @@ public class OutlineFont extends AFPFont {
public String getEncodingName() {
return charSet.getEncoding();
}

}

+ 5
- 0
src/java/org/apache/fop/afp/fonts/RasterFont.java View File

@@ -221,6 +221,11 @@ public class RasterFont extends AFPFont {
return getWidths(1000);
}

/** {@inheritDoc} */
public boolean hasChar(char c) {
return charSet.hasChar(c);
}

/**
* Map a Unicode character to a code point in the font.
* @param c character to map

+ 3
- 4
src/java/org/apache/fop/afp/modca/AbstractPageObject.java View File

@@ -35,7 +35,7 @@ import org.apache.fop.afp.fonts.AFPFont;
* page has a set of data objects associated with it. Each page within a
* document is independent from any other page, and each must establish its own
* environment parameters.
*
* <p>
* The page is the level in the document component hierarchy that is used for
* printing or displaying a document's content. The data objects contained in
* the page envelope in the data stream are presented when the page is
@@ -43,12 +43,11 @@ import org.apache.fop.afp.fonts.AFPFont;
* directs the placement and orientation of the data on the page. In addition,
* each page contains layout information that specifies the measurement units,
* page width, and page depth.
*
* <p>
* A page is initiated by a begin page structured field and terminated by an end
* page structured field. Structured fields that define objects and active
* environment groups or that specify attributes of the page may be encountered
* in page state.
*
*/
public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable {

@@ -202,7 +201,7 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject implemen
*
* @return the presentation text object
*/
private PresentationTextObject getPresentationTextObject() {
public PresentationTextObject getPresentationTextObject() {
if (currentPresentationTextObject == null) {
PresentationTextObject presentationTextObject
= factory.createPresentationTextObject();

+ 8
- 7
src/java/org/apache/fop/afp/modca/GraphicsObject.java View File

@@ -179,20 +179,20 @@ public class GraphicsObject extends AbstractDataObject {
}

/**
* Sets whether the following shape is to be filled
* Sets whether the following shape is to be filled.
*
* @param fill true if the following shape is to be filled
*/
public void setFill(boolean fill) {
setPatternSymbol(fill ?
GraphicsSetPatternSymbol.SOLID_FILL :
GraphicsSetPatternSymbol.NO_FILL);
setPatternSymbol(fill
? GraphicsSetPatternSymbol.SOLID_FILL
: GraphicsSetPatternSymbol.NO_FILL);
}

/**
* Sets the fill pattern of the next shape
* Sets the fill pattern of the next shape.
*
* @param the fill pattern of the next shape
* @param patternSymbol the fill pattern of the next shape
*/
public void setPatternSymbol(byte patternSymbol) {
if (patternSymbol != graphicsState.patternSymbol) {
@@ -332,6 +332,7 @@ public class GraphicsObject extends AbstractDataObject {
*/
public void newSegment() {
getData().newSegment();
graphicsState.lineWidth = 0; //Looks like a new segment invalidates the graphics state
}

/** {@inheritDoc} */
@@ -366,7 +367,7 @@ public class GraphicsObject extends AbstractDataObject {
}

/** the internal graphics state */
private class GraphicsState {
private static class GraphicsState {
/** the current color */
private Color color;


+ 63
- 0
src/java/org/apache/fop/afp/modca/IncludedResourceObject.java View File

@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.modca;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;

import org.apache.commons.io.IOUtils;

import org.apache.fop.afp.util.ResourceAccessor;


/**
* Encapsulates an included resource object that is loaded from an external file.
*/
public class IncludedResourceObject extends AbstractNamedAFPObject {

private ResourceAccessor resourceAccessor;
private URI uri;

/**
* Main constructor.
* @param name the name of the included resource
* @param resourceAccessor the resource accessor to load the external file with
* @param uri the URI of the external file
*/
public IncludedResourceObject(String name,
ResourceAccessor resourceAccessor, URI uri) {
super(name);
this.resourceAccessor = resourceAccessor;
this.uri = uri;
}

/** {@inheritDoc} */
public void writeToStream(OutputStream os) throws IOException {
InputStream in = resourceAccessor.createInputStream(this.uri);
try {
IOUtils.copy(in, os);
} finally {
IOUtils.closeQuietly(in);
}
}

}

+ 21
- 454
src/java/org/apache/fop/afp/modca/PresentationTextData.java View File

@@ -19,14 +19,13 @@

package org.apache.fop.afp.modca;

import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.fop.afp.AFPLineDataInfo;
import org.apache.fop.afp.AFPTextDataInfo;

import org.apache.fop.afp.ptoca.PtocaBuilder;
import org.apache.fop.afp.ptoca.PtocaConstants;
import org.apache.fop.afp.util.BinaryUtils;

/**
@@ -36,20 +35,21 @@ import org.apache.fop.afp.util.BinaryUtils;
* that position them - modal control sequences that adjust the positions by
* small amounts - other functions causing text to be presented with differences
* in appearance.
*
* <p>
* The graphic characters are expected to conform to a coded font representation
* so that they can be translated from the code point in the object data to the
* character in the coded font. The units of measure for linear displacements
* are derived from the PresentationTextDescriptor or from the hierarchical
* defaults.
*
* <p>
* In addition to graphic character code points, Presentation Text data can
* contain embedded control sequences. These are strings of two or more bytes
* which signal an alternate mode of processing for the content of the current
* Presentation Text data.
*
* <p>
* The content for this object can be created using {@link PtocaBuilder}.
*/
public class PresentationTextData extends AbstractAFPObject {
public class PresentationTextData extends AbstractAFPObject implements PtocaConstants {

/** the maximum size of the presentation text data.*/
private static final int MAX_SIZE = 8192;
@@ -57,27 +57,6 @@ public class PresentationTextData extends AbstractAFPObject {
/** the AFP data relating to this presentation text data. */
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();

/** the current x coordinate. */
private int currentX = -1;

/** the current y cooridnate */
private int currentY = -1;

/** the current font */
private String currentFont = "";

/** the current orientation */
private int currentOrientation = 0;

/** the current color */
private Color currentColor = new Color(0, 0, 0);

/** the current variable space increment */
private int currentVariableSpaceCharacterIncrement = 0;

/** the current inter character adjustment */
private int currentInterCharacterAdjustment = 0;

/**
* Default constructor for the PresentationTextData.
*/
@@ -85,6 +64,8 @@ public class PresentationTextData extends AbstractAFPObject {
this(false);
}

private static final int HEADER_LENGTH = 9;

/**
* Constructor for the PresentationTextData, the boolean flag indicate
* whether the control sequence prefix should be set to indicate the start
@@ -105,7 +86,7 @@ public class PresentationTextData extends AbstractAFPObject {
0x00, // Reserved
0x00, // Reserved
};
baos.write(data, 0, 9);
baos.write(data, 0, HEADER_LENGTH);

if (controlInd) {
baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2);
@@ -113,420 +94,25 @@ public class PresentationTextData extends AbstractAFPObject {
}

/**
* The Set Coded Font Local control sequence activates a coded font and
* specifies the character attributes to be used. This is a modal control
* sequence.
*
* @param font
* The font local identifier.
* @param afpdata
* The output stream to which data should be written.
*/
private void setCodedFont(byte font, ByteArrayOutputStream afpdata) {
// Avoid unnecessary specification of the font
if (String.valueOf(font).equals(currentFont)) {
return;
} else {
currentFont = String.valueOf(font);
}

afpdata.write(new byte[] {0x03, (byte) 0xF1, font}, 0, 3);
}

/**
* Establishes the current presentation position on the baseline at a new
* I-axis coordinate, which is a specified number of measurement units from
* the B-axis. There is no change to the current B-axis coordinate.
*
* @param coordinate
* The coordinate for the inline move.
* @param afpdata
* The output stream to which data should be written.
*/
private void absoluteMoveInline(int coordinate,
ByteArrayOutputStream afpdata) {
byte[] b = BinaryUtils.convert(coordinate, 2);
afpdata.write(new byte[] {0x04, (byte) 0xC7, b[0], b[1]}, 0, 4);
currentX = coordinate;
}

/**
* Establishes the baseline and the current presentation position at a new
* B-axis coordinate, which is a specified number of measurement units from
* the I-axis. There is no change to the current I-axis coordinate.
*
* @param coordinate
* The coordinate for the baseline move.
* @param afpdata
* The output stream to which data should be written.
*/
private void absoluteMoveBaseline(int coordinate,
ByteArrayOutputStream afpdata) {
byte[] b = BinaryUtils.convert(coordinate, 2);
afpdata.write(new byte[] {0x04, (byte) 0xD3, b[0], b[1]}, 0, 4);
currentY = coordinate;
}

private static final int TRANSPARENT_MAX_SIZE = 253;

/**
* The Transparent Data control sequence contains a sequence of code points
* that are presented without a scan for embedded control sequences.
*
* @param data
* The text data to add.
* @param afpdata
* The output stream to which data should be written.
*/
private void addTransparentData(byte[] data, ByteArrayOutputStream afpdata) {
// Calculate the length
int l = data.length + 2;
if (l > 255) {
// Check that we are not exceeding the maximum length
throw new IllegalArgumentException(
"Transparent data is longer than " + TRANSPARENT_MAX_SIZE + " bytes: " + data);
}
afpdata.write(new byte[] {BinaryUtils.convert(l)[0], (byte) 0xDB},
0, 2);
afpdata.write(data, 0, data.length);
}

/**
* Draws a line of specified length and specified width in the B-direction
* from the current presentation position. The location of the current
* presentation position is unchanged.
*
* @param length
* The length of the rule.
* @param width
* The width of the rule.
* @param afpdata
* The output stream to which data should be written.
*/
private void drawBaxisRule(int length, int width,
ByteArrayOutputStream afpdata) {
afpdata.write(new byte[] {
0x07, // Length
(byte) 0xE7, // Type
}, 0, 2);
// Rule length
byte[] data1 = BinaryUtils.shortToByteArray((short) length);
afpdata.write(data1, 0, data1.length);
// Rule width
byte[] data2 = BinaryUtils.shortToByteArray((short) width);
afpdata.write(data2, 0, data2.length);
// Rule width fraction
afpdata.write(0x00);
}

/**
* Draws a line of specified length and specified width in the I-direction
* from the current presentation position. The location of the current
* presentation position is unchanged.
*
* @param length
* The length of the rule.
* @param width
* The width of the rule.
* @param afpdata
* The output stream to which data should be written.
*/
private void drawIaxisRule(int length, int width,
ByteArrayOutputStream afpdata) {
afpdata.write(new byte[] {
0x07, // Length
(byte) 0xE5, // Type
}, 0, 2);
// Rule length
byte[] data1 = BinaryUtils.shortToByteArray((short) length);
afpdata.write(data1, 0, data1.length);
// Rule width
byte[] data2 = BinaryUtils.shortToByteArray((short) width);
afpdata.write(data2, 0, data2.length);
// Rule width fraction
afpdata.write(0x00);
}

/**
* Create the presentation text data for the byte array of data.
*
* @param textDataInfo
* the afp text data
* @throws MaximumSizeExceededException
* thrown if the maximum number of text data is exceeded
* @throws UnsupportedEncodingException
* thrown if character encoding is not supported
*/
public void createTextData(AFPTextDataInfo textDataInfo)
throws MaximumSizeExceededException, UnsupportedEncodingException {

ByteArrayOutputStream afpdata = new ByteArrayOutputStream();

int rotation = textDataInfo.getRotation();
if (currentOrientation != rotation) {
setTextOrientation(rotation, afpdata);
currentOrientation = rotation;
currentX = -1;
currentY = -1;
}

// Avoid unnecessary specification of the Y coordinate
int y = textDataInfo.getY();
if (currentY != y) {
absoluteMoveBaseline(y, afpdata);
currentX = -1;
}

// Avoid unnecessary specification of the X coordinate
int x = textDataInfo.getX();
if (currentX != x) {
absoluteMoveInline(x, afpdata);
}

// Avoid unnecessary specification of the variable space increment
if (textDataInfo.getVariableSpaceCharacterIncrement()
!= currentVariableSpaceCharacterIncrement) {
setVariableSpaceCharacterIncrement(textDataInfo
.getVariableSpaceCharacterIncrement(), afpdata);
currentVariableSpaceCharacterIncrement = textDataInfo
.getVariableSpaceCharacterIncrement();
}

// Avoid unnecessary specification of the inter character adjustment
if (textDataInfo.getInterCharacterAdjustment() != currentInterCharacterAdjustment) {
setInterCharacterAdjustment(textDataInfo.getInterCharacterAdjustment(),
afpdata);
currentInterCharacterAdjustment = textDataInfo
.getInterCharacterAdjustment();
}

// Avoid unnecessary specification of the text color
if (!textDataInfo.getColor().equals(currentColor)) {
setExtendedTextColor(textDataInfo.getColor(), afpdata);
currentColor = textDataInfo.getColor();
}

setCodedFont(BinaryUtils.convert(textDataInfo.getFontReference())[0],
afpdata);

// Add transparent data
String textString = textDataInfo.getString();
String encoding = textDataInfo.getEncoding();
byte[] data = textString.getBytes(encoding);
if (data.length <= TRANSPARENT_MAX_SIZE) {
addTransparentData(data, afpdata);
} else {
// data size greater than TRANSPARENT_MAX_SIZE so slice
int numTransData = data.length / TRANSPARENT_MAX_SIZE;
byte[] buff = new byte[TRANSPARENT_MAX_SIZE];
int currIndex = 0;
for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) {
currIndex = transDataCnt * TRANSPARENT_MAX_SIZE;
System.arraycopy(data, currIndex, buff, 0, TRANSPARENT_MAX_SIZE);
addTransparentData(buff, afpdata);
}
int remainingTransData = data.length / TRANSPARENT_MAX_SIZE;
buff = new byte[remainingTransData];
System.arraycopy(data, currIndex, buff, 0, remainingTransData);
addTransparentData(buff, afpdata);
}
currentX = -1;

int dataSize = afpdata.size();

if (baos.size() + dataSize > MAX_SIZE) {
currentX = -1;
currentY = -1;
throw new MaximumSizeExceededException();
}

byte[] outputdata = afpdata.toByteArray();
baos.write(outputdata, 0, outputdata.length);
}

private int ensurePositive(int value) {
if (value < 0) {
return 0;
}
return value;
}

/**
* Drawing of lines using the starting and ending coordinates, thickness and
* colour arguments.
*
* @param lineDataInfo the line data information.
* @throws MaximumSizeExceededException
* thrown if the maximum number of line data has been exceeded
*/
public void createLineData(AFPLineDataInfo lineDataInfo) throws MaximumSizeExceededException {

ByteArrayOutputStream afpdata = new ByteArrayOutputStream();

int orientation = lineDataInfo.getRotation();
if (currentOrientation != orientation) {
setTextOrientation(orientation, afpdata);
currentOrientation = orientation;
}

// Avoid unnecessary specification of the Y coordinate
int y1 = ensurePositive(lineDataInfo.getY1());
if (y1 != currentY) {
absoluteMoveBaseline(y1, afpdata);
}

// Avoid unnecessary specification of the X coordinate
int x1 = ensurePositive(lineDataInfo.getX1());
if (x1 != currentX) {
absoluteMoveInline(x1, afpdata);
}

Color color = lineDataInfo.getColor();
if (!color.equals(currentColor)) {
setExtendedTextColor(color, afpdata);
currentColor = color;
}

int x2 = ensurePositive(lineDataInfo.getX2());
int y2 = ensurePositive(lineDataInfo.getY2());
int thickness = lineDataInfo.getThickness();
if (y1 == y2) {
drawIaxisRule(x2 - x1, thickness, afpdata);
} else if (x1 == x2) {
drawBaxisRule(y2 - y1, thickness, afpdata);
} else {
log.error("Invalid axis rule unable to draw line");
return;
}

int dataSize = afpdata.size();

if (baos.size() + dataSize > MAX_SIZE) {
currentX = -1;
currentY = -1;
throw new MaximumSizeExceededException();
}

byte[] outputdata = afpdata.toByteArray();
baos.write(outputdata, 0, outputdata.length);
}

/**
* The Set Text Orientation control sequence establishes the I-direction and
* B-direction for the subsequent text. This is a modal control sequence.
*
* Semantics: This control sequence specifies the I-axis and B-axis
* orientations with respect to the Xp-axis for the current Presentation
* Text object. The orientations are rotational values expressed in degrees
* and minutes.
*
* @param orientation
* The text orientation (0, 90, 180, 270).
* @param os
* The output stream to which data should be written.
* Returns the number of data bytes still available in this object until it is full and a new
* one has to be started.
* @return the number of data bytes available
*/
private void setTextOrientation(int orientation,
ByteArrayOutputStream os) {
os.write(new byte[] {0x06, (byte) 0xF7, }, 0, 2);
switch (orientation) {
case 90:
os.write(0x2D);
os.write(0x00);
os.write(0x5A);
os.write(0x00);
break;
case 180:
os.write(0x5A);
os.write(0x00);
os.write(0x87);
os.write(0x00);
break;
case 270:
os.write(0x87);
os.write(0x00);
os.write(0x00);
os.write(0x00);
break;
default:
os.write(0x00);
os.write(0x00);
os.write(0x2D);
os.write(0x00);
break;
}
public int getBytesAvailable() {
return MAX_SIZE - baos.size() + HEADER_LENGTH;
}

/**
* The Set Extended Text Color control sequence specifies a color value and
* defines the color space and encoding for that value. The specified color
* value is applied to foreground areas of the text presentation space. This
* is a modal control sequence.
*
* @param col
* The color to be set.
* @param os
* The output stream to which data should be written.
* Returns the output stream the content data is written to.
* @return the output stream
*/
private void setExtendedTextColor(Color col, ByteArrayOutputStream os) {
byte[] colorData = new byte[] {
15, // Control sequence length
(byte) 0x81, // Control sequence function type
0x00, // Reserved; must be zero
0x01, // Color space - 0x01 = RGB
0x00, // Reserved; must be zero
0x00, // Reserved; must be zero
0x00, // Reserved; must be zero
0x00, // Reserved; must be zero
8, // Number of bits in component 1
8, // Number of bits in component 2
8, // Number of bits in component 3
0, // Number of bits in component 4
(byte) (col.getRed()), // Red intensity
(byte) (col.getGreen()), // Green intensity
(byte) (col.getBlue()), // Blue intensity
};

os.write(colorData, 0, colorData.length);
}

/**
* //TODO This is a modal control sequence.
*
* @param incr
* The increment to be set.
* @param os
* The output stream to which data should be written.
*/
private void setVariableSpaceCharacterIncrement(int incr,
ByteArrayOutputStream os) {
byte[] b = BinaryUtils.convert(incr, 2);

os.write(new byte[] {
4, // Control sequence length
(byte) 0xC5, // Control sequence function type
b[0], b[1] },
0, 4);
}

/**
* //TODO This is a modal control sequence.
*
* @param incr
* The increment to be set.
* @param os
* The output stream to which data should be written.
*/
private void setInterCharacterAdjustment(int incr, ByteArrayOutputStream os) {
byte[] b = BinaryUtils.convert(Math.abs(incr), 2);
os.write(new byte[] {
5, // Control sequence length
(byte) 0xC3, // Control sequence function type
b[0], b[1], (byte) (incr >= 0 ? 0 : 1) // Direction
}, 0, 5);
protected OutputStream getOutputStream() {
return this.baos;
}

/** {@inheritDoc} */
public void writeToStream(OutputStream os) throws IOException {
assert getBytesAvailable() >= 0;
byte[] data = baos.toByteArray();
byte[] size = BinaryUtils.convert(data.length - 1, 2);
data[1] = size[0];
@@ -534,23 +120,4 @@ public class PresentationTextData extends AbstractAFPObject {
os.write(data);
}

/**
* A control sequence is a sequence of bytes that specifies a control
* function. A control sequence consists of a control sequence introducer
* and zero or more parameters. The control sequence can extend multiple
* presentation text data objects, but must eventually be terminated. This
* method terminates the control sequence.
*
* @throws MaximumSizeExceededException
* thrown in the event that maximum size has been exceeded
*/
public void endControlSequence() throws MaximumSizeExceededException {
byte[] data = new byte[2];
data[0] = 0x02;
data[1] = (byte) 0xF8;
if (data.length + baos.size() > MAX_SIZE) {
throw new MaximumSizeExceededException();
}
baos.write(data, 0, data.length);
}
}

+ 45
- 15
src/java/org/apache/fop/afp/modca/PresentationTextObject.java View File

@@ -26,6 +26,10 @@ import java.util.List;

import org.apache.fop.afp.AFPLineDataInfo;
import org.apache.fop.afp.AFPTextDataInfo;
import org.apache.fop.afp.ptoca.LineDataInfoProducer;
import org.apache.fop.afp.ptoca.PtocaBuilder;
import org.apache.fop.afp.ptoca.PtocaProducer;
import org.apache.fop.afp.ptoca.TextDataInfoProducer;

/**
* The Presentation Text object is the data object used in document processing
@@ -41,6 +45,8 @@ import org.apache.fop.afp.AFPTextDataInfo;
* collection of the graphic characters and control codes is called Presentation
* Text, and the object that contains the Presentation Text is called the
* PresentationText object.
* <p>
* The content for this object can be created using {@link PtocaBuilder}.
*/
public class PresentationTextObject extends AbstractNamedAFPObject {

@@ -54,6 +60,8 @@ public class PresentationTextObject extends AbstractNamedAFPObject {
*/
private List/*<PresentationTextData>*/ presentationTextDataList = null;

private PtocaBuilder builder = new DefaultBuilder();

/**
* Construct a new PresentationTextObject for the specified name argument,
* the name should be an 8 character identifier.
@@ -72,17 +80,37 @@ public class PresentationTextObject extends AbstractNamedAFPObject {
* @throws UnsupportedEncodingException thrown if character encoding is not supported
*/
public void createTextData(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException {
createControlSequences(new TextDataInfoProducer(textDataInfo));
}

/**
* Creates a chain of control sequences using a producer.
* @param producer the producer
* @throws UnsupportedEncodingException thrown if character encoding is not supported
*/
public void createControlSequences(PtocaProducer producer)
throws UnsupportedEncodingException {
if (currentPresentationTextData == null) {
startPresentationTextData();
}
try {
currentPresentationTextData.createTextData(textDataInfo);
} catch (MaximumSizeExceededException msee) {
endPresentationTextData();
createTextData(textDataInfo);
producer.produce(builder);
} catch (UnsupportedEncodingException e) {
endPresentationTextData();
throw e;
} catch (IOException ioe) {
endPresentationTextData();
handleUnexpectedIOError(ioe);
}
}

private class DefaultBuilder extends PtocaBuilder {
protected OutputStream getOutputStreamForControlSequence(int length) {
if (length > currentPresentationTextData.getBytesAvailable()) {
endPresentationTextData();
startPresentationTextData();
}
return currentPresentationTextData.getOutputStream();
}
}

@@ -93,14 +121,10 @@ public class PresentationTextObject extends AbstractNamedAFPObject {
* @param lineDataInfo the line data information.
*/
public void createLineData(AFPLineDataInfo lineDataInfo) {
if (currentPresentationTextData == null) {
startPresentationTextData();
}
try {
currentPresentationTextData.createLineData(lineDataInfo);
} catch (MaximumSizeExceededException msee) {
endPresentationTextData();
createLineData(lineDataInfo);
createControlSequences(new LineDataInfoProducer(lineDataInfo));
} catch (UnsupportedEncodingException e) {
handleUnexpectedIOError(e); //Won't happen for lines
}
}

@@ -157,18 +181,24 @@ public class PresentationTextObject extends AbstractNamedAFPObject {
startPresentationTextData();
}
try {
currentPresentationTextData.endControlSequence();
} catch (MaximumSizeExceededException msee) {
builder.endChainedControlSequence();
} catch (IOException ioe) {
endPresentationTextData();
endControlSequence();
handleUnexpectedIOError(ioe);
//Should not occur since we're writing to byte arrays
}
}

private void handleUnexpectedIOError(IOException ioe) {
//"Unexpected" since we're currently dealing with ByteArrayOutputStreams here.
throw new RuntimeException("Unexpected I/O error: " + ioe.getMessage(), ioe);
}

/** {@inheritDoc} */
public String toString() {
if (presentationTextDataList != null) {
return presentationTextDataList.toString();
}
return null;
return super.toString();
}
}

+ 76
- 0
src/java/org/apache/fop/afp/ptoca/LineDataInfoProducer.java View File

@@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.ptoca;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.AFPLineDataInfo;

/**
* {@link PtocaProducer} implementation that interprets {@link AFPLineDataInfo} objects.
*/
public class LineDataInfoProducer implements PtocaProducer, PtocaConstants {

/** Static logging instance */
private static final Log log = LogFactory.getLog(LineDataInfoProducer.class);

private AFPLineDataInfo lineDataInfo;

/**
* Main constructor.
* @param lineDataInfo the info object
*/
public LineDataInfoProducer(AFPLineDataInfo lineDataInfo) {
this.lineDataInfo = lineDataInfo;
}

/** {@inheritDoc} */
public void produce(PtocaBuilder builder) throws IOException {
builder.setTextOrientation(lineDataInfo.getRotation());
int x1 = ensurePositive(lineDataInfo.getX1());
int y1 = ensurePositive(lineDataInfo.getY1());
builder.absoluteMoveBaseline(y1);
builder.absoluteMoveInline(x1);
builder.setExtendedTextColor(lineDataInfo.getColor());

int x2 = ensurePositive(lineDataInfo.getX2());
int y2 = ensurePositive(lineDataInfo.getY2());
int thickness = lineDataInfo.getThickness();
if (y1 == y2) {
builder.drawIaxisRule(x2 - x1, thickness);
} else if (x1 == x2) {
builder.drawBaxisRule(y2 - y1, thickness);
} else {
log.error("Invalid axis rule: unable to draw line");
return;
}
}

private static int ensurePositive(int value) {
if (value < 0) {
return 0;
}
return value;
}

}

+ 389
- 0
src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java View File

@@ -0,0 +1,389 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.ptoca;

import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.io.output.ByteArrayOutputStream;

/**
* Generator class for PTOCA data structures.
*/
public abstract class PtocaBuilder implements PtocaConstants {

private ByteArrayOutputStream baout = new ByteArrayOutputStream(256);

/** the current x coordinate. */
private int currentX = -1;

/** the current y coordinate */
private int currentY = -1;

/** the current font */
private int currentFont = Integer.MIN_VALUE;

/** the current orientation */
private int currentOrientation = 0;

/** the current color */
private Color currentColor = Color.BLACK;

/** the current variable space increment */
private int currentVariableSpaceCharacterIncrement = 0;

/** the current inter character adjustment */
private int currentInterCharacterAdjustment = 0;


/**
* Returns an {@link OutputStream} for the next control sequence. This gives a subclass a
* chance to do chunking of control sequences into multiple presentation text data objects.
* @param length the length of the following control sequence
* @return the output stream where the control sequence will be written to
*/
protected abstract OutputStream getOutputStreamForControlSequence(int length);

private static byte chained(byte functionType) {
return (byte)(functionType | CHAIN_BIT);
}

private void newControlSequence() {
baout.reset();
}

private void commit(byte functionType) throws IOException {
int length = baout.size() + 2;
assert length < 256;

OutputStream out = getOutputStreamForControlSequence(length);
out.write(length);
out.write(functionType);
baout.writeTo(out);
}

private void write(byte[] data, int offset, int length) {
baout.write(data, offset, length);
}

private void writeByte(int data) {
baout.write(data);
}

private void writeShort(int data) {
baout.write((data >>> 8) & 0xFF);
baout.write(data & 0xFF);
}

/**
* Writes the introducer for a chained control sequence.
* @throws IOException if an I/O error occurs
*/
public void writeIntroducer() throws IOException {
OutputStream out = getOutputStreamForControlSequence(ESCAPE.length);
out.write(ESCAPE);
}

/**
* The Set Coded Font Local control sequence activates a coded font and
* specifies the character attributes to be used.
* <p>
* This is a modal control sequence.
*
* @param font The font local identifier.
* @throws IOException if an I/O error occurs
*/
public void setCodedFont(byte font) throws IOException {
// Avoid unnecessary specification of the font
if (currentFont == font) {
return;
} else {
currentFont = font;
}

newControlSequence();
writeByte(font);
commit(chained(SCFL));
}

/**
* Establishes the current presentation position on the baseline at a new
* I-axis coordinate, which is a specified number of measurement units from
* the B-axis. There is no change to the current B-axis coordinate.
*
* @param coordinate The coordinate for the inline move.
* @throws IOException if an I/O error occurs
*/
public void absoluteMoveInline(int coordinate) throws IOException {
if (coordinate == this.currentX) {
return;
}
newControlSequence();
writeShort(coordinate);
commit(chained(AMI));

currentX = coordinate;
}

/**
* Moves the inline coordinate of the presentation position relative to the current
* inline position.
* @param increment the increment in 1/1440 inch units
* @throws IOException if an I/O error occurs
*/
public void relativeMoveInline(int increment) throws IOException {
newControlSequence();
writeShort(increment);
commit(chained(RMI));
}

/**
* Establishes the baseline and the current presentation position at a new
* B-axis coordinate, which is a specified number of measurement units from
* the I-axis. There is no change to the current I-axis coordinate.
*
* @param coordinate The coordinate for the baseline move.
* @throws IOException if an I/O error occurs
*/
public void absoluteMoveBaseline(int coordinate) throws IOException {
if (coordinate == this.currentY) {
return;
}
newControlSequence();
writeShort(coordinate);
commit(chained(AMB));

currentY = coordinate;
currentX = -1;
}

private static final int TRANSPARENT_MAX_SIZE = 253;

/**
* The Transparent Data control sequence contains a sequence of code points
* that are presented without a scan for embedded control sequences. If the data is larger
* than fits in one chunk, additional chunks are automatically generated.
*
* @param data The text data to add.
* @throws IOException if an I/O error occurs
*/
public void addTransparentData(byte[] data) throws IOException {
if (data.length <= TRANSPARENT_DATA_MAX_SIZE) {
addTransparentDataChunk(data);
} else {
// data size greater than TRANSPARENT_MAX_SIZE, so slice
int numTransData = data.length / TRANSPARENT_DATA_MAX_SIZE;
int currIndex = 0;
for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) {
addTransparentDataChunk(data, currIndex, TRANSPARENT_DATA_MAX_SIZE);
currIndex += TRANSPARENT_DATA_MAX_SIZE;
}
int left = data.length - currIndex;
addTransparentDataChunk(data, currIndex, left);
}
}

private void addTransparentDataChunk(byte[] data) throws IOException {
addTransparentDataChunk(data, 0, data.length);
}

private void addTransparentDataChunk(byte[] data, int offset, int length) throws IOException {
if (length > TRANSPARENT_MAX_SIZE) {
// Check that we are not exceeding the maximum length
throw new IllegalArgumentException(
"Transparent data is longer than " + TRANSPARENT_MAX_SIZE + " bytes");
}
newControlSequence();
write(data, offset, length);
commit(chained(TRN));
}

/**
* Draws a line of specified length and specified width in the B-direction
* from the current presentation position. The location of the current
* presentation position is unchanged.
*
* @param length The length of the rule.
* @param width The width of the rule.
* @throws IOException if an I/O error occurs
*/
public void drawBaxisRule(int length, int width) throws IOException {
newControlSequence();
writeShort(length); // Rule length
writeShort(width); // Rule width
writeByte(0); // Rule width fraction is always null. enough?
commit(chained(DBR));
}

/**
* Draws a line of specified length and specified width in the I-direction
* from the current presentation position. The location of the current
* presentation position is unchanged.
*
* @param length The length of the rule.
* @param width The width of the rule.
* @throws IOException if an I/O error occurs
*/
public void drawIaxisRule(int length, int width) throws IOException {
newControlSequence();
writeShort(length); // Rule length
writeShort(width); // Rule width
writeByte(0); // Rule width fraction is always null. enough?
commit(chained(DIR));
}

/**
* The Set Text Orientation control sequence establishes the I-direction and
* B-direction for the subsequent text. This is a modal control sequence.
*
* Semantics: This control sequence specifies the I-axis and B-axis
* orientations with respect to the Xp-axis for the current Presentation
* Text object. The orientations are rotational values expressed in degrees
* and minutes.
*
* @param orientation The text orientation (0, 90, 180, 270).
* @throws IOException if an I/O error occurs
*/
public void setTextOrientation(int orientation) throws IOException {
if (orientation == this.currentOrientation) {
return;
}
newControlSequence();
switch (orientation) {
case 90:
writeByte(0x2D);
writeByte(0x00);
writeByte(0x5A);
writeByte(0x00);
break;
case 180:
writeByte(0x5A);
writeByte(0x00);
writeByte(0x87);
writeByte(0x00);
break;
case 270:
writeByte(0x87);
writeByte(0x00);
writeByte(0x00);
writeByte(0x00);
break;
default:
writeByte(0x00);
writeByte(0x00);
writeByte(0x2D);
writeByte(0x00);
break;
}
commit(chained(STO));
this.currentOrientation = orientation;
currentX = -1;
currentY = -1;
}

/**
* The Set Extended Text Color control sequence specifies a color value and
* defines the color space and encoding for that value. The specified color
* value is applied to foreground areas of the text presentation space.
* <p>
* This is a modal control sequence.
*
* @param col The color to be set.
* @throws IOException if an I/O error occurs
*/
public void setExtendedTextColor(Color col) throws IOException {
if (col.equals(currentColor)) {
return;
}
newControlSequence();
writeByte(0x00); // Reserved; must be zero
writeByte(0x01); // Color space - 0x01 = RGB
writeByte(0x00); // Reserved; must be zero
writeByte(0x00); // Reserved; must be zero
writeByte(0x00); // Reserved; must be zero
writeByte(0x00); // Reserved; must be zero
writeByte(8); // Number of bits in component 1
writeByte(8); // Number of bits in component 2
writeByte(8); // Number of bits in component 3
writeByte(0); // Number of bits in component 4
writeByte(col.getRed()); // Red intensity
writeByte(col.getGreen()); // Green intensity
writeByte(col.getBlue()); // Blue intensity
commit(chained(SEC));
this.currentColor = col;
}

/**
* Sets the variable space character increment.
* <p>
* This is a modal control sequence.
*
* @param incr The increment to be set (positive integer, 1/1440 inch)
* @throws IOException if an I/O error occurs
*/
public void setVariableSpaceCharacterIncrement(int incr) throws IOException {
if (incr == this.currentVariableSpaceCharacterIncrement) {
return;
}
assert incr >= 0 && incr < (1 << 16);
newControlSequence();
writeShort(Math.abs(incr)); //Increment
commit(chained(SVI));

this.currentVariableSpaceCharacterIncrement = incr;
}

/**
* Sets the intercharacter adjustment (additional increment or decrement between graphic
* characters).
* <p>
* This is a modal control sequence.
*
* @param incr The increment to be set (1/1440 inch)
* @throws IOException if an I/O error occurs
*/
public void setInterCharacterAdjustment(int incr) throws IOException {
if (incr == this.currentInterCharacterAdjustment) {
return;
}
assert incr >= Short.MIN_VALUE && incr <= Short.MAX_VALUE;
newControlSequence();
writeShort(Math.abs(incr)); //Increment
writeByte(incr >= 0 ? 0 : 1); // Direction
commit(chained(SIA));

this.currentInterCharacterAdjustment = incr;
}

/**
* A control sequence is a sequence of bytes that specifies a control
* function. A control sequence consists of a control sequence introducer
* and zero or more parameters. The control sequence can extend multiple
* presentation text data objects, but must eventually be terminated. This
* method terminates the control sequence (by using a NOP command).
*
* @throws IOException if an I/O error occurs
*/
public void endChainedControlSequence() throws IOException {
newControlSequence();
commit(NOP);
}
}

+ 69
- 0
src/java/org/apache/fop/afp/ptoca/PtocaConstants.java View File

@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.ptoca;

/**
* A collection of PTOCA constants.
*/
public interface PtocaConstants {

/**
* "Escape" sequence for normal PTOCA command sequences.
*/
byte[] ESCAPE = new byte[] {0x2B, (byte)0xD3};

/** Bit to set for chained control sequences */
byte CHAIN_BIT = 1;

/** Set Intercharacter Adjustment */
byte SIA = (byte)0xC2;
/** Set Variable Space Character Increment */
byte SVI = (byte)0xC4;
/** Absolute Move Inline */
byte AMI = (byte)0xC6;
/** Relative Move Inline */
byte RMI = (byte)0xC8;

/** Absolute Move Baseline */
byte AMB = (byte)0xD2;

/** Transparent Data */
byte TRN = (byte)0xDA;

/** Draw I-axis Rule */
byte DIR = (byte)0xE4;
/** Draw B-axis Rule */
byte DBR = (byte)0xE6;

/** Set Extended Text Color */
byte SEC = (byte)0x80;

/** Set Coded Font Local */
byte SCFL = (byte)0xF0;
/** Set Text Orientation */
byte STO = (byte)0xF6;

/** No Operation */
byte NOP = (byte)0xF8;

/** Maximum size of transparent data chunks */
int TRANSPARENT_DATA_MAX_SIZE = 253;

}

+ 39
- 0
src/java/org/apache/fop/afp/ptoca/PtocaProducer.java View File

@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.ptoca;

import java.io.IOException;

import org.apache.fop.afp.modca.PresentationTextObject;

/**
* Producer interface that is passed to a {@link PresentationTextObject} to produce PTOCA control
* sequences using a {@link PtocaBuilder}.
*/
public interface PtocaProducer {

/**
* Produces the PTOCA control sequences by calling methods on {@link PtocaBuilder}.
* @param builder the builder object
* @throws IOException if an I/O error occurs
*/
void produce(PtocaBuilder builder) throws IOException;

}

+ 62
- 0
src/java/org/apache/fop/afp/ptoca/TextDataInfoProducer.java View File

@@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.ptoca;

import java.io.IOException;

import org.apache.fop.afp.AFPTextDataInfo;

/**
* {@link PtocaProducer} implementation that interprets {@link AFPTextDataInfo} objects.
*/
public class TextDataInfoProducer implements PtocaProducer, PtocaConstants {

private AFPTextDataInfo textDataInfo;

/**
* Main constructor.
* @param textDataInfo the info object
*/
public TextDataInfoProducer(AFPTextDataInfo textDataInfo) {
this.textDataInfo = textDataInfo;
}

/** {@inheritDoc} */
public void produce(PtocaBuilder builder) throws IOException {
builder.setTextOrientation(textDataInfo.getRotation());
builder.absoluteMoveBaseline(textDataInfo.getY());
builder.absoluteMoveInline(textDataInfo.getX());

builder.setVariableSpaceCharacterIncrement(
textDataInfo.getVariableSpaceCharacterIncrement());
builder.setInterCharacterAdjustment(
textDataInfo.getInterCharacterAdjustment());
builder.setExtendedTextColor(textDataInfo.getColor());
builder.setCodedFont((byte)textDataInfo.getFontReference());


// Add transparent data
String textString = textDataInfo.getString();
String encoding = textDataInfo.getEncoding();
byte[] data = textString.getBytes(encoding);
builder.addTransparentData(data);
}

}

+ 23
- 0
src/java/org/apache/fop/afp/ptoca/package.html View File

@@ -0,0 +1,23 @@
<!--
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$ -->
<HTML>
<TITLE>org.apache.fop.afp.ptoca Package</TITLE>
<BODY>
<P>Contains a collection of classes for working with Presentation Text Objects (PTOCA).</P>
</BODY>
</HTML>

+ 6
- 4
src/java/org/apache/fop/afp/svg/AFPImageElementBridge.java View File

@@ -19,19 +19,21 @@

package org.apache.fop.afp.svg;

import org.apache.fop.svg.AbstractFOPImageElementBridge;
import org.apache.xmlgraphics.image.loader.ImageFlavor;

import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.svg.AbstractFOPImageElementBridge;

/**
* An AFP specific implementation of a Batik SVGImageElementBridge
*/
public class AFPImageElementBridge extends AbstractFOPImageElementBridge {

private final ImageFlavor[] supportedFlavors = new ImageFlavor[]
{ImageFlavor.RAW_JPEG,
ImageFlavor.RAW_CCITTFAX,
{//ImageFlavor.RAW_JPEG,
//ImageFlavor.RAW_CCITTFAX,
ImageFlavor.GRAPHICS2D,
ImageFlavor.XML_DOM};
BatikImageFlavors.SVG_DOM};

/** {@inheritDoc} */
protected ImageFlavor[] getSupportedFlavours() {

+ 36
- 28
src/java/org/apache/fop/afp/svg/AFPTextHandler.java View File

@@ -25,6 +25,7 @@ import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.fonts.AFPFont;
@@ -77,7 +78,6 @@ public class AFPTextHandler implements FOPTextHandler {
* @return a font reference
*/
private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) {
FontInfo fontInfo = getFontInfo();
AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName);
// register if necessary
AFPFontAttributes afpFontAttributes = pageFonts.registerFont(
@@ -101,37 +101,45 @@ public class AFPTextHandler implements FOPTextHandler {
* {@inheritDoc}
*/
public void drawString(Graphics2D g, String str, float x, float y) throws IOException {
log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y);
AFPGraphics2D g2d = (AFPGraphics2D)g;
GraphicsObject graphicsObj = g2d.getGraphicsObject();
Color color = g2d.getColor();

// set the color
AFPPaintingState paintingState = g2d.getPaintingState();
if (paintingState.setColor(color)) {
graphicsObj.setColor(color);
if (log.isDebugEnabled()) {
log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y);
}

// set the character set
int fontReference = 0;
AFPPageFonts pageFonts = paintingState.getPageFonts();
if (overrideFont != null) {
String internalFontName = overrideFont.getFontName();
int fontSize = overrideFont.getFontSize();
if (g instanceof AFPGraphics2D) {
AFPGraphics2D g2d = (AFPGraphics2D)g;
GraphicsObject graphicsObj = g2d.getGraphicsObject();
Color color = g2d.getColor();

// set the color
AFPPaintingState paintingState = g2d.getPaintingState();
if (paintingState.setColor(color)) {
graphicsObj.setColor(color);
}

// set the character set
int fontReference = 0;
int fontSize;
String internalFontName;
AFPPageFonts pageFonts = paintingState.getPageFonts();
if (overrideFont != null) {
internalFontName = overrideFont.getFontName();
fontSize = overrideFont.getFontSize();
} else {
java.awt.Font awtFont = g2d.getFont();
Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont);
internalFontName = fopFont.getFontName();
fontSize = fopFont.getFontSize();
}
fontSize = (int)Math.round(
g2d.convertToAbsoluteLength(fontSize));
fontReference = registerPageFont(pageFonts, internalFontName, fontSize);
graphicsObj.setCharacterSet(fontReference);

// add the character string
graphicsObj.addString(str, Math.round(x), Math.round(y));
} else {
java.awt.Font awtFont = g2d.getFont();
// AffineTransform fontTransform = awtFont.getTransform();
FontInfo fontInfo = getFontInfo();
Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont);
String internalFontName = fopFont.getFontName();
int fontSize = fopFont.getFontSize();
fontReference = registerPageFont(pageFonts, internalFontName, fontSize);
//Inside Batik's SVG filter operations, you won't get an AFPGraphics2D
g.drawString(str, x, y);
}
graphicsObj.setCharacterSet(fontReference);

// add the character string
graphicsObj.addString(str, Math.round(x), Math.round(y));
}

/**

+ 8
- 0
src/java/org/apache/fop/afp/svg/AFPTextPainter.java View File

@@ -19,6 +19,9 @@

package org.apache.fop.afp.svg;

import java.awt.Graphics2D;

import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.svg.AbstractFOPTextPainter;
import org.apache.fop.svg.FOPTextHandler;

@@ -41,4 +44,9 @@ public class AFPTextPainter extends AbstractFOPTextPainter {
super(nativeTextHandler);
}

/** {@inheritDoc} */
protected boolean isSupportedGraphics2D(Graphics2D g2d) {
return g2d instanceof AFPGraphics2D;
}

}

+ 60
- 0
src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java View File

@@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.apache.fop.apps.FOUserAgent;

/**
* Default implementation of the {@link ResourceAccessor} interface for use inside FOP.
*/
public class DefaultFOPResourceAccessor implements ResourceAccessor {

private FOUserAgent userAgent;

/**
* Main constructor.
* @param userAgent the FO user agent
*/
public DefaultFOPResourceAccessor(FOUserAgent userAgent) {
this.userAgent = userAgent;
}

/** {@inheritDoc} */
public InputStream createInputStream(URI uri) throws IOException {
Source src = userAgent.resolveURI(uri.toASCIIString());
if (src == null) {
return null;
} else if (src instanceof StreamSource) {
StreamSource ss = (StreamSource)src;
InputStream in = ss.getInputStream();
return in;
} else {
return null;
}
}

}

+ 40
- 0
src/java/org/apache/fop/afp/util/ResourceAccessor.java View File

@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

/**
* Defines an interface through which external resource objects can be accessed.
*/
public interface ResourceAccessor {

/**
* Creates a new {@link InputStream} for the given URI that allows read access to an external
* resource.
* @param uri the URI of an external resource.
* @return the new input stream
* @throws IOException if an I/O error occurs while opening the resource
*/
InputStream createInputStream(URI uri) throws IOException;

}

+ 58
- 0
src/java/org/apache/fop/afp/util/SimpleResourceAccessor.java View File

@@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.afp.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;

/**
* Simple implementation of the {@link ResourceAccessor} interface for access via files.
*/
public class SimpleResourceAccessor implements ResourceAccessor {

private URI baseURI;

/**
* Creates a new simple resource accessor.
* @param basePath the base path to resolve relative URIs to
*/
public SimpleResourceAccessor(File basePath) {
this.baseURI = basePath.toURI();
}

/**
* Creates a new simple resource accessor.
* @param basePath the base path to resolve relative URIs to
*/
public SimpleResourceAccessor(String basePath) {
this(new File(basePath));
}

/** {@inheritDoc} */
public InputStream createInputStream(URI uri) throws IOException {
URI resolved = this.baseURI.resolve(uri);
URL url = resolved.toURL();
return url.openStream();
}

}

+ 38
- 0
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -46,6 +46,7 @@ import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.render.intermediate.IFDocumentHandler;

/**
* This is the user agent for FOP.
@@ -92,6 +93,7 @@ public class FOUserAgent {
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
private Map rendererOptions = new java.util.HashMap();
private File outputFile = null;
private IFDocumentHandler documentHandlerOverride = null;
private Renderer rendererOverride = null;
private FOEventHandler foEventHandlerOverride = null;
private boolean locatorEnabled = true; // true by default (for error messages).
@@ -116,6 +118,8 @@ public class FOUserAgent {
protected String author = null;
/** Title of the document. */
protected String title = null;
/** Subject of the document. */
protected String subject = null;
/** Set of keywords applicable to this document. */
protected String keywords = null;

@@ -158,6 +162,24 @@ public class FOUserAgent {

// ---------------------------------------------- rendering-run dependent stuff

/**
* Sets an explicit document handler to use which overrides the one that would be
* selected by default.
* @param documentHandler the document handler instance to use
*/
public void setDocumentHandlerOverride(IFDocumentHandler documentHandler) {
this.documentHandlerOverride = documentHandler;

}

/**
* Returns the overriding {@link IFDocumentHandler} instance, if any.
* @return the overriding document handler or null
*/
public IFDocumentHandler getDocumentHandlerOverride() {
return this.documentHandlerOverride;
}

/**
* Sets an explicit renderer to use which overrides the one defined by the
* render type setting.
@@ -273,6 +295,22 @@ public class FOUserAgent {
return title;
}

/**
* Sets the subject of the document.
* @param subject of document
*/
public void setSubject(String subject) {
this.subject = subject;
}

/**
* Returns the subject of the document
* @return the subject
*/
public String getSubject() {
return subject;
}

/**
* Sets the keywords for the document.
* @param keywords for the document

+ 10
- 0
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -47,6 +47,7 @@ import org.apache.fop.fonts.FontCache;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.util.ColorSpaceCache;
@@ -69,6 +70,9 @@ public class FopFactory implements ImageContext {
/** Registry for XML handlers */
private XMLHandlerRegistry xmlHandlers;

/** Registry for image handlers */
private ImageHandlerRegistry imageHandlers;

/** The registry for ElementMapping instances */
private ElementMappingRegistry elementMappingRegistry;

@@ -156,6 +160,7 @@ public class FopFactory implements ImageContext {
this.imageManager = new ImageManager(this);
this.rendererFactory = new RendererFactory();
this.xmlHandlers = new XMLHandlerRegistry();
this.imageHandlers = new ImageHandlerRegistry();
this.ignoredNamespaces = new java.util.HashSet();
}

@@ -276,6 +281,11 @@ public class FopFactory implements ImageContext {
return this.xmlHandlers;
}

/** @return the image handler registry */
public ImageHandlerRegistry getImageHandlerRegistry() {
return this.imageHandlers;
}

/** @return the element mapping registry */
public ElementMappingRegistry getElementMappingRegistry() {
return this.elementMappingRegistry;

+ 2
- 1
src/java/org/apache/fop/apps/MimeConstants.java View File

@@ -30,5 +30,6 @@ public interface MimeConstants extends org.apache.xmlgraphics.util.MimeConstants
String MIME_FOP_PRINT = "application/X-fop-print";
/** Apache FOP's area tree XML */
String MIME_FOP_AREA_TREE = "application/X-fop-areatree";

/** Apache FOP's intermediate format XML */
String MIME_FOP_IF = "application/X-fop-intermediate-format";
}

+ 58
- 75
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -36,8 +36,23 @@ import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink;
@@ -65,16 +80,7 @@ import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.util.QName;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.fop.util.XMLUtil;

/**
* This is a parser for the area tree XML (intermediate format) which is used to reread an area
@@ -245,7 +251,7 @@ public class AreaTreeParser {
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else {
lastAttributes = attributes;
lastAttributes = new AttributesImpl(attributes);
boolean handled = true;
if ("".equals(uri)) {
Maker maker = (Maker)makers.get(localName);
@@ -381,12 +387,12 @@ public class AreaTreeParser {
if (currentPageViewport != null) {
throw new IllegalStateException("currentPageViewport must be null");
}
Rectangle2D viewArea = getAttributeAsRectangle2D(attributes, "bounds");
int pageNumber = getAttributeAsInteger(attributes, "nr", -1);
Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "bounds");
int pageNumber = XMLUtil.getAttributeAsInt(attributes, "nr", -1);
String key = attributes.getValue("key");
String pageNumberString = attributes.getValue("formatted-nr");
String pageMaster = attributes.getValue("simple-page-master-name");
boolean blank = getAttributeAsBoolean(attributes, "blank", false);
boolean blank = XMLUtil.getAttributeAsBoolean(attributes, "blank", false);
currentPageViewport = new PageViewport(viewArea,
pageNumber, pageNumberString,
pageMaster, blank);
@@ -417,10 +423,10 @@ public class AreaTreeParser {
if (rv != null) {
throw new IllegalStateException("Current RegionViewport must be null");
}
Rectangle2D viewArea = getAttributeAsRectangle2D(attributes, "rect");
Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "rect");
rv = new RegionViewport(viewArea);
transferForeignObjects(attributes, rv);
rv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
rv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false));
setAreaAttributes(attributes, rv);
setTraits(attributes, rv, SUBSET_COMMON);
setTraits(attributes, rv, SUBSET_BOX);
@@ -485,14 +491,15 @@ public class AreaTreeParser {
throw new IllegalStateException("Current BodyRegion must be null");
}
String regionName = attributes.getValue("name");
int columnCount = getAttributeAsInteger(attributes, "columnCount", 1);
int columnGap = getAttributeAsInteger(attributes, "columnGap", 0);
int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1);
int columnGap = XMLUtil.getAttributeAsInt(attributes, "columnGap", 0);
RegionViewport rv = getCurrentRegionViewport();
body = new BodyRegion(Constants.FO_REGION_BODY,
regionName, rv, columnCount, columnGap);
transferForeignObjects(attributes, body);
body.setCTM(getAttributeAsCTM(attributes, "ctm"));
setAreaAttributes(attributes, body);
setTraits(attributes, body, SUBSET_BORDER_PADDING);
rv.setRegionReference(body);
currentPageViewport.getPage().setRegionViewport(
Constants.FO_REGION_BODY, rv);
@@ -537,8 +544,8 @@ public class AreaTreeParser {
private class SpanMaker extends AbstractMaker {

public void startElement(Attributes attributes) {
int ipd = getAttributeAsInteger(attributes, "ipd", 0);
int columnCount = getAttributeAsInteger(attributes, "columnCount", 1);
int ipd = XMLUtil.getAttributeAsInt(attributes, "ipd", 0);
int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1);
BodyRegion body = getCurrentBodyRegion();
Span span = new Span(columnCount,
body.getColumnGap(), ipd);
@@ -554,7 +561,7 @@ public class AreaTreeParser {
public void startElement(Attributes attributes) {
Footnote fn = getCurrentBodyRegion().getFootnote();
transferForeignObjects(attributes, fn);
fn.setTop(getAttributeAsInteger(attributes, "top-offset", 0));
fn.setTop(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
areaStack.push(fn);
}

@@ -579,18 +586,18 @@ public class AreaTreeParser {
private class BlockMaker extends AbstractMaker {

public void startElement(Attributes attributes) {
boolean isViewport = getAttributeAsBoolean(attributes,
boolean isViewport = XMLUtil.getAttributeAsBoolean(attributes,
"is-viewport-area", false);
Block block;
if (isViewport) {
BlockViewport bv = new BlockViewport();
bv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
bv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false));
bv.setCTM(getAttributeAsCTM(attributes, "ctm"));
if (bv.getPositioning() != BlockViewport.RELATIVE) {
bv.setXOffset(
getAttributeAsInteger(attributes, "left-position", 0));
XMLUtil.getAttributeAsInt(attributes, "left-position", 0));
bv.setYOffset(
getAttributeAsInteger(attributes, "top-position", 0));
XMLUtil.getAttributeAsInt(attributes, "top-position", 0));
}
block = bv;
} else {
@@ -607,10 +614,10 @@ public class AreaTreeParser {
block.setPositioning(Block.STACK);
}
if (attributes.getValue("left-offset") != null) {
block.setXOffset(getAttributeAsInteger(attributes, "left-offset", 0));
block.setXOffset(XMLUtil.getAttributeAsInt(attributes, "left-offset", 0));
}
if (attributes.getValue("top-offset") != null) {
block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0));
block.setYOffset(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
}
transferForeignObjects(attributes, block);
setAreaAttributes(attributes, block);
@@ -652,7 +659,7 @@ public class AreaTreeParser {
public void startElement(Attributes attributes) {
InlineArea inl = new InlineArea();
transferForeignObjects(attributes, inl);
inl.setOffset(getAttributeAsInteger(attributes, "offset", 0));
inl.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setAreaAttributes(attributes, inl);
setTraits(attributes, inl, SUBSET_COMMON);
setTraits(attributes, inl, SUBSET_BOX);
@@ -672,7 +679,7 @@ public class AreaTreeParser {
public void startElement(Attributes attributes) {
InlineParent ip = new InlineParent();
transferForeignObjects(attributes, ip);
ip.setOffset(getAttributeAsInteger(attributes, "offset", 0));
ip.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setAreaAttributes(attributes, ip);
setTraits(attributes, ip, SUBSET_COMMON);
setTraits(attributes, ip, SUBSET_BOX);
@@ -693,7 +700,7 @@ public class AreaTreeParser {
public void startElement(Attributes attributes) {
InlineBlockParent ibp = new InlineBlockParent();
transferForeignObjects(attributes, ibp);
ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0));
ibp.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setAreaAttributes(attributes, ibp);
setTraits(attributes, ibp, SUBSET_COMMON);
setTraits(attributes, ibp, SUBSET_BOX);
@@ -720,11 +727,11 @@ public class AreaTreeParser {
setTraits(attributes, text, SUBSET_BOX);
setTraits(attributes, text, SUBSET_COLOR);
setTraits(attributes, text, SUBSET_FONT);
text.setBaselineOffset(getAttributeAsInteger(attributes, "baseline", 0));
text.setOffset(getAttributeAsInteger(attributes, "offset", 0));
text.setTextLetterSpaceAdjust(getAttributeAsInteger(attributes,
text.setBaselineOffset(XMLUtil.getAttributeAsInt(attributes, "baseline", 0));
text.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
text.setTextLetterSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
"tlsadjust", 0));
text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes,
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
"twsadjust", 0));
Area parent = (Area)areaStack.peek();
parent.addChildArea(text);
@@ -739,7 +746,7 @@ public class AreaTreeParser {
private class WordMaker extends AbstractMaker {

public void endElement() {
int offset = getAttributeAsInteger(lastAttributes, "offset", 0);
int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0);
int[] letterAdjust
= ConversionUtils.toIntArray(
lastAttributes.getValue("letter-adjust"), "\\s");
@@ -758,11 +765,11 @@ public class AreaTreeParser {
private class SpaceMaker extends AbstractMaker {

public void endElement() {
int offset = getAttributeAsInteger(lastAttributes, "offset", 0);
int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0);
//TODO the isAdjustable parameter is currently not used/implemented
if (content.position() > 0) {
content.flip();
boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true);
boolean adjustable = XMLUtil.getAttributeAsBoolean(lastAttributes, "adj", true);
SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable);
AbstractTextArea text = getCurrentText();
space.setParentArea(text);
@@ -794,13 +801,13 @@ public class AreaTreeParser {
setTraits(attributes, leader, SUBSET_BOX);
setTraits(attributes, leader, SUBSET_COLOR);
setTraits(attributes, leader, SUBSET_FONT);
leader.setOffset(getAttributeAsInteger(attributes, "offset", 0));
leader.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
String ruleStyle = attributes.getValue("ruleStyle");
if (ruleStyle != null) {
leader.setRuleStyle(ruleStyle);
}
leader.setRuleThickness(
getAttributeAsInteger(attributes, "ruleThickness", 0));
XMLUtil.getAttributeAsInt(attributes, "ruleThickness", 0));
Area parent = (Area)areaStack.peek();
parent.addChildArea(leader);
}
@@ -815,9 +822,9 @@ public class AreaTreeParser {
setTraits(attributes, viewport, SUBSET_COMMON);
setTraits(attributes, viewport, SUBSET_BOX);
setTraits(attributes, viewport, SUBSET_COLOR);
viewport.setContentPosition(getAttributeAsRectangle2D(attributes, "pos"));
viewport.setClip(getAttributeAsBoolean(attributes, "clip", false));
viewport.setOffset(getAttributeAsInteger(attributes, "offset", 0));
viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos"));
viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false));
viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
Area parent = (Area)areaStack.peek();
parent.addChildArea(viewport);
areaStack.push(viewport);
@@ -884,7 +891,8 @@ public class AreaTreeParser {

public void startElement(Attributes attributes) {
String title = attributes.getValue("title");
boolean showChildren = getAttributeAsBoolean(attributes, "show-children", false);
boolean showChildren = XMLUtil.getAttributeAsBoolean(
attributes, "show-children", false);
String[] linkdata
= InternalLink.parseXMLAttribute(attributes.getValue("internal-link"));
PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]);
@@ -933,6 +941,7 @@ public class AreaTreeParser {
transferForeignObjects(attributes, reg);
reg.setCTM(getAttributeAsCTM(attributes, "ctm"));
setAreaAttributes(attributes, reg);
setTraits(attributes, reg, SUBSET_BORDER_PADDING);
rv.setRegionReference(reg);
currentPageViewport.getPage().setRegionViewport(
side, rv);
@@ -987,6 +996,9 @@ public class AreaTreeParser {
Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END,
Trait.START_INDENT, Trait.END_INDENT,
Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA};
private static final Object[] SUBSET_BORDER_PADDING = new Object[] {
Trait.BORDER_BEFORE, Trait.BORDER_AFTER, Trait.BORDER_START, Trait.BORDER_END,
Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END};

private void setTraits(Attributes attributes, Area area, Object[] traitSubset) {
for (int i = traitSubset.length; --i >= 0;) {
@@ -1044,9 +1056,9 @@ public class AreaTreeParser {
if (repeat != null) {
bkg.setRepeat(repeat);
}
bkg.setHoriz(getAttributeAsInteger(attributes,
bkg.setHoriz(XMLUtil.getAttributeAsInt(attributes,
"bkg-horz-offset", 0));
bkg.setVertical(getAttributeAsInteger(attributes,
bkg.setVertical(XMLUtil.getAttributeAsInt(attributes,
"bkg-vert-offset", 0));
}
area.addTrait(trait, bkg);
@@ -1058,7 +1070,7 @@ public class AreaTreeParser {
String fontName = attributes.getValue("font-name");
if (fontName != null) {
String fontStyle = attributes.getValue("font-style");
int fontWeight = getAttributeAsInteger(
int fontWeight = XMLUtil.getAttributeAsInt(
attributes, "font-weight", Font.WEIGHT_NORMAL);
area.addTrait(trait,
FontInfo.createFontKey(fontName, fontStyle, fontWeight));
@@ -1068,26 +1080,6 @@ public class AreaTreeParser {
}
}

private static boolean getAttributeAsBoolean(Attributes attributes, String name,
boolean defaultValue) {
String s = attributes.getValue(name);
if (s == null) {
return defaultValue;
} else {
return Boolean.valueOf(s).booleanValue();
}
}

private static int getAttributeAsInteger(Attributes attributes, String name,
int defaultValue) {
String s = attributes.getValue(name);
if (s == null) {
return defaultValue;
} else {
return Integer.parseInt(s);
}
}

private static CTM getAttributeAsCTM(Attributes attributes, String name) {
String s = attributes.getValue(name).trim();
if (s.startsWith("[") && s.endsWith("]")) {
@@ -1102,15 +1094,6 @@ public class AreaTreeParser {
}
}

private static Rectangle2D getAttributeAsRectangle2D(Attributes attributes, String name) {
String s = attributes.getValue(name).trim();
double[] values = ConversionUtils.toDoubleArray(s, "\\s");
if (values.length != 4) {
throw new IllegalArgumentException("Rectangle must consist of 4 double values!");
}
return new Rectangle2D.Double(values[0], values[1], values[2], values[3]);
}

private static void transferForeignObjects(Attributes atts, AreaTreeObject ato) {
for (int i = 0, c = atts.getLength(); i < c; i++) {
String ns = atts.getURI(i);

+ 10
- 4
src/java/org/apache/fop/area/Page.java View File

@@ -128,8 +128,10 @@ public class Page extends AreaTreeObject implements Serializable, Cloneable {
}
// set borders and padding traits
// (a little extensions wrt what prescribed by the specs at 6.4.14)
TraitSetter.addBorders(rr, r.getCommonBorderPaddingBackground(), false, false, false, false, null);
TraitSetter.addPadding(rr, r.getCommonBorderPaddingBackground(), false, false, false, false, null);
TraitSetter.addBorders(rr, r.getCommonBorderPaddingBackground(),
false, false, false, false, null);
TraitSetter.addPadding(rr, r.getCommonBorderPaddingBackground(),
false, false, false, false, null);
setRegionReferencePosition(rr, r, rvp.getViewArea());
rvp.setRegionReference(rr);
setRegionViewport(r.getNameId(), rvp);
@@ -182,8 +184,12 @@ public class Page extends AreaTreeObject implements Serializable, Cloneable {
FODimension reldims = new FODimension(0, 0);
rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(),
r.getWritingMode(), absRegVPRect, reldims));
rr.setIPD(reldims.ipd);
rr.setBPD(reldims.bpd);
rr.setIPD(reldims.ipd
- rr.getBorderAndPaddingWidthStart()
- rr.getBorderAndPaddingWidthEnd());
rr.setBPD(reldims.bpd
- rr.getBorderAndPaddingWidthBefore()
- rr.getBorderAndPaddingWidthAfter());
}

/**

+ 0
- 12
src/java/org/apache/fop/area/RegionReference.java View File

@@ -73,18 +73,6 @@ public class RegionReference extends Area implements Cloneable {
blocks.add(child);
}

/** {@inheritDoc} */
public int getBPD() {
// subtract bpd of borders and padding before / after
return super.getBPD() - getBorderAndPaddingWidthBefore() - getBorderAndPaddingWidthAfter();
}

/** {@inheritDoc} */
public int getIPD() {
// subtract ipd of borders and padding start / end
return super.getIPD() - getBorderAndPaddingWidthStart() - getBorderAndPaddingWidthEnd();
}

/**
* Set the Coordinate Transformation Matrix which transforms content
* coordinates in this region reference area which are specified in

+ 3
- 2
src/java/org/apache/fop/cli/AreaTreeInputHandler.java View File

@@ -26,16 +26,17 @@ import java.util.Vector;
import javax.xml.transform.Result;
import javax.xml.transform.sax.SAXResult;

import org.xml.sax.SAXException;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.fonts.FontInfo;
import org.xml.sax.SAXException;

/**
* InputHandler for the area tree XML (intermediate format) as input.
* InputHandler for the area tree XML (the old intermediate format) as input.
*/
public class AreaTreeInputHandler extends InputHandler {


+ 113
- 21
src/java/org/apache/fop/cli/CommandLineOptions.java View File

@@ -30,8 +30,11 @@ import java.util.Vector;

import javax.swing.UIManager;

import org.xml.sax.SAXException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.Version;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
@@ -43,12 +46,12 @@ import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.awt.AWTRenderer;
import org.apache.fop.render.intermediate.IFRenderer;
import org.apache.fop.render.pdf.PDFRenderer;
import org.apache.fop.render.print.PagesMode;
import org.apache.fop.render.print.PrintRenderer;
import org.apache.fop.render.xml.XMLRenderer;
import org.apache.fop.util.CommandLineLogger;
import org.xml.sax.SAXException;

/**
* Options parses the commandline arguments
@@ -70,8 +73,10 @@ public class CommandLineOptions {
public static final int XSLT_INPUT = 2;
/** input: Area Tree XML file */
public static final int AREATREE_INPUT = 3;
/** input: Intermediate Format XML file */
public static final int IF_INPUT = 4;
/** input: Image file */
public static final int IMAGE_INPUT = 4;
public static final int IMAGE_INPUT = 5;

/* show configuration information */
private Boolean showConfiguration = Boolean.FALSE;
@@ -87,6 +92,8 @@ public class CommandLineOptions {
private File xmlfile = null;
/* area tree input file */
private File areatreefile = null;
/* intermediate format input file */
private File iffile = null;
/* area tree input file */
private File imagefile = null;
/* output file */
@@ -200,6 +207,13 @@ public class CommandLineOptions {

//Make sure the prepared XMLRenderer is used
foUserAgent.setRendererOverride(xmlRenderer);
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode)) {
// render from FO to Intermediate Format
IFRenderer xml2Renderer = new IFRenderer();
xml2Renderer.setUserAgent(foUserAgent);

//Make sure the prepared IFRenderer is used
foUserAgent.setRendererOverride(xml2Renderer);
}
return true;
}
@@ -266,6 +280,8 @@ public class CommandLineOptions {
i = i + parseXMLInputOption(args, i);
} else if (args[i].equals("-atin")) {
i = i + parseAreaTreeInputOption(args, i);
} else if (args[i].equals("-ifin")) {
i = i + parseIFInputOption(args, i);
} else if (args[i].equals("-imagein")) {
i = i + parseImageInputOption(args, i);
} else if (args[i].equals("-awt")) {
@@ -309,6 +325,8 @@ public class CommandLineOptions {
i = i + parseCustomOutputOption(args, i);
} else if (args[i].equals("-at")) {
i = i + parseAreaTreeOption(args, i);
} else if (args[i].equals("-if")) {
i = i + parseIntermediateFormatOption(args, i);
} else if (args[i].equals("-v")) {
printVersion();
return false;
@@ -377,7 +395,7 @@ public class CommandLineOptions {
}

private int parseFOInputOption(String[] args, int i) throws FOPException {
inputmode = FO_INPUT;
setInputFormat(FO_INPUT);
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
throw new FOPException("you must specify the fo file for the '-fo' option");
@@ -393,7 +411,7 @@ public class CommandLineOptions {
}

private int parseXSLInputOption(String[] args, int i) throws FOPException {
inputmode = XSLT_INPUT;
setInputFormat(XSLT_INPUT);
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
throw new FOPException("you must specify the stylesheet "
@@ -405,7 +423,7 @@ public class CommandLineOptions {
}

private int parseXMLInputOption(String[] args, int i) throws FOPException {
inputmode = XSLT_INPUT;
setInputFormat(XSLT_INPUT);
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
throw new FOPException("you must specify the input file "
@@ -676,8 +694,25 @@ public class CommandLineOptions {
}
}

private int parseIntermediateFormatOption(String[] args, int i) throws FOPException {
setOutputMode(MimeConstants.MIME_FOP_IF);
if ((i + 1 == args.length)
|| (args[i + 1].charAt(0) == '-')) {
throw new FOPException("you must specify the intermediate format output file");
} else if ((i + 2 == args.length)
|| (args[i + 2].charAt(0) == '-')) {
// only output file is specified
outfile = new File(args[i + 1]);
return 1;
} else {
// mimic format and output file have been specified
outfile = new File(args[i + 2]);
return 2;
}
}

private int parseAreaTreeInputOption(String[] args, int i) throws FOPException {
inputmode = AREATREE_INPUT;
setInputFormat(AREATREE_INPUT);
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
throw new FOPException("you must specify the Area Tree file for the '-atin' option");
@@ -692,8 +727,24 @@ public class CommandLineOptions {
}
}

private int parseIFInputOption(String[] args, int i) throws FOPException {
setInputFormat(IF_INPUT);
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
throw new FOPException("you must specify the intermediate file for the '-ifin' option");
} else {
String filename = args[i + 1];
if (isSystemInOutFile(filename)) {
this.useStdIn = true;
} else {
iffile = new File(filename);
}
return 1;
}
}

private int parseImageInputOption(String[] args, int i) throws FOPException {
inputmode = IMAGE_INPUT;
setInputFormat(IMAGE_INPUT);
if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) {
throw new FOPException("you must specify the image file for the '-imagein' option");
@@ -800,6 +851,14 @@ public class CommandLineOptions {
}
}

private void setInputFormat(int format) throws FOPException {
if (inputmode == NOT_SET || inputmode == format) {
inputmode = format;
} else {
throw new FOPException("Only one input mode can be specified!");
}
}

/**
* checks whether all necessary information has been given in a consistent way
*/
@@ -854,11 +913,6 @@ public class CommandLineOptions {
throw new FOPException(
"FO output mode is only available if you use -xml and -xsl");
}
if (xmlfile != null || xsltfile != null) {
log.warn("fo input mode, but xmlfile or xslt file are set:");
log.error("xml file: " + xmlfile);
log.error("xslt file: " + xsltfile);
}
if (fofile != null && !fofile.exists()) {
throw new FileNotFoundException("Error: fo file "
+ fofile.getAbsolutePath()
@@ -872,24 +926,31 @@ public class CommandLineOptions {
throw new FOPException(
"Area Tree Output is not available if Area Tree is used as input!");
}
if (xmlfile != null || xsltfile != null) {
log.warn("area tree input mode, but xmlfile or xslt file are set:");
log.error("xml file: " + xmlfile);
log.error("xslt file: " + xsltfile);
}
if (areatreefile != null && !areatreefile.exists()) {
throw new FileNotFoundException("Error: area tree file "
+ areatreefile.getAbsolutePath()
+ " not found ");
}
} else if (inputmode == IMAGE_INPUT) {
} else if (inputmode == IF_INPUT) {
if (outputmode.equals(MimeConstants.MIME_XSL_FO)) {
throw new FOPException(
"FO output mode is only available if you use -xml and -xsl");
} else if (outputmode.equals(MimeConstants.MIME_FOP_AREA_TREE)) {
throw new FOPException(
"Area Tree Output is not available if Intermediate Format is used as input!");
} else if (outputmode.equals(MimeConstants.MIME_FOP_IF)) {
throw new FOPException(
"Intermediate Output is not available if Intermediate Format is used as input!");
}
if (xmlfile != null) {
log.warn("image input mode, but XML file is set:");
log.error("XML file: " + xmlfile.toString());
if (iffile != null && !iffile.exists()) {
throw new FileNotFoundException("Error: intermediate format file "
+ iffile.getAbsolutePath()
+ " not found ");
}
} else if (inputmode == IMAGE_INPUT) {
if (outputmode.equals(MimeConstants.MIME_XSL_FO)) {
throw new FOPException(
"FO output mode is only available if you use -xml and -xsl");
}
if (imagefile != null && !imagefile.exists()) {
throw new FileNotFoundException("Error: image file "
@@ -940,6 +1001,8 @@ public class CommandLineOptions {
return new InputHandler(fofile);
case AREATREE_INPUT:
return new AreaTreeInputHandler(areatreefile);
case IF_INPUT:
return new IFInputHandler(iffile);
case XSLT_INPUT:
return new InputHandler(xmlfile, xsltfile, xsltParams);
case IMAGE_INPUT:
@@ -1074,6 +1137,7 @@ public class CommandLineOptions {
+ " -fo infile xsl:fo input file \n"
+ " -xml infile xml input file, must be used together with -xsl \n"
+ " -atin infile area tree input file \n"
+ " -ifin infile intermediate format input file \n"
+ " -imagein infile image input file (piping through stdin not supported)\n"
+ " -xsl stylesheet xslt stylesheet \n \n"
+ " -param name value <value> to use for parameter <name> in xslt stylesheet\n"
@@ -1095,6 +1159,7 @@ public class CommandLineOptions {
+ " -at [mime] out representation of area tree as XML (outfile req'd) \n"
+ " specify optional mime output to allow AT to be converted\n"
+ " to final format later\n"
+ " -if out representation of area tree as intermediate format XML (outfile req'd)\n"
+ " -print input file will be rendered and sent to the printer \n"
+ " see options with \"-print help\" \n"
+ " -out mime outfile input will be rendered using the given MIME type\n"
@@ -1159,6 +1224,30 @@ public class CommandLineOptions {
}
log.info("xslt stylesheet: " + xsltfile.toString());
break;
case AREATREE_INPUT:
log.info("AT ");
if (this.useStdIn) {
log.info("area tree input file: from stdin");
} else {
log.info("area tree input file: " + areatreefile.toString());
}
break;
case IF_INPUT:
log.info("IF ");
if (this.useStdIn) {
log.info("intermediate input file: from stdin");
} else {
log.info("intermediate input file: " + iffile.toString());
}
break;
case IMAGE_INPUT:
log.info("Image ");
if (this.useStdIn) {
log.info("image input file: from stdin");
} else {
log.info("image input file: " + imagefile.toString());
}
break;
default:
log.info("unknown input type");
}
@@ -1187,6 +1276,9 @@ public class CommandLineOptions {
} else {
log.info("output file: " + outfile.toString());
}
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode)) {
log.info("intermediate format");
log.info("output file: " + outfile.toString());
} else {
log.info(outputmode);
if (this.useStdOut) {

+ 83
- 0
src/java/org/apache/fop/cli/IFInputHandler.java View File

@@ -0,0 +1,83 @@
/*
* 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.cli;

import java.io.File;
import java.io.OutputStream;
import java.util.Vector;

import javax.xml.transform.Result;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFParser;

/**
* InputHandler for the intermediate format XML as input.
*/
public class IFInputHandler extends InputHandler {

/**
* Constructor for XML->XSLT->intermediate XML input
* @param xmlfile XML file
* @param xsltfile XSLT file
* @param params Vector of command-line parameters (name, value,
* name, value, ...) for XSL stylesheet, null if none
*/
public IFInputHandler(File xmlfile, File xsltfile, Vector params) {
super(xmlfile, xsltfile, params);
}

/**
* Constructor for intermediate input
* @param iffile the file to read the intermediate format document from.
*/
public IFInputHandler(File iffile) {
super(iffile);
}

/** {@inheritDoc} */
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out)
throws FOPException {
IFDocumentHandler documentHandler
= userAgent.getFactory().getRendererFactory().createDocumentHandler(
userAgent, outputFormat);
try {
documentHandler.setResult(new StreamResult(out));
documentHandler.setDefaultFontInfo(new FontInfo());

//Create IF parser
IFParser parser = new IFParser();

// Resulting SAX events are sent to the parser
Result res = new SAXResult(parser.getContentHandler(documentHandler, userAgent));

transformTo(res);
} catch (IFException ife) {
throw new FOPException(ife);
}
}

}

+ 6
- 6
src/java/org/apache/fop/fo/XMLObj.java View File

@@ -33,6 +33,7 @@ import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;

/**
@@ -41,8 +42,6 @@ import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
*/
public abstract class XMLObj extends FONode implements ObjectBuiltListener {

private static final String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";

// temp reference for attributes
private Attributes attr = null;

@@ -116,7 +115,7 @@ public abstract class XMLObj extends FONode implements ObjectBuiltListener {

private static HashMap ns = new HashMap();
static {
ns.put("xlink", "http://www.w3.org/1999/xlink");
ns.put(XMLConstants.XLINK_PREFIX, XMLConstants.XLINK_NAMESPACE);
}

/**
@@ -143,7 +142,7 @@ public abstract class XMLObj extends FONode implements ObjectBuiltListener {
} else {
String pref = qname.substring(0, idx);
String tail = qname.substring(idx + 1);
if (pref.equals("xmlns")) {
if (pref.equals(XMLConstants.XMLNS_PREFIX)) {
ns.put(tail, rf);
} else {
element.setAttributeNS((String)ns.get(pref), tail, rf);
@@ -181,8 +180,9 @@ public abstract class XMLObj extends FONode implements ObjectBuiltListener {

element = doc.getDocumentElement();
buildTopLevel(doc, element);
if (!element.hasAttributeNS(XMLNS_NAMESPACE_URI, "xmlns")) {
element.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns",
if (!element.hasAttributeNS(
XMLConstants.XMLNS_NAMESPACE_URI, XMLConstants.XMLNS_PREFIX)) {
element.setAttributeNS(XMLConstants.XMLNS_NAMESPACE_URI, XMLConstants.XMLNS_PREFIX,
getNamespaceURI());
}


+ 19
- 7
src/java/org/apache/fop/fonts/FontLoader.java View File

@@ -53,16 +53,21 @@ public abstract class FontLoader {
protected boolean loaded = false;
/** true if the font will be embedded, false if it will be referenced only. */
protected boolean embedded = true;
/** true if kerning information shall be loaded if available. */
protected boolean useKerning = true;

/**
* Default constructor.
* @param fontFileURI the URI to the PFB file of a Type 1 font
* @param embedded indicates whether the font is embedded or referenced
* @param useKerning indicates whether kerning information shall be loaded if available
* @param resolver the font resolver used to resolve URIs
*/
public FontLoader(String fontFileURI, boolean embedded, FontResolver resolver) {
public FontLoader(String fontFileURI, boolean embedded, boolean useKerning,
FontResolver resolver) {
this.fontFileURI = fontFileURI;
this.embedded = embedded;
this.useKerning = useKerning;
this.resolver = resolver;
}

@@ -82,7 +87,8 @@ public abstract class FontLoader {
*/
public static CustomFont loadFont(File fontFile, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException {
return loadFont(fontFile.getAbsolutePath(), subFontName, embedded, encodingMode, resolver);
return loadFont(fontFile.getAbsolutePath(), subFontName,
embedded, encodingMode, true, resolver);
}

/**
@@ -96,8 +102,11 @@ public abstract class FontLoader {
* @throws IOException In case of an I/O error
*/
public static CustomFont loadFont(URL fontUrl, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException {
return loadFont(fontUrl.toExternalForm(), subFontName, embedded, encodingMode, resolver);
boolean embedded, EncodingMode encodingMode,
FontResolver resolver) throws IOException {
return loadFont(fontUrl.toExternalForm(), subFontName,
embedded, encodingMode, true,
resolver);
}

/**
@@ -106,12 +115,14 @@ public abstract class FontLoader {
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
* @param embedded indicates whether the font is embedded or referenced
* @param encodingMode the requested encoding mode
* @param useKerning indicates whether kerning information should be loaded if available
* @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
public static CustomFont loadFont(String fontFileURI, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException {
boolean embedded, EncodingMode encodingMode, boolean useKerning,
FontResolver resolver) throws IOException {
fontFileURI = fontFileURI.trim();
boolean type1 = isType1(fontFileURI);
FontLoader loader;
@@ -120,9 +131,10 @@ public abstract class FontLoader {
throw new IllegalArgumentException(
"CID encoding mode not supported for Type 1 fonts");
}
loader = new Type1FontLoader(fontFileURI, embedded, resolver);
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver);
} else {
loader = new TTFFontLoader(fontFileURI, subFontName, embedded, encodingMode, resolver);
loader = new TTFFontLoader(fontFileURI, subFontName,
embedded, encodingMode, useKerning, resolver);
}
return loader.getFont();
}

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

@@ -132,7 +132,7 @@ public class LazyFont extends Typeface implements FontDescriptor {
throw new RuntimeException("Cannot load font. No font URIs available.");
}
realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName,
this.embedded, this.encodingMode, resolver);
this.embedded, this.encodingMode, useKerning, resolver);
}
if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont;

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

@@ -225,7 +225,7 @@ public class FontInfoFinder {
}
try {
TTFFontLoader ttfLoader = new TTFFontLoader(
fontFileURI, fontName, true, EncodingMode.AUTO, resolver);
fontFileURI, fontName, true, EncodingMode.AUTO, true, resolver);
customFont = ttfLoader.getFont();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);

+ 8
- 4
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java View File

@@ -55,7 +55,7 @@ public class TTFFontLoader extends FontLoader {
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, FontResolver resolver) {
this(fontFileURI, null, true, EncodingMode.AUTO, resolver);
this(fontFileURI, null, true, EncodingMode.AUTO, true, resolver);
}

/**
@@ -65,11 +65,13 @@ public class TTFFontLoader extends FontLoader {
* TrueType fonts)
* @param embedded indicates whether the font is embedded or referenced
* @param encodingMode the requested encoding mode
* @param useKerning true to enable loading kerning info if available, false to disable
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) {
super(fontFileURI, embedded, resolver);
boolean embedded, EncodingMode encodingMode, boolean useKerning,
FontResolver resolver) {
super(fontFileURI, embedded, true, resolver);
this.subFontName = subFontName;
this.encodingMode = encodingMode;
if (this.encodingMode == EncodingMode.AUTO) {
@@ -164,7 +166,9 @@ public class TTFFontLoader extends FontLoader {
copyWidthsSingleByte(ttf);
}

copyKerning(ttf, isCid);
if (useKerning) {
copyKerning(ttf, isCid);
}
if (this.embedded && ttf.isEmbeddable()) {
returnFont.setEmbedFileName(this.fontFileURI);
}

+ 10
- 5
src/java/org/apache/fop/fonts/type1/Type1FontLoader.java View File

@@ -45,12 +45,13 @@ public class Type1FontLoader extends FontLoader {
* Constructs a new Type 1 font loader.
* @param fontFileURI the URI to the PFB file of a Type 1 font
* @param embedded indicates whether the font is embedded or referenced
* @param useKerning indicates whether to load kerning information if available
* @param resolver the font resolver used to resolve URIs
* @throws IOException In case of an I/O error
*/
public Type1FontLoader(String fontFileURI, boolean embedded, FontResolver resolver)
throws IOException {
super(fontFileURI, embedded, resolver);
public Type1FontLoader(String fontFileURI, boolean embedded, boolean useKerning,
FontResolver resolver) throws IOException {
super(fontFileURI, embedded, useKerning, resolver);
}

private String getPFMURI(String pfbURI) {
@@ -322,7 +323,9 @@ public class Type1FontLoader extends FontLoader {
singleFont.setWidth(chm.getCharCode(), (int)Math.round(chm.getWidthX()));
}
}
returnFont.replaceKerningMap(afm.createXKerningMapEncoded());
if (useKerning) {
returnFont.replaceKerningMap(afm.createXKerningMapEncoded());
}
} else {
returnFont.setFlags(pfm.getFlags());
returnFont.setFirstChar(pfm.getFirstChar());
@@ -330,7 +333,9 @@ public class Type1FontLoader extends FontLoader {
for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) {
singleFont.setWidth(i, pfm.getCharWidth(i));
}
returnFont.replaceKerningMap(pfm.getKerning());
if (useKerning) {
returnFont.replaceKerningMap(pfm.getKerning());
}
}
}


+ 36
- 0
src/java/org/apache/fop/image/loader/batik/BatikImageFlavors.java View File

@@ -0,0 +1,36 @@
/*
* 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.image.loader.batik;

import org.apache.batik.dom.svg.SVGDOMImplementation;

import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.XMLNamespaceEnabledImageFlavor;

/**
* Image flavors used by Batik.
*/
public interface BatikImageFlavors {

/** An SVG image in form of a W3C DOM instance */
XMLNamespaceEnabledImageFlavor SVG_DOM = new XMLNamespaceEnabledImageFlavor(
ImageFlavor.XML_DOM, SVGDOMImplementation.SVG_NAMESPACE_URI);

}

+ 94
- 0
src/java/org/apache/fop/image/loader/batik/ImageConverterG2D2SVG.java View File

@@ -0,0 +1,94 @@
/*
* 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.image.loader.batik;

import java.awt.Dimension;
import java.awt.geom.Rectangle2D;
import java.util.Map;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.svggen.SVGGeneratorContext;
import org.apache.batik.svggen.SVGGraphics2D;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;

/**
* This ImageConverter converts Java2D images into SVG images.
*/
public class ImageConverterG2D2SVG extends AbstractImageConverter {

/** {@inheritDoc} */
public Image convert(Image src, Map hints) throws ImageException {
checkSourceFlavor(src);
ImageGraphics2D g2dImage = (ImageGraphics2D)src;

DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();

// Create an instance of org.w3c.dom.Document
Document document = domImpl.createDocument(
SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
Element root = document.getDocumentElement();

// Create an SVGGeneratorContext to customize SVG generation
SVGGeneratorContext genCtx = SVGGeneratorContext.createDefault(document);
genCtx.setComment("Generated by Apache Batik's SVGGraphics2D");
genCtx.setEmbeddedFontsOn(true);

// Create an instance of the SVG Generator
SVGGraphics2D g2d = new SVGGraphics2D(genCtx, true);
ImageSize size = src.getSize();
Dimension dim = size.getDimensionMpt();
g2d.setSVGCanvasSize(dim);
//SVGGraphics2D doesn't generate the viewBox by itself
root.setAttribute("viewBox", "0 0 " + dim.width + " " + dim.height);

g2dImage.getGraphics2DImagePainter().paint(g2d,
new Rectangle2D.Float(0, 0, dim.width, dim.height));
//Populate the document root with the generated SVG content.
g2d.getRoot(root);

//Return the generated SVG image
ImageXMLDOM svgImage = new ImageXMLDOM(src.getInfo(), document, BatikImageFlavors.SVG_DOM);
g2d.dispose();
return svgImage;
}

/** {@inheritDoc} */
public ImageFlavor getSourceFlavor() {
return ImageFlavor.GRAPHICS2D;
}

/** {@inheritDoc} */
public ImageFlavor getTargetFlavor() {
return BatikImageFlavors.SVG_DOM;
}

}

+ 1
- 2
src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java View File

@@ -34,7 +34,6 @@ import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.UnitProcessor;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -198,7 +197,7 @@ public class PreloaderSVG extends AbstractImagePreloader {

//The whole image had to be loaded for this, so keep it
ImageXMLDOM xmlImage = new ImageXMLDOM(info,
doc, SVGDOMImplementation.SVG_NAMESPACE_URI);
doc, BatikImageFlavors.SVG_DOM);
info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage);
return info;
}

+ 3
- 37
src/java/org/apache/fop/pdf/PDFNumber.java View File

@@ -19,13 +19,11 @@

package org.apache.fop.pdf;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import org.apache.fop.util.DecimalFormatCache;

/**
* This class represents a simple number object. It also contains contains some
* utility methods for outputing numbers to PDF.
* utility methods for outputting numbers to PDF.
*/
public class PDFNumber extends PDFObject {

@@ -67,33 +65,6 @@ public class PDFNumber extends PDFObject {
return doubleOut(doubleDown, 6);
}

private static final String BASE_FORMAT = "0.################";

private static class DecimalFormatThreadLocal extends ThreadLocal {
private int dec;
public DecimalFormatThreadLocal(int dec) {
this.dec = dec;
}
protected synchronized Object initialValue() {
String s = "0";
if (dec > 0) {
s = BASE_FORMAT.substring(0, dec + 2);
}
DecimalFormat df = new DecimalFormat(s, new DecimalFormatSymbols(Locale.US));
return df;
}
};
//DecimalFormat is not thread-safe!
private static final ThreadLocal[] DECIMAL_FORMAT_CACHE = new DecimalFormatThreadLocal[17];
static {
for (int i = 0, c = DECIMAL_FORMAT_CACHE.length; i < c; i++) {
DECIMAL_FORMAT_CACHE[i] = new DecimalFormatThreadLocal(i);
}
}
/**
* Output a double value to a string suitable for PDF.
* In this method it is possible to set the maximum
@@ -104,12 +75,7 @@ public class PDFNumber extends PDFObject {
* @return the value as a string
*/
public static String doubleOut(double doubleDown, int dec) {
if (dec < 0 || dec >= DECIMAL_FORMAT_CACHE.length) {
throw new IllegalArgumentException("Parameter dec must be between 1 and "
+ (DECIMAL_FORMAT_CACHE.length + 1));
}
DecimalFormat df = (DecimalFormat)DECIMAL_FORMAT_CACHE[dec].get();
return df.format(doubleDown);
return DecimalFormatCache.getDecimalFormat(dec).format(doubleDown);
}

/** {@inheritDoc} */

+ 52
- 23
src/java/org/apache/fop/pdf/PDFPaintingState.java View File

@@ -62,14 +62,15 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
* @return true if the new paint changes the current paint
*/
public boolean setPaint(Paint p) {
Paint paint = ((PDFData)getData()).paint;
PDFData data = getPDFData();
Paint paint = data.paint;
if (paint == null) {
if (p != null) {
((PDFData)getData()).paint = p;
data.paint = p;
return true;
}
} else if (!paint.equals(p)) {
((PDFData)getData()).paint = p;
data.paint = p;
return true;
}
return false;
@@ -88,7 +89,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
* @return true if the clip will change the current clip.
*/
public boolean checkClip(Shape cl) {
Shape clip = ((PDFData)getData()).clip;
Shape clip = getPDFData().clip;
if (clip == null) {
if (cl != null) {
return true;
@@ -108,16 +109,39 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
* @param cl the new clip in the current state
*/
public void setClip(Shape cl) {
Shape clip = ((PDFData)getData()).clip;
PDFData data = getPDFData();
Shape clip = data.clip;
if (clip != null) {
Area newClip = new Area(clip);
newClip.intersect(new Area(cl));
((PDFData)getData()).clip = new GeneralPath(newClip);
data.clip = new GeneralPath(newClip);
} else {
((PDFData)getData()).clip = cl;
data.clip = cl;
}
}

/**
* Sets the character spacing (Tc).
* @param value the new value
* @return true if the value was changed with respect to the previous value
*/
public boolean setCharacterSpacing(float value) {
PDFData data = getPDFData();
if (value != data.characterSpacing) {
data.characterSpacing = value;
return true;
}
return false;
}

/**
* Returns the current character spacing (Tc) value.
* @return the Tc value
*/
public float getCharacterSpacing() {
return getPDFData().characterSpacing;
}

/**
* Get the current stack level.
*
@@ -149,8 +173,8 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
newState.addValues(state);
}
}
if (((PDFData)getData()).gstate != null) {
newState.addValues(((PDFData)getData()).gstate);
if (getPDFData().gstate != null) {
newState.addValues(getPDFData().gstate);
}
return newState;
}
@@ -177,32 +201,38 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
getStateStack().add(copy);
}

private PDFData getPDFData() {
return (PDFData)getData();
}

private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData {

private static final long serialVersionUID = 3527950647293177764L;

private Paint paint = null;
private Paint backPaint = null;
private int lineCap = 0;
private int lineJoin = 0;
private float miterLimit = 0;
private boolean text = false;
private int dashOffset = 0;
//private int lineCap = 0; //Disabled the ones that are not used, yet
//private int lineJoin = 0;
//private float miterLimit = 0;
//private int dashOffset = 0;
private Shape clip = null;
private PDFGState gstate = null;

//text state
private float characterSpacing = 0f;

/** {@inheritDoc} */
public Object clone() {
PDFData obj = (PDFData)super.clone();
obj.paint = this.paint;
obj.backPaint = this.paint;
obj.lineCap = this.lineCap;
obj.lineJoin = this.lineJoin;
obj.miterLimit = this.miterLimit;
obj.text = this.text;
obj.dashOffset = this.dashOffset;
//obj.lineCap = this.lineCap;
//obj.lineJoin = this.lineJoin;
//obj.miterLimit = this.miterLimit;
//obj.dashOffset = this.dashOffset;
obj.clip = this.clip;
obj.gstate = this.gstate;
obj.characterSpacing = this.characterSpacing;
return obj;
}

@@ -211,10 +241,9 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
return super.toString()
+ ", paint=" + paint
+ ", backPaint=" + backPaint
+ ", lineCap=" + lineCap
+ ", miterLimit=" + miterLimit
+ ", text=" + text
+ ", dashOffset=" + dashOffset
//+ ", lineCap=" + lineCap
//+ ", miterLimit=" + miterLimit
//+ ", dashOffset=" + dashOffset
+ ", clip=" + clip
+ ", gstate=" + gstate;
}

+ 26
- 4
src/java/org/apache/fop/pdf/PDFReference.java View File

@@ -33,7 +33,8 @@ import java.lang.ref.SoftReference;
*/
public class PDFReference implements PDFWritable {

private String indirectReference;
private int objectNumber;
private int generation;

private Reference objReference;

@@ -42,7 +43,8 @@ public class PDFReference implements PDFWritable {
* @param obj the object to be referenced
*/
public PDFReference(PDFObject obj) {
this.indirectReference = obj.referencePDF();
this.objectNumber = obj.getObjectNumber();
this.generation = obj.getGeneration();
this.objReference = new SoftReference(obj);
}

@@ -54,7 +56,11 @@ public class PDFReference implements PDFWritable {
if (ref == null) {
throw new NullPointerException("ref must not be null");
}
this.indirectReference = ref;
String[] parts = ref.split(" ");
assert parts.length == 3;
this.objectNumber = Integer.parseInt(parts[0]);
this.generation = Integer.parseInt(parts[1]);
assert "R".equals(parts[2]);
}

/**
@@ -73,9 +79,25 @@ public class PDFReference implements PDFWritable {
}
}

/**
* Returns the object number.
* @return the object number
*/
public int getObjectNumber() {
return this.objectNumber;
}

/**
* Returns the generation.
* @return the generation
*/
public int getGeneration() {
return this.generation;
}

/** {@inheritDoc} */
public String toString() {
return this.indirectReference;
return getObjectNumber() + " " + getGeneration() + " R";
}

/** {@inheritDoc} */

+ 9
- 1
src/java/org/apache/fop/pdf/PDFTextUtil.java View File

@@ -270,7 +270,15 @@ public abstract class PDFTextUtil {
* @param adjust the glyph adjust value in thousands of text unit space.
*/
public void adjustGlyphTJ(double adjust) {
bufTJ.append(endText).append(" ");
if (bufTJ == null) {
bufTJ = new StringBuffer();
}
if (bufTJ.length() > 0) {
bufTJ.append(endText).append(" ");
}
if (bufTJ.length() == 0) {
bufTJ.append("[");
}
bufTJ.append(PDFNumber.doubleOut(adjust, DEC - 4));
bufTJ.append(" ");
bufTJ.append(startText);

+ 12
- 4
src/java/org/apache/fop/pdf/PDFUri.java View File

@@ -41,14 +41,22 @@ public class PDFUri extends PDFAction {
* @return the action to place next to /A within a Link
*/
public String getAction() {
if (hasObjectNumber()) {
return referencePDF();
} else {
return getDictString();
}
}

private String getDictString() {
return "<< /URI (" + uri + ")\n/S /URI >>";
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public String toPDFString() {
throw new UnsupportedOperationException("This method should not be called");
//TODO Convert this class into a dictionary
return getObjectID() + getDictString() + "\nendobj\n";
//throw new UnsupportedOperationException("This method should not be called");
}

}

+ 2
- 11
src/java/org/apache/fop/render/AbstractGenericSVGHandler.java View File

@@ -33,11 +33,9 @@ import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.gvt.GraphicsNode;

import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.image.loader.batik.BatikUtil;
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl;
import org.apache.fop.render.RendererContext.RendererContextWrapper;
@@ -52,13 +50,6 @@ import org.apache.fop.svg.SVGUserAgent;
*/
public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererContextConstants {

/** Qualified name for the "conversion-mode" extension attribute. */
protected static final QName CONVERSION_MODE = new QName(
ExtensionElementMapping.URI, null, "conversion-mode");

/** "bitmap" value for the "conversion-mode" extension attribute. */
protected static final String BITMAP = "bitmap";

/** {@inheritDoc} */
public void handleXML(RendererContext context,
Document doc, String ns) throws Exception {
@@ -82,9 +73,9 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC
}

/**
* Builds the GVT root
* Builds the GVT root.
*
* @param rendererContext the renderer context
* @param userAgent the user agent
* @param ctx the batik bridge context
* @param doc the document
* @return a built GVT root tree

+ 141
- 0
src/java/org/apache/fop/render/AbstractImageHandlerGraphics2D.java View File

@@ -0,0 +1,141 @@
/*
* 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 java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;

import org.apache.fop.util.UnitConv;

/**
* Abstract base class for ImageHandler implementations that process Java2D images through
* the Graphics2DImagePainter interface.
*/
public abstract class AbstractImageHandlerGraphics2D implements ImageHandler {

/**
* Paints the image to a BufferedImage and returns that.
* @param painter the painter which will paint the actual image
* @param context the renderer context for the current renderer
* @param targetDimension the target dimensions of the image to be converted to a bitmap
* @param resolution the requested bitmap resolution
* @param gray true if the generated image should be in grayscales
* @param withAlpha true if an alpha channel should be created
* @return the generated BufferedImage
*/
protected BufferedImage paintToBufferedImage(
org.apache.xmlgraphics.java2d.Graphics2DImagePainter painter,
Dimension targetDimension,
int resolution, boolean gray, boolean withAlpha) {
int bmw = (int)Math.ceil(UnitConv.mpt2px(targetDimension.getWidth(), resolution));
int bmh = (int)Math.ceil(UnitConv.mpt2px(targetDimension.getHeight(), resolution));
BufferedImage bi;
if (gray) {
if (withAlpha) {
bi = createGrayBufferedImageWithAlpha(bmw, bmh);
} else {
bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_BYTE_GRAY);
}
} else {
if (withAlpha) {
bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_ARGB);
} else {
bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_RGB);
}
}
Graphics2D g2d = bi.createGraphics();
try {
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
setRenderingHintsForBufferedImage(g2d);

g2d.setBackground(Color.white);
g2d.setColor(Color.black);
if (!withAlpha) {
g2d.clearRect(0, 0, bmw, bmh);
}
/* debug code
int off = 2;
g2d.drawLine(off, 0, off, bmh);
g2d.drawLine(bmw - off, 0, bmw - off, bmh);
g2d.drawLine(0, off, bmw, off);
g2d.drawLine(0, bmh - off, bmw, bmh - off);
*/
double sx = (double)bmw / targetDimension.getWidth();
double sy = (double)bmh / targetDimension.getHeight();
g2d.scale(sx, sy);

//Paint the image on the BufferedImage
Rectangle2D area = new Rectangle2D.Double(
0.0, 0.0, targetDimension.getWidth(), targetDimension.getHeight());
painter.paint(g2d, area);
} finally {
g2d.dispose();
}
return bi;
}

private static BufferedImage createGrayBufferedImageWithAlpha(int width, int height) {
BufferedImage bi;
boolean alphaPremultiplied = true;
int bands = 2;
int[] bits = new int[bands];
for (int i = 0; i < bands; i++) {
bits[i] = 8;
}
ColorModel cm = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY),
bits,
true, alphaPremultiplied,
Transparency.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
WritableRaster wr = Raster.createInterleavedRaster(
DataBuffer.TYPE_BYTE,
width, height, bands,
new Point(0, 0));
bi = new BufferedImage(cm, wr, alphaPremultiplied, null);
return bi;
}

/**
* Sets rendering hints on the Graphics2D created for painting to a BufferedImage. Subclasses
* can modify the settings to customize the behavior.
* @param g2d the Graphics2D instance
*/
protected void setRenderingHintsForBufferedImage(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}

}

+ 13
- 12
src/java/org/apache/fop/render/AbstractImageHandlerRegistry.java View File

@@ -27,6 +27,7 @@ import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.util.Service;
@@ -43,8 +44,8 @@ public abstract class AbstractImageHandlerRegistry {

private static final Comparator HANDLER_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
ImageHandler h1 = (ImageHandler)o1;
ImageHandler h2 = (ImageHandler)o2;
ImageHandlerBase h1 = (ImageHandlerBase)o1;
ImageHandlerBase h2 = (ImageHandlerBase)o2;
return h1.getPriority() - h2.getPriority();
}
};
@@ -76,8 +77,8 @@ public abstract class AbstractImageHandlerRegistry {
*/
public void addHandler(String classname) {
try {
ImageHandler handlerInstance
= (ImageHandler)Class.forName(classname).newInstance();
ImageHandlerBase handlerInstance
= (ImageHandlerBase)Class.forName(classname).newInstance();
addHandler(handlerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
@@ -99,13 +100,13 @@ public abstract class AbstractImageHandlerRegistry {
* Add an image handler. The handler itself is inspected to find out what it supports.
* @param handler the ImageHandler instance
*/
public synchronized void addHandler(ImageHandler handler) {
public synchronized void addHandler(ImageHandlerBase handler) {
this.handlers.put(handler.getSupportedImageClass(), handler);

//Sorted insert
ListIterator iter = this.handlerList.listIterator();
while (iter.hasNext()) {
ImageHandler h = (ImageHandler)iter.next();
ImageHandlerBase h = (ImageHandlerBase)iter.next();
if (getHandlerComparator().compare(handler, h) < 0) {
iter.previous();
break;
@@ -121,7 +122,7 @@ public abstract class AbstractImageHandlerRegistry {
* @param img the Image to be handled
* @return the ImageHandler responsible for handling the image or null if none is available
*/
public ImageHandler getHandler(Image img) {
public ImageHandlerBase getHandler(Image img) {
return getHandler(img.getClass());
}

@@ -131,11 +132,11 @@ public abstract class AbstractImageHandlerRegistry {
* @param imageClass the Image subclass for which to get a handler
* @return the ImageHandler responsible for handling the image or null if none is available
*/
public synchronized ImageHandler getHandler(Class imageClass) {
ImageHandler handler = null;
public synchronized ImageHandlerBase getHandler(Class imageClass) {
ImageHandlerBase handler = null;
Class cl = imageClass;
while (cl != null) {
handler = (ImageHandler)handlers.get(cl);
handler = (ImageHandlerBase)handlers.get(cl);
if (handler != null) {
break;
}
@@ -154,7 +155,7 @@ public abstract class AbstractImageHandlerRegistry {
List flavors = new java.util.ArrayList();
Iterator iter = this.handlerList.iterator();
while (iter.hasNext()) {
ImageFlavor[] f = ((ImageHandler)iter.next()).getSupportedImageFlavors();
ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors();
for (int i = 0; i < f.length; i++) {
flavors.add(f[i]);
}
@@ -175,7 +176,7 @@ public abstract class AbstractImageHandlerRegistry {
Iterator providers = Service.providers(imageHandlerClass);
if (providers != null) {
while (providers.hasNext()) {
ImageHandler handler = (ImageHandler)providers.next();
ImageHandlerBase handler = (ImageHandlerBase)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding ImageHandler: "

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

@@ -475,7 +475,8 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
}
}

private static final QName FOX_TRANSFORM
/** Constant for the fox:transform extension attribute */
protected static final QName FOX_TRANSFORM
= new QName(ExtensionElementMapping.URI, "fox:transform");

/** {@inheritDoc} */

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

@@ -21,6 +21,7 @@ package org.apache.fop.render;

// Java
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.OutputStream;
@@ -111,7 +112,7 @@ public abstract class AbstractRenderer
private Set warnedXMLHandlers;

/** {@inheritDoc} */
public abstract void setupFontInfo(FontInfo fontInfo);
public abstract void setupFontInfo(FontInfo fontInfo) throws FOPException;

/** {@inheritDoc} */
public void setUserAgent(FOUserAgent agent) {
@@ -833,4 +834,34 @@ public abstract class AbstractRenderer
public String getMimeType() {
return null;
}

/**
* Converts a millipoint-based transformation matrix to points.
* @param at a millipoint-based transformation matrix
* @return a point-based transformation matrix
*/
protected AffineTransform mptToPt(AffineTransform at) {
double[] matrix = new double[6];
at.getMatrix(matrix);
//Convert to points
matrix[4] = matrix[4] / 1000;
matrix[5] = matrix[5] / 1000;
return new AffineTransform(matrix);
}

/**
* Converts a point-based transformation matrix to millipoints.
* @param at a point-based transformation matrix
* @return a millipoint-based transformation matrix
*/
protected AffineTransform ptToMpt(AffineTransform at) {
double[] matrix = new double[6];
at.getMatrix(matrix);
//Convert to millipoints
//Math.round() because things like this can happen: 65.6 * 1000 = 65.599999999999999
//which is bad for testing
matrix[4] = Math.round(matrix[4] * 1000);
matrix[5] = Math.round(matrix[5] * 1000);
return new AffineTransform(matrix);
}
}

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

@@ -23,6 +23,7 @@ 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;

/**
@@ -68,7 +69,7 @@ public abstract class AbstractRendererConfigurator {
* @param mimeType the MIME type of the renderer
* @return the requested configuration subtree, null if there's no configuration
*/
private Configuration getRendererConfig(String mimeType) {
protected Configuration getRendererConfig(String mimeType) {
Configuration cfg = userAgent.getFactory().getUserConfig();
if (cfg == null) {
if (log.isDebugEnabled()) {

+ 86
- 0
src/java/org/apache/fop/render/AbstractRenderingContext.java View File

@@ -0,0 +1,86 @@
/*
* 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 java.util.Collections;
import java.util.Map;

import org.apache.fop.apps.FOUserAgent;

/**
* Abstract base class for RenderingContext implementations.
*/
public abstract class AbstractRenderingContext implements RenderingContext {

private FOUserAgent userAgent;
private Map hints;

/**
* Main constructor.
* @param userAgent the user agent
*/
public AbstractRenderingContext(FOUserAgent userAgent) {
this.userAgent = userAgent;
}

/**
* Returns the user agent.
*
* @return The user agent
*/
public FOUserAgent getUserAgent() {
return userAgent;
}

/** {@inheritDoc} */
public void putHints(Map additionalHints) {
if (additionalHints == null) {
return;
}
if (this.hints == null) {
this.hints = new java.util.HashMap();
}
this.hints.putAll(additionalHints);
}

/** {@inheritDoc} */
public void putHint(Object key, Object value) {
this.hints.put(key, value);
}

/** {@inheritDoc} */
public Map getHints() {
if (this.hints == null) {
return Collections.EMPTY_MAP;
} else {
return Collections.unmodifiableMap(this.hints);
}
}

/** {@inheritDoc} */
public Object getHint(Object key) {
if (this.hints == null) {
return null;
} else {
return this.hints.get(key);
}
}
}


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

@@ -27,4 +27,4 @@ package org.apache.fop.render;
public interface Graphics2DImagePainter
extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter {

}
}

+ 4
- 4
src/java/org/apache/fop/render/ImageAdapter.java View File

@@ -34,10 +34,10 @@ public interface ImageAdapter {
* Paints an image at the given position.
* @param image the image which will be painted
* @param context the renderer context for the current renderer
* @param x X position of the image
* @param y Y position of the image
* @param width width of the image
* @param height height of the image
* @param x X position of the image (in millipoints)
* @param y Y position of the image (in millipoints)
* @param width width of the image (in millipoints)
* @param height height of the image (in millipoints)
* @throws IOException In case of an I/O error while writing the output format
*/
void paintImage(RenderedImage image,

+ 27
- 15
src/java/org/apache/fop/render/ImageHandler.java View File

@@ -19,27 +19,39 @@

package org.apache.fop.render;

import org.apache.xmlgraphics.image.loader.ImageFlavor;
import java.awt.Rectangle;
import java.io.IOException;

public interface ImageHandler {
import org.apache.xmlgraphics.image.loader.Image;

/**
* Returns the priority for this image handler. A lower value means higher priority. This
* information is used to build the ordered/prioritized list of supported ImageFlavors.
* The built-in handlers use priorities between 100 and 999.
* @return a positive integer (>0) indicating the priority
*/
int getPriority();
/**
* This interface is a service provider interface for image handlers.
*/
public interface ImageHandler extends ImageHandlerBase {

/**
* Returns the {@link ImageFlavor}s supported by this instance
* @return the supported image flavors
* Indicates whether the image handler is compatible with the indicated target represented
* by the rendering context object and with the image to be processed. The image is also
* passed as a parameter because a handler might not support every subtype of image that is
* presented. For example: in the case of {@code ImageXMLDOM}, the image might carry an SVG
* or some other XML format. One handler might only handle SVG but no other XML format.
* @param targetContext the target rendering context
* @param image the image to be processed (or null if only to check based on the rendering
* context)
* @return true if this handler is compatible with the target rendering context
*/
ImageFlavor[] getSupportedImageFlavors();
boolean isCompatible(RenderingContext targetContext, Image image);

/**
* Returns the {@link Class} subclass supported by this instance.
* @return the image Class type
* Handles the given {@link Image} instance painting it at the indicated position in the
* output format being generated.
* @param context the rendering context
* @param image the image to be handled
* @param pos the position and scaling of the image relative to the origin point of the
* current viewport (in millipoints)
* @throws IOException if an I/O error occurs
*/
Class getSupportedImageClass();
void handleImage(RenderingContext context, Image image,
Rectangle pos) throws IOException;

}

+ 50
- 0
src/java/org/apache/fop/render/ImageHandlerBase.java View File

@@ -0,0 +1,50 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.render;

import org.apache.xmlgraphics.image.loader.ImageFlavor;

/**
* This interface is a service provider base interface for image handlers. It only contains
* methods necessary for registration and is extended by sub-interfaces with the actual
* image handling contract.
*/
public interface ImageHandlerBase {

/**
* Returns the priority for this image handler. A lower value means higher priority. This
* information is used to build the ordered/prioritized list of supported ImageFlavors.
* The built-in handlers use priorities between 100 and 999.
* @return a positive integer (>0) indicating the priority
*/
int getPriority();

/**
* Returns the {@link ImageFlavor}s supported by this instance
* @return the supported image flavors
*/
ImageFlavor[] getSupportedImageFlavors();

/**
* Returns the {@link Class} subclass supported by this instance.
* @return the image Class type
*/
Class getSupportedImageClass();
}

+ 177
- 0
src/java/org/apache/fop/render/ImageHandlerRegistry.java View File

@@ -0,0 +1,177 @@
/*
* 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 java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.util.Service;

/**
* This class holds references to various image handlers. It also
* supports automatic discovery of additional handlers available through
* the class path.
*/
public class ImageHandlerRegistry {

/** the logger */
private static Log log = LogFactory.getLog(ImageHandlerRegistry.class);

private static final Comparator HANDLER_COMPARATOR = new Comparator() {
public int compare(Object o1, Object o2) {
ImageHandler h1 = (ImageHandler)o1;
ImageHandler h2 = (ImageHandler)o2;
return h1.getPriority() - h2.getPriority();
}
};

/** Map containing image handlers for various {@code Image} subclasses. */
private Map handlers = new java.util.HashMap();
/** List containing the same handlers as above but ordered by priority */
private List handlerList = new java.util.LinkedList();

private int handlerRegistrations;

/**
* Default constructor.
*/
public ImageHandlerRegistry() {
discoverHandlers();
}

/**
* Add an PDFImageHandler. The handler itself is inspected to find out what it supports.
* @param classname the fully qualified class name
*/
public void addHandler(String classname) {
try {
ImageHandler handlerInstance
= (ImageHandler)Class.forName(classname).newInstance();
addHandler(handlerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
+ classname);
} catch (InstantiationException e) {
throw new IllegalArgumentException("Could not instantiate "
+ classname);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not access "
+ classname);
} catch (ClassCastException e) {
throw new IllegalArgumentException(classname
+ " is not an "
+ ImageHandler.class.getName());
}
}

/**
* Add an image handler. The handler itself is inspected to find out what it supports.
* @param handler the ImageHandler instance
*/
public synchronized void addHandler(ImageHandler handler) {
Class imageClass = handler.getSupportedImageClass();
//List
this.handlers.put(imageClass, handler);

//Sorted insert (sort by priority)
ListIterator iter = this.handlerList.listIterator();
while (iter.hasNext()) {
ImageHandler h = (ImageHandler)iter.next();
if (HANDLER_COMPARATOR.compare(handler, h) < 0) {
iter.previous();
break;
}
}
iter.add(handler);
this.handlerRegistrations++;
}

/**
* Returns an {@code ImageHandler} which handles an specific image type given the MIME type
* of the image.
* @param targetContext the target rendering context that is used for identifying compatibility
* @param image the Image to be handled
* @return the image handler responsible for handling the image or null if none is available
*/
public ImageHandler getHandler(RenderingContext targetContext, Image image) {
ListIterator iter = this.handlerList.listIterator();
while (iter.hasNext()) {
ImageHandler h = (ImageHandler)iter.next();
if (h.isCompatible(targetContext, image)) {
//Return the first handler in the prioritized list that is compatible
return h;
}
}
return null;
}

/**
* Returns the ordered array of supported image flavors. The array needs to be ordered by
* priority so the image loader framework can return the preferred image type.
* @return the array of image flavors
*/
public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) {
//Extract all ImageFlavors into a single array
List flavors = new java.util.ArrayList();
Iterator iter = this.handlerList.iterator();
while (iter.hasNext()) {
ImageHandler handler = (ImageHandler)iter.next();
if (handler.isCompatible(context, null)) {
ImageFlavor[] f = handler.getSupportedImageFlavors();
for (int i = 0; i < f.length; i++) {
flavors.add(f[i]);
}
}
}
return (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]);
}

/**
* Discovers ImageHandler implementations through the classpath and dynamically
* registers them.
*/
private void discoverHandlers() {
// add mappings from available services
Iterator providers = Service.providers(ImageHandler.class);
if (providers != null) {
while (providers.hasNext()) {
ImageHandler handler = (ImageHandler)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding ImageHandler: "
+ handler.getClass().getName());
}
addHandler(handler);
} catch (IllegalArgumentException e) {
log.error("Error while adding ImageHandler", e);
}

}
}
}
}

+ 64
- 0
src/java/org/apache/fop/render/ImageHandlerUtil.java View File

@@ -0,0 +1,64 @@
/*
* 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 java.util.Map;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.fo.extensions.ExtensionElementMapping;

/**
* Utility methods for image handling.
*/
public class ImageHandlerUtil {

/** conversion-mode extension attribute */
public static final QName CONVERSION_MODE = new QName(
ExtensionElementMapping.URI, null, "conversion-mode");

/** Conversion mode: indicates that the image shall be converted to a bitmap. */
public static final String CONVERSION_MODE_BITMAP = "bitmap";

/**
* Indicates whether the image conversion mode is set to bitmap mode, i.e. the image shall
* be converted to a bitmap.
* @param mode the conversion mode
* @return true if conversion mode is "bitmap"
*/
public static boolean isConversionModeBitmap(String mode) {
return CONVERSION_MODE_BITMAP.equalsIgnoreCase(mode);
}

/**
* Indicates whether the image conversion mode is set to bitmap mode, i.e. the image shall
* be converted to a bitmap.
* @param foreignAttributes a map of foreign attributes (Map&lt;QName, Object&gt;)
* @return true if conversion mode is "bitmap"
*/
public static boolean isConversionModeBitmap(Map foreignAttributes) {
if (foreignAttributes == null) {
return false;
}
String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE);
return isConversionModeBitmap(conversionMode);
}

}

+ 12
- 8
src/java/org/apache/fop/render/PrintRenderer.java View File

@@ -24,6 +24,9 @@ import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Document;

import org.apache.fop.apps.FOPException;
import org.apache.fop.area.Area;
import org.apache.fop.area.Trait;
import org.apache.fop.fonts.CustomFontCollection;
@@ -34,7 +37,6 @@ import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.base14.Base14FontCollection;
import org.w3c.dom.Document;

/** Abstract base class of "Print" type renderers. */
public abstract class PrintRenderer extends AbstractRenderer {
@@ -74,12 +76,8 @@ public abstract class PrintRenderer extends AbstractRenderer {
return this.embedFontInfoList;
}

/**
* Set up the font info
*
* @param inFontInfo font info to set up
*/
public void setupFontInfo(FontInfo inFontInfo) {
/** {@inheritDoc} */
public void setupFontInfo(FontInfo inFontInfo) throws FOPException {
this.fontInfo = inFontInfo;
FontManager fontManager = userAgent.getFactory().getFontManager();
FontCollection[] fontCollections = new FontCollection[] {
@@ -96,7 +94,13 @@ public abstract class PrintRenderer extends AbstractRenderer {
*/
protected String getInternalFontNameForArea(Area area) {
FontTriplet triplet = (FontTriplet)area.getTrait(Trait.FONT);
return fontInfo.getInternalFontKey(triplet);
String key = fontInfo.getInternalFontKey(triplet);
if (key == null) {
//Find a default fallback font as last resort
triplet = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL);
key = fontInfo.getInternalFontKey(triplet);
}
return key;
}

/**

+ 53
- 4
src/java/org/apache/fop/render/PrintRendererConfigurator.java View File

@@ -41,9 +41,11 @@ 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;
@@ -53,13 +55,16 @@ 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)
*/
public class PrintRendererConfigurator extends AbstractRendererConfigurator
implements RendererConfigurator {
implements RendererConfigurator, IFDocumentHandlerConfigurator {

/** logger instance */
protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class);
@@ -87,6 +92,23 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator

PrintRenderer printRenderer = (PrintRenderer)renderer;
FontResolver fontResolver = printRenderer.getFontResolver();

FontEventListener listener = new FontEventAdapter(
renderer.getUserAgent().getEventBroadcaster());
List embedFontInfoList = buildFontList(cfg, fontResolver, listener);
printRenderer.addFontList(embedFontInfoList);
}

/**
* Builds the font list from configuration.
* @param cfg the configuration object
* @param fontResolver a font resolver
* @param listener the font event listener
* @return the list of {@code EmbedFontInfo} objects
* @throws FOPException if an error occurs while processing the configuration
*/
protected List buildFontList(Configuration cfg, FontResolver fontResolver,
FontEventListener listener) throws FOPException {
FopFactory factory = userAgent.getFactory();
FontManager fontManager = factory.getFontManager();
if (fontResolver == null) {
@@ -97,15 +119,13 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
boolean strict = factory.validateUserConfigStrictly();
FontCache fontCache = fontManager.getFontCache();

FontEventListener listener = new FontEventAdapter(
renderer.getUserAgent().getEventBroadcaster());
List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg,
fontResolver, strict, fontManager, listener);

if (fontCache != null && fontCache.hasChanged()) {
fontCache.save();
}
printRenderer.addFontList(embedFontInfoList);
return embedFontInfoList;
}

/**
@@ -437,4 +457,33 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
return embedFontInfo;
}

// ---=== IFDocumentHandler configuration ===---

/** {@inheritDoc} */
public void configure(IFDocumentHandler documentHandler) throws FOPException {
//nop
}

/** {@inheritDoc} */
public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo)
throws FOPException {
FontManager fontManager = userAgent.getFactory().getFontManager();
List fontCollections = new java.util.ArrayList();
fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled()));

Configuration cfg = super.getRendererConfig(documentHandler.getMimeType());
if (cfg != null) {
FontResolver fontResolver = new DefaultFontResolver(userAgent);
FontEventListener listener = new FontEventAdapter(
userAgent.getEventBroadcaster());
List fontList = buildFontList(cfg, fontResolver, listener);
fontCollections.add(new CustomFontCollection(fontResolver, fontList));
}

fontManager.setup(fontInfo,
(FontCollection[])fontCollections.toArray(
new FontCollection[fontCollections.size()]));
documentHandler.setFontInfo(fontInfo);
}

}

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

@@ -98,8 +98,9 @@ public interface Renderer {
* Set up the given FontInfo.
*
* @param fontInfo The font information
* @throws FOPException if an error occurs while setting up the font info object
*/
void setupFontInfo(FontInfo fontInfo);
void setupFontInfo(FontInfo fontInfo) throws FOPException;

/**
* Reports if out of order rendering is supported. <p>

+ 0
- 8
src/java/org/apache/fop/render/RendererContext.java View File

@@ -24,8 +24,6 @@ import java.util.Iterator;
import java.util.Map;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.xmlgraphics.util.QName;

/**
* The Render Context for external handlers. This provides a rendering context
@@ -33,12 +31,6 @@ import org.apache.xmlgraphics.util.QName;
* render target.
*/
public class RendererContext {
/** conversion-mode extension attribute */
protected static final QName CONVERSION_MODE = new QName(
ExtensionElementMapping.URI, null, "conversion-mode");

/** "bitmap" value for the "conversion-mode" extension attribute. */
protected static final String BITMAP = "bitmap";

private final String mime;
private final AbstractRenderer renderer;

+ 163
- 23
src/java/org/apache/fop/render/RendererFactory.java View File

@@ -34,6 +34,10 @@ import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
import org.apache.fop.render.intermediate.IFRenderer;

/**
* Factory for FOEventHandlers and Renderers.
@@ -45,7 +49,7 @@ public class RendererFactory {

private Map rendererMakerMapping = new java.util.HashMap();
private Map eventHandlerMakerMapping = new java.util.HashMap();
private Map documentHandlerMakerMapping = new java.util.HashMap();

/**
* Main constructor.
@@ -53,6 +57,7 @@ public class RendererFactory {
public RendererFactory() {
discoverRenderers();
discoverFOEventHandlers();
discoverDocumentHandlers();
}

/**
@@ -89,6 +94,23 @@ public class RendererFactory {
}
}

/**
* Add a new document handler maker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
* @param maker the intermediate format document handler maker
*/
public void addDocumentHandlerMaker(AbstractIFDocumentHandlerMaker maker) {
String[] mimes = maker.getSupportedMimeTypes();
for (int i = 0; i < mimes.length; i++) {
//This overrides any renderer previously set for a MIME type
if (documentHandlerMakerMapping.get(mimes[i]) != null) {
log.trace("Overriding document handler for " + mimes[i]
+ " with " + maker.getClass().getName());
}
documentHandlerMakerMapping.put(mimes[i], maker);
}
}

/**
* Add a new RendererMaker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
@@ -141,6 +163,32 @@ public class RendererFactory {
}
}

/**
* Add a new document handler maker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
* @param className the fully qualified class name of the document handler maker
*/
public void addDocumentHandlerMaker(String className) {
try {
AbstractIFDocumentHandlerMaker makerInstance
= (AbstractIFDocumentHandlerMaker)Class.forName(className).newInstance();
addDocumentHandlerMaker(makerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
+ className);
} catch (InstantiationException e) {
throw new IllegalArgumentException("Could not instantiate "
+ className);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not access "
+ className);
} catch (ClassCastException e) {
throw new IllegalArgumentException(className
+ " is not an "
+ AbstractIFDocumentHandlerMaker.class.getName());
}
}

/**
* Returns a RendererMaker which handles the given MIME type.
* @param mime the requested output format
@@ -163,6 +211,17 @@ public class RendererFactory {
return maker;
}

/**
* Returns a RendererMaker which handles the given MIME type.
* @param mime the requested output format
* @return the requested RendererMaker or null if none is available
*/
public AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) {
AbstractIFDocumentHandlerMaker maker
= (AbstractIFDocumentHandlerMaker)documentHandlerMakerMapping.get(mime);
return maker;
}

/**
* Creates a Renderer object based on render-type desired
* @param userAgent the user agent for access to configuration
@@ -172,24 +231,41 @@ public class RendererFactory {
*/
public Renderer createRenderer(FOUserAgent userAgent, String outputFormat)
throws FOPException {
if (userAgent.getRendererOverride() != null) {
if (userAgent.getDocumentHandlerOverride() != null) {
return createRendererForDocumentHandler(userAgent.getDocumentHandlerOverride());
} else if (userAgent.getRendererOverride() != null) {
return userAgent.getRendererOverride();
} else {
AbstractRendererMaker maker = getRendererMaker(outputFormat);
if (maker == null) {
throw new UnsupportedOperationException(
"No renderer for the requested format available: " + outputFormat);
}
Renderer rend = maker.makeRenderer(userAgent);
rend.setUserAgent(userAgent);
RendererConfigurator configurator = maker.getConfigurator(userAgent);
if (configurator != null) {
configurator.configure(rend);
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 {
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);
}
}
return rend;
}
}

private Renderer createRendererForDocumentHandler(IFDocumentHandler documentHandler) {
IFRenderer rend = new IFRenderer();
rend.setUserAgent(documentHandler.getContext().getUserAgent());
rend.setDocumentHandler(documentHandler);
return rend;
}

/**
* Creates FOEventHandler instances based on the desired output.
@@ -206,29 +282,64 @@ public class RendererFactory {
return userAgent.getFOEventHandlerOverride();
} else {
AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat);
if (maker == null) {
if (maker != null) {
return maker.makeFOEventHandler(userAgent, out);
} else {
AbstractRendererMaker rendMaker = getRendererMaker(outputFormat);
if (rendMaker == null && userAgent.getRendererOverride() == null) {
throw new UnsupportedOperationException(
"Don't know how to handle \"" + outputFormat + "\" as an output format."
+ " Neither an FOEventHandler, nor a Renderer could be found"
+ " for this output format.");
AbstractIFDocumentHandlerMaker documentHandlerMaker = null;
boolean outputStreamMissing = (userAgent.getRendererOverride() == null)
&& (userAgent.getDocumentHandlerOverride() == null);
if (rendMaker == null) {
documentHandlerMaker = getDocumentHandlerMaker(outputFormat);
if (documentHandlerMaker != null) {
outputStreamMissing &= (out == null)
&& (documentHandlerMaker.needsOutputStream());
}
} else {
if (out == null
&& userAgent.getRendererOverride() == null
&& rendMaker.needsOutputStream()) {
outputStreamMissing &= (out == null) && (rendMaker.needsOutputStream());
}
if (userAgent.getRendererOverride() != null
|| rendMaker != null
|| userAgent.getDocumentHandlerOverride() != null
|| documentHandlerMaker != null) {
if (outputStreamMissing) {
throw new FOPException(
"OutputStream has not been set");
}
//Found a Renderer so we need to construct an AreaTreeHandler.
return new AreaTreeHandler(userAgent, outputFormat, out);
} else {
throw new UnsupportedOperationException(
"Don't know how to handle \"" + outputFormat + "\" as an output format."
+ " Neither an FOEventHandler, nor a Renderer could be found"
+ " for this output format.");
}
} else {
return maker.makeFOEventHandler(userAgent, out);
}
}
}

/**
* Creates a {@code IFDocumentHandler} object based on the desired output format.
* @param userAgent the user agent for access to configuration
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
* @return the new {@code IFDocumentHandler} instance
* @throws FOPException if the document handler cannot be properly constructed
*/
public IFDocumentHandler createDocumentHandler(FOUserAgent userAgent, String outputFormat)
throws FOPException {
AbstractIFDocumentHandlerMaker maker = getDocumentHandlerMaker(outputFormat);
if (maker == null) {
throw new UnsupportedOperationException(
"No IF document handler for the requested format available: " + outputFormat);
}
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent);
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator();
if (configurator != null) {
configurator.configure(documentHandler);
}
return documentHandler;
}

/**
* @return an array of all supported MIME types
*/
@@ -242,6 +353,10 @@ public class RendererFactory {
while (iter.hasNext()) {
lst.add(((String)iter.next()));
}
iter = this.documentHandlerMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
}
Collections.sort(lst);
return (String[])lst.toArray(new String[lst.size()]);
}
@@ -296,4 +411,29 @@ public class RendererFactory {
}
}

/**
* Discovers {@code IFDocumentHandler} implementations through the classpath and dynamically
* registers them.
*/
private void discoverDocumentHandlers() {
// add mappings from available services
Iterator providers = Service.providers(IFDocumentHandler.class);
if (providers != null) {
while (providers.hasNext()) {
AbstractIFDocumentHandlerMaker maker
= (AbstractIFDocumentHandlerMaker)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding maker for IFDocumentHandler: "
+ maker.getClass().getName());
}
addDocumentHandlerMaker(maker);
} catch (IllegalArgumentException e) {
log.error("Error while adding maker for IFDocumentHandler", e);
}

}
}
}

}

+ 71
- 0
src/java/org/apache/fop/render/RenderingContext.java View File

@@ -0,0 +1,71 @@
/*
* 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 java.util.Map;

import org.apache.fop.apps.FOUserAgent;

/**
* Implementations of this interface provide context information needed by supporting classes
* during specific tasks (like image rendering).
*/
public interface RenderingContext {

/**
* Returns the MIME type associated with the current output format.
* @return the MIME type (ex. application/pdf)
*/
String getMimeType();

/**
* Returns the user agent. The user agent is used to access configuration and other information
* for the rendering process.
* @return the user agent
*/
FOUserAgent getUserAgent();

/**
* Adds additional hints to the existing hints, overriding existing hints.
* @param additionalHints a map of additional hints
*/
void putHints(Map additionalHints);

/**
* Sets an additional hint, overriding an existing hint.
* @param key the key
* @param value the value
*/
void putHint(Object key, Object value);

/**
* Returns an unmodifiable representation of all hints.
* @return the hints
*/
Map getHints();

/**
* Returns a hint identified by a key.
* @param key the key
* @return the hint or null if no hint with the given key could be found
*/
Object getHint(Object key);

}

+ 81
- 0
src/java/org/apache/fop/render/afp/AFPCustomizable.java View File

@@ -0,0 +1,81 @@
/*
* 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;

import org.apache.fop.afp.AFPResourceLevelDefaults;

/**
* Interface used to customize the AFP renderer or document handler.
*/
public interface AFPCustomizable {

/**
* Sets the number of bits used per pixel
*
* @param bitsPerPixel
* number of bits per pixel
*/
void setBitsPerPixel(int bitsPerPixel);

/**
* Sets whether images are color or not
*
* @param colorImages
* color image output
*/
void setColorImages(boolean colorImages);

/**
* Sets whether images are supported natively or not
*
* @param nativeImages
* native image support
*/
void setNativeImagesSupported(boolean nativeImages);

/**
* Sets the output/device resolution
*
* @param resolution
* the output resolution (dpi)
*/
void setResolution(int resolution);

/**
* Returns the output/device resolution.
*
* @return the resolution in dpi
*/
int getResolution();

/**
* Sets the default resource group file path
* @param filePath the default resource group file path
*/
void setDefaultResourceGroupFilePath(String filePath);

/**
* Sets the resource level defaults. The object passed in provides information which resource
* level shall be used by default for various kinds of resources.
* @param defaults the resource level defaults
*/
void setResourceLevelDefaults(AFPResourceLevelDefaults defaults);

}

+ 321
- 0
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

@@ -0,0 +1,321 @@
/*
* 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;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.util.Map;

import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceLevelDefaults;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.AFPUnitConverter;
import org.apache.fop.afp.DataStream;
import org.apache.fop.afp.fonts.AFPFontCollection;
import org.apache.fop.afp.fonts.AFPPageFonts;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.fonts.FontCollection;
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.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;

/**
* {@code IFDocumentHandler} implementation that produces AFP (MO:DCA).
*/
public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
implements AFPCustomizable {

//** logging instance */
//private static Log log = LogFactory.getLog(AFPDocumentHandler.class);

/** the resource manager */
private AFPResourceManager resourceManager;

/** the painting state */
private final AFPPaintingState paintingState;

/** unit converter */
private final AFPUnitConverter unitConv;

/** the AFP datastream */
private DataStream dataStream;

/** the map of page segments */
private Map/*<String,String>*/pageSegmentMap
= new java.util.HashMap/*<String,String>*/();

private boolean inPageHeader;

/**
* Default constructor.
*/
public AFPDocumentHandler() {
this.resourceManager = new AFPResourceManager();
this.paintingState = new AFPPaintingState();
this.unitConv = paintingState.getUnitConverter();
}

/** {@inheritDoc} */
public boolean supportsPagesOutOfOrder() {
return false;
}

/** {@inheritDoc} */
public String getMimeType() {
return MimeConstants.MIME_AFP;
}

/** {@inheritDoc} */
public void setContext(IFContext context) {
super.setContext(context);
}

/** {@inheritDoc} */
public IFDocumentHandlerConfigurator getConfigurator() {
return new AFPRendererConfigurator(getUserAgent());
}

/** {@inheritDoc} */
public void setDefaultFontInfo(FontInfo fontInfo) {
FontManager fontManager = getUserAgent().getFactory().getFontManager();
FontCollection[] fontCollections = new FontCollection[] {
new AFPFontCollection(getUserAgent().getEventBroadcaster(), null)
};

FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo());
fi.setEventListener(new FontEventAdapter(getUserAgent().getEventBroadcaster()));
fontManager.setup(fi, fontCollections);
setFontInfo(fi);
}

AFPPaintingState getPaintingState() {
return this.paintingState;
}

DataStream getDataStream() {
return this.dataStream;
}

AFPResourceManager getResourceManager() {
return this.resourceManager;
}

/** {@inheritDoc} */
public void startDocument() throws IFException {
super.startDocument();
try {
paintingState.setColor(Color.WHITE);

this.dataStream = resourceManager.createDataStream(paintingState, outputStream);

this.dataStream.startDocument();
} catch (IOException e) {
throw new IFException("I/O error in startDocument()", e);
}
}

/** {@inheritDoc} */
public void endDocumentHeader() throws IFException {
}

/** {@inheritDoc} */
public void endDocument() throws IFException {
try {
this.dataStream.endDocument();
this.dataStream = null;
this.resourceManager.writeToStream();
this.resourceManager = null;
} catch (IOException ioe) {
throw new IFException("I/O error in endDocument()", ioe);
}
super.endDocument();
}

/** {@inheritDoc} */
public void startPageSequence(String id) throws IFException {
try {
dataStream.startPageGroup();
} catch (IOException ioe) {
throw new IFException("I/O error in startPageSequence()", ioe);
}
}

/** {@inheritDoc} */
public void endPageSequence() throws IFException {
//nop
}

/**
* Returns the base AFP transform
*
* @return the base AFP transform
*/
private AffineTransform getBaseTransform() {
AffineTransform baseTransform = new AffineTransform();
double scale = unitConv.mpt2units(1);
baseTransform.scale(scale, scale);
return baseTransform;
}

/** {@inheritDoc} */
public void startPage(int index, String name, String pageMasterName, Dimension size)
throws IFException {
paintingState.clear();
pageSegmentMap.clear();

AffineTransform baseTransform = getBaseTransform();
paintingState.concatenate(baseTransform);

int pageWidth = Math.round(unitConv.mpt2units(size.width));
paintingState.setPageWidth(pageWidth);

int pageHeight = Math.round(unitConv.mpt2units(size.height));
paintingState.setPageHeight(pageHeight);

int pageRotation = paintingState.getPageRotation();
int resolution = paintingState.getResolution();

dataStream.startPage(pageWidth, pageHeight, pageRotation,
resolution, resolution);
}

/** {@inheritDoc} */
public void startPageHeader() throws IFException {
super.startPageHeader();
this.inPageHeader = true;
}

/** {@inheritDoc} */
public void endPageHeader() throws IFException {
this.inPageHeader = false;
super.endPageHeader();
}

/** {@inheritDoc} */
public IFPainter startPageContent() throws IFException {
return new AFPPainter(this);
}

/** {@inheritDoc} */
public void endPageContent() throws IFException {
}

/** {@inheritDoc} */
public void endPage() throws IFException {
try {
AFPPageFonts pageFonts = paintingState.getPageFonts();
if (pageFonts != null && !pageFonts.isEmpty()) {
dataStream.addFontsToCurrentPage(pageFonts);
}

dataStream.endPage();
} catch (IOException ioe) {
throw new IFException("I/O error in endPage()", ioe);
}
}

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

// ---=== AFPCustomizable ===---

/** {@inheritDoc} */
public void setBitsPerPixel(int bitsPerPixel) {
paintingState.setBitsPerPixel(bitsPerPixel);
}

/** {@inheritDoc} */
public void setColorImages(boolean colorImages) {
paintingState.setColorImages(colorImages);
}

/** {@inheritDoc} */
public void setNativeImagesSupported(boolean nativeImages) {
paintingState.setNativeImagesSupported(nativeImages);
}

/** {@inheritDoc} */
public void setResolution(int resolution) {
paintingState.setResolution(resolution);
}

/** {@inheritDoc} */
public int getResolution() {
return paintingState.getResolution();
}

/** {@inheritDoc} */
public void setDefaultResourceGroupFilePath(String filePath) {
resourceManager.setDefaultResourceGroupFilePath(filePath);
}

/** {@inheritDoc} */
public void setResourceLevelDefaults(AFPResourceLevelDefaults defaults) {
resourceManager.setResourceLevelDefaults(defaults);
}

/**
* Returns the page segment name for a given URI if it actually represents a page segment.
* Otherwise, it just returns null.
* @param uri the URI that identifies the page segment
* @return the page segment name or null if there's no page segment for the given URI
*/
String getPageSegmentNameFor(String uri) {
return (String)pageSegmentMap.get(uri);
}

}

+ 54
- 0
src/java/org/apache/fop/render/afp/AFPDocumentHandlerMaker.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;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;

/**
* Intermediate format document handler factory for AFP output.
*/
public class AFPDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker {

//TODO Revert to normal MIME after stabilization!
private static final String[] MIMES = new String[]
{MimeConstants.MIME_AFP + ";mode=painter"};

/** {@inheritDoc} */
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
AFPDocumentHandler handler = new AFPDocumentHandler();
handler.setContext(new IFContext(ua));
return handler;
}

/** {@inheritDoc} */
public boolean needsOutputStream() {
return true;
}

/** {@inheritDoc} */
public String[] getSupportedMimeTypes() {
return MIMES;
}

}

+ 1
- 0
src/java/org/apache/fop/render/afp/AFPEventProducer.xml View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"/>

+ 13
- 12
src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java View File

@@ -24,10 +24,12 @@ import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceLevel;
import org.apache.fop.render.afp.extensions.AFPElementMapping;
import org.apache.xmlgraphics.util.QName;

/**
* Parses any AFP foreign attributes
@@ -36,13 +38,16 @@ public class AFPForeignAttributeReader {
private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp");

/** the resource-name attribute */
public static final String RESOURCE_NAME = "afp:resource-name";
public static final QName RESOURCE_NAME = new QName(
AFPElementMapping.NAMESPACE, "afp:resource-name");

/** the resource-level attribute */
public static final String RESOURCE_LEVEL = "afp:resource-level";
public static final QName RESOURCE_LEVEL = new QName(
AFPElementMapping.NAMESPACE, "afp:resource-level");

/** the resource-group-file attribute */
public static final String RESOURCE_GROUP_FILE = "afp:resource-group-file";
public static final QName RESOURCE_GROUP_FILE = new QName(
AFPElementMapping.NAMESPACE, "afp:resource-group-file");

/**
* Main constructor
@@ -59,8 +64,7 @@ public class AFPForeignAttributeReader {
public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) {
AFPResourceInfo resourceInfo = new AFPResourceInfo();
if (foreignAttributes != null && !foreignAttributes.isEmpty()) {
QName resourceNameKey = new QName(AFPElementMapping.NAMESPACE, RESOURCE_NAME);
String resourceName = (String)foreignAttributes.get(resourceNameKey);
String resourceName = (String)foreignAttributes.get(RESOURCE_NAME);
if (resourceName != null) {
resourceInfo.setName(resourceName);
}
@@ -81,16 +85,13 @@ public class AFPForeignAttributeReader {
public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) {
AFPResourceLevel resourceLevel = null;
if (foreignAttributes != null && !foreignAttributes.isEmpty()) {
QName resourceLevelKey = new QName(AFPElementMapping.NAMESPACE, RESOURCE_LEVEL);
if (foreignAttributes.containsKey(resourceLevelKey)) {
String levelString = (String)foreignAttributes.get(resourceLevelKey);
if (foreignAttributes.containsKey(RESOURCE_LEVEL)) {
String levelString = (String)foreignAttributes.get(RESOURCE_LEVEL);
resourceLevel = AFPResourceLevel.valueOf(levelString);
// if external get resource group file attributes
if (resourceLevel != null && resourceLevel.isExternal()) {
QName resourceGroupFileKey = new QName(AFPElementMapping.NAMESPACE,
RESOURCE_GROUP_FILE);
String resourceGroupFile
= (String)foreignAttributes.get(resourceGroupFileKey);
= (String)foreignAttributes.get(RESOURCE_GROUP_FILE);
if (resourceGroupFile == null) {
String msg = RESOURCE_GROUP_FILE + " not specified";
log.error(msg);

+ 47
- 18
src/java/org/apache/fop/render/afp/AFPImageHandler.java View File

@@ -20,6 +20,7 @@
package org.apache.fop.render.afp;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Map;
@@ -29,12 +30,12 @@ import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPUnitConverter;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerBase;

/**
* A base abstract AFP image handler
*/
public abstract class AFPImageHandler implements ImageHandler {
public abstract class AFPImageHandler implements ImageHandlerBase {
private static final int X = 0;
private static final int Y = 1;

@@ -55,33 +56,64 @@ public abstract class AFPImageHandler implements ImageHandler {
AFPDataObjectInfo dataObjectInfo = createDataObjectInfo();

// set resource information
Map foreignAttributes = rendererImageInfo.getForeignAttributes();
AFPResourceInfo resourceInfo
= foreignAttributeReader.getResourceInfo(foreignAttributes);
resourceInfo.setUri(rendererImageInfo.getURI());
dataObjectInfo.setResourceInfo(resourceInfo);
setResourceInformation(dataObjectInfo,
rendererImageInfo.getURI(),
rendererImageInfo.getForeignAttributes());

// set object area
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo();

Point origin = rendererImageInfo.getOrigin();
Rectangle2D position = rendererImageInfo.getPosition();
float srcX = origin.x + (float)position.getX();
float srcY = origin.y + (float)position.getY();
int srcX = Math.round(origin.x + (float)position.getX());
int srcY = Math.round(origin.y + (float)position.getY());
Rectangle targetRect = new Rectangle(
srcX,
srcY,
(int)Math.round(position.getWidth()),
(int)Math.round(position.getHeight()));

AFPRendererContext rendererContext
= (AFPRendererContext)rendererImageInfo.getRendererContext();
AFPInfo afpInfo = rendererContext.getInfo();
AFPPaintingState paintingState = afpInfo.getPaintingState();

dataObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, targetRect));

return dataObjectInfo;
}

/**
* Sets resource information on the data object info.
* @param dataObjectInfo the data object info instance
* @param uri the image's URI (or null if no URI is available)
* @param foreignAttributes a Map of foreign attributes (or null)
*/
protected void setResourceInformation(AFPDataObjectInfo dataObjectInfo,
String uri, Map foreignAttributes) {
AFPResourceInfo resourceInfo
= foreignAttributeReader.getResourceInfo(foreignAttributes);
resourceInfo.setUri(uri);
dataObjectInfo.setResourceInfo(resourceInfo);
}

/**
* Creates and returns an {@link AFPObjectAreaInfo} instance for the placement of the image.
* @param paintingState the painting state
* @param targetRect the target rectangle in which to place the image (coordinates in mpt)
* @return the newly created object area info instance
*/
public static AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState,
Rectangle targetRect) {
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo();
AFPUnitConverter unitConv = paintingState.getUnitConverter();
int[] coords = unitConv.mpts2units(new float[] {srcX, srcY});

int[] coords = unitConv.mpts2units(new float[] {targetRect.x, targetRect.y});
objectAreaInfo.setX(coords[X]);
objectAreaInfo.setY(coords[Y]);

int width = Math.round(unitConv.mpt2units((float)position.getWidth()));
int width = Math.round(unitConv.mpt2units(targetRect.width));
objectAreaInfo.setWidth(width);

int height = Math.round(unitConv.mpt2units((float)position.getHeight()));
int height = Math.round(unitConv.mpt2units(targetRect.height));
objectAreaInfo.setHeight(height);

int resolution = paintingState.getResolution();
@@ -89,10 +121,7 @@ public abstract class AFPImageHandler implements ImageHandler {
objectAreaInfo.setWidthRes(resolution);

objectAreaInfo.setRotation(paintingState.getRotation());

dataObjectInfo.setObjectAreaInfo(objectAreaInfo);

return dataObjectInfo;
return objectAreaInfo;
}

/**

+ 67
- 7
src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java View File

@@ -19,8 +19,10 @@

package org.apache.fop.render.afp;

import java.awt.Rectangle;
import java.io.IOException;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
@@ -31,12 +33,16 @@ import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.afp.AFPGraphicsObjectInfo;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerUtil;
import org.apache.fop.render.RenderingContext;

/**
* PDFImageHandler implementation which handles Graphics2D images.
*/
public class AFPImageHandlerGraphics2D extends AFPImageHandler {
public class AFPImageHandlerGraphics2D extends AFPImageHandler implements ImageHandler {

private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.GRAPHICS2D
@@ -65,18 +71,13 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler {
AFPGraphicsObjectInfo graphicsObjectInfo
= (AFPGraphicsObjectInfo)super.generateDataObjectInfo(rendererImageInfo);

AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo();
if (!resourceInfo.levelChanged()) {
resourceInfo.setLevel(afpInfo.getResourceManager().getResourceLevelDefaults()
.getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC));
}
setDefaultResourceLevel(graphicsObjectInfo, afpInfo.getResourceManager());

// set mime type (unsupported by MOD:CA registry)
graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA);

// set g2d
boolean textAsShapes = false;

AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes);

graphicsObjectInfo.setGraphics2D(g2d);
@@ -88,6 +89,15 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler {
}
}

private void setDefaultResourceLevel(AFPGraphicsObjectInfo graphicsObjectInfo,
AFPResourceManager resourceManager) {
AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo();
if (!resourceInfo.levelChanged()) {
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults()
.getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC));
}
}

/** {@inheritDoc} */
public int getPriority() {
return 200;
@@ -107,4 +117,54 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler {
protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPGraphicsObjectInfo();
}

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;

AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)createDataObjectInfo();

// set resource information
setResourceInformation(graphicsObjectInfo,
image.getInfo().getOriginalURI(),
afpContext.getForeignAttributes());

// Positioning
graphicsObjectInfo.setObjectAreaInfo(
createObjectAreaInfo(afpContext.getPaintingState(), pos));

setDefaultResourceLevel(graphicsObjectInfo, afpContext.getResourceManager());

// Image content
ImageGraphics2D imageG2D = (ImageGraphics2D)image;
boolean textAsShapes = false; //TODO Make configurable
AFPGraphics2D g2d = new AFPGraphics2D(
textAsShapes,
afpContext.getPaintingState(),
afpContext.getResourceManager(),
graphicsObjectInfo.getResourceInfo(),
afpContext.getFontInfo());
g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

graphicsObjectInfo.setGraphics2D(g2d);
graphicsObjectInfo.setPainter(imageG2D.getGraphics2DImagePainter());

// Create image
afpContext.getResourceManager().createObject(graphicsObjectInfo);
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
boolean supported = (image == null || image instanceof ImageGraphics2D)
&& targetContext instanceof AFPRenderingContext;
if (supported) {
String mode = (String)targetContext.getHint(ImageHandlerUtil.CONVERSION_MODE);
if (ImageHandlerUtil.isConversionModeBitmap(mode)) {
//Disabling this image handler automatically causes a bitmap to be generated
return false;
}
}
return supported;
}
}

+ 24
- 10
src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java View File

@@ -19,12 +19,15 @@

package org.apache.fop.render.afp;

import java.io.IOException;
import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
import org.apache.xmlgraphics.util.MimeConstants;

import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.fop.afp.AFPImageObjectInfo;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
import org.apache.fop.render.RenderingContext;

/**
* AFPImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4).
@@ -36,17 +39,18 @@ public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream
};

/** {@inheritDoc} */
public AFPDataObjectInfo generateDataObjectInfo(
AFPRendererImageInfo rendererImageInfo) throws IOException {
AFPImageObjectInfo imageObjectInfo
= (AFPImageObjectInfo)super.generateDataObjectInfo(rendererImageInfo);

ImageRawCCITTFax ccitt = (ImageRawCCITTFax) rendererImageInfo.getImage();
protected void setAdditionalParameters(AFPDataObjectInfo dataObjectInfo,
ImageRawStream image) {
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo;
ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;
int compression = ccitt.getCompression();
imageObjectInfo.setCompression(compression);

imageObjectInfo.setBitsPerPixel(1);
return imageObjectInfo;

//CCITTFax flavor doesn't have TIFF associated but the AFP library listens to
//that to identify CCITT encoded images. CCITT is not exclusive to TIFF.
imageObjectInfo.setMimeType(MimeConstants.MIME_TIFF);
}

/** {@inheritDoc} */
@@ -69,4 +73,14 @@ public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream
return FLAVORS;
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof AFPRenderingContext) {
AFPRenderingContext afpContext = (AFPRenderingContext)targetContext;
return (afpContext.getPaintingState().isNativeImagesSupported())
&& (image == null || image instanceof ImageRawCCITTFax);
}
return false;
}

}

+ 16
- 1
src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java View File

@@ -19,10 +19,15 @@

package org.apache.fop.render.afp;

import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS;
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;

import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.fop.render.RenderingContext;

/**
* AFPImageHandler implementation which handles raw stream images.
*/
@@ -52,4 +57,14 @@ public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream {
protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPDataObjectInfo();
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof AFPRenderingContext) {
AFPRenderingContext afpContext = (AFPRenderingContext)targetContext;
return (afpContext.getPaintingState().isNativeImagesSupported())
&& (image == null || image instanceof ImageRawJPEG || image instanceof ImageRawEPS);
}
return false;
}
}

+ 64
- 11
src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java View File

@@ -20,6 +20,7 @@
package org.apache.fop.render.afp;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.io.IOException;
@@ -28,6 +29,7 @@ import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageSize;
@@ -41,13 +43,16 @@ import org.apache.fop.afp.AFPImageObjectInfo;
import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.util.bitmap.BitmapImageUtil;

/**
* PDFImageHandler implementation which handles RenderedImage instances.
*/
public class AFPImageHandlerRenderedImage extends AFPImageHandler {
public class AFPImageHandlerRenderedImage extends AFPImageHandler implements ImageHandler {

/** logging instance */
private static Log log = LogFactory.getLog(AFPImageHandlerRenderedImage.class);
@@ -67,34 +72,40 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler {
= (AFPRendererContext)rendererImageInfo.getRendererContext();
AFPInfo afpInfo = rendererContext.getInfo();

AFPResourceInfo resourceInfo = imageObjectInfo.getResourceInfo();
if (!resourceInfo.levelChanged()) {
resourceInfo.setLevel(afpInfo.getResourceManager().getResourceLevelDefaults()
.getDefaultResourceLevel(ResourceObject.TYPE_IMAGE));
}
setDefaultResourceLevel(imageObjectInfo, afpInfo.getResourceManager());

AFPPaintingState paintingState = afpInfo.getPaintingState();
ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img;
Dimension targetSize = new Dimension(afpInfo.getWidth(), afpInfo.getHeight());

updateDataObjectInfo(imageObjectInfo, paintingState, imageRendered, targetSize);
return imageObjectInfo;
}

private AFPDataObjectInfo updateDataObjectInfo(AFPImageObjectInfo imageObjectInfo,
AFPPaintingState paintingState, ImageRendered imageRendered, Dimension targetSize)
throws IOException {

int resolution = paintingState.getResolution();
int maxPixelSize = paintingState.getBitsPerPixel();
if (paintingState.isColorImages()) {
maxPixelSize *= 3; //RGB only at the moment
}
ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img;
RenderedImage renderedImage = imageRendered.getRenderedImage();

ImageInfo imageInfo = rendererImageInfo.getImageInfo();
ImageInfo imageInfo = imageRendered.getInfo();
ImageSize intrinsicSize = imageInfo.getSize();

boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage);
boolean usePageSegments = useFS10
&& !resourceInfo.getLevel().isInline();
&& !imageObjectInfo.getResourceInfo().getLevel().isInline();

ImageSize effIntrinsicSize = intrinsicSize;
if (usePageSegments) {
//Resize, optionally resample and convert image
Dimension resampledDim = new Dimension(
(int)Math.ceil(UnitConv.mpt2px(afpInfo.getWidth(), resolution)),
(int)Math.ceil(UnitConv.mpt2px(afpInfo.getHeight(), resolution)));
(int)Math.ceil(UnitConv.mpt2px(targetSize.getWidth(), resolution)),
(int)Math.ceil(UnitConv.mpt2px(targetSize.getHeight(), resolution)));

imageObjectInfo.setCreatePageSegment(true);
imageObjectInfo.getResourceInfo().setImageDimension(resampledDim);
@@ -130,6 +141,8 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler {
int dataWidth = renderedImage.getWidth();
imageObjectInfo.setDataWidth(dataWidth);

//TODO To reduce AFP file size, investigate using a compression scheme.
//Currently, all image data is uncompressed.
ColorModel cm = renderedImage.getColorModel();
if (log.isTraceEnabled()) {
log.trace("ColorModel: " + cm);
@@ -209,6 +222,15 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler {
return imageObjectInfo;
}

private void setDefaultResourceLevel(AFPImageObjectInfo imageObjectInfo,
AFPResourceManager resourceManager) {
AFPResourceInfo resourceInfo = imageObjectInfo.getResourceInfo();
if (!resourceInfo.levelChanged()) {
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults()
.getDefaultResourceLevel(ResourceObject.TYPE_IMAGE));
}
}

/** {@inheritDoc} */
protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPImageObjectInfo();
@@ -229,4 +251,35 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler {
return FLAVORS;
}

/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos)
throws IOException {
AFPRenderingContext afpContext = (AFPRenderingContext)context;

AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo();

// set resource information
setResourceInformation(imageObjectInfo,
image.getInfo().getOriginalURI(),
afpContext.getForeignAttributes());
setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager());

// Positioning
imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(afpContext.getPaintingState(), pos));
Dimension targetSize = pos.getSize();

// Image content
ImageRendered imageRend = (ImageRendered)image;
updateDataObjectInfo(imageObjectInfo, afpContext.getPaintingState(), imageRend, targetSize);

// Create image
afpContext.getResourceManager().createObject(imageObjectInfo);
}

/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) {
return (image == null || image instanceof ImageRendered)
&& targetContext instanceof AFPRenderingContext;
}

}

+ 0
- 0
src/java/org/apache/fop/render/afp/AFPImageHandlerSVG.java View File


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

Loading…
Cancel
Save