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

<include name="org/apache/fop/area/AreaTreeControl*"/> <include name="org/apache/fop/area/AreaTreeControl*"/>
<include name="org/apache/fop/svg/**"/> <include name="org/apache/fop/svg/**"/>
<include name="org/apache/fop/fonts/**"/> <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/CMYKColorSpace*.class"/>
<include name="org/apache/fop/util/Color*.class"/> <include name="org/apache/fop/util/Color*.class"/>
<include name="org/apache/fop/util/ASCII*.class"/> <include name="org/apache/fop/util/ASCII*.class"/>
<include name="org/apache/fop/util/SubInputStream.class"/> <include name="org/apache/fop/util/SubInputStream.class"/>
<include name="org/apache/fop/util/Finalizable.class"/> <include name="org/apache/fop/util/Finalizable.class"/>
<include name="org/apache/fop/util/CharUtilities.class"/> <include name="org/apache/fop/util/CharUtilities.class"/>
<include name="org/apache/fop/util/DecimalFormatCache*.class"/>
</patternset> </patternset>
<!-- PDF transcoder --> <!-- PDF transcoder -->
<patternset> <patternset>
<include name="org/apache/fop/render/pdf/**"/> <include name="org/apache/fop/render/pdf/**"/>
<exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/> <exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/>
<exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/> <exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/>
<include name="org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.class"/>
<include name="org/apache/fop/render/*RendererConfigurator**"/> <include name="org/apache/fop/render/*RendererConfigurator**"/>
<include name="org/apache/fop/util/AbstractPaintingState**"/> <include name="org/apache/fop/util/AbstractPaintingState**"/>
<include name="org/apache/fop/pdf/**"/> <include name="org/apache/fop/pdf/**"/>
<test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${junit.reports.dir}" outfile="TEST-FO-tree"/> <test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${junit.reports.dir}" outfile="TEST-FO-tree"/>
</junit> </junit>
</target> </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>
<target name="junit-text-linebreak" depends="junit-compile" description="Runs FOP's JUnit unicode linebreak tests" if="junit.present"> <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"/> <echo message="Running tests for Unicode UAX#14 support"/>
</junit> </junit>
</target> </target>
<target name="junit-reduced" depends="junit-userconfig, junit-basic, junit-transcoder, junit-text-linebreak, junit-fotree"/> <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"> <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> <fail><condition><or><isset property="fop.junit.error"/><isset property="fop.junit.failure"/><not><isset property="hyphenation.present"/></not></or></condition>
NOTE: NOTE:

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

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

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

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


import org.xml.sax.SAXException;

import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop; import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants; 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.ExampleObj2XML;
import embedding.model.ProjectMember; import embedding.model.ProjectMember;


/** /**
* Example for the intermediate format that demonstrates the concatenation of two documents * 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. * files.
*/ */
public class ExampleConcat { public class ExampleConcat {
* Converts an XSL-FO document to an intermediate file. * Converts an XSL-FO document to an intermediate file.
* @param src the source file * @param src the source file
* @param xslt the stylesheet 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 IOException In case of an I/O problem
* @throws FOPException In case of a FOP problem * @throws FOPException In case of a FOP problem
* @throws TransformerException In case of a XSL transformation problem * @throws TransformerException In case of a XSL transformation problem
//Create a user agent //Create a user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent(); 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 // Setup output
OutputStream out = new java.io.FileOutputStream(intermediate); OutputStream out = new java.io.FileOutputStream(intermediate);
out = new java.io.BufferedOutputStream(out); out = new java.io.BufferedOutputStream(out);
try { 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) // on the user agent)
Fop fop = fopFactory.newFop(null, userAgent, out); Fop fop = fopFactory.newFop(null, userAgent, out);




/** /**
* Concatenates an array of intermediate files to a single PDF file. * 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 * @param pdffile the target PDF file
* @throws IOException In case of an I/O problem * @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem * @throws TransformerException In case of a XSL transformation problem
* @throws SAXException In case of an XML-related 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) public void concatToPDF(File[] files, File pdffile)
throws IOException, TransformerException, SAXException {
throws IOException, TransformerException, SAXException, IFException {
// Setup output // Setup output
OutputStream out = new java.io.FileOutputStream(pdffile); OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out); out = new java.io.BufferedOutputStream(out);
try { try {
//Setup fonts and user agent
FontInfo fontInfo = new FontInfo();
//Setup user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent(); 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 //Iterate over all intermediate files
AreaTreeParser parser = new AreaTreeParser();
for (int i = 0; i < files.length; i++) { for (int i = 0; i < files.length; i++) {
Source src = new StreamSource(files[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 { } finally {
out.close(); out.close();
} }
*/ */
public static void main(String[] args) { public static void main(String[] args) {
try { try {
System.out.println("FOP ExampleConcat\n");
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n");


//Setup directories //Setup directories
File baseDir = new File("."); File baseDir = new File(".");
//Setup output file //Setup output file
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File[] files = new File[] { 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++) { for (int i = 0; i < files.length; i++) {
System.out.println("Intermediate file " + (i + 1) + ": " System.out.println("Intermediate file " + (i + 1) + ": "
+ files[i].getCanonicalPath()); + files[i].getCanonicalPath());

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

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


import org.xml.sax.SAXException;

import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants; 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.ExampleObj2XML;
import embedding.model.ProjectTeam; import embedding.model.ProjectTeam;


/** /**
* Stamps an intermediate file and renders it to a PDF file. * 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 stampSheet the stylesheet that does the stamping
* @param pdffile the target PDF file * @param pdffile the target PDF file
* @throws IOException In case of an I/O problem * @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem * @throws TransformerException In case of a XSL transformation problem
* @throws SAXException In case of an XML-related 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 // Setup output
OutputStream out = new java.io.FileOutputStream(pdffile); OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out); out = new java.io.BufferedOutputStream(out);
try { try {
//Setup fonts and user agent
FontInfo fontInfo = new FontInfo();
//user agent
FOUserAgent userAgent = fopFactory.newFOUserAgent(); 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); Source xslt = new StreamSource(stampSheet);


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


//Send XSLT result to AreaTreeParser //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 //Start XSLT transformation and area tree parsing
transformer.transform(src, res); transformer.transform(src, res);

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


//Setup directories //Setup directories
File baseDir = new File("."); File baseDir = new File(".");


//Setup output file //Setup output file
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); 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("Stamp XSLT: " + stampxsltfile.getCanonicalPath());
System.out.println("PDF Output File: " + pdffile.getCanonicalPath()); System.out.println("PDF Output File: " + pdffile.getCanonicalPath());
System.out.println(); System.out.println();
ExampleConcat concatapp = new ExampleConcat(); ExampleConcat concatapp = new ExampleConcat();
concatapp.convertToIntermediate( concatapp.convertToIntermediate(
team1.getSourceForProjectTeam(), team1.getSourceForProjectTeam(),
new StreamSource(xsltfile), atfile);
new StreamSource(xsltfile), iffile);


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


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



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

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

import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;


import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source; import javax.xml.transform.Source;
import javax.xml.transform.Transformer; import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.xmlgraphics.image.loader.util.ImageUtil;


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


/** /**


InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
try { 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(); Element rootEl = planDoc.getDocumentElement();
if (!PlanElementMapping.NAMESPACE.equals(rootEl.getNamespaceURI())) {
if (!PlanElementMapping.NAMESPACE.equals(
rootEl.getNamespaceURI())) {
in.reset(); in.reset();
return null; return null;
} }


//Have to render the plan to know its size
PlanRenderer pr = new PlanRenderer();
Document svgDoc = pr.createSVGDocument(planDoc); Document svgDoc = pr.createSVGDocument(planDoc);
float width = pr.getWidth(); float width = pr.getWidth();
float height = pr.getHeight(); float height = pr.getHeight();
} }
} }


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

import org.w3c.dom.Element; import org.w3c.dom.Element;


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

import org.apache.fop.svg.SVGUtilities; import org.apache.fop.svg.SVGUtilities;


/** /**


String title = ""; String title = "";


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


Element svgRoot = doc.getDocumentElement(); 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", svgRoot.setAttributeNS(null, "style",
"font-size:" + 8 "font-size:" + 8
+ ";font-family:" + ";font-family:"
java.awt.Font.PLAIN, (int)fontSize); java.awt.Font.PLAIN, (int)fontSize);


if (bord) { 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"); border.setAttributeNS(null, "style", "stroke:black;fill:none");
svgRoot.appendChild(border); svgRoot.appendChild(border);
} }

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


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

</header> </header>
<body> <body>
<note> <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> </note>
<section id="introduction"> <section id="introduction">
<title>Introduction</title> <title>Introduction</title>
<p> <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>. <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>
<p> <p>
The intermediate format can be used to generate intermediate documents that are modified The intermediate format can be used to generate intermediate documents that are modified
to a single output file. to a single output file.
</p> </p>
</section> </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"> <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> <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>
<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>
<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> </p>
<source><![CDATA[ <source><![CDATA[
FopFactory fopFactory = FopFactory.newInstance(); FopFactory fopFactory = FopFactory.newInstance();
AreaTreeModel treeModel = new RenderPagesModel(userAgent, AreaTreeModel treeModel = new RenderPagesModel(userAgent,
MimeConstants.MIME_PDF, fontInfo, out); 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(); AreaTreeParser parser = new AreaTreeParser();
Source src = new StreamSource(myIFFile); Source src = new StreamSource(myIFFile);
parser.parse(src, treeModel, userAgent); parser.parse(src, treeModel, userAgent);
out.close(); out.close();
}]]></source> }]]></source>
<p> <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 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 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 applies to the AreaTreeModel instance, in this case an instance of a subclass called
is now finished. is now finished.
</p> </p>
<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 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. specify a "mimic renderer" by inserting a MIME type between "-at" and the output file.
</p> </p>
<title>Concatenating Documents</title> <title>Concatenating Documents</title>
<p> <p>
This initial example is obviously not very useful. It would be faster to create the PDF file 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 same AreaTreeModel instance which essentially concatenates all the input document to one single
output document. output document.
</p> </p>
<section id="modifying"> <section id="modifying">
<title>Modifying Documents</title> <title>Modifying Documents</title>
<p> <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 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 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. later time. You're invited to help us with that.
</p> </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>
<section id="advanced"> <section id="advanced">
<title>Advanced Use</title> <title>Advanced Use</title>
<p> <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 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 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 do custom serialization (to a W3C DOM, for example) and/or to directly modify the area tree using
</p> </p>
</section> </section>
</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> </body>
</document> </document>

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

<document xmlns="http://xmlgraphics.apache.org/fop/intermediate" <document xmlns="http://xmlgraphics.apache.org/fop/intermediate"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlgraphics.apache.org/fop/intermediate fop-intermediate-format-ng.xsd" 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> <header>
<x:xmpmeta xmlns:x="adobe:ns:meta/"> <x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
</header> </header>
<page-sequence id="ps1"> <page-sequence id="ps1">
<page index="1" name="1">
<page index="0" name="1" width="595275" height="841889">
<page-header> <page-header>
<ps:ps-setup-code xmlns:ps="apache:fop:extensions:postscript">%FOPTestPSSetupCode: General <ps:ps-setup-code xmlns:ps="apache:fop:extensions:postscript">%FOPTestPSSetupCode: General
setup code here!</ps:ps-setup-code> setup code here!</ps:ps-setup-code>
<content> <content>
<!-- Note: this is not actual content that is supposed to make any sense. <!-- 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. --> 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" <font family="Helvetica" style="normal" weight="400" variant="normal" size="12000"
color="black"/> 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"/> <image xlink:href="myimage.svg" x="0" y="0" width="20000" height="20000"/>
</box>
</box>
</viewport>
</viewport>
</content> </content>
<page-trailer> <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-trailer>
</page> </page>
</page-sequence> </page-sequence>
<trailer/>
</document> </document>

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

targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" targetNamespace="http://xmlgraphics.apache.org/fop/intermediate"
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate"> xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate">
<xs:include schemaLocation="fop-intermediate-format-ng-datatypes.xsd"/> <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:complexType name="contentType">
<xs:choice maxOccurs="unbounded" minOccurs="0"> <xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="box">
<xs:element name="viewport">
<xs:complexType> <xs:complexType>
<xs:complexContent> <xs:complexContent>
<xs:extension base="mf:contentType"> <xs:extension base="mf:contentType">
<xs:attribute name="transform" type="xs:string"/> <xs:attribute name="transform" type="xs:string"/>
<xs:attributeGroup ref="mf:sizeAtts"/> <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:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
<xs:attribute name="variant" type="mf:fontVariantType"/> <xs:attribute name="variant" type="mf:fontVariantType"/>
<xs:attribute name="weight" type="mf:fontWeightType"/> <xs:attribute name="weight" type="mf:fontWeightType"/>
<xs:attribute name="stretch" type="mf:fontStretchType"/> <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:attribute name="color" type="mf:colorType"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:complexType> <xs:complexType>
<xs:simpleContent> <xs:simpleContent>
<xs:extension base="xs:string"> <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:simpleType>
<xs:list itemType="xs:integer"/>
<xs:list itemType="mf:lengthType"/>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute ref="xml:space"/>
</xs:extension> </xs:extension>
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>
</xs:element> </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:complexType>
<xs:attribute name="d" type="mf:pathDataType" use="required"/>
<xs:attributeGroup ref="mf:fillStrokeAtts"/>
<xs:attributeGroup ref="mf:rectAtts"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="clip-rect">
<xs:element name="rect">
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="mf:rectAtts"/> <xs:attributeGroup ref="mf:rectAtts"/>
<xs:attributeGroup ref="mf:fillAtts"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="draw-rect">
<xs:element name="line">
<xs:complexType> <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:complexType>
</xs:element> </xs:element>
<xs:element name="draw-border-line">
<xs:element name="border-rect">
<xs:complexType> <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:complexType>
</xs:element> </xs:element>
<xs:element name="image"> <xs:element name="image">
<xs:extension base="xs:anyType"> <xs:extension base="xs:anyType">
<!-- Either use element content with any namespace or xlink:href --> <!-- Either use element content with any namespace or xlink:href -->
<xs:attributeGroup ref="mf:rectAtts"/> <xs:attributeGroup ref="mf:rectAtts"/>
<xs:anyAttribute namespace="http://www.w3.org/1999/xlink" processContents="skip"/>
<xs:attributeGroup ref="mf:foreignAtts"/>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
</xs:choice> </xs:choice>
</xs:complexType> </xs:complexType>
<xs:attributeGroup name="sizeAtts"> <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>
<xs:attributeGroup name="rectAtts"> <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 ref="mf:sizeAtts"/>
</xs:attributeGroup> </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="fill" type="xs:string" default="none"/>
<xs:attribute name="stroke" 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:attributeGroup>
</xs:schema> </xs:schema>

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

<xs:simpleType name="colorType"> <xs:simpleType name="colorType">
<xs:restriction base="xs:string"/> <xs:restriction base="xs:string"/>
</xs:simpleType> </xs:simpleType>
<xs:simpleType name="pathDataType">
<xs:restriction base="xs:string"/>
<xs:simpleType name="lengthType">
<xs:restriction base="xs:int"/>
</xs:simpleType> </xs:simpleType>
<xs:simpleType name="fontStyleType"> <xs:simpleType name="fontStyleType">
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="outset"/> <xs:enumeration value="outset"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </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> </xs:schema>

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

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

<!-- $Id$ --> <!-- $Id$ -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" 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="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-datatypes.xsd"/>
<xs:include schemaLocation="fop-intermediate-format-ng-content.xsd"/> <xs:include schemaLocation="fop-intermediate-format-ng-content.xsd"/>
<xs:element name="document"> <xs:element name="document">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element ref="mf:header"/> <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:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="header"> <xs:element name="header">
<xs:complexType> <xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded"> <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:choice>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="bookmark-tree">
<xs:element name="trailer">
<xs:complexType> <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:complexType>
</xs:element> </xs:element>
<xs:element name="page-sequence"> <xs:element name="page-sequence">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element ref="mf:page"/>
<xs:element ref="mf:page" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="id" type="xs:ID"/> <xs:attribute name="id" type="xs:ID"/>
<xs:attributeGroup ref="mf:foreignAtts"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="page"> <xs:element name="page">
<xs:complexType> <xs:complexType>
<xs:sequence> <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="content" type="mf:contentType"/>
<xs:element name="page-trailer" minOccurs="0"> <xs:element name="page-trailer" minOccurs="0">
<xs:complexType> <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:complexType>
</xs:element> </xs:element>
</xs:sequence> </xs:sequence>
<xs:attribute name="index" type="xs:nonNegativeInteger" use="required"/> <xs:attribute name="index" type="xs:nonNegativeInteger" use="required"/>
<xs:attribute name="name" type="xs:string"/> <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:complexType>
</xs:element> </xs:element>
<xs:complexType name="anyContent">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any namespace="##other" processContents="lax"/>
</xs:choice>
</xs:complexType>
</xs:schema> </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

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

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

org.apache.fop.render.awt.AWTRendererMaker org.apache.fop.render.awt.AWTRendererMaker
org.apache.fop.render.print.PrintRendererMaker org.apache.fop.render.print.PrintRendererMaker
org.apache.fop.render.afp.AFPRendererMaker 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

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

org.apache.fop.image.loader.batik.ImageConverterSVG2G2D org.apache.fop.image.loader.batik.ImageConverterSVG2G2D
org.apache.fop.image.loader.batik.ImageConverterG2D2SVG
org.apache.fop.image.loader.batik.ImageConverterWMF2G2D org.apache.fop.image.loader.batik.ImageConverterWMF2G2D

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

import org.apache.xmlgraphics.java2d.TextHandler; import org.apache.xmlgraphics.java2d.TextHandler;
import org.apache.xmlgraphics.ps.ImageEncodingHelper; import org.apache.xmlgraphics.ps.ImageEncodingHelper;
import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.MimeConstants;
import org.apache.xmlgraphics.util.UnitConv;


import org.apache.fop.afp.goca.GraphicsSetLineType; import org.apache.fop.afp.goca.GraphicsSetLineType;
import org.apache.fop.afp.modca.GraphicsObject; import org.apache.fop.afp.modca.GraphicsObject;
this.gc = gc; 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. * Apply the stroke to the AFP graphics object.
* This takes the java stroke and outputs the appropriate settings * This takes the java stroke and outputs the appropriate settings


// set line width // set line width
float lineWidth = basicStroke.getLineWidth(); 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!) // set line type/style (note: this is an approximation at best!)
float[] dashArray = basicStroke.getDashArray(); float[] dashArray = basicStroke.getDashArray();
/** {@inheritDoc} */ /** {@inheritDoc} */
public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image,
float x, float y, float width, float height) { 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); + ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height);
} }



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



package org.apache.fop.afp; package org.apache.fop.afp;


import java.awt.Point;

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

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


private int resolution = 240; // 240 dpi private int resolution = 240; // 240 dpi


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


// /** reference orientation */ // /** reference orientation */
// private int orientation = 0; // private int orientation = 0;
return this.unitConv; 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} */ /** {@inheritDoc} */
public Object clone() { public Object clone() {
AFPPaintingState paintingState = (AFPPaintingState)super.clone(); AFPPaintingState paintingState = (AFPPaintingState)super.clone();

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



import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map; 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.AbstractNamedAFPObject;
import org.apache.fop.afp.modca.AbstractPageObject; import org.apache.fop.afp.modca.AbstractPageObject;
import org.apache.fop.afp.modca.IncludeObject; 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.PageSegment;
import org.apache.fop.afp.modca.Registry; import org.apache.fop.afp.modca.Registry;
import org.apache.fop.afp.modca.ResourceGroup; 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 * Manages the creation and storage of document resources
*/ */
public class AFPResourceManager { public class AFPResourceManager {

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

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


/** Maintain a reference count of instream objects for referencing purposes */ /** Maintain a reference count of instream objects for referencing purposes */
private int instreamObjectCount = 0; 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>*/; = new java.util.HashMap()/*<AFPResourceInfo,String>*/;


private Map pageSegmentMap = new java.util.HashMap(); private Map pageSegmentMap = new java.util.HashMap();
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo();
updateResourceInfoUri(resourceInfo); updateResourceInfoUri(resourceInfo);


String objectName = (String)includableObjectsMap.get(resourceInfo);
String objectName = (String)includeNameMap.get(resourceInfo);
if (objectName != null) { if (objectName != null) {
// an existing data resource so reference it by adding an include to the current page // an existing data resource so reference it by adding an include to the current page
includeObject(dataObjectInfo, objectName); includeObject(dataObjectInfo, objectName);
useInclude &= resourceGroup != null; useInclude &= resourceGroup != null;
if (useInclude) { 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 { } else {
// not to be included so inline data object directly into the current page // not to be included so inline data object directly into the current page


private void includeObject(AFPDataObjectInfo dataObjectInfo, private void includeObject(AFPDataObjectInfo dataObjectInfo,
String objectName) { 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, private void includePageSegment(AFPDataObjectInfo dataObjectInfo,
String pageSegmentName) { String pageSegmentName) {
currentPage.createIncludePageSegment(pageSegmentName, x, y, createHardPageSegments); 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 * Sets resource level defaults. The existing defaults over merged with the ones passed in
* as parameter. * as parameter.
public AFPResourceLevelDefaults getResourceLevelDefaults() { public AFPResourceLevelDefaults getResourceLevelDefaults() {
return this.resourceLevelDefaults; return this.resourceLevelDefaults;
} }
}

}

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

* @return a point on the current page * @return a point on the current page
*/ */
private Point getPoint(int x, int y) { 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

*/ */
public abstract CharacterSet getCharacterSet(int size); 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} */ /** {@inheritDoc} */

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



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


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

import org.apache.fop.afp.AFPConstants; import org.apache.fop.afp.AFPConstants;
import org.apache.fop.afp.util.StringUtils; import org.apache.fop.afp.util.StringUtils;


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


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

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


} }
this.codePage = codePage; this.codePage = codePage;
this.encoding = encoding; this.encoding = encoding;
this.encoder = Charset.forName(encoding).newEncoder();
this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
this.path = path; this.path = path;


this.characterSetOrientations = new java.util.HashMap(4); this.characterSetOrientations = new java.util.HashMap(4);
return c; 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. * Map a Unicode character to a code point in the font.
* The code tables are already converted to Unicode therefore * The code tables are already converted to Unicode therefore
* @return the mapped character * @return the mapped character
*/ */
public char mapChar(char c) { public char mapChar(char c) {
//TODO This is not strictly correct but we'll let it be for the moment
return c; return c;
} }



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

*/ */
public class CharacterSetOrientation { 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 * The ascender height for the character set
*/ */
private int capHeight; 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 * The height of lowercase letters
* @return the widths of all characters * @return the widths of all characters
*/ */
public int[] getWidths() { 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; return arr;
} }


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


/** /**
* @param width the widths of the character * @param width the widths of the character
*/ */
public void setWidth(int character, int width) { public void setWidth(int character, int width) {

if (character >= chars.length) {
if (character >= charsWidths.length) {
// Increase the size of the array if necessary // 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

return getWidths(1000); return getWidths(1000);
} }


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

/** /**
* Map a Unicode character to a code point in the font. * Map a Unicode character to a code point in the font.
* @param c character to map * @param c character to map
public String getEncodingName() { public String getEncodingName() {
return charSet.getEncoding(); return charSet.getEncoding();
} }

} }

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

return getWidths(1000); return getWidths(1000);
} }


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

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

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

* page has a set of data objects associated with it. Each page within a * 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 * document is independent from any other page, and each must establish its own
* environment parameters. * environment parameters.
*
* <p>
* The page is the level in the document component hierarchy that is used for * 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 * 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 * the page envelope in the data stream are presented when the page is
* directs the placement and orientation of the data on the page. In addition, * directs the placement and orientation of the data on the page. In addition,
* each page contains layout information that specifies the measurement units, * each page contains layout information that specifies the measurement units,
* page width, and page depth. * page width, and page depth.
*
* <p>
* A page is initiated by a begin page structured field and terminated by an end * 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 * page structured field. Structured fields that define objects and active
* environment groups or that specify attributes of the page may be encountered * environment groups or that specify attributes of the page may be encountered
* in page state. * in page state.
*
*/ */
public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable { public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable {


* *
* @return the presentation text object * @return the presentation text object
*/ */
private PresentationTextObject getPresentationTextObject() {
public PresentationTextObject getPresentationTextObject() {
if (currentPresentationTextObject == null) { if (currentPresentationTextObject == null) {
PresentationTextObject presentationTextObject PresentationTextObject presentationTextObject
= factory.createPresentationTextObject(); = factory.createPresentationTextObject();

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

} }


/** /**
* 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 * @param fill true if the following shape is to be filled
*/ */
public void setFill(boolean fill) { 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) { public void setPatternSymbol(byte patternSymbol) {
if (patternSymbol != graphicsState.patternSymbol) { if (patternSymbol != graphicsState.patternSymbol) {
*/ */
public void newSegment() { public void newSegment() {
getData().newSegment(); getData().newSegment();
graphicsState.lineWidth = 0; //Looks like a new segment invalidates the graphics state
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
} }


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



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

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



package org.apache.fop.afp.modca; package org.apache.fop.afp.modca;


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


import org.apache.commons.io.output.ByteArrayOutputStream; 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; import org.apache.fop.afp.util.BinaryUtils;


/** /**
* that position them - modal control sequences that adjust the positions by * that position them - modal control sequences that adjust the positions by
* small amounts - other functions causing text to be presented with differences * small amounts - other functions causing text to be presented with differences
* in appearance. * in appearance.
*
* <p>
* The graphic characters are expected to conform to a coded font representation * 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 * 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 * character in the coded font. The units of measure for linear displacements
* are derived from the PresentationTextDescriptor or from the hierarchical * are derived from the PresentationTextDescriptor or from the hierarchical
* defaults. * defaults.
*
* <p>
* In addition to graphic character code points, Presentation Text data can * In addition to graphic character code points, Presentation Text data can
* contain embedded control sequences. These are strings of two or more bytes * 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 * which signal an alternate mode of processing for the content of the current
* Presentation Text data. * 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.*/ /** the maximum size of the presentation text data.*/
private static final int MAX_SIZE = 8192; private static final int MAX_SIZE = 8192;
/** the AFP data relating to this presentation text data. */ /** the AFP data relating to this presentation text data. */
private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 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. * Default constructor for the PresentationTextData.
*/ */
this(false); this(false);
} }


private static final int HEADER_LENGTH = 9;

/** /**
* Constructor for the PresentationTextData, the boolean flag indicate * Constructor for the PresentationTextData, the boolean flag indicate
* whether the control sequence prefix should be set to indicate the start * whether the control sequence prefix should be set to indicate the start
0x00, // Reserved 0x00, // Reserved
0x00, // Reserved 0x00, // Reserved
}; };
baos.write(data, 0, 9);
baos.write(data, 0, HEADER_LENGTH);


if (controlInd) { if (controlInd) {
baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2);
} }


/** /**
* 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} */ /** {@inheritDoc} */
public void writeToStream(OutputStream os) throws IOException { public void writeToStream(OutputStream os) throws IOException {
assert getBytesAvailable() >= 0;
byte[] data = baos.toByteArray(); byte[] data = baos.toByteArray();
byte[] size = BinaryUtils.convert(data.length - 1, 2); byte[] size = BinaryUtils.convert(data.length - 1, 2);
data[1] = size[0]; data[1] = size[0];
os.write(data); 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



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


*/ */
private List/*<PresentationTextData>*/ presentationTextDataList = null; private List/*<PresentationTextData>*/ presentationTextDataList = null;


private PtocaBuilder builder = new DefaultBuilder();

/** /**
* Construct a new PresentationTextObject for the specified name argument, * Construct a new PresentationTextObject for the specified name argument,
* the name should be an 8 character identifier. * the name should be an 8 character identifier.
* @throws UnsupportedEncodingException thrown if character encoding is not supported * @throws UnsupportedEncodingException thrown if character encoding is not supported
*/ */
public void createTextData(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { 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) { if (currentPresentationTextData == null) {
startPresentationTextData(); startPresentationTextData();
} }
try { try {
currentPresentationTextData.createTextData(textDataInfo);
} catch (MaximumSizeExceededException msee) {
endPresentationTextData();
createTextData(textDataInfo);
producer.produce(builder);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
endPresentationTextData(); endPresentationTextData();
throw e; 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();
} }
} }


* @param lineDataInfo the line data information. * @param lineDataInfo the line data information.
*/ */
public void createLineData(AFPLineDataInfo lineDataInfo) { public void createLineData(AFPLineDataInfo lineDataInfo) {
if (currentPresentationTextData == null) {
startPresentationTextData();
}
try { try {
currentPresentationTextData.createLineData(lineDataInfo);
} catch (MaximumSizeExceededException msee) {
endPresentationTextData();
createLineData(lineDataInfo);
createControlSequences(new LineDataInfoProducer(lineDataInfo));
} catch (UnsupportedEncodingException e) {
handleUnexpectedIOError(e); //Won't happen for lines
} }
} }


startPresentationTextData(); startPresentationTextData();
} }
try { try {
currentPresentationTextData.endControlSequence();
} catch (MaximumSizeExceededException msee) {
builder.endChainedControlSequence();
} catch (IOException ioe) {
endPresentationTextData(); 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} */ /** {@inheritDoc} */
public String toString() { public String toString() {
if (presentationTextDataList != null) { if (presentationTextDataList != null) {
return presentationTextDataList.toString(); return presentationTextDataList.toString();
} }
return null;
return super.toString();
} }
} }

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

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

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

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

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

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

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



package org.apache.fop.afp.svg; package org.apache.fop.afp.svg;


import org.apache.fop.svg.AbstractFOPImageElementBridge;
import org.apache.xmlgraphics.image.loader.ImageFlavor; 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 * An AFP specific implementation of a Batik SVGImageElementBridge
*/ */
public class AFPImageElementBridge extends AbstractFOPImageElementBridge { public class AFPImageElementBridge extends AbstractFOPImageElementBridge {


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


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

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



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

import org.apache.fop.afp.AFPGraphics2D; import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.fonts.AFPFont; import org.apache.fop.afp.fonts.AFPFont;
* @return a font reference * @return a font reference
*/ */
private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) { private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) {
FontInfo fontInfo = getFontInfo();
AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName); AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName);
// register if necessary // register if necessary
AFPFontAttributes afpFontAttributes = pageFonts.registerFont( AFPFontAttributes afpFontAttributes = pageFonts.registerFont(
* {@inheritDoc} * {@inheritDoc}
*/ */
public void drawString(Graphics2D g, String str, float x, float y) throws IOException { 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); fontReference = registerPageFont(pageFonts, internalFontName, fontSize);
graphicsObj.setCharacterSet(fontReference);

// add the character string
graphicsObj.addString(str, Math.round(x), Math.round(y));
} else { } 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



package org.apache.fop.afp.svg; 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.AbstractFOPTextPainter;
import org.apache.fop.svg.FOPTextHandler; import org.apache.fop.svg.FOPTextHandler;


super(nativeTextHandler); 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

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

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

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

import org.apache.fop.render.Renderer; import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererFactory; import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry; import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.render.intermediate.IFDocumentHandler;


/** /**
* This is the user agent for FOP. * This is the user agent for FOP.
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
private Map rendererOptions = new java.util.HashMap(); private Map rendererOptions = new java.util.HashMap();
private File outputFile = null; private File outputFile = null;
private IFDocumentHandler documentHandlerOverride = null;
private Renderer rendererOverride = null; private Renderer rendererOverride = null;
private FOEventHandler foEventHandlerOverride = null; private FOEventHandler foEventHandlerOverride = null;
private boolean locatorEnabled = true; // true by default (for error messages). private boolean locatorEnabled = true; // true by default (for error messages).
protected String author = null; protected String author = null;
/** Title of the document. */ /** Title of the document. */
protected String title = null; protected String title = null;
/** Subject of the document. */
protected String subject = null;
/** Set of keywords applicable to this document. */ /** Set of keywords applicable to this document. */
protected String keywords = null; protected String keywords = null;




// ---------------------------------------------- rendering-run dependent stuff // ---------------------------------------------- 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 * Sets an explicit renderer to use which overrides the one defined by the
* render type setting. * render type setting.
return title; 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. * Sets the keywords for the document.
* @param keywords for the document * @param keywords for the document

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

import org.apache.fop.fonts.FontManager; import org.apache.fop.fonts.FontManager;
import org.apache.fop.hyphenation.HyphenationTreeResolver; import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.layoutmgr.LayoutManagerMaker; import org.apache.fop.layoutmgr.LayoutManagerMaker;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.RendererFactory; import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry; import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.util.ColorSpaceCache; import org.apache.fop.util.ColorSpaceCache;
/** Registry for XML handlers */ /** Registry for XML handlers */
private XMLHandlerRegistry xmlHandlers; private XMLHandlerRegistry xmlHandlers;


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

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


this.imageManager = new ImageManager(this); this.imageManager = new ImageManager(this);
this.rendererFactory = new RendererFactory(); this.rendererFactory = new RendererFactory();
this.xmlHandlers = new XMLHandlerRegistry(); this.xmlHandlers = new XMLHandlerRegistry();
this.imageHandlers = new ImageHandlerRegistry();
this.ignoredNamespaces = new java.util.HashSet(); this.ignoredNamespaces = new java.util.HashSet();
} }


return this.xmlHandlers; return this.xmlHandlers;
} }


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

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

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

String MIME_FOP_PRINT = "application/X-fop-print"; String MIME_FOP_PRINT = "application/X-fop-print";
/** Apache FOP's area tree XML */ /** Apache FOP's area tree XML */
String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; 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

import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler; 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.Log;
import org.apache.commons.logging.LogFactory; 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.apps.FOUserAgent;
import org.apache.fop.area.Trait.Background; import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink; import org.apache.fop.area.Trait.InternalLink;
import org.apache.fop.util.ContentHandlerFactoryRegistry; import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils; import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener; 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 * This is a parser for the area tree XML (intermediate format) which is used to reread an area
delegate.startDocument(); delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes); delegate.startElement(uri, localName, qName, attributes);
} else { } else {
lastAttributes = attributes;
lastAttributes = new AttributesImpl(attributes);
boolean handled = true; boolean handled = true;
if ("".equals(uri)) { if ("".equals(uri)) {
Maker maker = (Maker)makers.get(localName); Maker maker = (Maker)makers.get(localName);
if (currentPageViewport != null) { if (currentPageViewport != null) {
throw new IllegalStateException("currentPageViewport must be 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 key = attributes.getValue("key");
String pageNumberString = attributes.getValue("formatted-nr"); String pageNumberString = attributes.getValue("formatted-nr");
String pageMaster = attributes.getValue("simple-page-master-name"); 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, currentPageViewport = new PageViewport(viewArea,
pageNumber, pageNumberString, pageNumber, pageNumberString,
pageMaster, blank); pageMaster, blank);
if (rv != null) { if (rv != null) {
throw new IllegalStateException("Current RegionViewport must be null"); throw new IllegalStateException("Current RegionViewport must be null");
} }
Rectangle2D viewArea = getAttributeAsRectangle2D(attributes, "rect");
Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "rect");
rv = new RegionViewport(viewArea); rv = new RegionViewport(viewArea);
transferForeignObjects(attributes, rv); transferForeignObjects(attributes, rv);
rv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
rv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false));
setAreaAttributes(attributes, rv); setAreaAttributes(attributes, rv);
setTraits(attributes, rv, SUBSET_COMMON); setTraits(attributes, rv, SUBSET_COMMON);
setTraits(attributes, rv, SUBSET_BOX); setTraits(attributes, rv, SUBSET_BOX);
throw new IllegalStateException("Current BodyRegion must be null"); throw new IllegalStateException("Current BodyRegion must be null");
} }
String regionName = attributes.getValue("name"); 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(); RegionViewport rv = getCurrentRegionViewport();
body = new BodyRegion(Constants.FO_REGION_BODY, body = new BodyRegion(Constants.FO_REGION_BODY,
regionName, rv, columnCount, columnGap); regionName, rv, columnCount, columnGap);
transferForeignObjects(attributes, body); transferForeignObjects(attributes, body);
body.setCTM(getAttributeAsCTM(attributes, "ctm")); body.setCTM(getAttributeAsCTM(attributes, "ctm"));
setAreaAttributes(attributes, body); setAreaAttributes(attributes, body);
setTraits(attributes, body, SUBSET_BORDER_PADDING);
rv.setRegionReference(body); rv.setRegionReference(body);
currentPageViewport.getPage().setRegionViewport( currentPageViewport.getPage().setRegionViewport(
Constants.FO_REGION_BODY, rv); Constants.FO_REGION_BODY, rv);
private class SpanMaker extends AbstractMaker { private class SpanMaker extends AbstractMaker {


public void startElement(Attributes attributes) { 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(); BodyRegion body = getCurrentBodyRegion();
Span span = new Span(columnCount, Span span = new Span(columnCount,
body.getColumnGap(), ipd); body.getColumnGap(), ipd);
public void startElement(Attributes attributes) { public void startElement(Attributes attributes) {
Footnote fn = getCurrentBodyRegion().getFootnote(); Footnote fn = getCurrentBodyRegion().getFootnote();
transferForeignObjects(attributes, fn); transferForeignObjects(attributes, fn);
fn.setTop(getAttributeAsInteger(attributes, "top-offset", 0));
fn.setTop(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
areaStack.push(fn); areaStack.push(fn);
} }


private class BlockMaker extends AbstractMaker { private class BlockMaker extends AbstractMaker {


public void startElement(Attributes attributes) { public void startElement(Attributes attributes) {
boolean isViewport = getAttributeAsBoolean(attributes,
boolean isViewport = XMLUtil.getAttributeAsBoolean(attributes,
"is-viewport-area", false); "is-viewport-area", false);
Block block; Block block;
if (isViewport) { if (isViewport) {
BlockViewport bv = new BlockViewport(); BlockViewport bv = new BlockViewport();
bv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
bv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false));
bv.setCTM(getAttributeAsCTM(attributes, "ctm")); bv.setCTM(getAttributeAsCTM(attributes, "ctm"));
if (bv.getPositioning() != BlockViewport.RELATIVE) { if (bv.getPositioning() != BlockViewport.RELATIVE) {
bv.setXOffset( bv.setXOffset(
getAttributeAsInteger(attributes, "left-position", 0));
XMLUtil.getAttributeAsInt(attributes, "left-position", 0));
bv.setYOffset( bv.setYOffset(
getAttributeAsInteger(attributes, "top-position", 0));
XMLUtil.getAttributeAsInt(attributes, "top-position", 0));
} }
block = bv; block = bv;
} else { } else {
block.setPositioning(Block.STACK); block.setPositioning(Block.STACK);
} }
if (attributes.getValue("left-offset") != null) { 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) { if (attributes.getValue("top-offset") != null) {
block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0));
block.setYOffset(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0));
} }
transferForeignObjects(attributes, block); transferForeignObjects(attributes, block);
setAreaAttributes(attributes, block); setAreaAttributes(attributes, block);
public void startElement(Attributes attributes) { public void startElement(Attributes attributes) {
InlineArea inl = new InlineArea(); InlineArea inl = new InlineArea();
transferForeignObjects(attributes, inl); transferForeignObjects(attributes, inl);
inl.setOffset(getAttributeAsInteger(attributes, "offset", 0));
inl.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setAreaAttributes(attributes, inl); setAreaAttributes(attributes, inl);
setTraits(attributes, inl, SUBSET_COMMON); setTraits(attributes, inl, SUBSET_COMMON);
setTraits(attributes, inl, SUBSET_BOX); setTraits(attributes, inl, SUBSET_BOX);
public void startElement(Attributes attributes) { public void startElement(Attributes attributes) {
InlineParent ip = new InlineParent(); InlineParent ip = new InlineParent();
transferForeignObjects(attributes, ip); transferForeignObjects(attributes, ip);
ip.setOffset(getAttributeAsInteger(attributes, "offset", 0));
ip.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setAreaAttributes(attributes, ip); setAreaAttributes(attributes, ip);
setTraits(attributes, ip, SUBSET_COMMON); setTraits(attributes, ip, SUBSET_COMMON);
setTraits(attributes, ip, SUBSET_BOX); setTraits(attributes, ip, SUBSET_BOX);
public void startElement(Attributes attributes) { public void startElement(Attributes attributes) {
InlineBlockParent ibp = new InlineBlockParent(); InlineBlockParent ibp = new InlineBlockParent();
transferForeignObjects(attributes, ibp); transferForeignObjects(attributes, ibp);
ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0));
ibp.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setAreaAttributes(attributes, ibp); setAreaAttributes(attributes, ibp);
setTraits(attributes, ibp, SUBSET_COMMON); setTraits(attributes, ibp, SUBSET_COMMON);
setTraits(attributes, ibp, SUBSET_BOX); setTraits(attributes, ibp, SUBSET_BOX);
setTraits(attributes, text, SUBSET_BOX); setTraits(attributes, text, SUBSET_BOX);
setTraits(attributes, text, SUBSET_COLOR); setTraits(attributes, text, SUBSET_COLOR);
setTraits(attributes, text, SUBSET_FONT); 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)); "tlsadjust", 0));
text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes,
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
"twsadjust", 0)); "twsadjust", 0));
Area parent = (Area)areaStack.peek(); Area parent = (Area)areaStack.peek();
parent.addChildArea(text); parent.addChildArea(text);
private class WordMaker extends AbstractMaker { private class WordMaker extends AbstractMaker {


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


public void endElement() { 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 //TODO the isAdjustable parameter is currently not used/implemented
if (content.position() > 0) { if (content.position() > 0) {
content.flip(); content.flip();
boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true);
boolean adjustable = XMLUtil.getAttributeAsBoolean(lastAttributes, "adj", true);
SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable); SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable);
AbstractTextArea text = getCurrentText(); AbstractTextArea text = getCurrentText();
space.setParentArea(text); space.setParentArea(text);
setTraits(attributes, leader, SUBSET_BOX); setTraits(attributes, leader, SUBSET_BOX);
setTraits(attributes, leader, SUBSET_COLOR); setTraits(attributes, leader, SUBSET_COLOR);
setTraits(attributes, leader, SUBSET_FONT); setTraits(attributes, leader, SUBSET_FONT);
leader.setOffset(getAttributeAsInteger(attributes, "offset", 0));
leader.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
String ruleStyle = attributes.getValue("ruleStyle"); String ruleStyle = attributes.getValue("ruleStyle");
if (ruleStyle != null) { if (ruleStyle != null) {
leader.setRuleStyle(ruleStyle); leader.setRuleStyle(ruleStyle);
} }
leader.setRuleThickness( leader.setRuleThickness(
getAttributeAsInteger(attributes, "ruleThickness", 0));
XMLUtil.getAttributeAsInt(attributes, "ruleThickness", 0));
Area parent = (Area)areaStack.peek(); Area parent = (Area)areaStack.peek();
parent.addChildArea(leader); parent.addChildArea(leader);
} }
setTraits(attributes, viewport, SUBSET_COMMON); setTraits(attributes, viewport, SUBSET_COMMON);
setTraits(attributes, viewport, SUBSET_BOX); setTraits(attributes, viewport, SUBSET_BOX);
setTraits(attributes, viewport, SUBSET_COLOR); 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(); Area parent = (Area)areaStack.peek();
parent.addChildArea(viewport); parent.addChildArea(viewport);
areaStack.push(viewport); areaStack.push(viewport);


public void startElement(Attributes attributes) { public void startElement(Attributes attributes) {
String title = attributes.getValue("title"); String title = attributes.getValue("title");
boolean showChildren = getAttributeAsBoolean(attributes, "show-children", false);
boolean showChildren = XMLUtil.getAttributeAsBoolean(
attributes, "show-children", false);
String[] linkdata String[] linkdata
= InternalLink.parseXMLAttribute(attributes.getValue("internal-link")); = InternalLink.parseXMLAttribute(attributes.getValue("internal-link"));
PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]); PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]);
transferForeignObjects(attributes, reg); transferForeignObjects(attributes, reg);
reg.setCTM(getAttributeAsCTM(attributes, "ctm")); reg.setCTM(getAttributeAsCTM(attributes, "ctm"));
setAreaAttributes(attributes, reg); setAreaAttributes(attributes, reg);
setTraits(attributes, reg, SUBSET_BORDER_PADDING);
rv.setRegionReference(reg); rv.setRegionReference(reg);
currentPageViewport.getPage().setRegionViewport( currentPageViewport.getPage().setRegionViewport(
side, rv); side, rv);
Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END, Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END,
Trait.START_INDENT, Trait.END_INDENT, Trait.START_INDENT, Trait.END_INDENT,
Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA}; 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) { private void setTraits(Attributes attributes, Area area, Object[] traitSubset) {
for (int i = traitSubset.length; --i >= 0;) { for (int i = traitSubset.length; --i >= 0;) {
if (repeat != null) { if (repeat != null) {
bkg.setRepeat(repeat); bkg.setRepeat(repeat);
} }
bkg.setHoriz(getAttributeAsInteger(attributes,
bkg.setHoriz(XMLUtil.getAttributeAsInt(attributes,
"bkg-horz-offset", 0)); "bkg-horz-offset", 0));
bkg.setVertical(getAttributeAsInteger(attributes,
bkg.setVertical(XMLUtil.getAttributeAsInt(attributes,
"bkg-vert-offset", 0)); "bkg-vert-offset", 0));
} }
area.addTrait(trait, bkg); area.addTrait(trait, bkg);
String fontName = attributes.getValue("font-name"); String fontName = attributes.getValue("font-name");
if (fontName != null) { if (fontName != null) {
String fontStyle = attributes.getValue("font-style"); String fontStyle = attributes.getValue("font-style");
int fontWeight = getAttributeAsInteger(
int fontWeight = XMLUtil.getAttributeAsInt(
attributes, "font-weight", Font.WEIGHT_NORMAL); attributes, "font-weight", Font.WEIGHT_NORMAL);
area.addTrait(trait, area.addTrait(trait,
FontInfo.createFontKey(fontName, fontStyle, fontWeight)); FontInfo.createFontKey(fontName, fontStyle, fontWeight));
} }
} }


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) { private static CTM getAttributeAsCTM(Attributes attributes, String name) {
String s = attributes.getValue(name).trim(); String s = attributes.getValue(name).trim();
if (s.startsWith("[") && s.endsWith("]")) { if (s.startsWith("[") && s.endsWith("]")) {
} }
} }


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) { private static void transferForeignObjects(Attributes atts, AreaTreeObject ato) {
for (int i = 0, c = atts.getLength(); i < c; i++) { for (int i = 0, c = atts.getLength(); i < c; i++) {
String ns = atts.getURI(i); String ns = atts.getURI(i);

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

} }
// set borders and padding traits // set borders and padding traits
// (a little extensions wrt what prescribed by the specs at 6.4.14) // (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()); setRegionReferencePosition(rr, r, rvp.getViewArea());
rvp.setRegionReference(rr); rvp.setRegionReference(rr);
setRegionViewport(r.getNameId(), rvp); setRegionViewport(r.getNameId(), rvp);
FODimension reldims = new FODimension(0, 0); FODimension reldims = new FODimension(0, 0);
rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(), rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(),
r.getWritingMode(), absRegVPRect, reldims)); 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

blocks.add(child); 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 * Set the Coordinate Transformation Matrix which transforms content
* coordinates in this region reference area which are specified in * coordinates in this region reference area which are specified in

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

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


import org.xml.sax.SAXException;

import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.AreaTreeModel; import org.apache.fop.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser; import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel; import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.fonts.FontInfo; 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 { public class AreaTreeInputHandler extends InputHandler {



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



import javax.swing.UIManager; import javax.swing.UIManager;


import org.xml.sax.SAXException;

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

import org.apache.fop.Version; import org.apache.fop.Version;
import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.pdf.PDFXMode; import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.render.Renderer; import org.apache.fop.render.Renderer;
import org.apache.fop.render.awt.AWTRenderer; 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.pdf.PDFRenderer;
import org.apache.fop.render.print.PagesMode; import org.apache.fop.render.print.PagesMode;
import org.apache.fop.render.print.PrintRenderer; import org.apache.fop.render.print.PrintRenderer;
import org.apache.fop.render.xml.XMLRenderer; import org.apache.fop.render.xml.XMLRenderer;
import org.apache.fop.util.CommandLineLogger; import org.apache.fop.util.CommandLineLogger;
import org.xml.sax.SAXException;


/** /**
* Options parses the commandline arguments * Options parses the commandline arguments
public static final int XSLT_INPUT = 2; public static final int XSLT_INPUT = 2;
/** input: Area Tree XML file */ /** input: Area Tree XML file */
public static final int AREATREE_INPUT = 3; public static final int AREATREE_INPUT = 3;
/** input: Intermediate Format XML file */
public static final int IF_INPUT = 4;
/** input: Image file */ /** input: Image file */
public static final int IMAGE_INPUT = 4;
public static final int IMAGE_INPUT = 5;


/* show configuration information */ /* show configuration information */
private Boolean showConfiguration = Boolean.FALSE; private Boolean showConfiguration = Boolean.FALSE;
private File xmlfile = null; private File xmlfile = null;
/* area tree input file */ /* area tree input file */
private File areatreefile = null; private File areatreefile = null;
/* intermediate format input file */
private File iffile = null;
/* area tree input file */ /* area tree input file */
private File imagefile = null; private File imagefile = null;
/* output file */ /* output file */


//Make sure the prepared XMLRenderer is used //Make sure the prepared XMLRenderer is used
foUserAgent.setRendererOverride(xmlRenderer); 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; return true;
} }
i = i + parseXMLInputOption(args, i); i = i + parseXMLInputOption(args, i);
} else if (args[i].equals("-atin")) { } else if (args[i].equals("-atin")) {
i = i + parseAreaTreeInputOption(args, i); i = i + parseAreaTreeInputOption(args, i);
} else if (args[i].equals("-ifin")) {
i = i + parseIFInputOption(args, i);
} else if (args[i].equals("-imagein")) { } else if (args[i].equals("-imagein")) {
i = i + parseImageInputOption(args, i); i = i + parseImageInputOption(args, i);
} else if (args[i].equals("-awt")) { } else if (args[i].equals("-awt")) {
i = i + parseCustomOutputOption(args, i); i = i + parseCustomOutputOption(args, i);
} else if (args[i].equals("-at")) { } else if (args[i].equals("-at")) {
i = i + parseAreaTreeOption(args, i); i = i + parseAreaTreeOption(args, i);
} else if (args[i].equals("-if")) {
i = i + parseIntermediateFormatOption(args, i);
} else if (args[i].equals("-v")) { } else if (args[i].equals("-v")) {
printVersion(); printVersion();
return false; return false;
} }


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


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


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


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 { private int parseAreaTreeInputOption(String[] args, int i) throws FOPException {
inputmode = AREATREE_INPUT;
setInputFormat(AREATREE_INPUT);
if ((i + 1 == args.length) if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) { || (isOption(args[i + 1]))) {
throw new FOPException("you must specify the Area Tree file for the '-atin' option"); throw new FOPException("you must specify the Area Tree file for the '-atin' option");
} }
} }


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 { private int parseImageInputOption(String[] args, int i) throws FOPException {
inputmode = IMAGE_INPUT;
setInputFormat(IMAGE_INPUT);
if ((i + 1 == args.length) if ((i + 1 == args.length)
|| (isOption(args[i + 1]))) { || (isOption(args[i + 1]))) {
throw new FOPException("you must specify the image file for the '-imagein' option"); throw new FOPException("you must specify the image file for the '-imagein' option");
} }
} }


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 * checks whether all necessary information has been given in a consistent way
*/ */
throw new FOPException( throw new FOPException(
"FO output mode is only available if you use -xml and -xsl"); "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()) { if (fofile != null && !fofile.exists()) {
throw new FileNotFoundException("Error: fo file " throw new FileNotFoundException("Error: fo file "
+ fofile.getAbsolutePath() + fofile.getAbsolutePath()
throw new FOPException( throw new FOPException(
"Area Tree Output is not available if Area Tree is used as input!"); "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()) { if (areatreefile != null && !areatreefile.exists()) {
throw new FileNotFoundException("Error: area tree file " throw new FileNotFoundException("Error: area tree file "
+ areatreefile.getAbsolutePath() + areatreefile.getAbsolutePath()
+ " not found "); + " not found ");
} }
} else if (inputmode == IMAGE_INPUT) {
} else if (inputmode == IF_INPUT) {
if (outputmode.equals(MimeConstants.MIME_XSL_FO)) { if (outputmode.equals(MimeConstants.MIME_XSL_FO)) {
throw new FOPException( throw new FOPException(
"FO output mode is only available if you use -xml and -xsl"); "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()) { if (imagefile != null && !imagefile.exists()) {
throw new FileNotFoundException("Error: image file " throw new FileNotFoundException("Error: image file "
return new InputHandler(fofile); return new InputHandler(fofile);
case AREATREE_INPUT: case AREATREE_INPUT:
return new AreaTreeInputHandler(areatreefile); return new AreaTreeInputHandler(areatreefile);
case IF_INPUT:
return new IFInputHandler(iffile);
case XSLT_INPUT: case XSLT_INPUT:
return new InputHandler(xmlfile, xsltfile, xsltParams); return new InputHandler(xmlfile, xsltfile, xsltParams);
case IMAGE_INPUT: case IMAGE_INPUT:
+ " -fo infile xsl:fo input file \n" + " -fo infile xsl:fo input file \n"
+ " -xml infile xml input file, must be used together with -xsl \n" + " -xml infile xml input file, must be used together with -xsl \n"
+ " -atin infile area tree input file \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" + " -imagein infile image input file (piping through stdin not supported)\n"
+ " -xsl stylesheet xslt stylesheet \n \n" + " -xsl stylesheet xslt stylesheet \n \n"
+ " -param name value <value> to use for parameter <name> in xslt stylesheet\n" + " -param name value <value> to use for parameter <name> in xslt stylesheet\n"
+ " -at [mime] out representation of area tree as XML (outfile req'd) \n" + " -at [mime] out representation of area tree as XML (outfile req'd) \n"
+ " specify optional mime output to allow AT to be converted\n" + " specify optional mime output to allow AT to be converted\n"
+ " to final format later\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" + " -print input file will be rendered and sent to the printer \n"
+ " see options with \"-print help\" \n" + " see options with \"-print help\" \n"
+ " -out mime outfile input will be rendered using the given MIME type\n" + " -out mime outfile input will be rendered using the given MIME type\n"
} }
log.info("xslt stylesheet: " + xsltfile.toString()); log.info("xslt stylesheet: " + xsltfile.toString());
break; 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: default:
log.info("unknown input type"); log.info("unknown input type");
} }
} else { } else {
log.info("output file: " + outfile.toString()); 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 { } else {
log.info(outputmode); log.info(outputmode);
if (this.useStdOut) { if (this.useStdOut) {

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

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



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


/** /**
*/ */
public abstract class XMLObj extends FONode implements 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 // temp reference for attributes
private Attributes attr = null; private Attributes attr = null;




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


/** /**
} else { } else {
String pref = qname.substring(0, idx); String pref = qname.substring(0, idx);
String tail = qname.substring(idx + 1); String tail = qname.substring(idx + 1);
if (pref.equals("xmlns")) {
if (pref.equals(XMLConstants.XMLNS_PREFIX)) {
ns.put(tail, rf); ns.put(tail, rf);
} else { } else {
element.setAttributeNS((String)ns.get(pref), tail, rf); element.setAttributeNS((String)ns.get(pref), tail, rf);


element = doc.getDocumentElement(); element = doc.getDocumentElement();
buildTopLevel(doc, element); 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()); getNamespaceURI());
} }



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

protected boolean loaded = false; protected boolean loaded = false;
/** true if the font will be embedded, false if it will be referenced only. */ /** true if the font will be embedded, false if it will be referenced only. */
protected boolean embedded = true; protected boolean embedded = true;
/** true if kerning information shall be loaded if available. */
protected boolean useKerning = true;


/** /**
* Default constructor. * Default constructor.
* @param fontFileURI the URI to the PFB file of a Type 1 font * @param fontFileURI the URI to the PFB file of a Type 1 font
* @param embedded indicates whether the font is embedded or referenced * @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 * @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.fontFileURI = fontFileURI;
this.embedded = embedded; this.embedded = embedded;
this.useKerning = useKerning;
this.resolver = resolver; this.resolver = resolver;
} }


*/ */
public static CustomFont loadFont(File fontFile, String subFontName, public static CustomFont loadFont(File fontFile, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { 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);
} }


/** /**
* @throws IOException In case of an I/O error * @throws IOException In case of an I/O error
*/ */
public static CustomFont loadFont(URL fontUrl, String subFontName, 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);
} }


/** /**
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
* @param embedded indicates whether the font is embedded or referenced * @param embedded indicates whether the font is embedded or referenced
* @param encodingMode the requested encoding mode * @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 * @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font * @return the newly loaded font
* @throws IOException In case of an I/O error * @throws IOException In case of an I/O error
*/ */
public static CustomFont loadFont(String fontFileURI, String subFontName, 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(); fontFileURI = fontFileURI.trim();
boolean type1 = isType1(fontFileURI); boolean type1 = isType1(fontFileURI);
FontLoader loader; FontLoader loader;
throw new IllegalArgumentException( throw new IllegalArgumentException(
"CID encoding mode not supported for Type 1 fonts"); "CID encoding mode not supported for Type 1 fonts");
} }
loader = new Type1FontLoader(fontFileURI, embedded, resolver);
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver);
} else { } else {
loader = new TTFFontLoader(fontFileURI, subFontName, embedded, encodingMode, resolver);
loader = new TTFFontLoader(fontFileURI, subFontName,
embedded, encodingMode, useKerning, resolver);
} }
return loader.getFont(); return loader.getFont();
} }

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

throw new RuntimeException("Cannot load font. No font URIs available."); throw new RuntimeException("Cannot load font. No font URIs available.");
} }
realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName,
this.embedded, this.encodingMode, resolver);
this.embedded, this.encodingMode, useKerning, resolver);
} }
if (realFont instanceof FontDescriptor) { if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont; realFontDescriptor = (FontDescriptor) realFont;

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

} }
try { try {
TTFFontLoader ttfLoader = new TTFFontLoader( TTFFontLoader ttfLoader = new TTFFontLoader(
fontFileURI, fontName, true, EncodingMode.AUTO, resolver);
fontFileURI, fontName, true, EncodingMode.AUTO, true, resolver);
customFont = ttfLoader.getFont(); customFont = ttfLoader.getFont();
if (this.eventListener != null) { if (this.eventListener != null) {
customFont.setEventListener(this.eventListener); customFont.setEventListener(this.eventListener);

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

* @param resolver the FontResolver for font URI resolution * @param resolver the FontResolver for font URI resolution
*/ */
public TTFFontLoader(String fontFileURI, FontResolver resolver) { public TTFFontLoader(String fontFileURI, FontResolver resolver) {
this(fontFileURI, null, true, EncodingMode.AUTO, resolver);
this(fontFileURI, null, true, EncodingMode.AUTO, true, resolver);
} }


/** /**
* TrueType fonts) * TrueType fonts)
* @param embedded indicates whether the font is embedded or referenced * @param embedded indicates whether the font is embedded or referenced
* @param encodingMode the requested encoding mode * @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 * @param resolver the FontResolver for font URI resolution
*/ */
public TTFFontLoader(String fontFileURI, String subFontName, 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.subFontName = subFontName;
this.encodingMode = encodingMode; this.encodingMode = encodingMode;
if (this.encodingMode == EncodingMode.AUTO) { if (this.encodingMode == EncodingMode.AUTO) {
copyWidthsSingleByte(ttf); copyWidthsSingleByte(ttf);
} }


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

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

* Constructs a new Type 1 font loader. * Constructs a new Type 1 font loader.
* @param fontFileURI the URI to the PFB file of a Type 1 font * @param fontFileURI the URI to the PFB file of a Type 1 font
* @param embedded indicates whether the font is embedded or referenced * @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 * @param resolver the font resolver used to resolve URIs
* @throws IOException In case of an I/O error * @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) { private String getPFMURI(String pfbURI) {
singleFont.setWidth(chm.getCharCode(), (int)Math.round(chm.getWidthX())); singleFont.setWidth(chm.getCharCode(), (int)Math.round(chm.getWidthX()));
} }
} }
returnFont.replaceKerningMap(afm.createXKerningMapEncoded());
if (useKerning) {
returnFont.replaceKerningMap(afm.createXKerningMapEncoded());
}
} else { } else {
returnFont.setFlags(pfm.getFlags()); returnFont.setFlags(pfm.getFlags());
returnFont.setFirstChar(pfm.getFirstChar()); returnFont.setFirstChar(pfm.getFirstChar());
for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) { for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) {
singleFont.setWidth(i, pfm.getCharWidth(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

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

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

import org.apache.batik.bridge.UnitProcessor; import org.apache.batik.bridge.UnitProcessor;
import org.apache.batik.bridge.UserAgent; import org.apache.batik.bridge.UserAgent;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory; import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.svg.SVGOMDocument; import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;


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

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



package org.apache.fop.pdf; 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 * 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 { public class PDFNumber extends PDFObject {


return doubleOut(doubleDown, 6); 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. * Output a double value to a string suitable for PDF.
* In this method it is possible to set the maximum * In this method it is possible to set the maximum
* @return the value as a string * @return the value as a string
*/ */
public static String doubleOut(double doubleDown, int dec) { 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} */ /** {@inheritDoc} */

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

* @return true if the new paint changes the current paint * @return true if the new paint changes the current paint
*/ */
public boolean setPaint(Paint p) { public boolean setPaint(Paint p) {
Paint paint = ((PDFData)getData()).paint;
PDFData data = getPDFData();
Paint paint = data.paint;
if (paint == null) { if (paint == null) {
if (p != null) { if (p != null) {
((PDFData)getData()).paint = p;
data.paint = p;
return true; return true;
} }
} else if (!paint.equals(p)) { } else if (!paint.equals(p)) {
((PDFData)getData()).paint = p;
data.paint = p;
return true; return true;
} }
return false; return false;
* @return true if the clip will change the current clip. * @return true if the clip will change the current clip.
*/ */
public boolean checkClip(Shape cl) { public boolean checkClip(Shape cl) {
Shape clip = ((PDFData)getData()).clip;
Shape clip = getPDFData().clip;
if (clip == null) { if (clip == null) {
if (cl != null) { if (cl != null) {
return true; return true;
* @param cl the new clip in the current state * @param cl the new clip in the current state
*/ */
public void setClip(Shape cl) { public void setClip(Shape cl) {
Shape clip = ((PDFData)getData()).clip;
PDFData data = getPDFData();
Shape clip = data.clip;
if (clip != null) { if (clip != null) {
Area newClip = new Area(clip); Area newClip = new Area(clip);
newClip.intersect(new Area(cl)); newClip.intersect(new Area(cl));
((PDFData)getData()).clip = new GeneralPath(newClip);
data.clip = new GeneralPath(newClip);
} else { } 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. * Get the current stack level.
* *
newState.addValues(state); newState.addValues(state);
} }
} }
if (((PDFData)getData()).gstate != null) {
newState.addValues(((PDFData)getData()).gstate);
if (getPDFData().gstate != null) {
newState.addValues(getPDFData().gstate);
} }
return newState; return newState;
} }
getStateStack().add(copy); getStateStack().add(copy);
} }


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

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


private static final long serialVersionUID = 3527950647293177764L; private static final long serialVersionUID = 3527950647293177764L;


private Paint paint = null; private Paint paint = null;
private Paint backPaint = 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 Shape clip = null;
private PDFGState gstate = null; private PDFGState gstate = null;


//text state
private float characterSpacing = 0f;

/** {@inheritDoc} */ /** {@inheritDoc} */
public Object clone() { public Object clone() {
PDFData obj = (PDFData)super.clone(); PDFData obj = (PDFData)super.clone();
obj.paint = this.paint; obj.paint = this.paint;
obj.backPaint = 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.clip = this.clip;
obj.gstate = this.gstate; obj.gstate = this.gstate;
obj.characterSpacing = this.characterSpacing;
return obj; return obj;
} }


return super.toString() return super.toString()
+ ", paint=" + paint + ", paint=" + paint
+ ", backPaint=" + backPaint + ", backPaint=" + backPaint
+ ", lineCap=" + lineCap
+ ", miterLimit=" + miterLimit
+ ", text=" + text
+ ", dashOffset=" + dashOffset
//+ ", lineCap=" + lineCap
//+ ", miterLimit=" + miterLimit
//+ ", dashOffset=" + dashOffset
+ ", clip=" + clip + ", clip=" + clip
+ ", gstate=" + gstate; + ", gstate=" + gstate;
} }

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

*/ */
public class PDFReference implements PDFWritable { public class PDFReference implements PDFWritable {


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


private Reference objReference; private Reference objReference;


* @param obj the object to be referenced * @param obj the object to be referenced
*/ */
public PDFReference(PDFObject obj) { public PDFReference(PDFObject obj) {
this.indirectReference = obj.referencePDF();
this.objectNumber = obj.getObjectNumber();
this.generation = obj.getGeneration();
this.objReference = new SoftReference(obj); this.objReference = new SoftReference(obj);
} }


if (ref == null) { if (ref == null) {
throw new NullPointerException("ref must not be 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]);
} }


/** /**
} }
} }


/**
* 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} */ /** {@inheritDoc} */
public String toString() { public String toString() {
return this.indirectReference;
return getObjectNumber() + " " + getGeneration() + " R";
} }


/** {@inheritDoc} */ /** {@inheritDoc} */

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

* @param adjust the glyph adjust value in thousands of text unit space. * @param adjust the glyph adjust value in thousands of text unit space.
*/ */
public void adjustGlyphTJ(double adjust) { 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(PDFNumber.doubleOut(adjust, DEC - 4));
bufTJ.append(" "); bufTJ.append(" ");
bufTJ.append(startText); bufTJ.append(startText);

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

* @return the action to place next to /A within a Link * @return the action to place next to /A within a Link
*/ */
public String getAction() { public String getAction() {
if (hasObjectNumber()) {
return referencePDF();
} else {
return getDictString();
}
}

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


/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public String toPDFString() { 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

import org.apache.batik.gvt.GraphicsNode; import org.apache.batik.gvt.GraphicsNode;


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


import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.EventBroadcaster; 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.BatikUtil;
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl;
import org.apache.fop.render.RendererContext.RendererContextWrapper; import org.apache.fop.render.RendererContext.RendererContextWrapper;
*/ */
public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererContextConstants { 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} */ /** {@inheritDoc} */
public void handleXML(RendererContext context, public void handleXML(RendererContext context,
Document doc, String ns) throws Exception { Document doc, String ns) throws Exception {
} }


/** /**
* 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 ctx the batik bridge context
* @param doc the document * @param doc the document
* @return a built GVT root tree * @return a built GVT root tree

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

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



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

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


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


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


* @param imageClass the Image subclass for which to get a handler * @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 * @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; Class cl = imageClass;
while (cl != null) { while (cl != null) {
handler = (ImageHandler)handlers.get(cl);
handler = (ImageHandlerBase)handlers.get(cl);
if (handler != null) { if (handler != null) {
break; break;
} }
List flavors = new java.util.ArrayList(); List flavors = new java.util.ArrayList();
Iterator iter = this.handlerList.iterator(); Iterator iter = this.handlerList.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
ImageFlavor[] f = ((ImageHandler)iter.next()).getSupportedImageFlavors();
ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors();
for (int i = 0; i < f.length; i++) { for (int i = 0; i < f.length; i++) {
flavors.add(f[i]); flavors.add(f[i]);
} }
Iterator providers = Service.providers(imageHandlerClass); Iterator providers = Service.providers(imageHandlerClass);
if (providers != null) { if (providers != null) {
while (providers.hasNext()) { while (providers.hasNext()) {
ImageHandler handler = (ImageHandler)providers.next();
ImageHandlerBase handler = (ImageHandlerBase)providers.next();
try { try {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Dynamically adding ImageHandler: " log.debug("Dynamically adding ImageHandler: "

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

} }
} }


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"); = new QName(ExtensionElementMapping.URI, "fox:transform");


/** {@inheritDoc} */ /** {@inheritDoc} */

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



// Java // Java
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
private Set warnedXMLHandlers; private Set warnedXMLHandlers;


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


/** {@inheritDoc} */ /** {@inheritDoc} */
public void setUserAgent(FOUserAgent agent) { public void setUserAgent(FOUserAgent agent) {
public String getMimeType() { public String getMimeType() {
return null; 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

import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;


/** /**
* @param mimeType the MIME type of the renderer * @param mimeType the MIME type of the renderer
* @return the requested configuration subtree, null if there's no configuration * @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(); Configuration cfg = userAgent.getFactory().getUserConfig();
if (cfg == null) { if (cfg == null) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {

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

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

public interface Graphics2DImagePainter public interface Graphics2DImagePainter
extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter { extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter {


}
}

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

* Paints an image at the given position. * Paints an image at the given position.
* @param image the image which will be painted * @param image the image which will be painted
* @param context the renderer context for the current renderer * @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 * @throws IOException In case of an I/O error while writing the output format
*/ */
void paintImage(RenderedImage image, void paintImage(RenderedImage image,

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



package org.apache.fop.render; 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

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

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

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

import java.util.List; import java.util.List;
import java.util.Map; 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.Area;
import org.apache.fop.area.Trait; import org.apache.fop.area.Trait;
import org.apache.fop.fonts.CustomFontCollection; import org.apache.fop.fonts.CustomFontCollection;
import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.base14.Base14FontCollection; import org.apache.fop.fonts.base14.Base14FontCollection;
import org.w3c.dom.Document;


/** Abstract base class of "Print" type renderers. */ /** Abstract base class of "Print" type renderers. */
public abstract class PrintRenderer extends AbstractRenderer { public abstract class PrintRenderer extends AbstractRenderer {
return this.embedFontInfoList; 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; this.fontInfo = inFontInfo;
FontManager fontManager = userAgent.getFactory().getFontManager(); FontManager fontManager = userAgent.getFactory().getFontManager();
FontCollection[] fontCollections = new FontCollection[] { FontCollection[] fontCollections = new FontCollection[] {
*/ */
protected String getInternalFontNameForArea(Area area) { protected String getInternalFontNameForArea(Area area) {
FontTriplet triplet = (FontTriplet)area.getTrait(Trait.FONT); 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

import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.FopFactory;
import org.apache.fop.fonts.CustomFontCollection;
import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.EncodingMode;
import org.apache.fop.fonts.FontCache; import org.apache.fop.fonts.FontCache;
import org.apache.fop.fonts.FontCollection;
import org.apache.fop.fonts.FontEventAdapter; import org.apache.fop.fonts.FontEventAdapter;
import org.apache.fop.fonts.FontEventListener; import org.apache.fop.fonts.FontEventListener;
import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.FontUtil;
import org.apache.fop.fonts.autodetect.FontFileFinder; import org.apache.fop.fonts.autodetect.FontFileFinder;
import org.apache.fop.fonts.autodetect.FontInfoFinder; 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; import org.apache.fop.util.LogUtil;


/** /**
* Base Print renderer configurator (mostly handles font configuration) * Base Print renderer configurator (mostly handles font configuration)
*/ */
public class PrintRendererConfigurator extends AbstractRendererConfigurator public class PrintRendererConfigurator extends AbstractRendererConfigurator
implements RendererConfigurator {
implements RendererConfigurator, IFDocumentHandlerConfigurator {


/** logger instance */ /** logger instance */
protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class); protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class);


PrintRenderer printRenderer = (PrintRenderer)renderer; PrintRenderer printRenderer = (PrintRenderer)renderer;
FontResolver fontResolver = printRenderer.getFontResolver(); 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(); FopFactory factory = userAgent.getFactory();
FontManager fontManager = factory.getFontManager(); FontManager fontManager = factory.getFontManager();
if (fontResolver == null) { if (fontResolver == null) {
boolean strict = factory.validateUserConfigStrictly(); boolean strict = factory.validateUserConfigStrictly();
FontCache fontCache = fontManager.getFontCache(); FontCache fontCache = fontManager.getFontCache();


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


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


/** /**
return embedFontInfo; 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

* Set up the given FontInfo. * Set up the given FontInfo.
* *
* @param fontInfo The font information * @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> * Reports if out of order rendering is supported. <p>

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

import java.util.Map; import java.util.Map;


import org.apache.fop.apps.FOUserAgent; 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 * The Render Context for external handlers. This provides a rendering context
* render target. * render target.
*/ */
public class RendererContext { 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 String mime;
private final AbstractRenderer renderer; private final AbstractRenderer renderer;

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

import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.FOEventHandler; 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. * Factory for FOEventHandlers and Renderers.


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


/** /**
* Main constructor. * Main constructor.
public RendererFactory() { public RendererFactory() {
discoverRenderers(); discoverRenderers();
discoverFOEventHandlers(); discoverFOEventHandlers();
discoverDocumentHandlers();
} }


/** /**
} }
} }


/**
* 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 * Add a new RendererMaker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one. * particular MIME type, this call overwrites the existing one.
} }
} }


/**
* 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. * Returns a RendererMaker which handles the given MIME type.
* @param mime the requested output format * @param mime the requested output format
return maker; 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 * Creates a Renderer object based on render-type desired
* @param userAgent the user agent for access to configuration * @param userAgent the user agent for access to configuration
*/ */
public Renderer createRenderer(FOUserAgent userAgent, String outputFormat) public Renderer createRenderer(FOUserAgent userAgent, String outputFormat)
throws FOPException { throws FOPException {
if (userAgent.getRendererOverride() != null) {
if (userAgent.getDocumentHandlerOverride() != null) {
return createRendererForDocumentHandler(userAgent.getDocumentHandlerOverride());
} else if (userAgent.getRendererOverride() != null) {
return userAgent.getRendererOverride(); return userAgent.getRendererOverride();
} else { } else {
AbstractRendererMaker maker = getRendererMaker(outputFormat); 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. * Creates FOEventHandler instances based on the desired output.
return userAgent.getFOEventHandlerOverride(); return userAgent.getFOEventHandlerOverride();
} else { } else {
AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat); AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat);
if (maker == null) {
if (maker != null) {
return maker.makeFOEventHandler(userAgent, out);
} else {
AbstractRendererMaker rendMaker = getRendererMaker(outputFormat); 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 { } 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( throw new FOPException(
"OutputStream has not been set"); "OutputStream has not been set");
} }
//Found a Renderer so we need to construct an AreaTreeHandler. //Found a Renderer so we need to construct an AreaTreeHandler.
return new AreaTreeHandler(userAgent, outputFormat, out); 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 * @return an array of all supported MIME types
*/ */
while (iter.hasNext()) { while (iter.hasNext()) {
lst.add(((String)iter.next())); lst.add(((String)iter.next()));
} }
iter = this.documentHandlerMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
}
Collections.sort(lst); Collections.sort(lst);
return (String[])lst.toArray(new String[lst.size()]); return (String[])lst.toArray(new String[lst.size()]);
} }
} }
} }


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

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

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

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

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

<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"/>

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



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

import org.apache.xmlgraphics.util.QName;

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


/** /**
* Parses any AFP foreign attributes * Parses any AFP foreign attributes
private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp");


/** the resource-name attribute */ /** 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 */ /** 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 */ /** 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 * Main constructor
public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) { public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) {
AFPResourceInfo resourceInfo = new AFPResourceInfo(); AFPResourceInfo resourceInfo = new AFPResourceInfo();
if (foreignAttributes != null && !foreignAttributes.isEmpty()) { 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) { if (resourceName != null) {
resourceInfo.setName(resourceName); resourceInfo.setName(resourceName);
} }
public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) { public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) {
AFPResourceLevel resourceLevel = null; AFPResourceLevel resourceLevel = null;
if (foreignAttributes != null && !foreignAttributes.isEmpty()) { 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); resourceLevel = AFPResourceLevel.valueOf(levelString);
// if external get resource group file attributes // if external get resource group file attributes
if (resourceLevel != null && resourceLevel.isExternal()) { if (resourceLevel != null && resourceLevel.isExternal()) {
QName resourceGroupFileKey = new QName(AFPElementMapping.NAMESPACE,
RESOURCE_GROUP_FILE);
String resourceGroupFile String resourceGroupFile
= (String)foreignAttributes.get(resourceGroupFileKey);
= (String)foreignAttributes.get(RESOURCE_GROUP_FILE);
if (resourceGroupFile == null) { if (resourceGroupFile == null) {
String msg = RESOURCE_GROUP_FILE + " not specified"; String msg = RESOURCE_GROUP_FILE + " not specified";
log.error(msg); log.error(msg);

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

package org.apache.fop.render.afp; package org.apache.fop.render.afp;


import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPUnitConverter; import org.apache.fop.afp.AFPUnitConverter;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerBase;


/** /**
* A base abstract AFP image handler * 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 X = 0;
private static final int Y = 1; private static final int Y = 1;


AFPDataObjectInfo dataObjectInfo = createDataObjectInfo(); AFPDataObjectInfo dataObjectInfo = createDataObjectInfo();


// set resource information // 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(); Point origin = rendererImageInfo.getOrigin();
Rectangle2D position = rendererImageInfo.getPosition(); 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 rendererContext
= (AFPRendererContext)rendererImageInfo.getRendererContext(); = (AFPRendererContext)rendererImageInfo.getRendererContext();
AFPInfo afpInfo = rendererContext.getInfo(); AFPInfo afpInfo = rendererContext.getInfo();
AFPPaintingState paintingState = afpInfo.getPaintingState(); 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(); 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.setX(coords[X]);
objectAreaInfo.setY(coords[Y]); objectAreaInfo.setY(coords[Y]);


int width = Math.round(unitConv.mpt2units((float)position.getWidth()));
int width = Math.round(unitConv.mpt2units(targetRect.width));
objectAreaInfo.setWidth(width); objectAreaInfo.setWidth(width);


int height = Math.round(unitConv.mpt2units((float)position.getHeight()));
int height = Math.round(unitConv.mpt2units(targetRect.height));
objectAreaInfo.setHeight(height); objectAreaInfo.setHeight(height);


int resolution = paintingState.getResolution(); int resolution = paintingState.getResolution();
objectAreaInfo.setWidthRes(resolution); objectAreaInfo.setWidthRes(resolution);


objectAreaInfo.setRotation(paintingState.getRotation()); objectAreaInfo.setRotation(paintingState.getRotation());

dataObjectInfo.setObjectAreaInfo(objectAreaInfo);

return dataObjectInfo;
return objectAreaInfo;
} }


/** /**

+ 67
- 7
src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java View File



package org.apache.fop.render.afp; package org.apache.fop.render.afp;


import java.awt.Rectangle;
import java.io.IOException; import java.io.IOException;


import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.fop.afp.AFPGraphicsObjectInfo; import org.apache.fop.afp.AFPGraphicsObjectInfo;
import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.modca.ResourceObject; 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. * 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[] { private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.GRAPHICS2D ImageFlavor.GRAPHICS2D
AFPGraphicsObjectInfo graphicsObjectInfo AFPGraphicsObjectInfo graphicsObjectInfo
= (AFPGraphicsObjectInfo)super.generateDataObjectInfo(rendererImageInfo); = (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) // set mime type (unsupported by MOD:CA registry)
graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA);


// set g2d // set g2d
boolean textAsShapes = false; boolean textAsShapes = false;

AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes);


graphicsObjectInfo.setGraphics2D(g2d); graphicsObjectInfo.setGraphics2D(g2d);
} }
} }


private void setDefaultResourceLevel(AFPGraphicsObjectInfo graphicsObjectInfo,
AFPResourceManager resourceManager) {
AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo();
if (!resourceInfo.levelChanged()) {
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults()
.getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC));
}
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public int getPriority() { public int getPriority() {
return 200; return 200;
protected AFPDataObjectInfo createDataObjectInfo() { protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPGraphicsObjectInfo(); 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



package org.apache.fop.render.afp; 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.AFPDataObjectInfo;
import org.apache.fop.afp.AFPImageObjectInfo; 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). * AFPImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4).
}; };


/** {@inheritDoc} */ /** {@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(); int compression = ccitt.getCompression();
imageObjectInfo.setCompression(compression); imageObjectInfo.setCompression(compression);


imageObjectInfo.setBitsPerPixel(1); 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} */ /** {@inheritDoc} */
return FLAVORS; 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



package org.apache.fop.render.afp; 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.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.xmlgraphics.image.loader.impl.ImageRawStream;


import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.fop.render.RenderingContext;

/** /**
* AFPImageHandler implementation which handles raw stream images. * AFPImageHandler implementation which handles raw stream images.
*/ */
protected AFPDataObjectInfo createDataObjectInfo() { protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPDataObjectInfo(); 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

package org.apache.fop.render.afp; package org.apache.fop.render.afp;


import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.ColorModel; import java.awt.image.ColorModel;
import java.awt.image.RenderedImage; import java.awt.image.RenderedImage;
import java.io.IOException; import java.io.IOException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; 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.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageSize; import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.fop.afp.AFPObjectAreaInfo; import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.modca.ResourceObject; 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; import org.apache.fop.util.bitmap.BitmapImageUtil;


/** /**
* PDFImageHandler implementation which handles RenderedImage instances. * PDFImageHandler implementation which handles RenderedImage instances.
*/ */
public class AFPImageHandlerRenderedImage extends AFPImageHandler {
public class AFPImageHandlerRenderedImage extends AFPImageHandler implements ImageHandler {


/** logging instance */ /** logging instance */
private static Log log = LogFactory.getLog(AFPImageHandlerRenderedImage.class); private static Log log = LogFactory.getLog(AFPImageHandlerRenderedImage.class);
= (AFPRendererContext)rendererImageInfo.getRendererContext(); = (AFPRendererContext)rendererImageInfo.getRendererContext();
AFPInfo afpInfo = rendererContext.getInfo(); 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(); 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 resolution = paintingState.getResolution();
int maxPixelSize = paintingState.getBitsPerPixel(); int maxPixelSize = paintingState.getBitsPerPixel();
if (paintingState.isColorImages()) { if (paintingState.isColorImages()) {
maxPixelSize *= 3; //RGB only at the moment maxPixelSize *= 3; //RGB only at the moment
} }
ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img;
RenderedImage renderedImage = imageRendered.getRenderedImage(); RenderedImage renderedImage = imageRendered.getRenderedImage();


ImageInfo imageInfo = rendererImageInfo.getImageInfo();
ImageInfo imageInfo = imageRendered.getInfo();
ImageSize intrinsicSize = imageInfo.getSize(); ImageSize intrinsicSize = imageInfo.getSize();


boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage); boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage);
boolean usePageSegments = useFS10 boolean usePageSegments = useFS10
&& !resourceInfo.getLevel().isInline();
&& !imageObjectInfo.getResourceInfo().getLevel().isInline();


ImageSize effIntrinsicSize = intrinsicSize; ImageSize effIntrinsicSize = intrinsicSize;
if (usePageSegments) { if (usePageSegments) {
//Resize, optionally resample and convert image //Resize, optionally resample and convert image
Dimension resampledDim = new Dimension( 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.setCreatePageSegment(true);
imageObjectInfo.getResourceInfo().setImageDimension(resampledDim); imageObjectInfo.getResourceInfo().setImageDimension(resampledDim);
int dataWidth = renderedImage.getWidth(); int dataWidth = renderedImage.getWidth();
imageObjectInfo.setDataWidth(dataWidth); imageObjectInfo.setDataWidth(dataWidth);


//TODO To reduce AFP file size, investigate using a compression scheme.
//Currently, all image data is uncompressed.
ColorModel cm = renderedImage.getColorModel(); ColorModel cm = renderedImage.getColorModel();
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
log.trace("ColorModel: " + cm); log.trace("ColorModel: " + cm);
return imageObjectInfo; 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} */ /** {@inheritDoc} */
protected AFPDataObjectInfo createDataObjectInfo() { protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPImageObjectInfo(); return new AFPImageObjectInfo();
return FLAVORS; 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