Browse Source

Merged back Temp_Accessibility branch into Trunk


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@830293 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Vincent Hennebert 14 years ago
parent
commit
be1d3250bd
100 changed files with 3688 additions and 130 deletions
  1. 7
    0
      build.xml
  2. 1
    0
      src/documentation/content/xdocs/site.xml
  3. 152
    0
      src/documentation/content/xdocs/trunk/accessibility.xml
  4. 16
    4
      src/documentation/content/xdocs/trunk/pdfa.xml
  5. 2
    1
      src/java/META-INF/services/org.apache.fop.fo.ElementMapping
  6. 87
    0
      src/java/org/apache/fop/accessibility/Accessibility.java
  7. 54
    0
      src/java/org/apache/fop/accessibility/AccessibilityEventProducer.java
  8. 4
    0
      src/java/org/apache/fop/accessibility/AccessibilityEventProducer.xml
  9. 95
    0
      src/java/org/apache/fop/accessibility/AccessibilityPreprocessor.java
  10. 102
    0
      src/java/org/apache/fop/accessibility/StructureTree.java
  11. 95
    0
      src/java/org/apache/fop/accessibility/StructureTreeBuilder.java
  12. 88
    0
      src/java/org/apache/fop/accessibility/addPtr.xsl
  13. 100
    0
      src/java/org/apache/fop/accessibility/reduceFOTree.xsl
  14. 50
    0
      src/java/org/apache/fop/apps/FOUserAgent.java
  15. 6
    1
      src/java/org/apache/fop/apps/Fop.java
  16. 18
    0
      src/java/org/apache/fop/apps/FopFactory.java
  17. 9
    0
      src/java/org/apache/fop/apps/FopFactoryConfigurator.java
  18. 89
    15
      src/java/org/apache/fop/area/AreaTreeParser.java
  19. 5
    1
      src/java/org/apache/fop/area/Trait.java
  20. 4
    0
      src/java/org/apache/fop/cli/CommandLineOptions.java
  21. 1
    0
      src/java/org/apache/fop/events/EventFormatter.xml
  22. 9
    1
      src/java/org/apache/fop/fo/Constants.java
  23. 3
    0
      src/java/org/apache/fop/fo/FONode.java
  24. 12
    0
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  25. 12
    1
      src/java/org/apache/fop/fo/FOValidationEventProducer.java
  26. 2
    0
      src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
  27. 1
    1
      src/java/org/apache/fop/fo/extensions/ExternalDocument.java
  28. 73
    0
      src/java/org/apache/fop/fo/extensions/InternalElementMapping.java
  29. 16
    1
      src/java/org/apache/fop/fo/flow/AbstractGraphics.java
  30. 11
    2
      src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java
  31. 11
    2
      src/java/org/apache/fop/fo/flow/Block.java
  32. 9
    1
      src/java/org/apache/fop/fo/flow/Character.java
  33. 9
    1
      src/java/org/apache/fop/fo/flow/Inline.java
  34. 9
    1
      src/java/org/apache/fop/fo/flow/PageNumber.java
  35. 12
    3
      src/java/org/apache/fop/fo/flow/table/TableFObj.java
  36. 34
    0
      src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java
  37. 1
    0
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  38. 11
    0
      src/java/org/apache/fop/layoutmgr/TraitSetter.java
  39. 1
    0
      src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java
  40. 1
    0
      src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java
  41. 6
    4
      src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
  42. 1
    0
      src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
  43. 1
    1
      src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java
  44. 18
    1
      src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
  45. 12
    1
      src/java/org/apache/fop/pdf/PDFAMode.java
  46. 9
    0
      src/java/org/apache/fop/pdf/PDFArray.java
  47. 19
    0
      src/java/org/apache/fop/pdf/PDFDocument.java
  48. 33
    0
      src/java/org/apache/fop/pdf/PDFFactory.java
  49. 13
    0
      src/java/org/apache/fop/pdf/PDFLink.java
  50. 20
    2
      src/java/org/apache/fop/pdf/PDFNumsArray.java
  51. 29
    0
      src/java/org/apache/fop/pdf/PDFPage.java
  52. 44
    0
      src/java/org/apache/fop/pdf/PDFParentTree.java
  53. 26
    3
      src/java/org/apache/fop/pdf/PDFProfile.java
  54. 45
    1
      src/java/org/apache/fop/pdf/PDFRoot.java
  55. 159
    0
      src/java/org/apache/fop/pdf/PDFStructElem.java
  56. 55
    0
      src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
  57. 3
    2
      src/java/org/apache/fop/render/AbstractRendererConfigurator.java
  58. 1
    0
      src/java/org/apache/fop/render/afp/AFPEventProducer.xml
  59. 2
    0
      src/java/org/apache/fop/render/intermediate/IFConstants.java
  60. 47
    0
      src/java/org/apache/fop/render/intermediate/IFContext.java
  61. 108
    20
      src/java/org/apache/fop/render/intermediate/IFParser.java
  62. 33
    3
      src/java/org/apache/fop/render/intermediate/IFRenderer.java
  63. 36
    3
      src/java/org/apache/fop/render/intermediate/IFSerializer.java
  64. 17
    0
      src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java
  65. 9
    0
      src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java
  66. 150
    0
      src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java
  67. 109
    1
      src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
  68. 43
    8
      src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
  69. 8
    3
      src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
  70. 16
    2
      src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
  71. 7
    1
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
  72. 7
    1
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
  73. 12
    3
      src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
  74. 299
    0
      src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
  75. 71
    20
      src/java/org/apache/fop/render/pdf/PDFPainter.java
  76. 87
    8
      src/java/org/apache/fop/render/pdf/PDFRenderer.java
  77. 9
    0
      src/java/org/apache/fop/render/pdf/PDFRenderingContext.java
  78. 6
    1
      src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
  79. 2
    1
      src/java/org/apache/fop/render/txt/TXTRenderer.java
  80. 19
    1
      src/java/org/apache/fop/render/xml/XMLRenderer.java
  81. 9
    1
      src/java/org/apache/fop/util/DOM2SAX.java
  82. 160
    0
      src/java/org/apache/fop/util/TransformerDefaultHandler.java
  83. 36
    0
      src/java/org/apache/fop/util/XMLUtil.java
  84. 3
    2
      src/sandbox/org/apache/fop/render/svg/SVGPainter.java
  85. 3
    0
      status.xml
  86. 52
    0
      test/accessibility/README
  87. 34
    0
      test/accessibility/background-image_jpg_repeat.fo
  88. 36
    0
      test/accessibility/background-image_jpg_single.fo
  89. 34
    0
      test/accessibility/background-image_png_repeat.fo
  90. 36
    0
      test/accessibility/background-image_png_single.fo
  91. 34
    0
      test/accessibility/background-image_svg_repeat.fo
  92. 36
    0
      test/accessibility/background-image_svg_single.fo
  93. 205
    0
      test/accessibility/complete.fo
  94. 23
    0
      test/accessibility/config-painter.xconf
  95. 24
    0
      test/accessibility/config-renderer.xconf
  96. 35
    0
      test/accessibility/image_jpg.fo
  97. 35
    0
      test/accessibility/image_png.fo
  98. 45
    0
      test/accessibility/image_svg.fo
  99. 35
    0
      test/accessibility/image_wmf.fo
  100. 0
    0
      test/accessibility/leader.fo

+ 7
- 0
build.xml View File

<include name="**/*.java"/> <include name="**/*.java"/>
<exclude name="org/apache/fop/render/*/**/*.java"/> <exclude name="org/apache/fop/render/*/**/*.java"/>
<exclude name="org/apache/fop/afp/**/*.java"/> <exclude name="org/apache/fop/afp/**/*.java"/>
<exclude name="org/apache/fop/accessibility/**/*.java"/>
</fileset> </fileset>
</eventResourceGenerator> </eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/events/EventFormatter.xml" tab="remove" tablength="2"/> <fixcrlf file="${src.java.dir}/org/apache/fop/events/EventFormatter.xml" tab="remove" tablength="2"/>
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/accessibility/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/accessibility/AccessibilityEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/accessibility/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml" tab="remove" tablength="2"/>
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/afp/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml"> <eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/afp/event-model.xml" translationfile="${src.java.dir}/org/apache/fop/afp/AFPEventProducer.xml">
<fileset dir="${src.java.dir}"> <fileset dir="${src.java.dir}">
<include name="org/apache/fop/afp/**/*.java"/> <include name="org/apache/fop/afp/**/*.java"/>

+ 1
- 0
src/documentation/content/xdocs/site.xml View File

<extensions label="Extensions" href="extensions.html"/> <extensions label="Extensions" href="extensions.html"/>
<events label="Events" href="events.html"/> <events label="Events" href="events.html"/>
<metadata label="Metadata" href="metadata.html"/> <metadata label="Metadata" href="metadata.html"/>
<accessibility label="Accessibility" href="accessibility.html"/>
</features> </features>
</trunk> </trunk>

+ 152
- 0
src/documentation/content/xdocs/trunk/accessibility.xml View File

<?xml version="1.0" 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$ -->
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "document-v20.dtd">
<document>
<header>
<title>Accessibility</title>
</header>
<body>
<section id="overview">
<title>Overview</title>
<p>
This page describes the
<a href="http://en.wikipedia.org/wiki/Accessibility">accessibility</a>
features of Apache FOP.
<a href="http://www.section508.gov/">Section 508</a> defines accessibility in the context
of electronic documents for the USA but other countries have similar requirements.
</p>
<p>
Accessibility features are available only for the PDF output format and there are some
implementation limitations. Also, certain actions must be undertaken by the content creator
to ensure that FOP can create a truly accessible document.
</p>
</section>
<section>
<title>Enabling accessibility</title>
<p>There are 3 ways to enable accessibility:</p>
<ol>
<li>
<strong>Command line:</strong> The command line option -a turns on accessibility:
<code>fop -a -fo mydocument.fo -pdf mydocument.pdf</code>
</li>
<li>
<strong>Embedding:</strong> <code>userAgent.setAccessibility(true);</code>
</li>
<li>
<strong>Optional setting in fop.xconf file:</strong>
<pre>
&lt;fop version="1.0"&gt;
&lt;accessibility&gt;true&lt;/accessibility&gt;
...
&lt;/fop&gt;
</pre>
</li>
</ol>
<p>
When accessibility is enabled, additional information relating to the logical structure of
the document is added to the PDF. That information allows the PDF viewer (or a
text-to-speech application) to retrieve the natural reading order of the document.
</p>
<note>The processing of the logical structure is memory-hungry. You may need to adjust the
Java heap size in order to process larger files.</note>
</section>
<section id="source">
<title>Changes to your XSL-FO input files</title>
<p>
Apache FOP cannot automatically generate accessible PDFs. Some of the work can only be
performed by the content provider. Following are some changes that may be necessary to
your XSL-FO content in order to generate really accessible documents:
</p>
<ul>
<li>Table cells must have a table row as their parent.</li>
<li>
Images must have an alternate text: use the <code>fox:alt-text</code> extension attribute
(in the <a href="extensions.html#fox-namespace">fox namespace</a>) on
<code>fo:external-graphic</code> and <code>fo:instream-foreign-object</code> to specify a
short text describing the image.
</li>
<li>
Ensure that the order of <code>fo:block-container</code> elements in a page corresponds to
the reading order.
</li>
<li>
Specify the natural language of the document using the language and country properties
(or via the <code>xml:lang</code> shorthand property).
</li>
</ul>
</section>
<section id="testing">
<title>Testing</title>
<p>
Accessible PDFs can be tested, for example, using Adobe Acrobat Professional. Its
Accessibility Check feature creates a report indicating any deficiencies with a PDF
document. Alternatively, you can just let a screen reader read the document aloud.
</p>
</section>
<section id="limitations">
<title>Limitations</title>
<p>
Accessibility support in Apache FOP is relatively new, so there are certain
limitations. Please help us identify and close any gaps.
</p>
<ul>
<li>
The natural language can currently only be specified at the page-sequence level. The
document language is derived from the language of the first page-sequence. It is
currently not possible to override the language inside the content below the
page-sequence level.
</li>
<li>
It's currently not possible to specify the expanded form of an abbreviation or acronym.
</li>
<li>
SVG graphics (or images in general) are treated as a single figure. Text contained in
SVGs is not accessible. It's only possible to work with <code>fox:alt-text</code>.
</li>
<li>
XSL-FO's role property is currently not supported. It could theoretically be used to
differentiate between headings and normal text. At the moment, the two are simply
identified as paragraphs.
</li>
<li>
The side regions (region-before, region-after etc.) are currently not specially
identified. Screen readers may read their content at page changes.
</li>
</ul>
</section>
<section id="links">
<title>Related Links</title>
<p>
Many resources providing guidance about creating accessible documents can be found on the
web. Here are a few links, along with additional resources around the topic:
</p>
<ul>
<li><a href="http://www.section508.gov/">US Government - Website on Section 508</a></li>
<li><a href="http://en.wikipedia.org/wiki/Accessibility">Wikipedia on Accessibility in general</a></li>
<li><a href="http://en.wikipedia.org/wiki/Portable_Document_Format#Accessibility">Wikipedia on Accessibility in PDF</a></li>
<li>
<a href="http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf">PDF
Reference 1.4</a> (look up chapters 9.7 "Tagged PDF" and 9.8 "Accessibility Support")
</li>
<li><a href="pdfa.html">PDF/A support in Apache FOP</a></li>
<li><a href="http://wiki.apache.org/xmlgraphics-fop/PDF_Accessibility">Developer-oriented details on the accessibility features (on the Wiki)</a></li>
</ul>
</section>
</body>
</document>

+ 16
- 4
src/documentation/content/xdocs/trunk/pdfa.xml View File

lack of a full license to get a detailed error protocol. lack of a full license to get a detailed error protocol.
</p> </p>
<p> <p>
<strong>PDF/A-1a</strong> is not implemented, yet. This is mostly because of the requirement
for tagged PDF which is not available in FOP, yet.
<strong>PDF/A-1a</strong> is based on PDF-A-1b and adds accessibility features
(such as Tagged PDF). This format is available within the limitation described on
the <a href="accessibility.html">Accessibility page</a>.
</p> </p>
</section> </section>
<section id="command-line"> <section id="command-line">
as a parameter. If there is a violation of one of the validation rules for as a parameter. If there is a violation of one of the validation rules for
PDF/A, an error message is presented and the processing stops. PDF/A, an error message is presented and the processing stops.
</p> </p>
<p>
PDF/A-1a is enabled by specifying "-pdfprofile PDF/A-1a".
</p>
</section> </section>
<section id="embedded"> <section id="embedded">
<title>Usage (embedded)</title> <title>Usage (embedded)</title>
If one of the validation rules of PDF/A is violated, an PDFConformanceException If one of the validation rules of PDF/A is violated, an PDFConformanceException
(descendant of RuntimeException) is thrown. (descendant of RuntimeException) is thrown.
</p> </p>
<p>
For PDF/A-1a, just use the string "PDF/A-1a" instead of "PDF/A-1b".
</p>
</section> </section>
<section id="rules"> <section id="rules">
<title>PDF/A in Action</title> <title>PDF/A in Action</title>
embedded in clear text so non-PDF-aware applications can extract the XMP metadata. embedded in clear text so non-PDF-aware applications can extract the XMP metadata.
</li> </li>
</ul> </ul>
<note>
There are additional requirements if you want to enabled PDF/A-1a (Tagged PDF). This is
particularly the specification of the natural language and alternative descriptions for
images. Please refer to the <a href="accessibility.html">Accessibility page</a> for details.
</note>
</section> </section>
<section id="profile-compatibility"> <section id="profile-compatibility">
<title>PDF profile compatibility</title> <title>PDF profile compatibility</title>
<p> <p>
The PDF profiles "PDF/X-3:2003" and "PDF/A-1b" are compatible and can both be
activated at the same time.
The PDF profiles "PDF/X-3:2003" and "PDF/A-1b" (or "PDF/A-1a") are compatible and can
both be activated at the same time.
</p> </p>
</section> </section>
<section id="interoperability"> <section id="interoperability">

+ 2
- 1
src/java/META-INF/services/org.apache.fop.fo.ElementMapping View File

org.apache.fop.fo.extensions.svg.SVGElementMapping org.apache.fop.fo.extensions.svg.SVGElementMapping
org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping
org.apache.fop.fo.extensions.ExtensionElementMapping org.apache.fop.fo.extensions.ExtensionElementMapping
org.apache.fop.fo.extensions.InternalElementMapping
org.apache.fop.fo.extensions.OldExtensionElementMapping org.apache.fop.fo.extensions.OldExtensionElementMapping
org.apache.fop.fo.extensions.xmp.XMPElementMapping org.apache.fop.fo.extensions.xmp.XMPElementMapping
org.apache.fop.fo.extensions.xmp.RDFElementMapping org.apache.fop.fo.extensions.xmp.RDFElementMapping
org.apache.fop.render.ps.extensions.PSExtensionElementMapping org.apache.fop.render.ps.extensions.PSExtensionElementMapping
org.apache.fop.render.afp.extensions.AFPElementMapping org.apache.fop.render.afp.extensions.AFPElementMapping
org.apache.fop.render.pcl.extensions.PCLElementMapping
org.apache.fop.render.pcl.extensions.PCLElementMapping

+ 87
- 0
src/java/org/apache/fop/accessibility/Accessibility.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.accessibility;

import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.helpers.DefaultHandler;

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

/**
* Helper class for FOP's accessibility features.
*/
public final class Accessibility {

/** Constant string for the rendering options key to enable accessibility features. */
public static final String ACCESSIBILITY = "accessibility";

// TODO what if the default factory is not a SAXTransformerFactory?
private static SAXTransformerFactory tfactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();

private static Templates addPtrTemplates;

private static Templates reduceFOTreeTemplates;

private Accessibility() { }

/**
* Decorates the given handler so the structure tree used for accessibility
* features can be branched off the main content stream.
* @param handler the handler to decorate
* @param userAgent the user agent
* @return the decorated handler
* @throws FOPException if an error occurs setting up the decoration
*/
public static DefaultHandler decorateDefaultHandler(DefaultHandler handler,
FOUserAgent userAgent) throws FOPException {
try {
setupTemplates();
TransformerHandler addPtr = tfactory.newTransformerHandler(addPtrTemplates);
Transformer reduceFOTree = reduceFOTreeTemplates.newTransformer();
return new AccessibilityPreprocessor(addPtr, reduceFOTree, userAgent, handler);
} catch (TransformerConfigurationException e) {
throw new FOPException(e);
}
}

private static synchronized void setupTemplates() throws TransformerConfigurationException {
if (addPtrTemplates == null) {
addPtrTemplates = loadTemplates("addPtr.xsl");
}
if (reduceFOTreeTemplates == null) {
reduceFOTreeTemplates = loadTemplates("reduceFOTree.xsl");
}
}

private static Templates loadTemplates(String source) throws TransformerConfigurationException {
Source src = new StreamSource(Accessibility.class.getResource(source).toExternalForm());
return tfactory.newTemplates(src);
}

}

+ 54
- 0
src/java/org/apache/fop/accessibility/AccessibilityEventProducer.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.accessibility;

import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.events.EventProducer;

/**
* Event producer for accessibility-related events.
*/
public interface AccessibilityEventProducer extends EventProducer {

/** Provider class for the event producer. */
public final class Provider {

private Provider() { }

/**
* Returns an event producer.
*
* @param broadcaster the event broadcaster to use
* @return the event producer
*/
public static AccessibilityEventProducer get(EventBroadcaster broadcaster) {
return (AccessibilityEventProducer) broadcaster.getEventProducerFor(
AccessibilityEventProducer.class);
}
}

/**
* The structure tree is missing in the XML file.
*
* @param source the event source
* @event.severity FATAL
*/
void noStructureTreeInXML(Object source);
}

+ 4
- 0
src/java/org/apache/fop/accessibility/AccessibilityEventProducer.xml View File

<?xml version="1.0" encoding="UTF-8"?>
<catalogue xml:lang="en">
<message key="org.apache.fop.accessibility.AccessibilityEventProducer.noStructureTreeInXML">Accessibility is enabled but structure tree is missing in XML file. Please disable accessibility, or re-generate XML file in accessibility mode.</message>
</catalogue>

+ 95
- 0
src/java/org/apache/fop/accessibility/AccessibilityPreprocessor.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.accessibility;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

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

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

/**
* This class prepares an XSL-FO document for accessibility. It adds a unique
* identifier to every applicable FO, then creates the structure tree, before
* handing the document over to the regular handler.
*/
class AccessibilityPreprocessor extends TransformerDefaultHandler {

private final ByteArrayOutputStream enrichedFOBuffer = new ByteArrayOutputStream();

private final Transformer reduceFOTree;

private final FOUserAgent userAgent;

private final DefaultHandler fopHandler;

public AccessibilityPreprocessor(TransformerHandler addPtr, Transformer reduceFOTree,
FOUserAgent userAgent, DefaultHandler fopHandler) {
super(addPtr);
this.reduceFOTree = reduceFOTree;
this.userAgent = userAgent;
this.fopHandler = fopHandler;
getTransformerHandler().setResult(new StreamResult(enrichedFOBuffer));
}

/** {@inheritDoc} */
public void endDocument() throws SAXException {
super.endDocument();
// do the second transform to struct
try {
//TODO this must be optimized, no buffering (ex. SAX-based tee-proxy)
byte[] enrichedFO = enrichedFOBuffer.toByteArray();
Source src = new StreamSource(new ByteArrayInputStream(enrichedFO));
DOMResult res = new DOMResult();
reduceFOTree.transform(src, res);
StructureTree structureTree = new StructureTree();
NodeList pageSequences = res.getNode().getFirstChild().getChildNodes();
for (int i = 0; i < pageSequences.getLength(); i++) {
structureTree.addPageSequenceStructure(pageSequences.item(i).getChildNodes());
}
userAgent.setStructureTree(structureTree);

SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
saxParserFactory.setValidating(false);
SAXParser saxParser = saxParserFactory.newSAXParser();
InputStream in = new ByteArrayInputStream(enrichedFO);
saxParser.parse(in, fopHandler);
} catch (Exception e) {
throw new SAXException(e);
}
}

}

+ 102
- 0
src/java/org/apache/fop/accessibility/StructureTree.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.accessibility;

import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* A reduced version of the document's FO tree, containing only its logical
* structure. Used by accessible output formats.
*/
public final class StructureTree {

private final List pageSequenceStructures = new ArrayList();

/**
* Package-private default constructor.
*/
StructureTree() { }

private static boolean flowOrStaticContentNodes(NodeList nodes) {
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE) {
return false;
}
String name = node.getLocalName();
if (!(name.equals("flow") || name.equals("static-content"))) {
return false;
}
}
return true;
}

void addPageSequenceStructure(NodeList structureTree) {
assert flowOrStaticContentNodes(structureTree);
pageSequenceStructures.add(structureTree);
}

/**
* Returns the list of nodes that are the children of the given page sequence.
*
* @param index index of the page sequence, 0-based
* @return its children nodes
*/
public NodeList getPageSequence(int index) {
return (NodeList) pageSequenceStructures.get(index);
}

/**
* Returns an XML-like representation of the structure trees.
* <p>
* <strong>Note:</strong> use only for debugging purpose, as this method
* performs non-trivial operations.
* </p>
* @return a string representation of this object
*/
public String toString() {
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
Writer str = new StringWriter();
for (Iterator iter = pageSequenceStructures.iterator(); iter.hasNext();) {
NodeList nodes = (NodeList) iter.next();
for (int i = 0, c = nodes.getLength(); i < c; i++) {
t.transform(new DOMSource(nodes.item(i)), new StreamResult(str));
}
}
return str.toString();
} catch (Exception e) {
return e.toString();
}
}

}

+ 95
- 0
src/java/org/apache/fop/accessibility/StructureTreeBuilder.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.accessibility;

import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import org.apache.fop.util.DelegatingContentHandler;

/**
* Helper class that re-builds a structure tree from what is stored in an
* intermediate XML file (IF XML or Area Tree XML).
*/
public final class StructureTreeBuilder {

private final SAXTransformerFactory factory;

private final StructureTree structureTree = new StructureTree();

/**
* Creates a new instance.
*
* @param factory a factory internally used to build the structures of page
* sequences
*/
public StructureTreeBuilder(SAXTransformerFactory factory) {
this.factory = factory;
}

/**
* Returns the structure tree that will result from the parsing.
*
* @return the structure tree built by this object
*/
public StructureTree getStructureTree() {
return structureTree;
}

/**
* Returns a ContenHandler for parsing the structure of a new page sequence.
* It is assumed that page sequences are being parsed in the document order.
*
* @return a handler for parsing the &lt;structure-tree&gt; or
* &lt;structureTree&gt; element and its descendants
* @throws SAXException if there is an error when creating the handler
*/
public ContentHandler getHandlerForNextPageSequence() throws SAXException {
TransformerHandler structureTreeBuilder;
try {
structureTreeBuilder = factory.newTransformerHandler();
} catch (TransformerConfigurationException e) {
throw new SAXException(e);
}
final DOMResult domResult = new DOMResult();
structureTreeBuilder.setResult(domResult);
return new DelegatingContentHandler(structureTreeBuilder) {

public void characters(char[] ch, int start, int length) throws SAXException {
/*
* There's no text node in the structure tree. This is just
* whitespace => ignore
*/
}

public void endDocument() throws SAXException {
super.endDocument();
structureTree.addPageSequenceStructure(domResult.getNode().getFirstChild()
.getChildNodes());
}
};
}

}

+ 88
- 0
src/java/org/apache/fop/accessibility/addPtr.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:fo="http://www.w3.org/1999/XSL/Format"
xmlns:foi="http://xmlgraphics.apache.org/fop/internal">

<xsl:template name="addPtr">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="foi:ptr">
<xsl:value-of select="generate-id()"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<!-- Block-level Formatting Objects -->
<xsl:template match="fo:block|fo:block-container">
<xsl:call-template name="addPtr"/>
</xsl:template>

<!-- Inline-level Formatting Objects -->
<xsl:template match="fo:character|fo:inline|fo:inline-container">
<xsl:call-template name="addPtr"/>
</xsl:template>

<xsl:template match="fo:external-graphic|fo:instream-foreign-object">
<xsl:call-template name="addPtr"/>
</xsl:template>

<xsl:template match="fo:page-number|fo:page-number-citation|fo:page-number-citation-last">
<xsl:call-template name="addPtr"/>
</xsl:template>

<!-- Formatting Objects for Tables -->
<xsl:template match="fo:table-and-caption|fo:table-caption|fo:table">
<xsl:call-template name="addPtr"/>
</xsl:template>

<xsl:template match="fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell">
<xsl:call-template name="addPtr"/>
</xsl:template>

<!-- Formatting Objects for Lists -->
<xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body">
<xsl:call-template name="addPtr"/>
</xsl:template>

<!-- Dynamic Effects: Link and Multi Formatting Objects -->
<xsl:template match="fo:basic-link">
<xsl:call-template name="addPtr"/>
</xsl:template>

<!-- Out-of-Line Formatting Objects -->
<xsl:template match="fo:float|fo:footnote|fo:footnote-body">
<xsl:call-template name="addPtr"/>
</xsl:template>

<!-- Other Formatting Objects -->
<xsl:template match="fo:wrapper|fo:marker">
<xsl:call-template name="addPtr"/>
</xsl:template>


<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

+ 100
- 0
src/java/org/apache/fop/accessibility/reduceFOTree.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:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
xmlns:foi="http://xmlgraphics.apache.org/fop/internal">

<xsl:output method="xml" indent="no"/>

<xsl:template name="copy">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!-- Declarations and Pagination and Layout Formatting Objects -->
<xsl:template match="fo:root|fo:page-sequence|fo:static-content|fo:flow">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Block-level Formatting Objects -->
<xsl:template match="fo:block|fo:block-container">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Inline-level Formatting Objects -->
<xsl:template match="fo:character|fo:inline|fo:inline-container">
<xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="fo:external-graphic|fo:instream-foreign-object">
<xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="fo:page-number|fo:page-number-citation|fo:page-number-citation-last">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Formatting Objects for Tables -->
<xsl:template match="fo:table-and-caption|fo:table-caption|fo:table">
<xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Formatting Objects for Lists -->
<xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Dynamic Effects: Link and Multi Formatting Objects -->
<xsl:template match="fo:basic-link">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Out-of-Line Formatting Objects -->
<xsl:template match="fo:float|fo:footnote|fo:footnote-body">
<xsl:call-template name="copy"/>
</xsl:template>

<!-- Other Formatting Objects -->
<xsl:template match="fo:wrapper|fo:marker">
<xsl:call-template name="copy"/>
</xsl:template>


<!-- Discard descendants of fo:leader -->
<xsl:template match="fo:leader"/>

<!-- Keep foi:ptr and fox:alt-text attributes, discard everything else -->
<xsl:template match="@foi:ptr|@fox:alt-text">
<xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="@*"/>


<!-- Discard text -->
<xsl:template match="text()"/>

</xsl:stylesheet>

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

import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;


import org.apache.fop.Version; import org.apache.fop.Version;
import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.accessibility.StructureTree;
import org.apache.fop.events.DefaultEventBroadcaster; import org.apache.fop.events.DefaultEventBroadcaster;
import org.apache.fop.events.Event; import org.apache.fop.events.Event;
import org.apache.fop.events.EventBroadcaster; import org.apache.fop.events.EventBroadcaster;
private boolean conserveMemoryPolicy = false; private boolean conserveMemoryPolicy = false;
private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster(); private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster();


private StructureTree structureTree;

/** Producer: Metadata element for the system/software that produces /** Producer: Metadata element for the system/software that produces
* the document. (Some renderers can store this in the document.) * the document. (Some renderers can store this in the document.)
*/ */
this.factory = factory; this.factory = factory;
setBaseURL(factory.getBaseURL()); setBaseURL(factory.getBaseURL());
setTargetResolution(factory.getTargetResolution()); setTargetResolution(factory.getTargetResolution());
setAccessibility(factory.isAccessibilityEnabled());
} }


/** @return the associated FopFactory instance */ /** @return the associated FopFactory instance */
return rendererOverride; return rendererOverride;
} }



/** /**
* Sets an explicit FOEventHandler instance which overrides the one * Sets an explicit FOEventHandler instance which overrides the one
* defined by the render type setting. * defined by the render type setting.
this.conserveMemoryPolicy = conserveMemoryPolicy; this.conserveMemoryPolicy = conserveMemoryPolicy;
} }


/**
* Activates accessibility (for output formats that support it).
*
* @param accessibility <code>true</code> to enable accessibility support
*/
public void setAccessibility(boolean accessibility) {
if (accessibility) {
getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE);
}
}

/**
* Check if accessibility is enabled.
* @return true if accessibility is enabled
*/
public boolean isAccessibilityEnabled() {
Boolean enabled = (Boolean)this.getRendererOptions().get(Accessibility.ACCESSIBILITY);
if (enabled != null) {
return enabled.booleanValue();
} else {
return false;
}
}

/**
* Sets the document's structure tree, for use by accessible output formats.
*
* @param structureTree a simplified version of the FO tree, retaining only
* its logical structure
*/
public void setStructureTree(StructureTree structureTree) {
this.structureTree = structureTree;
}

/**
* Returns the document's structure tree, for use by accessible output
* formats.
*
* @return a simplified version of the FO tree, retaining only its logical
* structure
*/
public StructureTree getStructureTree() {
return this.structureTree;
}
} }



+ 6
- 1
src/java/org/apache/fop/apps/Fop.java View File



import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;


import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.fo.FOTreeBuilder; import org.apache.fop.fo.FOTreeBuilder;


/** /**
if (foTreeBuilder == null) { if (foTreeBuilder == null) {
createDefaultHandler(); createDefaultHandler();
} }
return this.foTreeBuilder;
if (this.foUserAgent.isAccessibilityEnabled()) {
return Accessibility.decorateDefaultHandler(this.foTreeBuilder, foUserAgent);
} else {
return this.foTreeBuilder;
}
} }


/** /**

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

*/ */
private String base = null; private String base = null;


/**
* Controls if accessibility is turned on or off
*/
private boolean accessibility = false;

/** The base URL for all hyphen URL resolutions. */ /** The base URL for all hyphen URL resolutions. */
private String hyphenBase = null; private String hyphenBase = null;


return userAgent; return userAgent;
} }


/**
* Sets accessibility support.
*
* @param value <code>true</code> to enable accessibility, <code>false</code> otherwise
*/
void setAccessibility(boolean value) {
this.accessibility = value;
}

boolean isAccessibilityEnabled() {
return accessibility;
}

/** /**
* Returns a new {@link Fop} instance. FOP will be configured with a default user agent * Returns a new {@link Fop} instance. FOP will be configured with a default user agent
* instance. * instance.

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

log.debug("Initializing FopFactory Configuration"); log.debug("Initializing FopFactory Configuration");
} }


if (cfg.getChild("accessibility", false) != null) {
try {
this.factory.setAccessibility(
cfg.getChild("accessibility").getValueAsBoolean());
} catch (ConfigurationException e) {
throw new FOPException(e);
}
}

// strict configuration // strict configuration
if (cfg.getChild("strict-configuration", false) != null) { if (cfg.getChild("strict-configuration", false) != null) {
try { try {

+ 89
- 15
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.DOMImplementation; import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;


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

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


import org.apache.fop.accessibility.AccessibilityEventProducer;
import org.apache.fop.accessibility.StructureTreeBuilder;
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.fop.util.DelegatingContentHandler;
import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.XMLUtil; import org.apache.fop.util.XMLUtil;


/** /**
private Locator locator; private Locator locator;




private StructureTreeBuilder structureTreeBuilder;

private ContentHandler structureTreeBuilderWrapper;

private Attributes pageSequenceAttributes;

private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {

private StructureTreeBuilderWrapper()
throws SAXException {
super(structureTreeBuilder.getHandlerForNextPageSequence());
}

public void endDocument() throws SAXException {
super.endDocument();
startAreaTreeElement("pageSequence", pageSequenceAttributes);
pageSequenceAttributes = null;
}
}

public Handler(AreaTreeModel treeModel, FOUserAgent userAgent, public Handler(AreaTreeModel treeModel, FOUserAgent userAgent,
ElementMappingRegistry elementMappingRegistry) { ElementMappingRegistry elementMappingRegistry) {
this.treeModel = treeModel; this.treeModel = treeModel;
makers.put("bookmarkTree", new BookmarkTreeMaker()); makers.put("bookmarkTree", new BookmarkTreeMaker());
makers.put("bookmark", new BookmarkMaker()); makers.put("bookmark", new BookmarkMaker());
makers.put("destination", new DestinationMaker()); makers.put("destination", new DestinationMaker());

if (userAgent.isAccessibilityEnabled()) {
structureTreeBuilder = new StructureTreeBuilder(tFactory);
userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
}
} }


private Area findAreaType(Class clazz) { private Area findAreaType(Class clazz) {
delegate.startDocument(); delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes); delegate.startElement(uri, localName, qName, attributes);
} else { } else {
lastAttributes = new AttributesImpl(attributes);
boolean handled = true; boolean handled = true;
if ("".equals(uri)) { if ("".equals(uri)) {
Maker maker = (Maker)makers.get(localName);
content.clear();
ignoreCharacters = true;
if (maker != null) {
ignoreCharacters = maker.ignoreCharacters();
maker.startElement(attributes);
} else if ("extension-attachments".equals(localName)) {
//TODO implement me
if (localName.equals("pageSequence") && userAgent.isAccessibilityEnabled()) {
structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
pageSequenceAttributes = new AttributesImpl(attributes);
} else if (localName.equals("structureTree")) {
if (userAgent.isAccessibilityEnabled()) {
delegate = structureTreeBuilderWrapper;
} else {
/* Delegate to a handler that does nothing */
delegate = new DefaultHandler();
}
delegateStack.push(qName);
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else { } else {
handled = false;
if (pageSequenceAttributes != null) {
/*
* This means that no structure-element tag was
* found in the XML, otherwise a
* StructureTreeBuilderWrapper object would have
* been created, which would have reset the
* pageSequenceAttributes field.
*/
AccessibilityEventProducer.Provider
.get(userAgent.getEventBroadcaster())
.noStructureTreeInXML(this);
}
handled = startAreaTreeElement(localName, attributes);
} }
} else { } else {
ContentHandlerFactoryRegistry registry ContentHandlerFactoryRegistry registry
} }
} }


private boolean startAreaTreeElement(String localName, Attributes attributes)
throws SAXException {
lastAttributes = new AttributesImpl(attributes);
Maker maker = (Maker)makers.get(localName);
content.clear();
ignoreCharacters = true;
if (maker != null) {
ignoreCharacters = maker.ignoreCharacters();
maker.startElement(attributes);
} else if ("extension-attachments".equals(localName)) {
//TODO implement me
} else {
return false;
}
return true;
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public void endElement(String uri, String localName, String qName) throws SAXException { public void endElement(String uri, String localName, String qName) throws SAXException {
if (delegate != null) { if (delegate != null) {
setTraits(attributes, ip, SUBSET_BOX); setTraits(attributes, ip, SUBSET_BOX);
setTraits(attributes, ip, SUBSET_COLOR); setTraits(attributes, ip, SUBSET_COLOR);
setTraits(attributes, ip, SUBSET_LINK); setTraits(attributes, ip, SUBSET_LINK);
setPtr(ip, attributes);
Area parent = (Area)areaStack.peek(); Area parent = (Area)areaStack.peek();
parent.addChildArea(ip); parent.addChildArea(ip);
areaStack.push(ip); areaStack.push(ip);
"tlsadjust", 0)); "tlsadjust", 0));
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes, text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
"twsadjust", 0)); "twsadjust", 0));
setPtr(text, attributes);
Area parent = (Area)areaStack.peek(); Area parent = (Area)areaStack.peek();
parent.addChildArea(text); parent.addChildArea(text);
areaStack.push(text); areaStack.push(text);
viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos")); viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos"));
viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false)); viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false));
viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setPtr(viewport, attributes);
Area parent = (Area)areaStack.peek(); Area parent = (Area)areaStack.peek();
parent.addChildArea(viewport); parent.addChildArea(viewport);
areaStack.push(viewport); areaStack.push(viewport);
transferForeignObjects(attributes, image); transferForeignObjects(attributes, image);
setAreaAttributes(attributes, image); setAreaAttributes(attributes, image);
setTraits(attributes, image, SUBSET_COMMON); setTraits(attributes, image, SUBSET_COMMON);
setPtr(image, attributes);
getCurrentViewport().setContent(image); getCurrentViewport().setContent(image);
} }
} }
ExtensionAttachment attachment = (ExtensionAttachment)obj; ExtensionAttachment attachment = (ExtensionAttachment)obj;
ato.addExtensionAttachment(attachment); ato.addExtensionAttachment(attachment);
} else { } else {
log.warn("Don't know how to handle externally generated object: " + obj);
}
log.warn("Don't know how to handle externally generated object: " + obj);
} }
} }
}


private void setAreaAttributes(Attributes attributes, Area area) { private void setAreaAttributes(Attributes attributes, Area area) {
area.setIPD(Integer.parseInt(attributes.getValue("ipd"))); area.setIPD(Integer.parseInt(attributes.getValue("ipd")));
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);
if (ns.length() > 0) { if (ns.length() > 0) {
if ("http://www.w3.org/2000/xmlns/".equals(ns)) {
if (XMLConstants.XMLNS_NAMESPACE_URI.equals(ns)) {
continue; continue;
} }
QName qname = new QName(ns, atts.getQName(i)); QName qname = new QName(ns, atts.getQName(i));
} }
} }


private void setPtr(Area area, Attributes attributes) {
String ptr = attributes.getValue("ptr");
if (ptr != null) {
area.addTrait(Trait.PTR, ptr);
}
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException { public void characters(char[] ch, int start, int length) throws SAXException {
if (delegate != null) { if (delegate != null) {

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

public static final Integer OVERLINE_COLOR = new Integer(35); public static final Integer OVERLINE_COLOR = new Integer(35);
/** Trait for color of linethrough decorations when rendering inline parent. */ /** Trait for color of linethrough decorations when rendering inline parent. */
public static final Integer LINETHROUGH_COLOR = new Integer(36); public static final Integer LINETHROUGH_COLOR = new Integer(36);
/** The ptr trait. Used for accessibility */
public static final Integer PTR = new Integer(37);


/** Maximum value used by trait keys */ /** Maximum value used by trait keys */
public static final int MAX_TRAIT_KEY = 36;
public static final int MAX_TRAIT_KEY = 37;


private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1]; private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1];


static { static {
// Create a hashmap mapping trait code to name for external representation // Create a hashmap mapping trait code to name for external representation
//put(ID_LINK, new TraitInfo("id-link", String.class)); //put(ID_LINK, new TraitInfo("id-link", String.class));
put(PTR, new TraitInfo("ptr", String.class));
put(INTERNAL_LINK, new TraitInfo("internal-link", InternalLink.class)); put(INTERNAL_LINK, new TraitInfo("internal-link", InternalLink.class));
put(EXTERNAL_LINK, new TraitInfo("external-link", ExternalLink.class)); put(EXTERNAL_LINK, new TraitInfo("external-link", ExternalLink.class));
put(FONT, new TraitInfo("font", FontTriplet.class)); put(FONT, new TraitInfo("font", FontTriplet.class));

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

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.accessibility.Accessibility;
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;
i = i + parseAreaTreeOption(args, i); i = i + parseAreaTreeOption(args, i);
} else if (args[i].equals("-if")) { } else if (args[i].equals("-if")) {
i = i + parseIntermediateFormatOption(args, i); i = i + parseIntermediateFormatOption(args, i);
} else if (args[i].equals("-a")) {
this.renderingOptions.put(Accessibility.ACCESSIBILITY, Boolean.TRUE);
} else if (args[i].equals("-v")) { } else if (args[i].equals("-v")) {
/* Currently just print the version */ /* Currently just print the version */
printVersion(); printVersion();
+ " -nocopy PDF file will be encrypted without copy content permission\n" + " -nocopy PDF file will be encrypted without copy content permission\n"
+ " -noedit PDF file will be encrypted without edit content permission\n" + " -noedit PDF file will be encrypted without edit content permission\n"
+ " -noannotations PDF file will be encrypted without edit annotation permission\n" + " -noannotations PDF file will be encrypted without edit annotation permission\n"
+ " -a enables accessibility features (Tagged PDF etc., default off)\n"
+ " -pdfprofile prof PDF file will be generated with the specified profile\n" + " -pdfprofile prof PDF file will be generated with the specified profile\n"
+ " (Examples for prof: PDF/A-1b or PDF/X-3:2003)\n\n" + " (Examples for prof: PDF/A-1b or PDF/X-3:2003)\n\n"
+ " -conserve Enable memory-conservation policy (trades memory-consumption for disk I/O)\n" + " -conserve Enable memory-conservation policy (trades memory-consumption for disk I/O)\n"

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

<message key="org.apache.fop.fonts.FontEventAdapter.fontSubstituted">Font "{requested}" not found. Substituting with "{effective}".</message> <message key="org.apache.fop.fonts.FontEventAdapter.fontSubstituted">Font "{requested}" not found. Substituting with "{effective}".</message>
<message key="org.apache.fop.fonts.FontEventAdapter.fontLoadingErrorAtAutoDetection">Unable to load font file: {fontURL}.[ Reason: {e}]</message> <message key="org.apache.fop.fonts.FontEventAdapter.fontLoadingErrorAtAutoDetection">Unable to load font file: {fontURL}.[ Reason: {e}]</message>
<message key="org.apache.fop.fonts.FontEventAdapter.glyphNotAvailable">Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}".</message> <message key="org.apache.fop.fonts.FontEventAdapter.glyphNotAvailable">Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}".</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.altTextMissing">Alternate text is missing on {foElement}.{{locator}}</message>
</catalogue> </catalogue>

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

* multi-column layouts. * multi-column layouts.
*/ */
int PR_X_DISABLE_COLUMN_BALANCING = 273; int PR_X_DISABLE_COLUMN_BALANCING = 273;
/** Property constant - FOP proprietary: FOP internal use for accessibility */
int PR_X_PTR = 274;
/**
* Property constant - FOP proprietary: alternative text for e-g and i-f-o.
* Used for accessibility.
*/
int PR_X_ALT_TEXT = 275;

/** Number of property constants defined */ /** Number of property constants defined */
int PROPERTY_COUNT = 273;
int PROPERTY_COUNT = 275;


// compound property constants // compound property constants



+ 3
- 0
src/java/org/apache/fop/fo/FONode.java View File

import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.fo.extensions.svg.SVGElementMapping; import org.apache.fop.fo.extensions.svg.SVGElementMapping;
import org.apache.fop.fo.pagination.Root; import org.apache.fop.fo.pagination.Root;
import org.apache.fop.util.CharUtilities; import org.apache.fop.util.CharUtilities;
return "fo:" + localName; return "fo:" + localName;
} else if (namespaceURI.equals(ExtensionElementMapping.URI)) { } else if (namespaceURI.equals(ExtensionElementMapping.URI)) {
return "fox:" + localName; return "fox:" + localName;
} else if (namespaceURI.equals(InternalElementMapping.URI)) {
return "foi:" + localName; // used FOP internally for accessibility
} else if (namespaceURI.equals(SVGElementMapping.URI)) { } else if (namespaceURI.equals(SVGElementMapping.URI)) {
return "svg:" + localName; return "svg:" + localName;
} else { } else {

+ 12
- 0
src/java/org/apache/fop/fo/FOPropertyMapping.java View File

m.setDefault(""); m.setDefault("");
addPropertyMaker("id", m); addPropertyMaker("id", m);


// foi:ptr, used for accessibility
m = new StringProperty.Maker(PR_X_PTR);
m.setInherited(false);
m.setDefault("");
addPropertyMaker("foi:ptr", m);

// fox:alt-text, used for accessibility
m = new StringProperty.Maker(PR_X_ALT_TEXT);
m.setInherited(false);
m.setDefault("");
addPropertyMaker("fox:alt-text", m);

// provisional-label-separation // provisional-label-separation
m = new LengthProperty.Maker(PR_PROVISIONAL_LABEL_SEPARATION); m = new LengthProperty.Maker(PR_PROVISIONAL_LABEL_SEPARATION);
m.setInherited(true); m.setInherited(true);

+ 12
- 1
src/java/org/apache/fop/fo/FOValidationEventProducer.java View File

/** /**
* Provider class for the event producer. * Provider class for the event producer.
*/ */
class Provider {
final class Provider {

private Provider() { }


/** /**
* Returns an event producer. * Returns an event producer.
void unknownFormattingObject(Object source, String elementName, void unknownFormattingObject(Object source, String elementName,
QName offendingNode, Locator loc); QName offendingNode, Locator loc);


/**
* Alternate text is missing for a graphic element.
*
* @param source the event source
* @param foElement name of the element (external-graphic or instream-foreign-object)
* @param loc the location of the error or null
* @event.severity WARN
*/
void altTextMissing(Object source, String foElement, Locator loc);
} }

+ 2
- 0
src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java View File

propertyAttributes.add("orphan-content-limit"); propertyAttributes.add("orphan-content-limit");
propertyAttributes.add("internal-destination"); propertyAttributes.add("internal-destination");
propertyAttributes.add("disable-column-balancing"); propertyAttributes.add("disable-column-balancing");
//These are FOP's extension properties for accessibility
propertyAttributes.add("alt-text");
} }


/** /**

+ 1
- 1
src/java/org/apache/fop/fo/extensions/ExternalDocument.java View File

import org.apache.fop.fo.properties.LengthRangeProperty; import org.apache.fop.fo.properties.LengthRangeProperty;


/** /**
* Class for the fox:external-document extenstion element.
* Class for the fox:external-document extension element.
*/ */
public class ExternalDocument extends AbstractPageSequence implements GraphicsProperties { public class ExternalDocument extends AbstractPageSequence implements GraphicsProperties {



+ 73
- 0
src/java/org/apache/fop/fo/extensions/InternalElementMapping.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.fo.extensions;

import java.util.HashMap;
import java.util.Set;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.fo.ElementMapping;

/**
* Element mapping for FOP's internal extension to XSL-FO.
*/
public class InternalElementMapping extends ElementMapping {

/** The FOP extension namespace URI */
public static final String URI = "http://xmlgraphics.apache.org/fop/internal";

private static final Set PROPERTY_ATTRIBUTES = new java.util.HashSet();

static {
//These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add("ptr");
}

/**
* Constructor.
*/
public InternalElementMapping() {
namespaceURI = URI;
}

/**
* Initialize the data structures.
*/
protected void initialize() {
if (foObjs == null) {
foObjs = new HashMap();
}
}

/** {@inheritDoc} */
public String getStandardPrefix() {
return "foi";
}

/** {@inheritDoc} */
public boolean isAttributeProperty(QName attributeName) {
if (!URI.equals(attributeName.getNamespaceURI())) {
throw new IllegalArgumentException("The namespace URIs don't match");
}
return PROPERTY_ATTRIBUTES.contains(attributeName.getLocalName());
}

}

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

import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.LengthRangeProperty; import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.fo.properties.SpaceProperty; import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;


/** /**
* Common base class for the <a href="http://www.w3.org/TR/xsl/#fo_instream-foreign-object"> * Common base class for the <a href="http://www.w3.org/TR/xsl/#fo_instream-foreign-object">
* and <a href="http://www.w3.org/TR/xsl/#fo_external-graphic"> * and <a href="http://www.w3.org/TR/xsl/#fo_external-graphic">
* <code>fo:external-graphic</code></a> flow formatting objects. * <code>fo:external-graphic</code></a> flow formatting objects.
*/ */
public abstract class AbstractGraphics extends FObj implements GraphicsProperties {
public abstract class AbstractGraphics extends FObj
implements GraphicsProperties, StructurePointerPropertySet {


// The value of properties relevant for fo:instream-foreign-object // The value of properties relevant for fo:instream-foreign-object
// and external-graphics. // and external-graphics.
private int scaling; private int scaling;
private int textAlign; private int textAlign;
private Length width; private Length width;
private String ptr; // used for accessibility
// Unused but valid items, commented out for performance: // Unused but valid items, commented out for performance:
// private CommonAccessibility commonAccessibility; // private CommonAccessibility commonAccessibility;
// private CommonAural commonAural; // private CommonAural commonAural;
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum();
height = pList.get(PR_HEIGHT).getLength(); height = pList.get(PR_HEIGHT).getLength();
id = pList.get(PR_ID).getString(); id = pList.get(PR_ID).getString();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange(); inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange();
keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep();
keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep();
scaling = pList.get(PR_SCALING).getEnum(); scaling = pList.get(PR_SCALING).getEnum();
textAlign = pList.get(PR_TEXT_ALIGN).getEnum(); textAlign = pList.get(PR_TEXT_ALIGN).getEnum();
width = pList.get(PR_WIDTH).getLength(); width = pList.get(PR_WIDTH).getLength();
if (getUserAgent().isAccessibilityEnabled()) {
String altText = pList.get(PR_X_ALT_TEXT).getString();
if (altText.equals("")) {
getFOValidationEventProducer().altTextMissing(this, getLocalName(), getLocator());
}
}
} }


/** /**
return keepWithPrevious; return keepWithPrevious;
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** @return the graphic's intrinsic width in millipoints */ /** @return the graphic's intrinsic width in millipoints */
public abstract int getIntrinsicWidth(); public abstract int getIntrinsicWidth();



+ 11
- 2
src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java View File



import java.awt.Color; import java.awt.Color;


import org.xml.sax.Locator;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.Locator;


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.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.SpaceProperty; import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;


/** /**
* Common base class for the <a href="http://www.w3.org/TR/xsl/#fo_page-number-citation"> * Common base class for the <a href="http://www.w3.org/TR/xsl/#fo_page-number-citation">
* <a href="http://www.w3.org/TR/xsl/#fo_page-number-citation-last"> * <a href="http://www.w3.org/TR/xsl/#fo_page-number-citation-last">
* <code>fo:page-number-citation-last</code></a> objects. * <code>fo:page-number-citation-last</code></a> objects.
*/ */
public abstract class AbstractPageNumberCitation extends FObj {
public abstract class AbstractPageNumberCitation extends FObj
implements StructurePointerPropertySet {


// The value of properties relevant for fo:page-number-citation(-last). // The value of properties relevant for fo:page-number-citation(-last).
private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonBorderPaddingBackground commonBorderPaddingBackground;
private int alignmentBaseline; private int alignmentBaseline;
private Length baselineShift; private Length baselineShift;
private int dominantBaseline; private int dominantBaseline;
private String ptr; // used for accessibility
// private ToBeImplementedProperty letterSpacing; // private ToBeImplementedProperty letterSpacing;
private SpaceProperty lineHeight; private SpaceProperty lineHeight;
private String refId; private String refId;
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum();
// letterSpacing = pList.get(PR_LETTER_SPACING); // letterSpacing = pList.get(PR_LETTER_SPACING);
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
refId = pList.get(PR_REF_ID).getString(); refId = pList.get(PR_REF_ID).getString();
textDecoration = pList.getTextDecorationProps(); textDecoration = pList.getTextDecorationProps();
// textShadow = pList.get(PR_TEXT_SHADOW); // textShadow = pList.get(PR_TEXT_SHADOW);
return textDecoration; return textDecoration;
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** @return the "alignment-adjust" property */ /** @return the "alignment-adjust" property */
public Length getAlignmentAdjust() { public Length getAlignmentAdjust() {
return alignmentAdjust; return alignmentAdjust;

+ 11
- 2
src/java/org/apache/fop/fo/flow/Block.java View File



import java.awt.Color; import java.awt.Color;


import org.xml.sax.Locator;

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.datatypes.Numeric; import org.apache.fop.datatypes.Numeric;
import org.apache.fop.fo.properties.CommonRelativePosition; import org.apache.fop.fo.properties.CommonRelativePosition;
import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.SpaceProperty; import org.apache.fop.fo.properties.SpaceProperty;
import org.xml.sax.Locator;
import org.apache.fop.fo.properties.StructurePointerPropertySet;


/** /**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_block"> * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_block">
* <code>fo:block object</code></a>. * <code>fo:block object</code></a>.
*/ */
public class Block extends FObjMixed implements BreakPropertySet {
public class Block extends FObjMixed implements BreakPropertySet, StructurePointerPropertySet {


// used for FO validation // used for FO validation
private boolean blockOrInlineItemFound = false; private boolean blockOrInlineItemFound = false;
private int lineHeightShiftAdjustment; private int lineHeightShiftAdjustment;
private int lineStackingStrategy; private int lineStackingStrategy;
private Numeric orphans; private Numeric orphans;
private String ptr; //used for accessibility
private int whiteSpaceTreatment; private int whiteSpaceTreatment;
private int span; private int span;
private int textAlign; private int textAlign;
lineHeightShiftAdjustment = pList.get(PR_LINE_HEIGHT_SHIFT_ADJUSTMENT).getEnum(); lineHeightShiftAdjustment = pList.get(PR_LINE_HEIGHT_SHIFT_ADJUSTMENT).getEnum();
lineStackingStrategy = pList.get(PR_LINE_STACKING_STRATEGY).getEnum(); lineStackingStrategy = pList.get(PR_LINE_STACKING_STRATEGY).getEnum();
orphans = pList.get(PR_ORPHANS).getNumeric(); orphans = pList.get(PR_ORPHANS).getNumeric();
ptr = pList.get(PR_X_PTR).getString(); //used for accessibility
whiteSpaceTreatment = pList.get(PR_WHITE_SPACE_TREATMENT).getEnum(); whiteSpaceTreatment = pList.get(PR_WHITE_SPACE_TREATMENT).getEnum();
span = pList.get(PR_SPAN).getEnum(); span = pList.get(PR_SPAN).getEnum();
textAlign = pList.get(PR_TEXT_ALIGN).getEnum(); textAlign = pList.get(PR_TEXT_ALIGN).getEnum();
return breakAfter; return breakAfter;
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** @return the "break-before" property. */ /** @return the "break-before" property. */
public int getBreakBefore() { public int getBreakBefore() {
return breakBefore; return breakBefore;

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

import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.SpaceProperty; import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;


/** /**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_character"> * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_character">
* <code>fo:character</code></a> object. * <code>fo:character</code></a> object.
*/ */
public class Character extends FObj {
public class Character extends FObj implements StructurePointerPropertySet {
// The value of properties relevant for fo:character. // The value of properties relevant for fo:character.
private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonBorderPaddingBackground commonBorderPaddingBackground;
private CommonFont commonFont; private CommonFont commonFont;
private CommonTextDecoration textDecoration; private CommonTextDecoration textDecoration;
// private ToBeImplementedProperty textShadow; // private ToBeImplementedProperty textShadow;
private Property wordSpacing; private Property wordSpacing;
private String ptr; // used for accessibility
// Unused but valid items, commented out for performance: // Unused but valid items, commented out for performance:
// private CommonAural commonAural; // private CommonAural commonAural;
// private CommonMarginInline commonMarginInline; // private CommonMarginInline commonMarginInline;
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
textDecoration = pList.getTextDecorationProps(); textDecoration = pList.getTextDecorationProps();
wordSpacing = pList.get(PR_WORD_SPACING); wordSpacing = pList.get(PR_WORD_SPACING);
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
return keepWithPrevious; return keepWithPrevious;
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public String getLocalName() { public String getLocalName() {
return "character"; return "character";

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

import org.apache.fop.fo.FONode; import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.properties.StructurePointerPropertySet;


/** /**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_inline"> * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_inline">
* <code>fo:inline</code></a> formatting object. * <code>fo:inline</code></a> formatting object.
*/ */
public class Inline extends InlineLevel {
public class Inline extends InlineLevel implements StructurePointerPropertySet {
// The value of properties relevant for fo:inline. // The value of properties relevant for fo:inline.
// See also superclass InlineLevel // See also superclass InlineLevel
private Length alignmentAdjust; private Length alignmentAdjust;
private int alignmentBaseline; private int alignmentBaseline;
private Length baselineShift; private Length baselineShift;
private String ptr; // used for accessibility
private int dominantBaseline; private int dominantBaseline;
// Unused but valid items, commented out for performance: // Unused but valid items, commented out for performance:
// private CommonRelativePosition commonRelativePosition; // private CommonRelativePosition commonRelativePosition;
alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum();
baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength();
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
return dominantBaseline; return dominantBaseline;
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public String getLocalName() { public String getLocalName() {
return "inline"; return "inline";

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

import org.apache.fop.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.SpaceProperty; import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;


/** /**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_page-number"> * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_page-number">
* <code>fo:page-number</code></a> object. * <code>fo:page-number</code></a> object.
*/ */
public class PageNumber extends FObj {
public class PageNumber extends FObj implements StructurePointerPropertySet {
// The value of properties relevant for fo:page-number. // The value of properties relevant for fo:page-number.
private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonBorderPaddingBackground commonBorderPaddingBackground;
private CommonFont commonFont; private CommonFont commonFont;
private int alignmentBaseline; private int alignmentBaseline;
private Length baselineShift; private Length baselineShift;
private int dominantBaseline; private int dominantBaseline;
private String ptr; // used for accessibility
// private ToBeImplementedProperty letterSpacing; // private ToBeImplementedProperty letterSpacing;
private SpaceProperty lineHeight; private SpaceProperty lineHeight;
/** Holds the text decoration values. May be null */ /** Holds the text decoration values. May be null */
// letterSpacing = pList.get(PR_LETTER_SPACING); // letterSpacing = pList.get(PR_LETTER_SPACING);
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
textDecoration = pList.getTextDecorationProps(); textDecoration = pList.getTextDecorationProps();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
// textShadow = pList.get(PR_TEXT_SHADOW); // textShadow = pList.get(PR_TEXT_SHADOW);


// implicit properties // implicit properties
return lineHeight; return lineHeight;
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public String getLocalName() { public String getLocalName() {
return "page-number"; return "page-number";

+ 12
- 3
src/java/org/apache/fop/fo/flow/table/TableFObj.java View File



package org.apache.fop.fo.flow.table; package org.apache.fop.fo.flow.table;


import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Numeric; import org.apache.fop.datatypes.Numeric;
import org.apache.fop.datatypes.ValidationPercentBaseContext; import org.apache.fop.datatypes.ValidationPercentBaseContext;
import org.apache.fop.fo.properties.NumberProperty; import org.apache.fop.fo.properties.NumberProperty;
import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.PropertyMaker; import org.apache.fop.fo.properties.PropertyMaker;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.layoutmgr.table.CollapsingBorderModel; import org.apache.fop.layoutmgr.table.CollapsingBorderModel;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;


/** /**
* Common base class for table-related FOs * Common base class for table-related FOs
*/ */
public abstract class TableFObj extends FObj {
public abstract class TableFObj extends FObj implements StructurePointerPropertySet {


private Numeric borderAfterPrecedence; private Numeric borderAfterPrecedence;
private Numeric borderBeforePrecedence; private Numeric borderBeforePrecedence;
private Numeric borderEndPrecedence; private Numeric borderEndPrecedence;
private Numeric borderStartPrecedence; private Numeric borderStartPrecedence;
private String ptr;


ConditionalBorder borderBefore; ConditionalBorder borderBefore;
ConditionalBorder borderAfter; ConditionalBorder borderAfter;
borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric();
borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric();
borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric();
ptr = pList.get(PR_X_PTR).getString();
if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java
&& getNameId() != FO_TABLE_CELL && getNameId() != FO_TABLE_CELL
&& getCommonBorderPaddingBackground().hasPadding( && getCommonBorderPaddingBackground().hasPadding(
} }
} }


/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** /**
* Prepares the borders of this element if the collapsing-border model is in use. * Prepares the borders of this element if the collapsing-border model is in use.
* Conflict resolution with parent elements is done where applicable. * Conflict resolution with parent elements is done where applicable.

+ 34
- 0
src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.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.fo.properties;

/**
* Defines property access methods for internal structure pointer extension properties.
*/
public interface StructurePointerPropertySet {

/**
* Returns the value of the "foi:ptr" property, the internal structure pointer used
* for tagged PDF and other formats that support a structure tree in addition to paged content.
* @return the "foi:ptr" property
*/
String getPtr();

}

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



addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); addMarkersToPage(false, isFirst(firstPos), isLast(lastPos));


TraitSetter.addPtr(curBlockArea, getBlockFO().getPtr()); // used for accessibility
TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter); effSpaceBefore, effSpaceAfter);
flush(); flush();

+ 11
- 0
src/java/org/apache/fop/layoutmgr/TraitSetter.java View File

} }
} }


/**
* Adds the ptr trait to the area.
* @param area the area to set the traits on
* @param ptr string
*/
public static void addPtr(Area area, String ptr) {
if (ptr != null && ptr.length() > 0) {
area.addTrait(Trait.PTR, ptr);
}
}
/** /**
* Sets the producer's ID as a trait on the area. This can be used to track back the * Sets the producer's ID as a trait on the area. This can be used to track back the
* generating FO node. * generating FO node.

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

transferForeignAttributes(viewportArea); transferForeignAttributes(viewportArea);


Viewport vp = new Viewport(viewportArea); Viewport vp = new Viewport(viewportArea);
TraitSetter.addPtr(vp, fobj.getPtr()); // used for accessibility
TraitSetter.setProducerID(vp, fobj.getId()); TraitSetter.setProducerID(vp, fobj.getId());
vp.setIPD(imageLayout.getViewportSize().width); vp.setIPD(imageLayout.getViewportSize().width);
vp.setBPD(imageLayout.getViewportSize().height); vp.setBPD(imageLayout.getViewportSize().height);

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

text.setBaselineOffset(font.getAscender()); text.setBaselineOffset(font.getAscender());
TraitSetter.addFontTraits(text, font); TraitSetter.addFontTraits(text, font);
text.addTrait(Trait.COLOR, fobj.getColor()); text.addTrait(Trait.COLOR, fobj.getColor());
TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility
TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); TraitSetter.addTextDecoration(text, fobj.getTextDecoration());
} }



+ 6
- 4
src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java View File



package org.apache.fop.layoutmgr.inline; package org.apache.fop.layoutmgr.inline;


import org.apache.fop.area.LinkResolver;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.datatypes.URISpecification; import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.Constants; import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.layoutmgr.PageSequenceLayoutManager; import org.apache.fop.layoutmgr.PageSequenceLayoutManager;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.Trait;
import org.apache.fop.area.LinkResolver;
import org.apache.fop.layoutmgr.TraitSetter;


/** /**
* LayoutManager for the fo:basic-link formatting object * LayoutManager for the fo:basic-link formatting object
private void setupBasicLinkArea(InlineArea area) { private void setupBasicLinkArea(InlineArea area) {
BasicLink fobj = (BasicLink) this.fobj; BasicLink fobj = (BasicLink) this.fobj;
// internal destinations take precedence: // internal destinations take precedence:
TraitSetter.addPtr(area, fobj.getPtr()); // used for accessibility
if (fobj.hasInternalDestination()) { if (fobj.hasInternalDestination()) {
String idref = fobj.getInternalDestination(); String idref = fobj.getInternalDestination();
PageSequenceLayoutManager pslm = getPSLM(); PageSequenceLayoutManager pslm = getPSLM();

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

} }
TraitSetter.setProducerID(text, node.getId()); TraitSetter.setProducerID(text, node.getId());
TraitSetter.addTextDecoration(text, node.getTextDecoration()); TraitSetter.addTextDecoration(text, node.getTextDecoration());
TraitSetter.addPtr(text, node.getPtr()); // used for accessibility
return text; return text;
} }



+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java View File

text.setBaselineOffset(font.getAscender()); text.setBaselineOffset(font.getAscender());
TraitSetter.addFontTraits(text, font); TraitSetter.addFontTraits(text, font);
text.addTrait(Trait.COLOR, fobj.getColor()); text.addTrait(Trait.COLOR, fobj.getColor());
TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility
TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); TraitSetter.addTextDecoration(text, fobj.getTextDecoration());


return text; return text;

+ 18
- 1
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.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.area.Trait; import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.TextArea; import org.apache.fop.area.inline.TextArea;
import org.apache.fop.fo.Constants; import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FOText; import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fonts.Font; import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontSelector; import org.apache.fop.fonts.FontSelector;
import org.apache.fop.layoutmgr.InlineKnuthSequence; import org.apache.fop.layoutmgr.InlineKnuthSequence;
} }
TraitSetter.addFontTraits(textArea, font); TraitSetter.addFontTraits(textArea, font);
textArea.addTrait(Trait.COLOR, this.foText.getColor()); textArea.addTrait(Trait.COLOR, this.foText.getColor());
TraitSetter.addPtr(textArea, getPtr()); // used for accessibility
TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration()); TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration());


return textArea; return textArea;
} }


/**
* used for accessibility
* @return ptr of fobj
*/
private String getPtr() {
FObj fobj = this.parentLM.getFObj();
if (fobj instanceof StructurePointerPropertySet) {
return (((StructurePointerPropertySet) fobj).getPtr());
} else {
//No structure pointer applicable
return null;
}
}

private void addToLetterAdjust(final int index, final int width) { private void addToLetterAdjust(final int index, final int width) {
if (this.letterAdjustArray[index] == null) { if (this.letterAdjustArray[index] == null) {
this.letterAdjustArray[index] = new MinOptMax(width); this.letterAdjustArray[index] = new MinOptMax(width);

+ 12
- 1
src/java/org/apache/fop/pdf/PDFAMode.java View File

return this.name; return this.name;
} }


/** @return true if this mode obey the restrictions established by PDF/A-1b. */
/**
* Indicates whether this mode obeys the restrictions established by PDF/A-1a.
* @return true if this mode obeys the restrictions established by PDF/A-1a.
*/
public boolean isPDFA1LevelA() {
return (this != DISABLED);
}

/**
* Indicates whether this mode obeys the restrictions established by PDF/A-1b.
* @return true if this mode obeys the restrictions established by PDF/A-1b.
*/
public boolean isPDFA1LevelB() { public boolean isPDFA1LevelB() {
return (this != DISABLED); return (this != DISABLED);
//PDF/A-1a is a superset of PDF/A-1b! //PDF/A-1a is a superset of PDF/A-1b!

+ 9
- 0
src/java/org/apache/fop/pdf/PDFArray.java View File

} }
} }


/**
* Indicates whether the given object exists in the array.
* @param obj the object to look for
* @return true if obj is contained
*/
public boolean contains(Object obj) {
return this.values.contains(obj);
}

/** /**
* Returns the length of the array * Returns the length of the array
* @return the length of the array * @return the length of the array

+ 19
- 0
src/java/org/apache/fop/pdf/PDFDocument.java View File

return this.root; return this.root;
} }


/**
* Makes sure a Lang entry has been set on the document catalog, setting it
* to a default value if necessary. When accessibility is enabled the
* language must be specified for any text element in the document.
*/
public void enforceLanguageOnRoot() {
if (root.getLanguage() == null) {
String fallbackLanguage;
if (getProfile().getPDFAMode().isPDFA1LevelA()) {
//According to Annex B of ISO-19005-1:2005(E), section B.2
fallbackLanguage = "x-unknown";
} else {
//No language has been set on the first page-sequence, so fall back to "en".
fallbackLanguage = "en";
}
root.setLanguage(fallbackLanguage);
}
}

/** /**
* Get the {@link PDFInfo} object for this document. * Get the {@link PDFInfo} object for this document.
* *

+ 33
- 0
src/java/org/apache/fop/pdf/PDFFactory.java View File

public PDFPage makePage(PDFResources resources, int pageIndex, public PDFPage makePage(PDFResources resources, int pageIndex,
Rectangle2D mediaBox, Rectangle2D cropBox, Rectangle2D mediaBox, Rectangle2D cropBox,
Rectangle2D bleedBox, Rectangle2D trimBox) { Rectangle2D bleedBox, Rectangle2D trimBox) {
/*
* create a PDFPage with the next object number, the given
* resources, contents and dimensions
*/
PDFPage page = new PDFPage(resources, pageIndex, mediaBox, cropBox, bleedBox, trimBox); PDFPage page = new PDFPage(resources, pageIndex, mediaBox, cropBox, bleedBox, trimBox);


getDocument().assignObjectNumber(page); getDocument().assignObjectNumber(page);
return pageLabels; return pageLabels;
} }


/**
* Creates and returns a StructTreeRoot object. Used for accessibility.
* @param parentTree the value of the ParenTree entry
* @return structure Tree Root element
*/
public PDFStructTreeRoot makeStructTreeRoot(PDFParentTree parentTree) {
PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot(parentTree);
getDocument().assignObjectNumber(structTreeRoot);
getDocument().addTrailerObject(structTreeRoot);
getDocument().getRoot().setStructTreeRoot(structTreeRoot);
return structTreeRoot;
}

/**
* Creates and returns a StructElem object.
*
* @param structureType the structure type of the new element (value for the
* S entry)
* @param parent the parent of the new structure element in the structure
* hierarchy
* @return the newly created element
*/
public PDFStructElem makeStructureElement(PDFName structureType, PDFObject parent) {
PDFStructElem structElem = new PDFStructElem(parent, structureType);
getDocument().assignObjectNumber(structElem);
getDocument().addTrailerObject(structElem);
return structElem;
}

/** /**
* Make a the head object of the name dictionary (the /Dests object). * Make a the head object of the name dictionary (the /Dests object).
* *

+ 13
- 0
src/java/org/apache/fop/pdf/PDFLink.java View File

private float bry; private float bry;
private String color; private String color;
private PDFAction action; private PDFAction action;
private Integer structParent;


/** /**
* create objects associated with a link annotation (GoToR) * create objects associated with a link annotation (GoToR)
this.action = action; this.action = action;
} }



/**
* Sets the value of the StructParent entry for this link.
*
* @param structParent key in the structure parent tree
*/
public void setStructParent(int structParent) {
this.structParent = new Integer(structParent);
}

/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
+ (brx) + " " + (bry) + " ]\n" + "/C [ " + (brx) + " " + (bry) + " ]\n" + "/C [ "
+ this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A " + this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A "
+ this.action.getAction() + "\n" + "/H /I\n" + this.action.getAction() + "\n" + "/H /I\n"
+ (this.structParent != null
? "/StructParent " + this.structParent.toString() + "\n" : "")
+ fFlag + "\n>>\nendobj\n"; + fFlag + "\n>>\nendobj\n";
return s; return s;
} }

+ 20
- 2
src/java/org/apache/fop/pdf/PDFNumsArray.java View File

return this.map.size(); return this.map.size();
} }


/**
* Sets an entry.
* @param key the key of the value to set
* @param obj the new value
*/
public void put(Integer key, Object obj) {
this.map.put(key, obj);
}

/** /**
* Sets an entry. * Sets an entry.
* @param key the key of the value to set * @param key the key of the value to set
* @param obj the new value * @param obj the new value
*/ */
public void put(int key, Object obj) { public void put(int key, Object obj) {
this.map.put(new Integer(key), obj);
put(new Integer(key), obj);
}

/**
* Gets an entry.
* @param key the key of requested value
* @return the requested value
*/
public Object get(Integer key) {
return this.map.get(key);
} }


/** /**
* @return the requested value * @return the requested value
*/ */
public Object get(int key) { public Object get(int key) {
return this.map.get(new Integer(key));
return get(new Integer(key));
} }


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

+ 29
- 0
src/java/org/apache/fop/pdf/PDFPage.java View File

return this.pageIndex; return this.pageIndex;
} }


/**
* Sets the "StructParents" value.
* @param structParents the integer key of this object's entry in the structural parent tree.
*/
public void setStructParents(int structParents) {
put("StructParents", structParents);
//This is a PDF 1.5 feature. It is set as a work-around for a bug in Adobe Acrobat
//which reports this missing even if the PDF file is PDF 1.4.
setTabs(new PDFName("S"));
}

/**
* Returns the value of the StructParents entry.
*
* @return the StructParents value, <code>null</code> if the entry has not been set
*/
public Integer getStructParents() {
return (Integer) get("StructParents");
}

/**
* Specifies the tab order for annotations on a page.
* @param value one of the allowed values (see PDF 1.5)
* @since PDF 1.5
*/
public void setTabs(PDFName value) {
put("Tabs", value);
}

} }

+ 44
- 0
src/java/org/apache/fop/pdf/PDFParentTree.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.pdf;

/**
* Class representing a PDF /ParentTree.
*/
public class PDFParentTree extends PDFNumberTreeNode {

/**
* Returns the number tree corresponding to this parent tree.
*
* @return the number tree
*/
public PDFNumsArray getNums() {
PDFNumsArray nums = super.getNums();
if (nums == null) {
nums = new PDFNumsArray(this);
setNums(nums);
}
return nums;
}
}





+ 26
- 3
src/java/org/apache/fop/pdf/PDFProfile.java View File

*/ */
protected void validateProfileCombination() { protected void validateProfileCombination() {
if (pdfAMode != PDFAMode.DISABLED) { if (pdfAMode != PDFAMode.DISABLED) {
if (pdfAMode == PDFAMode.PDFA_1A) {
throw new UnsupportedOperationException("PDF/A-1a is not implemented, yet");
}
if (pdfAMode == PDFAMode.PDFA_1B) { if (pdfAMode == PDFAMode.PDFA_1B) {
if (pdfXMode != PDFXMode.DISABLED && pdfXMode != PDFXMode.PDFX_3_2003) { if (pdfXMode != PDFXMode.DISABLED && pdfXMode != PDFXMode.PDFX_3_2003) {
throw new PDFConformanceException( throw new PDFConformanceException(
} }
} }


/**
* Checks a few things required for tagged PDF.
*/
public void verifyTaggedPDF() {
if (getPDFAMode().isPDFA1LevelA()) {
final String err = "{0} requires the {1} dictionary entry to be set";
PDFDictionary markInfo = getDocument().getRoot().getMarkInfo();
if (markInfo == null) {
throw new PDFConformanceException(format(
"{0} requires the MarkInfo dictionary to be present", getPDFAMode()));
}
if (!Boolean.TRUE.equals(markInfo.get("Marked"))) {
throw new PDFConformanceException(format(err,
new Object[] {getPDFAMode(), "Marked"}));
}
if (getDocument().getRoot().getStructTreeRoot() == null) {
throw new PDFConformanceException(format(err,
new Object[] {getPDFAMode(), "StructTreeRoot"}));
}
if (getDocument().getRoot().getLanguage() == null) {
throw new PDFConformanceException(format(err,
new Object[] {getPDFAMode(), "Lang"}));
}
}
}

/** @return true if the ID entry must be present in the trailer. */ /** @return true if the ID entry must be present in the trailer. */
public boolean isIDEntryRequired() { public boolean isIDEntryRequired() {
return isPDFAActive() || isPDFXActive(); return isPDFAActive() || isPDFXActive();

+ 45
- 1
src/java/org/apache/fop/pdf/PDFRoot.java View File



package org.apache.fop.pdf; package org.apache.fop.pdf;


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

/** /**
* Class representing a Root (/Catalog) object. * Class representing a Root (/Catalog) object.
*/ */
* object must be created before the PDF document is * object must be created before the PDF document is
* generated, but it is not assigned an object ID until * generated, but it is not assigned an object ID until
* it is about to be written (immediately before the xref * it is about to be written (immediately before the xref
* table as part of the trsailer). (mark-fop@inomial.com)
* table as part of the trailer). (mark-fop@inomial.com)
* *
* @param objnum the object's number * @param objnum the object's number
* @param pages the PDFPages object * @param pages the PDFPages object
setRootPages(pages); setRootPages(pages);
} }


/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
getDocument().getProfile().verifyTaggedPDF();
return super.output(stream);
}

/** /**
* Set the page mode for the PDF document. * Set the page mode for the PDF document.
* *
put("Lang", lang); put("Lang", lang);
} }


/**
* Sets the StructTreeRoot object. Used for accessibility.
* @param structTreeRoot of this document
*/
public void setStructTreeRoot(PDFStructTreeRoot structTreeRoot) {
if (structTreeRoot == null) {
throw new NullPointerException("structTreeRoot must not be null");
}
put("StructTreeRoot", structTreeRoot);
}

/**
* Returns the StructTreeRoot object.
* @return the structure tree root (or null if accessibility is not enabled)
*/
public PDFStructTreeRoot getStructTreeRoot() {
return (PDFStructTreeRoot)get("StructTreeRoot");
}

/**
* Marks this document as conforming to the Tagged PDF conventions.
*/
public void makeTagged() {
PDFDictionary dict = new PDFDictionary();
dict.put("Marked", Boolean.TRUE);
put("MarkInfo", dict); //new PDFMarkInfo()
}

/**
* Returns the MarkInfo dictionary.
* @return the MarkInfo dictionary (or null if it's not present)
*/
public PDFDictionary getMarkInfo() {
return (PDFDictionary)get("MarkInfo");
}
} }

+ 159
- 0
src/java/org/apache/fop/pdf/PDFStructElem.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.pdf;

import java.util.Locale;

import org.apache.fop.util.XMLUtil;

/**
* Class representing a PDF Structure Element.
*/
public class PDFStructElem extends PDFDictionary {

private PDFStructElem parentElement;

/**
* Creates a new structure element.
*
* @param parent parent of this element
* @param structureType the structure type of this element
*/
PDFStructElem(PDFObject parent, PDFName structureType) {
if (parent instanceof PDFStructElem) {
parentElement = (PDFStructElem) parent;
}
put("Type", new PDFName("StructElem"));
put("S", structureType);
setParent(parent);
}

/**
* Returns the parent of this structure element.
*
* @return the parent, <code>null</code> if the parent is not a structure
* element (i.e., is the structure tree root)
*/
public PDFStructElem getParentStructElem() {
return parentElement;
}

/** {@inheritDoc} */
public void setParent(PDFObject parent) {
if (parent != null) {
put("P", new PDFReference(parent));
}
}

/**
* Returns the kids of this structure element.
*
* @return the value of the K entry
*/
private PDFArray getKids() {
return (PDFArray) get("K");
}

/**
* Add a kid to this structure element. This element will then add itself to
* its parent structure element if it has not already, and so will the
* parent, and so on.
*
* @param kid element to be added
*/
public void addKid(PDFObject kid) {
PDFArray kids = getKids();
if (kids == null) {
kids = new PDFArray();
put("K", kids);
}
kids.add(kid);
joinHierarchy();
}

private boolean containsKid(PDFObject kid) {
PDFArray kids = getKids();
return kids != null && kids.contains(kid);
}

private void joinHierarchy() {
if (parentElement != null && !parentElement.containsKid(this)) {
parentElement.addKid(this);
}
}

/**
* Sets the given mcid as the kid of this structure element. This element
* will then add itself to its parent structure element if it has not
* already, and so will the parent, and so on.
*
* @param mcid mcid of the marked-content sequence corresponding to this
* structure element's kid
*/
public void setMCIDKid(int mcid) {
put("K", mcid);
joinHierarchy();
}

/**
* Sets the page reference of this structure element.
*
* @param page value for the Pg entry
*/
public void setPage(PDFPage page) {
put("Pg", page);
}

/**
* Returns the structure type of this structure element.
*
* @return the value of the S entry
*/
public PDFName getStructureType() {
return (PDFName)get("S");
}

/**
* Sets the language of this structure element.
* @param language the language (as defined in the section about
* "Natural Language Specification")
*/
private void setLanguage(String language) {
put("Lang", language);
}

/**
* Sets the language of this structure element.
*
* @param language a value for the Lang entry
*/
public void setLanguage(Locale language) {
setLanguage(XMLUtil.toRFC3066(language));
}

/**
* Returns the language of this structure element.
*
* @return the value of the Lang entry (<code>null</code> if no language was specified)
*/
public String getLanguage() {
return (String)get("Lang");
}
}

+ 55
- 0
src/java/org/apache/fop/pdf/PDFStructTreeRoot.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.pdf;

/**
* Class representing a PDF /StructTreeRoot dictionary.
*/
public class PDFStructTreeRoot extends PDFDictionary {

/**
* Creates a new /StructTreeRoot dictionary.
*
* @param parentTree the value of the ParenTree entry
*/
PDFStructTreeRoot(PDFParentTree parentTree) {
put("Type", new PDFName("StructTreeRoot"));
put("K", new PDFArray());
put("ParentTree", parentTree);
}

/**
* Returns the children element of this StructTreeRoot.
*
* @return the value of the K entry
*/
public PDFArray getKids() {
return (PDFArray)get("K");
}

/**
* Adds the given object to the array of kids.
*
* @param kid an object to be added to the K entry
*/
public void addKid(PDFObject kid) {
getKids().add(kid);
}
}

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

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


import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.Configuration;

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


/** /**
public abstract class AbstractRendererConfigurator extends AbstractConfigurator { public abstract class AbstractRendererConfigurator extends AbstractConfigurator {


private static final String TYPE = "renderer"; private static final String TYPE = "renderer";
/** /**
* Default constructor * Default constructor
* @param userAgent user agent * @param userAgent user agent
protected Configuration getRendererConfig(String mimeType) { protected Configuration getRendererConfig(String mimeType) {
return super.getConfig(mimeType); return super.getConfig(mimeType);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */

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

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

+ 2
- 0
src/java/org/apache/fop/render/intermediate/IFConstants.java View File

String EL_BORDER_RECT = "border-rect"; String EL_BORDER_RECT = "border-rect";
String EL_FONT = "font"; String EL_FONT = "font";
String EL_TEXT = "text"; String EL_TEXT = "text";
/** Parent element of the logical structure tree. */
String EL_STRUCTURE_TREE = "structure-tree";
} }

+ 47
- 0
src/java/org/apache/fop/render/intermediate/IFContext.java View File

package org.apache.fop.render.intermediate; package org.apache.fop.render.intermediate;


import java.util.Collections; import java.util.Collections;
import java.util.Locale;
import java.util.Map; import java.util.Map;


import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.QName;
/** foreign attributes: Map<QName, Object> */ /** foreign attributes: Map<QName, Object> */
private Map foreignAttributes = Collections.EMPTY_MAP; private Map foreignAttributes = Collections.EMPTY_MAP;


private Locale language;

private String structurePointer;

/** /**
* Main constructor. * Main constructor.
* @param ua the user agent * @param ua the user agent
setForeignAttributes(null); setForeignAttributes(null);
} }


/**
* Sets the currently applicable language.
* @param lang the language
*/
public void setLanguage(Locale lang) {
this.language = lang;
}

/**
* Returns the currently applicable language.
* @return the language (or null if the language is undefined)
*/
public Locale getLanguage() {
return this.language;
}

/**
* Sets the structure pointer for the following painted marks. This method is used when
* accessibility features are enabled.
* @param ptr the structure pointer
*/
public void setStructurePointer(String ptr) {
this.structurePointer = ptr;
}

/**
* Resets the current structure pointer.
* @see #setStructurePointer(String)
*/
public void resetStructurePointer() {
setStructurePointer(null);
}

/**
* Returns the current structure pointer.
* @return the structure pointer (or null if no pointer is active)
* @see #setStructurePointer(String)
*/
public String getStructurePointer() {
return this.structurePointer;
}

} }

+ 108
- 20
src/java/org/apache/fop/render/intermediate/IFParser.java View File

import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.util.Map; import java.util.Map;
import java.util.Set;


import javax.xml.transform.Source; import javax.xml.transform.Source;
import javax.xml.transform.Transformer; import javax.xml.transform.Transformer;


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

import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;


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


import org.apache.fop.accessibility.AccessibilityEventProducer;
import org.apache.fop.accessibility.StructureTreeBuilder;
import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry; import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.util.ContentHandlerFactoryRegistry; import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.DOMBuilderContentHandlerFactory; import org.apache.fop.util.DOMBuilderContentHandlerFactory;
import org.apache.fop.util.DefaultErrorListener; import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.DelegatingContentHandler;
import org.apache.fop.util.XMLUtil; import org.apache.fop.util.XMLUtil;


/** /**
private static SAXTransformerFactory tFactory private static SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance(); = (SAXTransformerFactory)SAXTransformerFactory.newInstance();


private static Set handledNamespaces = new java.util.HashSet();

static {
handledNamespaces.add(XMLNS_NAMESPACE_URI);
handledNamespaces.add(XML_NAMESPACE);
handledNamespaces.add(NAMESPACE);
handledNamespaces.add(XLINK_NAMESPACE);
}

/** /**
* Parses an intermediate file and paints it. * Parses an intermediate file and paints it.
* @param src the Source instance pointing to the intermediate file * @param src the Source instance pointing to the intermediate file


private ContentHandler navParser; private ContentHandler navParser;


private StructureTreeBuilder structureTreeBuilder;

private ContentHandler structureTreeBuilderWrapper;

private Attributes pageSequenceAttributes;

private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {

private StructureTreeBuilderWrapper()
throws SAXException {
super(structureTreeBuilder.getHandlerForNextPageSequence());
}

public void endDocument() throws SAXException {
super.endDocument();
startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes);
pageSequenceAttributes = null;
}
}

public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent, public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent,
ElementMappingRegistry elementMappingRegistry) { ElementMappingRegistry elementMappingRegistry) {
this.documentHandler = documentHandler; this.documentHandler = documentHandler;
elementHandlers.put(EL_LINE, new LineHandler()); elementHandlers.put(EL_LINE, new LineHandler());
elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler()); elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
elementHandlers.put(EL_IMAGE, new ImageHandler()); elementHandlers.put(EL_IMAGE, new ImageHandler());

if (userAgent.isAccessibilityEnabled()) {
structureTreeBuilder = new StructureTreeBuilder(tFactory);
userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
}
} }


private void establishForeignAttributes(Map foreignAttributes) { private void establishForeignAttributes(Map foreignAttributes) {
documentHandler.getContext().resetForeignAttributes(); documentHandler.getContext().resetForeignAttributes();
} }


private void establishStructurePointer(String ptr) {
documentHandler.getContext().setStructurePointer(ptr);
}

private void resetStructurePointer() {
documentHandler.getContext().resetStructurePointer();
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attributes) public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException { throws SAXException {
if (delegate != null) { if (delegate != null) {
//delegateStack.push(qName);
delegateDepth++; delegateDepth++;
delegate.startElement(uri, localName, qName, attributes); delegate.startElement(uri, localName, qName, attributes);
} else { } else {
boolean handled = true; boolean handled = true;
if (NAMESPACE.equals(uri)) { if (NAMESPACE.equals(uri)) {
lastAttributes = new AttributesImpl(attributes);
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
content.setLength(0);
ignoreCharacters = true;
if (elementHandler != null) {
ignoreCharacters = elementHandler.ignoreCharacters();
try {
elementHandler.startElement(attributes);
} catch (IFException ife) {
handleIFException(ife);
if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) {
pageSequenceAttributes = new AttributesImpl(attributes);
structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
} else if (localName.equals(EL_STRUCTURE_TREE)) {
if (userAgent.isAccessibilityEnabled()) {
delegate = structureTreeBuilderWrapper;
} else {
/* Delegate to a handler that does nothing */
delegate = new DefaultHandler();
} }
} else if ("extension-attachments".equals(localName)) {
//TODO implement me
delegateDepth++;
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else { } else {
handled = false;
if (pageSequenceAttributes != null) {
/*
* This means that no structure-element tag was
* found in the XML, otherwise a
* StructureTreeBuilderWrapper object would have
* been created, which would have reset the
* pageSequenceAttributes field.
*/
AccessibilityEventProducer.Provider
.get(userAgent.getEventBroadcaster())
.noStructureTreeInXML(this);
}
handled = startIFElement(localName, attributes);
} }
} else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) { } else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) {
if (this.navParser == null) { if (this.navParser == null) {
} }
} }


private boolean startIFElement(String localName, Attributes attributes)
throws SAXException {
lastAttributes = new AttributesImpl(attributes);
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
content.setLength(0);
ignoreCharacters = true;
if (elementHandler != null) {
ignoreCharacters = elementHandler.ignoreCharacters();
try {
elementHandler.startElement(attributes);
} catch (IFException ife) {
handleIFException(ife);
}
return true;
} else {
return false;
}
}

private void handleIFException(IFException ife) throws SAXException { private void handleIFException(IFException ife) throws SAXException {
if (ife.getCause() instanceof SAXException) { if (ife.getCause() instanceof SAXException) {
//unwrap //unwrap


public void startElement(Attributes attributes) throws IFException { public void startElement(Attributes attributes) throws IFException {
String id = attributes.getValue("id"); String id = attributes.getValue("id");
String xmllang = attributes.getValue(XML_NAMESPACE, "lang");
if (xmllang != null) {
documentHandler.getContext().setLanguage(
XMLUtil.convertRFC3066ToLocale(xmllang));
}
Map foreignAttributes = getForeignAttributes(lastAttributes); Map foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes); establishForeignAttributes(foreignAttributes);
documentHandler.startPageSequence(id); documentHandler.startPageSequence(id);


public void endElement() throws IFException { public void endElement() throws IFException {
documentHandler.endPageSequence(); documentHandler.endPageSequence();
documentHandler.getContext().setLanguage(null);
} }


} }
s = lastAttributes.getValue("word-spacing"); s = lastAttributes.getValue("word-spacing");
int wordSpacing = (s != null ? Integer.parseInt(s) : 0); int wordSpacing = (s != null ? Integer.parseInt(s) : 0);
int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx"); int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx");
setStructurePointer(lastAttributes);
painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString()); painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString());
resetStructurePointer();
} }


public boolean ignoreCharacters() { public boolean ignoreCharacters() {
int height = Integer.parseInt(lastAttributes.getValue("height")); int height = Integer.parseInt(lastAttributes.getValue("height"));
Map foreignAttributes = getForeignAttributes(lastAttributes); Map foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes); establishForeignAttributes(foreignAttributes);
setStructurePointer(lastAttributes);
if (foreignObject != null) { if (foreignObject != null) {
painter.drawImage(foreignObject, painter.drawImage(foreignObject,
new Rectangle(x, y, width, height)); new Rectangle(x, y, width, height));
painter.drawImage(uri, new Rectangle(x, y, width, height)); painter.drawImage(uri, new Rectangle(x, y, width, height));
} }
resetForeignAttributes(); resetForeignAttributes();
resetStructurePointer();
inForeignObject = false; inForeignObject = false;
} }


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);
if (ns.length() > 0) { if (ns.length() > 0) {
if ("http://www.w3.org/2000/xmlns/".equals(ns)) {
continue;
} else if (NAMESPACE.equals(ns)) {
continue;
} else if (XLINK_NAMESPACE.equals(ns)) {
if (handledNamespaces.contains(ns)) {
continue; continue;
} }
if (foreignAttributes == null) { if (foreignAttributes == null) {
return foreignAttributes; return foreignAttributes;
} }


private void setStructurePointer(Attributes attributes) {
String ptr = attributes.getValue("ptr");
if (ptr != null && ptr.length() > 0) {
establishStructurePointer(ptr);
}
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException { public void characters(char[] ch, int start, int length) throws SAXException {
if (delegate != null) { if (delegate != null) {

+ 33
- 3
src/java/org/apache/fop/render/intermediate/IFRenderer.java View File

import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Stack; import java.util.Stack;


try { try {
if (this.inPageSequence) { if (this.inPageSequence) {
documentHandler.endPageSequence(); documentHandler.endPageSequence();
documentHandler.getContext().setLanguage(null);
} else { } else {
if (this.documentMetadata == null) { if (this.documentMetadata == null) {
this.documentMetadata = createDefaultDocumentMetadata(); this.documentMetadata = createDefaultDocumentMetadata();
this.inPageSequence = true; this.inPageSequence = true;
} }
establishForeignAttributes(pageSequence.getForeignAttributes()); establishForeignAttributes(pageSequence.getForeignAttributes());
documentHandler.getContext().setLanguage(toLocale(pageSequence));
documentHandler.startPageSequence(null); documentHandler.startPageSequence(null);
resetForeignAttributes(); resetForeignAttributes();
processExtensionAttachments(pageSequence); processExtensionAttachments(pageSequence);
} }
} }


private Locale toLocale(PageSequence pageSequence) {
if (pageSequence.getLanguage() != null) {
if (pageSequence.getCountry() != null) {
return new Locale(pageSequence.getLanguage(), pageSequence.getCountry());
} else {
return new Locale(pageSequence.getLanguage());
}
}
return null;
}

private Metadata createDefaultDocumentMetadata() { private Metadata createDefaultDocumentMetadata() {
Metadata xmp = new Metadata(); Metadata xmp = new Metadata();
DublinCoreAdapter dc = DublinCoreSchema.getAdapter(xmp); DublinCoreAdapter dc = DublinCoreSchema.getAdapter(xmp);
documentHandler.getContext().resetForeignAttributes(); documentHandler.getContext().resetForeignAttributes();
} }


private void establishStructurePointer(String ptr) {
documentHandler.getContext().setStructurePointer(ptr);
}

private void resetStructurePointer() {
documentHandler.getContext().resetStructurePointer();
}

/** {@inheritDoc} */ /** {@inheritDoc} */
protected void saveGraphicsState() { protected void saveGraphicsState() {
graphicContextStack.push(graphicContext); graphicContextStack.push(graphicContext);
currentIPPosition = saveIP; currentIPPosition = saveIP;
currentBPPosition = saveBP; currentBPPosition = saveBP;


currentBPPosition += (int)(bv.getAllocBPD());
currentBPPosition += bv.getAllocBPD();
} }
viewportDimensionStack.pop(); viewportDimensionStack.pop();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public void renderViewport(Viewport viewport) { public void renderViewport(Viewport viewport) {
String ptr = (String) viewport.getTrait(Trait.PTR);
establishStructurePointer(ptr);
Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD()); Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD());
viewportDimensionStack.push(dim); viewportDimensionStack.push(dim);
super.renderViewport(viewport); super.renderViewport(viewport);
viewportDimensionStack.pop(); viewportDimensionStack.pop();
resetStructurePointer();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
// stuff we only need if a link must be created: // stuff we only need if a link must be created:
Rectangle ipRect = null; Rectangle ipRect = null;
AbstractAction action = null; AbstractAction action = null;
String ptr = (String) ip.getTrait(Trait.PTR); // used for accessibility
// make sure the rect is determined *before* calling super! // make sure the rect is determined *before* calling super!
int ipp = currentIPPosition; int ipp = currentIPPosition;
int bpp = currentBPPosition + ip.getOffset(); int bpp = currentBPPosition + ip.getOffset();


// warn if link trait found but not allowed, else create link // warn if link trait found but not allowed, else create link
if (linkTraitFound) { if (linkTraitFound) {
action.setStructurePointer(ptr); // used for accessibility
Link link = new Link(action, ipRect); Link link = new Link(action, ipRect);
this.deferredLinks.add(link); this.deferredLinks.add(link);
} }


String fontName = getInternalFontNameForArea(text); String fontName = getInternalFontNameForArea(text);
int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
String ptr = (String)text.getTrait(Trait.PTR); // used for accessibility
establishStructurePointer(ptr);


// This assumes that *all* CIDFonts use a /ToUnicode mapping // This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface tf = getTypeface(fontName); Typeface tf = getTypeface(fontName);


textUtil.flush(); textUtil.flush();
renderTextDecoration(tf, size, text, bl, rx); renderTextDecoration(tf, size, text, bl, rx);
resetStructurePointer();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
private static final int INITIAL_BUFFER_SIZE = 16; private static final int INITIAL_BUFFER_SIZE = 16;
private int[] dx = new int[INITIAL_BUFFER_SIZE]; private int[] dx = new int[INITIAL_BUFFER_SIZE];
private int lastDXPos = 0; private int lastDXPos = 0;
private StringBuffer text = new StringBuffer();
private final StringBuffer text = new StringBuffer();
private int startx, starty; private int startx, starty;
private int tls, tws; private int tls, tws;
private boolean combined = false;
private final boolean combined = false;


void addChar(char ch) { void addChar(char ch) {
text.append(ch); text.append(ch);

+ 36
- 3
src/java/org/apache/fop/render/intermediate/IFSerializer.java View File

import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;


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

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.AttributesImpl;


import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.QName;
import org.apache.xmlgraphics.util.XMLizable; import org.apache.xmlgraphics.util.XMLizable;


import org.apache.fop.accessibility.StructureTree;
import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.PrintRendererConfigurator; import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.RenderingContext; import org.apache.fop.render.RenderingContext;
implements IFConstants, IFPainter, IFDocumentNavigationHandler { implements IFConstants, IFPainter, IFDocumentNavigationHandler {


private IFDocumentHandler mimicHandler; private IFDocumentHandler mimicHandler;
private int pageSequenceIndex; // used for accessibility


/** Holds the intermediate format state */ /** Holds the intermediate format state */
private IFState state; private IFState state;
if (id != null) { if (id != null) {
atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id); atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id);
} }
Locale lang = getContext().getLanguage();
if (lang != null) {
atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA,
XMLUtil.toRFC3066(lang));
}
addForeignAttributes(atts); addForeignAttributes(atts);
handler.startElement(EL_PAGE_SEQUENCE, atts); handler.startElement(EL_PAGE_SEQUENCE, atts);
if (this.getUserAgent().isAccessibilityEnabled()) {
StructureTree structureTree = getUserAgent().getStructureTree();
handler.startElement(EL_STRUCTURE_TREE); // add structure tree
NodeList nodes = structureTree.getPageSequence(pageSequenceIndex++);
for (int i = 0, n = nodes.getLength(); i < n; i++) {
Node node = nodes.item(i);
new DOM2SAX(handler).writeFragment(node);
}
handler.endElement(EL_STRUCTURE_TREE);
}
} catch (SAXException e) { } catch (SAXException e) {
throw new IFException("SAX error in startPageSequence()", e); throw new IFException("SAX error in startPageSequence()", e);
} }
addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "width", Integer.toString(rect.width));
addAttribute(atts, "height", Integer.toString(rect.height)); addAttribute(atts, "height", Integer.toString(rect.height));
addForeignAttributes(atts); addForeignAttributes(atts);
addStructurePointerAttribute(atts);
handler.element(EL_IMAGE, atts); handler.element(EL_IMAGE, atts);
} catch (SAXException e) { } catch (SAXException e) {
throw new IFException("SAX error in startGroup()", e); throw new IFException("SAX error in startGroup()", e);
} }
} }


private void addForeignAttributes(AttributesImpl atts) {
private void addForeignAttributes(AttributesImpl atts) throws SAXException {
Map foreignAttributes = getContext().getForeignAttributes(); Map foreignAttributes = getContext().getForeignAttributes();
if (!foreignAttributes.isEmpty()) { if (!foreignAttributes.isEmpty()) {
Iterator iter = foreignAttributes.entrySet().iterator(); Iterator iter = foreignAttributes.entrySet().iterator();
addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "width", Integer.toString(rect.width));
addAttribute(atts, "height", Integer.toString(rect.height)); addAttribute(atts, "height", Integer.toString(rect.height));
addForeignAttributes(atts); addForeignAttributes(atts);
addStructurePointerAttribute(atts);
handler.startElement(EL_IMAGE, atts); handler.startElement(EL_IMAGE, atts);
new DOM2SAX(handler).writeDocument(doc, true); new DOM2SAX(handler).writeDocument(doc, true);
handler.endElement(EL_IMAGE); handler.endElement(EL_IMAGE);
if (dx != null) { if (dx != null) {
addAttribute(atts, "dx", IFUtil.toString(dx)); addAttribute(atts, "dx", IFUtil.toString(dx));
} }
addStructurePointerAttribute(atts);
handler.startElement(EL_TEXT, atts); handler.startElement(EL_TEXT, atts);
char[] chars = text.toCharArray(); char[] chars = text.toCharArray();
handler.characters(chars, 0, chars.length); handler.characters(chars, 0, chars.length);
} }


private void addAttribute(AttributesImpl atts, private void addAttribute(AttributesImpl atts,
org.apache.xmlgraphics.util.QName attribute, String value) {
org.apache.xmlgraphics.util.QName attribute, String value) throws SAXException {
handler.startPrefixMapping(attribute.getPrefix(), attribute.getNamespaceURI());
XMLUtil.addAttribute(atts, attribute, value); XMLUtil.addAttribute(atts, attribute, value);
} }


XMLUtil.addAttribute(atts, localName, value); XMLUtil.addAttribute(atts, localName, value);
} }


private void addStructurePointerAttribute(AttributesImpl atts) {
String ptr = getContext().getStructurePointer();
if (ptr != null) {
addAttribute(atts, "ptr", ptr);
}
}

// ---=== IFDocumentNavigationHandler ===--- // ---=== IFDocumentNavigationHandler ===---


private Map incompleteActions = new java.util.HashMap(); private Map incompleteActions = new java.util.HashMap();
AttributesImpl atts = new AttributesImpl(); AttributesImpl atts = new AttributesImpl();
atts.addAttribute(null, "rect", "rect", atts.addAttribute(null, "rect", "rect",
XMLConstants.CDATA, IFUtil.toString(link.getTargetRect())); XMLConstants.CDATA, IFUtil.toString(link.getTargetRect()));
if (getUserAgent().isAccessibilityEnabled()) {
addAttribute(atts, "ptr", link.getAction().getStructurePointer());
}
try { try {
handler.startElement(DocumentNavigationExtensionConstants.LINK, atts); handler.startElement(DocumentNavigationExtensionConstants.LINK, atts);
serializeXMLizable(link.getAction()); serializeXMLizable(link.getAction());

+ 17
- 0
src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java View File

public abstract class AbstractAction implements XMLizable { public abstract class AbstractAction implements XMLizable {


private String id; private String id;
private String structurePointer;


/** /**
* Sets an ID to make the action referencable. * Sets an ID to make the action referencable.
return this.id; return this.id;
} }


/**
* Sets the structure element corresponding to this action.
* @param structurePointer a reference to the structure element
*/
public void setStructurePointer(String structurePointer) {
this.structurePointer = structurePointer;
}

/**
* Returns the structure element corresponding to this action.
* @return the reference to the structure element
*/
public String getStructurePointer() {
return structurePointer;
}

/** /**
* Indicates whether the action has an ID and is therefore referencable. * Indicates whether the action has an ID and is therefore referencable.
* @return true if the action has an ID * @return true if the action has an ID

+ 9
- 0
src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java View File



private IFDocumentNavigationHandler navHandler; private IFDocumentNavigationHandler navHandler;


private String structurePointer;

/** /**
* Main constructor. * Main constructor.
* @param navHandler the navigation handler that will receive the events * @param navHandler the navigation handler that will receive the events
throw new SAXException(localName + " must be the root element!"); throw new SAXException(localName + " must be the root element!");
} }
Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect"); Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect");
structurePointer = attributes.getValue("ptr");
Link link = new Link(null, targetRect); Link link = new Link(null, targetRect);
objectStack.push(link); objectStack.push(link);
} else if (GOTO_XY.getLocalName().equals(localName)) { } else if (GOTO_XY.getLocalName().equals(localName)) {
} }
action = new GoToXYAction(id, pageIndex, location); action = new GoToXYAction(id, pageIndex, location);
} }
if (structurePointer != null) {
action.setStructurePointer(structurePointer);
}
objectStack.push(action); objectStack.push(action);
} else if (GOTO_URI.getLocalName().equals(localName)) { } else if (GOTO_URI.getLocalName().equals(localName)) {
String id = attributes.getValue("id"); String id = attributes.getValue("id");
if (id != null) { if (id != null) {
action.setID(id); action.setID(id);
} }
if (structurePointer != null) {
action.setStructurePointer(structurePointer);
}
objectStack.push(action); objectStack.push(action);
} else { } else {
throw new SAXException( throw new SAXException(

+ 150
- 0
src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.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.pdf;

import java.util.Map;

import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFObject;
import org.apache.fop.pdf.PDFStructElem;

/**
* This class provides the standard mappings from Formatting Objects to PDF structure types.
*/
final class FOToPDFRoleMap {

private static final Map STANDARD_MAPPINGS = new java.util.HashMap();

private static final PDFName TFOOT = new PDFName("TFoot");
private static final PDFName THEAD = new PDFName("THead");
private static final PDFName NON_STRUCT = new PDFName("NonStruct");

static {
addMapping("block", "P");

PDFName st = new PDFName("Div");
addMapping("block-container", st);
addMapping("inline-container", st);
addMapping("table-and-caption", st);
addMapping("float", st);

st = new PDFName("Span");
addMapping("inline", st);
addMapping("wrapper", st);
addMapping("character", st);

addMapping("root", "Document");
addMapping("page-sequence", "Part");
addMapping("flow", "Sect");
addMapping("static-content", "Sect");

st = new PDFName("Quote");
addMapping("page-number", st);
addMapping("page-number-citation", st);
addMapping("page-number-citation-last", st);

st = new PDFName("Figure");
addMapping("external-graphic", st);
addMapping("instream-foreign-object", st);

addMapping("table-caption", "Caption");
addMapping("table", "Table");
addMapping("table-body", "TBody");
addMapping("table-header", THEAD);
addMapping("table-footer", TFOOT);
addMapping("table-row", "TR");
addMapping("table-cell", new TableCellMapper());

addMapping("list-block", "L");
addMapping("list-item", "LI");
addMapping("list-item-label", "Lbl");
addMapping("list-item-body", "LBody");

addMapping("basic-link", "Link");
addMapping("footnote", "Note");
addMapping("footnote-body", "Sect");
addMapping("marker", "Private");
}

private static void addMapping(String fo, String pdfName) {
addMapping(fo, new PDFName(pdfName));
}

private static void addMapping(String fo, PDFName pdfName) {
addMapping(fo, new SimpleMapper(pdfName));
}

private static void addMapping(String fo, Mapper mapper) {
STANDARD_MAPPINGS.put(fo, mapper);
}

/**
* Maps a Formatting Object to a PDFName representing the associated structure type.
* @param fo the formatting object's local name
* @param parent the parent of the structure element to be mapped
* @return the structure type or null if no match could be found
*/
public static PDFName mapFormattingObject(String fo, PDFObject parent) {
Mapper mapper = (Mapper)STANDARD_MAPPINGS.get(fo);
if (mapper != null) {
return mapper.getStructureType(parent);
} else {
return NON_STRUCT;
}
}

private interface Mapper {
PDFName getStructureType(PDFObject parent);
}

private static class SimpleMapper implements Mapper {

private PDFName structureType;

public SimpleMapper(PDFName structureType) {
this.structureType = structureType;
}

public PDFName getStructureType(PDFObject parent) {
return structureType;
}

}

private static class TableCellMapper implements Mapper {

private static final PDFName TD = new PDFName("TD");
private static final PDFName TH = new PDFName("TH");

public PDFName getStructureType(PDFObject parent) {
PDFStructElem grandParent = (PDFStructElem)
((PDFStructElem)parent).getParentStructElem();
//TODO What to do with cells from table-footer? Currently they are mapped on TD.
if (THEAD.equals(grandParent.getStructureType())) {
return TH;
} else {
return TD;
}
}

}

private FOToPDFRoleMap() { }
}

+ 109
- 1
src/java/org/apache/fop/render/pdf/PDFContentGenerator.java View File

/** Text generation utility holding the current font status */ /** Text generation utility holding the current font status */
protected PDFTextUtil textutil; protected PDFTextUtil textutil;


private boolean inMarkedContentSequence;
private boolean inArtifactMode;


/** /**
* Main constructor. Creates a new PDF stream and additional helper classes for text painting * Main constructor. Creates a new PDF stream and additional helper classes for text painting
currentStream.add("q\n"); currentStream.add("q\n");
} }


/** {@inheritDoc} */
protected void saveGraphicsState(String structElemType, int sequenceNum) {
endTextObject();
currentState.save();
beginMarkedContentSequence(structElemType, sequenceNum);
currentStream.add("q\n");
}

/**
* Begins a new marked content sequence (BDC or BMC). If the parameter structElemType is null,
* the sequenceNum is ignored and instead of a BDC with the MCID as parameter, an "Artifact"
* and a BMC command is generated.
* @param structElemType Structure Element Type
* @param mcid Sequence number
*/
protected void beginMarkedContentSequence(String structElemType, int mcid) {
assert !this.inMarkedContentSequence;
assert !this.inArtifactMode;
if (structElemType != null) {
currentStream.add(structElemType + " <</MCID " + String.valueOf(mcid) + ">>\n"
+ "BDC\n");
} else {
currentStream.add("/Artifact\nBMC\n");
this.inArtifactMode = true;
}
this.inMarkedContentSequence = true;
}

void endMarkedContentSequence() {
currentStream.add("EMC\n");
this.inMarkedContentSequence = false;
this.inArtifactMode = false;
}

/** /**
* Restored the graphics state valid before the previous {@link #saveGraphicsState()}. * Restored the graphics state valid before the previous {@link #saveGraphicsState()}.
* @param popState true if the state should also be popped, false if only the PDF command * @param popState true if the state should also be popped, false if only the PDF command
} }
} }


/** {@inheritDoc} */
/**
* Same as {@link #restoreGraphicsState(boolean)}, with <code>true</code> as
* a parameter.
*/
protected void restoreGraphicsState() { protected void restoreGraphicsState() {
restoreGraphicsState(true); restoreGraphicsState(true);
} }


/**
* Same as {@link #restoreGraphicsState()}, additionally ending the current
* marked content sequence if any.
*/
protected void restoreGraphicsStateAccess() {
endTextObject();
currentStream.add("Q\n");
if (this.inMarkedContentSequence) {
endMarkedContentSequence();
}
currentState.restore();
}

/**
* Separates 2 text elements, ending the current marked content sequence and
* starting a new one.
*
* @param structElemType structure element type
* @param mcid sequence number
* @see #beginMarkedContentSequence(String, int)
*/
protected void separateTextElements(String structElemType, int mcid) {
textutil.endTextObject();
endMarkedContentSequence();
beginMarkedContentSequence(structElemType, mcid);
textutil.beginTextObject();
}

/** Indicates the beginning of a text object. */ /** Indicates the beginning of a text object. */
protected void beginTextObject() { protected void beginTextObject() {
if (!textutil.isInTextObject()) { if (!textutil.isInTextObject()) {
} }
} }


/**
* Indicates the beginning of a marked-content text object.
*
* @param structElemType structure element type
* @param mcid sequence number
* @see #beginTextObject()
* @see #beginMarkedContentSequence(String, int)
*/
protected void beginTextObject(String structElemType, int mcid) {
if (!textutil.isInTextObject()) {
beginMarkedContentSequence(structElemType, mcid);
textutil.beginTextObject();
}
}

/** Indicates the end of a text object. */ /** Indicates the end of a text object. */
protected void endTextObject() { protected void endTextObject() {
if (textutil.isInTextObject()) { if (textutil.isInTextObject()) {
if (this.inMarkedContentSequence) {
endMarkedContentSequence();
}
textutil.endTextObject(); textutil.endTextObject();
} }
} }
restoreGraphicsState(); restoreGraphicsState();
} }


/**
* Places a previously registered image at a certain place on the page,
* bracketing it as a marked-content sequence.
*
* @param x X coordinate
* @param y Y coordinate
* @param w width for image
* @param h height for image
* @param xobj the image XObject
* @param structElemType structure element type
* @param mcid sequence number
* @see #beginMarkedContentSequence(String, int)
*/
public void placeImage(float x, float y, float w, float h, PDFXObject xobj,
String structElemType, int mcid) {
saveGraphicsState(structElemType, mcid);
add(format(w) + " 0 0 "
+ format(-h) + " "
+ format(x) + " "
+ format(y + h)
+ " cm\n" + xobj.getName() + " Do\n");
restoreGraphicsStateAccess();
}


} }

+ 43
- 8
src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java View File

import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;


import org.w3c.dom.NodeList;

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.render.intermediate.IFDocumentNavigationHandler; import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFPainter; import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.util.XMLUtil;


/** /**
* {@link IFDocumentHandler} implementation that produces PDF. * {@link IFDocumentHandler} implementation that produces PDF.
/** logging instance */ /** logging instance */
private static Log log = LogFactory.getLog(PDFDocumentHandler.class); private static Log log = LogFactory.getLog(PDFDocumentHandler.class);


private int pageSequenceIndex;

private boolean accessEnabled;

private PDFLogicalStructureHandler logicalStructureHandler;

/** the PDF Document being created */ /** the PDF Document being created */
protected PDFDocument pdfDoc; protected PDFDocument pdfDoc;


/** Used for bookmarks/outlines. */ /** Used for bookmarks/outlines. */
protected Map pageReferences = new java.util.HashMap(); protected Map pageReferences = new java.util.HashMap();


private PDFDocumentNavigationHandler documentNavigationHandler
private final PDFDocumentNavigationHandler documentNavigationHandler
= new PDFDocumentNavigationHandler(this); = new PDFDocumentNavigationHandler(this);


/** /**


/** {@inheritDoc} */ /** {@inheritDoc} */
public boolean supportsPagesOutOfOrder() { public boolean supportsPagesOutOfOrder() {
return true;
return !accessEnabled;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
return this.pdfUtil; return this.pdfUtil;
} }


PDFLogicalStructureHandler getLogicalStructureHandler() {
return logicalStructureHandler;
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public void startDocument() throws IFException { public void startDocument() throws IFException {
super.startDocument(); super.startDocument();
try { try {
this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream); this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream);
this.accessEnabled = getUserAgent().isAccessibilityEnabled();
if (accessEnabled) {
pdfDoc.getRoot().makeTagged();
logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
}
} catch (IOException e) { } catch (IOException e) {
throw new IFException("I/O error in startDocument()", e); throw new IFException("I/O error in startDocument()", e);
} }
try { try {
pdfDoc.getResources().addFonts(pdfDoc, fontInfo); pdfDoc.getResources().addFonts(pdfDoc, fontInfo);
pdfDoc.outputTrailer(this.outputStream); pdfDoc.outputTrailer(this.outputStream);

this.pdfDoc = null; this.pdfDoc = null;


pdfResources = null; pdfResources = null;


/** {@inheritDoc} */ /** {@inheritDoc} */
public void startPageSequence(String id) throws IFException { public void startPageSequence(String id) throws IFException {
//TODO page sequence title, country and language
//TODO page sequence title

if (this.pdfDoc.getRoot().getLanguage() == null
&& getContext().getLanguage() != null) {
//No document-level language set, so we use the first page-sequence's language
this.pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(getContext().getLanguage()));
}

if (accessEnabled) {
NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
logicalStructureHandler.processStructureTree(nodes, getContext().getLanguage());
}
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
toPointAndScale(cropBox, scaleX, scaleY), toPointAndScale(cropBox, scaleX, scaleY),
toPointAndScale(bleedBox, scaleX, scaleY), toPointAndScale(bleedBox, scaleX, scaleY),
toPointAndScale(trimBox, scaleX, scaleY)); toPointAndScale(trimBox, scaleX, scaleY));
if (accessEnabled) {
logicalStructureHandler.startPage(currentPage);
}


pdfUtil.generatePageLabel(index, name); pdfUtil.generatePageLabel(index, name);


currentPageRef = new PageReference(currentPage, size); currentPageRef = new PageReference(currentPage, size);
this.pageReferences.put(new Integer(index), currentPageRef); this.pageReferences.put(new Integer(index), currentPageRef);


this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, this.currentPage);
this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream,
this.currentPage);
// Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's
AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0, AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0,
(scaleY * size.height) / 1000f); (scaleY * size.height) / 1000f);


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


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


/** {@inheritDoc} */ /** {@inheritDoc} */
public void endPage() throws IFException { public void endPage() throws IFException {
if (accessEnabled) {
logicalStructureHandler.endPage();
}
try { try {
this.documentNavigationHandler.commit(); this.documentNavigationHandler.commit();
this.pdfDoc.registerObject(generator.getStream()); this.pdfDoc.registerObject(generator.getStream());


static final class PageReference { static final class PageReference {


private PDFReference pageRef;
private Dimension pageDimension;
private final PDFReference pageRef;
private final Dimension pageDimension;


private PageReference(PDFPage page, Dimension dim) { private PageReference(PDFPage page, Dimension dim) {
this.pageRef = page.makeReference(); this.pageRef = page.makeReference();

+ 8
- 3
src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java View File

*/ */
public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler { public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler {


private PDFDocumentHandler documentHandler;
private final PDFDocumentHandler documentHandler;


private Map incompleteActions = new java.util.HashMap();
private Map completeActions = new java.util.HashMap();
private final Map incompleteActions = new java.util.HashMap();
private final Map completeActions = new java.util.HashMap();


/** /**
* Default constructor. * Default constructor.
PDFLink pdfLink = getPDFDoc().getFactory().makeLink( PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
targetRect2D, pdfAction); targetRect2D, pdfAction);
if (pdfLink != null) { if (pdfLink != null) {
String ptr = link.getAction().getStructurePointer();
if (documentHandler.getUserAgent().isAccessibilityEnabled()
&& ptr != null && ptr.length() > 0) {
documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr);
}
documentHandler.currentPage.addAnnotation(pdfLink); documentHandler.currentPage.addAnnotation(pdfLink);
} }
} }

+ 16
- 2
src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java View File

import org.apache.fop.render.AbstractImageHandlerGraphics2D; import org.apache.fop.render.AbstractImageHandlerGraphics2D;
import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RenderingContext; import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
import org.apache.fop.svg.PDFGraphics2D; import org.apache.fop.svg.PDFGraphics2D;


/** /**
renderer.currentPage, renderer.currentPage,
renderer.getFontInfo()); renderer.getFontInfo());
Rectangle effPos = new Rectangle(origin.x + pos.x, origin.y + pos.y, pos.width, pos.height); Rectangle effPos = new Rectangle(origin.x + pos.x, origin.y + pos.y, pos.width, pos.height);
if (context.getUserAgent().isAccessibilityEnabled()) {
pdfContext.setMarkedContentInfo(renderer.addCurrentImageToStructureTree());
}
handleImage(pdfContext, image, effPos); handleImage(pdfContext, image, effPos);
return null; return null;
} }
float sy = fheight / (float)imh; float sy = fheight / (float)imh;


generator.comment("G2D start"); generator.comment("G2D start");
generator.saveGraphicsState();
boolean accessibilityEnabled = context.getUserAgent().isAccessibilityEnabled();
if (accessibilityEnabled) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.saveGraphicsState(mci.tag, mci.mcid);
} else {
generator.saveGraphicsState();
}
generator.updateColor(Color.black, false, null); generator.updateColor(Color.black, false, null);
generator.updateColor(Color.black, true, null); generator.updateColor(Color.black, true, null);


imageG2D.getGraphics2DImagePainter().paint(graphics, area); imageG2D.getGraphics2DImagePainter().paint(graphics, area);


generator.add(graphics.getString()); generator.add(graphics.getString());
generator.restoreGraphicsState();
if (accessibilityEnabled) {
generator.restoreGraphicsStateAccess();
} else {
generator.restoreGraphicsState();
}
generator.comment("G2D end"); generator.comment("G2D end");
} }



+ 7
- 1
src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java View File

import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RenderingContext; import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;


/** /**
* Image handler implementation which handles raw JPEG images for PDF output. * Image handler implementation which handles raw JPEG images for PDF output.
float y = (float)pos.getY() / 1000f; float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f; float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f; float h = (float)pos.getHeight() / 1000f;
generator.placeImage(x, y, w, h, xobj);
if (context.getUserAgent().isAccessibilityEnabled()) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid);
} else {
generator.placeImage(x, y, w, h, xobj);
}
} }


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

+ 7
- 1
src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java View File

import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RenderingContext; import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;


/** /**
* Image handler implementation which handles RenderedImage instances for PDF output. * Image handler implementation which handles RenderedImage instances for PDF output.
float y = (float)pos.getY() / 1000f; float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 1000f; float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f; float h = (float)pos.getHeight() / 1000f;
generator.placeImage(x, y, w, h, xobj);
if (context.getUserAgent().isAccessibilityEnabled()) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid);
} else {
generator.placeImage(x, y, w, h, xobj);
}
} }


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

+ 12
- 3
src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java View File

import org.apache.fop.image.loader.batik.BatikImageFlavors; import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext; import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
import org.apache.fop.svg.PDFAElementBridge; import org.apache.fop.svg.PDFAElementBridge;
import org.apache.fop.svg.PDFBridgeContext; import org.apache.fop.svg.PDFBridgeContext;
import org.apache.fop.svg.PDFGraphics2D; import org.apache.fop.svg.PDFGraphics2D;
float w = (float)ctx.getDocumentSize().getWidth() * 1000f; float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
float h = (float)ctx.getDocumentSize().getHeight() * 1000f; float h = (float)ctx.getDocumentSize().getHeight() * 1000f;


float sx = pos.width / (float)w;
float sy = pos.height / (float)h;
float sx = pos.width / w;
float sy = pos.height / h;


//Scaling and translation for the bounding box of the image //Scaling and translation for the bounding box of the image
AffineTransform scaling = new AffineTransform( AffineTransform scaling = new AffineTransform(
*/ */
generator.comment("SVG setup"); generator.comment("SVG setup");
generator.saveGraphicsState(); generator.saveGraphicsState();
if (context.getUserAgent().isAccessibilityEnabled()) {
MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
generator.beginMarkedContentSequence(mci.tag, mci.mcid);
}
generator.setColor(Color.black, false); generator.setColor(Color.black, false);
generator.setColor(Color.black, true); generator.setColor(Color.black, true);


eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI()); eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
} }
generator.getState().restore(); generator.getState().restore();
generator.restoreGraphicsState();
if (context.getUserAgent().isAccessibilityEnabled()) {
generator.restoreGraphicsStateAccess();
} else {
generator.restoreGraphicsState();
}
generator.comment("SVG end"); generator.comment("SVG end");
} }



+ 299
- 0
src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.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.pdf;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFParentTree;
import org.apache.fop.pdf.PDFStructElem;
import org.apache.fop.pdf.PDFStructTreeRoot;


/**
* Handles the creation of the logical structure in the PDF document.
*/
class PDFLogicalStructureHandler {

private static final PDFName MCR = new PDFName("MCR");

private static final PDFName OBJR = new PDFName("OBJR");

private static final MarkedContentInfo ARTIFACT = new MarkedContentInfo(null, -1, null);

private final PDFDocument pdfDoc;

/**
* Map of references to the corresponding structure elements.
*/
private final Map structTreeMap = new HashMap();

private final PDFParentTree parentTree = new PDFParentTree();

private int parentTreeKey;

private PDFPage currentPage;

/**
* The array of references, from marked-content sequences in the current
* page, to their parent structure elements. This will be a value in the
* structure parent tree, whose corresponding key will be the page's
* StructParents entry.
*/
private PDFArray pageParentTreeArray;

private PDFStructElem rootStructureElement;

/**
* Class providing the necessary information for bracketing content
* associated to a structure element as a marked-content sequence.
*/
static final class MarkedContentInfo {

/**
* A value that can be used for the tag operand of a marked-content
* operator. This is the structure type of the corresponding structure
* element.
*/
final String tag;

/**
* The value for the MCID entry of the marked-content sequence's property list.
*/
final int mcid;

private final PDFStructElem parent;

private MarkedContentInfo(String tag, int mcid, PDFStructElem parent) {
this.tag = tag;
this.mcid = mcid;
this.parent = parent;
}
}

/**
* Creates a new instance for handling the logical structure of the given document.
*
* @param pdfDoc a document
*/
PDFLogicalStructureHandler(PDFDocument pdfDoc) {
this.pdfDoc = pdfDoc;
PDFStructTreeRoot structTreeRoot = pdfDoc.getFactory().makeStructTreeRoot(parentTree);
rootStructureElement = pdfDoc.getFactory().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot), structTreeRoot);
structTreeRoot.addKid(rootStructureElement);
}

/**
* Converts the given structure tree into PDF.
*
* @param structureTree the structure tree of the current page sequence
* @param language language set on the page sequence
*/
void processStructureTree(NodeList structureTree, Locale language) {
pdfDoc.enforceLanguageOnRoot();
PDFStructElem structElemPart = pdfDoc.getFactory().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject("page-sequence", rootStructureElement),
rootStructureElement);
rootStructureElement.addKid(structElemPart);
if (language != null) {
structElemPart.setLanguage(language);
}

for (int i = 0, n = structureTree.getLength(); i < n; i++) {
Node node = structureTree.item(i);
assert node.getLocalName().equals("flow")
|| node.getLocalName().equals("static-content");
PDFStructElem structElemSect = pdfDoc.getFactory().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), structElemPart),
structElemPart);
structElemPart.addKid(structElemSect);
NodeList childNodes = node.getChildNodes();
for (int j = 0, m = childNodes.getLength(); j < m; j++) {
processNode(childNodes.item(j), structElemSect, true);
}
}
}

private void processNode(Node node, PDFStructElem parent, boolean addKid) {
Node attr = node.getAttributes().getNamedItemNS(InternalElementMapping.URI, "ptr");
assert attr != null;
String ptr = attr.getNodeValue();
String nodeName = node.getLocalName();
PDFStructElem structElem = pdfDoc.getFactory().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(nodeName, parent), parent);
// TODO necessary? If a page-sequence is empty (e.g., contains a single
// empty fo:block), should the block still be added to the structure
// tree? This is not being done for descendant empty elements...
if (addKid) {
parent.addKid(structElem);
}
if (nodeName.equals("external-graphic") || nodeName.equals("instream-foreign-object")) {
Node altTextNode = node.getAttributes().getNamedItemNS(
ExtensionElementMapping.URI, "alt-text");
if (altTextNode != null) {
structElem.put("Alt", altTextNode.getNodeValue());
} else {
structElem.put("Alt", "No alternate text specified");
}
}
structTreeMap.put(ptr, structElem);
NodeList nodes = node.getChildNodes();
for (int i = 0, n = nodes.getLength(); i < n; i++) {
processNode(nodes.item(i), structElem, false);
}
}

private int getNextParentTreeKey() {
return parentTreeKey++;
}

/**
* Receive notification of the beginning of a new page.
*
* @param page the page that will be rendered in PDF
*/
void startPage(PDFPage page) {
currentPage = page;
currentPage.setStructParents(getNextParentTreeKey());
pageParentTreeArray = new PDFArray();
}

/**
* Receive notification of the end of the current page.
*/
void endPage() {
// TODO
// Values in a number tree must be indirect references to the PDF
// objects associated to the keys. To enforce that the array is
// registered to the PDF document. Unfortunately that can't be done
// earlier since a call to PDFContentGenerator.flushPDFDoc can be made
// before the array is complete, which would result in only part of it
// being output to the PDF.
// This should really be handled by PDFNumsArray
pdfDoc.registerObject(pageParentTreeArray);
parentTree.getNums().put(currentPage.getStructParents(), pageParentTreeArray);
}

private MarkedContentInfo addToParentTree(String structurePointer) {
PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer);
if (parent == null) {
return ARTIFACT;
} else {
pageParentTreeArray.add(parent);
String type = parent.getStructureType().toString();
int mcid = pageParentTreeArray.length() - 1;
return new MarkedContentInfo(type, mcid, parent);
}
}

/**
* Adds a content item corresponding to text into the structure tree, if
* there is a structure element associated to it.
*
* @param structurePointer reference to the parent structure element of the
* piece of text
* @return the necessary information for bracketing the content as a
* marked-content sequence. If there is no element in the structure tree
* associated to that content, returns an instance whose
* {@link MarkedContentInfo#tag} value is <code>null</code>. The content
* must then be treated as an artifact.
*/
MarkedContentInfo addTextContentItem(String structurePointer) {
MarkedContentInfo mci = addToParentTree(structurePointer);
if (mci != ARTIFACT) {
PDFDictionary contentItem = new PDFDictionary();
contentItem.put("Type", MCR);
contentItem.put("Pg", this.currentPage);
contentItem.put("MCID", mci.mcid);
mci.parent.addKid(contentItem);
}
return mci;
}

/**
* Adds a content item corresponding to an image into the structure tree, if
* there is a structure element associated to it.
*
* @param structurePointer reference to the parent structure element of the
* image
* @return the necessary information for bracketing the content as a
* marked-content sequence. If there is no element in the structure tree
* associated to that image, returns an instance whose
* {@link MarkedContentInfo#tag} value is <code>null</code>. The image
* must then be treated as an artifact.
*/
MarkedContentInfo addImageContentItem(String structurePointer) {
MarkedContentInfo mci = addToParentTree(structurePointer);
if (mci != ARTIFACT) {
mci.parent.setMCIDKid(mci.mcid);
mci.parent.setPage(this.currentPage);
}
return mci;
}

// While the PDF spec allows images to be referred as PDF objects, this
// makes the Acrobat Pro checker complain that the image is not accessible.
// Its alt-text is still read aloud though. Using marked-content sequences
// like for text works.
// MarkedContentInfo addImageObject(String parentReference) {
// MarkedContentInfo mci = addToParentTree(parentReference);
// if (mci != ARTIFACT) {
// PDFDictionary contentItem = new PDFDictionary();
// contentItem.put("Type", OBJR);
// contentItem.put("Pg", this.currentPage);
// contentItem.put("Obj", null);
// mci.parent.addKid(contentItem);
// }
// return mci;
// }

/**
* Adds a content item corresponding to the given link into the structure
* tree.
*
* @param link a link
* @param structurePointer reference to the corresponding parent structure element
*/
void addLinkContentItem(PDFLink link, String structurePointer) {
int structParent = getNextParentTreeKey();
link.setStructParent(structParent);
parentTree.getNums().put(structParent, link);
PDFDictionary contentItem = new PDFDictionary();
contentItem.put("Type", OBJR);
contentItem.put("Pg", this.currentPage);
contentItem.put("Obj", link);
PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer);
parent.addKid(contentItem);
}

}

+ 71
- 20
src/java/org/apache/fop/render/pdf/PDFPainter.java View File



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


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

import org.apache.fop.fonts.Font; import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState; import org.apache.fop.render.intermediate.IFState;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle; import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.CharUtilities; import org.apache.fop.util.CharUtilities;
*/ */
public class PDFPainter extends AbstractIFPainter { public class PDFPainter extends AbstractIFPainter {


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

private PDFDocumentHandler documentHandler;
private final PDFDocumentHandler documentHandler;


/** The current content generator */ /** The current content generator */
protected PDFContentGenerator generator; protected PDFContentGenerator generator;


private PDFBorderPainter borderPainter;
private final PDFBorderPainter borderPainter;

private boolean accessEnabled;

private MarkedContentInfo imageMCI;

private PDFLogicalStructureHandler logicalStructureHandler;


/** /**
* Default constructor. * Default constructor.
* @param documentHandler the parent document handler * @param documentHandler the parent document handler
* @param logicalStructureHandler the logical structure handler
*/ */
public PDFPainter(PDFDocumentHandler documentHandler) {
public PDFPainter(PDFDocumentHandler documentHandler,
PDFLogicalStructureHandler logicalStructureHandler) {
super(); super();
this.documentHandler = documentHandler; this.documentHandler = documentHandler;
this.logicalStructureHandler = logicalStructureHandler;
this.generator = documentHandler.generator; this.generator = documentHandler.generator;
this.borderPainter = new PDFBorderPainter(this.generator); this.borderPainter = new PDFBorderPainter(this.generator);
this.state = IFState.create(); this.state = IFState.create();
accessEnabled = this.getUserAgent().isAccessibilityEnabled();
} }


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


/** {@inheritDoc} */ /** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect) throws IFException {
public void drawImage(String uri, Rectangle rect)
throws IFException {
PDFXObject xobject = getPDFDoc().getXObject(uri); PDFXObject xobject = getPDFDoc().getXObject(uri);
if (xobject != null) { if (xobject != null) {
placeImage(rect, xobject);
return;
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
placeImageAccess(rect, xobject);
} else {
placeImage(rect, xobject);
}
} else {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
}
drawImageUsingURI(uri, rect);
flushPDFDoc();
} }
}


drawImageUsingURI(uri, rect);

flushPDFDoc();
private void prepareImageMCID(String ptr) {
imageMCI = logicalStructureHandler.addImageContentItem(ptr);
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
protected RenderingContext createRenderingContext() { protected RenderingContext createRenderingContext() {
PDFRenderingContext pdfContext = new PDFRenderingContext( PDFRenderingContext pdfContext = new PDFRenderingContext(
getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo());
pdfContext.setMarkedContentInfo(imageMCI);
return pdfContext; return pdfContext;
} }


+ " cm " + xobj.getName() + " Do\n"); + " cm " + xobj.getName() + " Do\n");
generator.restoreGraphicsState(); generator.restoreGraphicsState();
} }
/**
* Places a previously registered image at a certain place on the page - Accessibility version
* @param x X coordinate
* @param y Y coordinate
* @param w width for image
* @param h height for image
* @param xobj the image XObject
*/
private void placeImageAccess(Rectangle rect, PDFXObject xobj) {
generator.saveGraphicsState(imageMCI.tag, imageMCI.mcid);
generator.add(format(rect.width) + " 0 0 "
+ format(-rect.height) + " "
+ format(rect.x) + " "
+ format(rect.y + rect.height )
+ " cm " + xobj.getName() + " Do\n");
generator.restoreGraphicsStateAccess();
}


/** {@inheritDoc} */ /** {@inheritDoc} */
public void drawImage(Document doc, Rectangle rect) throws IFException { public void drawImage(Document doc, Rectangle rect) throws IFException {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
}
drawImageUsingDocument(doc, rect); drawImageUsingDocument(doc, rect);

flushPDFDoc(); flushPDFDoc();
} }


} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text)
public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx,
String text)
throws IFException { throws IFException {
generator.updateColor(state.getTextColor(), true, null);
generator.beginTextObject();
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr);
if (generator.getTextUtil().isInTextObject()) {
generator.separateTextElements(mci.tag, mci.mcid);
}
generator.updateColor(state.getTextColor(), true, null);
generator.beginTextObject(mci.tag, mci.mcid);
} else {
generator.updateColor(state.getTextColor(), true, null);
generator.beginTextObject();
}

FontTriplet triplet = new FontTriplet( FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant() //TODO Ignored: state.getFontVariant()
PDFTextUtil textutil = generator.getTextUtil(); PDFTextUtil textutil = generator.getTextUtil();
textutil.updateTf(fontKey, fontSize, tf.isMultiByte()); textutil.updateTf(fontKey, fontSize, tf.isMultiByte());


generator.updateCharacterSpacing((float)letterSpacing / 1000f);
generator.updateCharacterSpacing(letterSpacing / 1000f);


textutil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f)); textutil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f));
int l = text.length(); int l = text.length();

+ 87
- 8
src/java/org/apache/fop/render/pdf/PDFRenderer.java View File

import java.io.OutputStream; import java.io.OutputStream;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;


import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageException;
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.fop.area.inline.Leader; import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea; import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea; import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.WordArea; import org.apache.fop.area.inline.WordArea;
import org.apache.fop.datatypes.URISpecification; import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
import org.apache.fop.traits.RuleStyle; import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.AbstractPaintingState; import org.apache.fop.util.AbstractPaintingState;
import org.apache.fop.util.CharUtilities; import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.XMLUtil;
import org.apache.fop.util.AbstractPaintingState.AbstractData; import org.apache.fop.util.AbstractPaintingState.AbstractData;


/** /**
* this is used for prepared pages that cannot be immediately * this is used for prepared pages that cannot be immediately
* rendered * rendered
*/ */
protected Map pages = null;
private Map pages;


/** /**
* Maps unique PageViewport key to PDF page reference * Maps unique PageViewport key to PDF page reference
/** Image handler registry */ /** Image handler registry */
private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry(); private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();


private boolean accessEnabled;

private PDFLogicalStructureHandler logicalStructureHandler;

private int pageSequenceIndex;

/** Reference in the structure tree to the image being rendered. */
private String imageReference;


/** /**
* create the PDF renderer * create the PDF renderer
public void setUserAgent(FOUserAgent agent) { public void setUserAgent(FOUserAgent agent) {
super.setUserAgent(agent); super.setUserAgent(agent);
this.pdfUtil = new PDFRenderingUtil(getUserAgent()); this.pdfUtil = new PDFRenderingUtil(getUserAgent());
accessEnabled = agent.isAccessibilityEnabled();
} }


PDFRenderingUtil getPDFUtil() { PDFRenderingUtil getPDFUtil() {
} }
ostream = stream; ostream = stream;
this.pdfDoc = pdfUtil.setupPDFDocument(stream); this.pdfDoc = pdfUtil.setupPDFDocument(stream);
if (accessEnabled) {
pdfDoc.getRoot().makeTagged();
logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
}
} }


/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public boolean supportsOutOfOrder() { public boolean supportsOutOfOrder() {
//return false;
return true;
return !accessEnabled;
} }


/** /**
info.setTitle(str); info.setTitle(str);
} }
} }
Locale language = null;
if (pageSequence.getLanguage() != null) { if (pageSequence.getLanguage() != null) {
String lang = pageSequence.getLanguage(); String lang = pageSequence.getLanguage();
String country = pageSequence.getCountry(); String country = pageSequence.getCountry();
String langCode = lang + (country != null ? "-" + country : "");
if (lang != null) {
language = (country == null) ? new Locale(lang) : new Locale(lang, country);
}
if (pdfDoc.getRoot().getLanguage() == null) { if (pdfDoc.getRoot().getLanguage() == null) {
//Only set if not set already (first non-null is used) //Only set if not set already (first non-null is used)
//Note: No checking is performed whether the values are valid! //Note: No checking is performed whether the values are valid!
pdfDoc.getRoot().setLanguage(langCode);
pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(language));
} }
} }
pdfUtil.generateDefaultXMPMetadata(); pdfUtil.generateDefaultXMPMetadata();
if (accessEnabled) {
NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
logicalStructureHandler.processStructureTree(nodes, language);
}
} }


/** /**
} }
currentPageRef = currentPage.referencePDF(); currentPageRef = currentPage.referencePDF();


if (accessEnabled) {
logicalStructureHandler.startPage(currentPage);
}

Rectangle bounds = page.getViewArea(); Rectangle bounds = page.getViewArea();
pageHeight = bounds.height; pageHeight = bounds.height;




super.renderPage(page); super.renderPage(page);


if (accessEnabled) {
logicalStructureHandler.endPage();
}

this.pdfDoc.registerObject(generator.getStream()); this.pdfDoc.registerObject(generator.getStream());
currentPage.setContents(generator.getStream()); currentPage.setContents(generator.getStream());
PDFAnnotList annots = currentPage.getAnnotations(); PDFAnnotList annots = currentPage.getAnnotations();
+ pdfDoc.getProfile()); + pdfDoc.getProfile());
} else if (action != null) { } else if (action != null) {
PDFLink pdfLink = factory.makeLink(ipRect, action); PDFLink pdfLink = factory.makeLink(ipRect, action);
if (accessEnabled) {
String ptr = (String) ip.getTrait(Trait.PTR);
logicalStructureHandler.addLinkContentItem(pdfLink, ptr);
}
currentPage.addAnnotation(pdfLink); currentPage.addAnnotation(pdfLink);
} }
} }
} }


/** {@inheritDoc} */
public void renderViewport(Viewport viewport) {
imageReference = (String) viewport.getTrait(Trait.PTR);
super.renderViewport(viewport);
imageReference = null;
}

private Typeface getTypeface(String fontName) { private Typeface getTypeface(String fontName) {
Typeface tf = (Typeface) fontInfo.getFonts().get(fontName); Typeface tf = (Typeface) fontInfo.getFonts().get(fontName);
if (tf instanceof LazyFont) { if (tf instanceof LazyFont) {
Color ct = (Color) text.getTrait(Trait.COLOR); Color ct = (Color) text.getTrait(Trait.COLOR);
updateColor(ct, true); updateColor(ct, true);


beginTextObject();
if (accessEnabled) {
String ptr = (String) text.getTrait(Trait.PTR);
MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr);
if (generator.getTextUtil().isInTextObject()) {
generator.separateTextElements(mci.tag, mci.mcid);
}
generator.beginTextObject(mci.tag, mci.mcid);
} else {
beginTextObject();
}


String fontName = getInternalFontNameForArea(text); String fontName = getInternalFontNameForArea(text);
int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
* @param xobj the image XObject * @param xobj the image XObject
*/ */
public void placeImage(float x, float y, float w, float h, PDFXObject xobj) { public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
saveGraphicsState();
if (accessEnabled) {
MarkedContentInfo mci = logicalStructureHandler.addImageContentItem(imageReference);
generator.saveGraphicsState(mci.tag, mci.mcid);
} else {
saveGraphicsState();
}
generator.add(format(w) + " 0 0 " generator.add(format(w) + " 0 0 "
+ format(-h) + " " + format(-h) + " "
+ format(currentIPPosition / 1000f + x) + " " + format(currentIPPosition / 1000f + x) + " "
+ format(currentBPPosition / 1000f + h + y) + format(currentBPPosition / 1000f + h + y)
+ " cm\n" + xobj.getName() + " Do\n"); + " cm\n" + xobj.getName() + " Do\n");
restoreGraphicsState();
if (accessEnabled) {
generator.restoreGraphicsStateAccess();
} else {
restoreGraphicsState();
}
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
return context; return context;
} }


/** {@inheritDoc} */
public void renderDocument(Document doc, String ns, Rectangle2D pos, Map foreignAttributes) {
if (accessEnabled) {
MarkedContentInfo mci = logicalStructureHandler.addImageContentItem(imageReference);
generator.beginMarkedContentSequence(mci.tag, mci.mcid);
}
super.renderDocument(doc, ns, pos, foreignAttributes);
if (accessEnabled) {
generator.endMarkedContentSequence();
}
}

/** /**
* Render leader area. * Render leader area.
* This renders a leader area which is an area with a rule. * This renders a leader area which is an area with a rule.
public void setEncryptionParams(PDFEncryptionParams encryptionParams) { public void setEncryptionParams(PDFEncryptionParams encryptionParams) {
this.pdfUtil.setEncryptionParams(encryptionParams); this.pdfUtil.setEncryptionParams(encryptionParams);
} }

MarkedContentInfo addCurrentImageToStructureTree() {
return logicalStructureHandler.addImageContentItem(imageReference);
}
} }



+ 9
- 0
src/java/org/apache/fop/render/pdf/PDFRenderingContext.java View File

import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontInfo;
import org.apache.fop.pdf.PDFPage; import org.apache.fop.pdf.PDFPage;
import org.apache.fop.render.AbstractRenderingContext; import org.apache.fop.render.AbstractRenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;


/** /**
* Rendering context for PDF production. * Rendering context for PDF production.
private PDFContentGenerator generator; private PDFContentGenerator generator;
private FontInfo fontInfo; private FontInfo fontInfo;
private PDFPage page; private PDFPage page;
private MarkedContentInfo mci;


/** /**
* Main constructor. * Main constructor.
return this.fontInfo; return this.fontInfo;
} }


void setMarkedContentInfo(MarkedContentInfo mci) {
this.mci = mci;
}

MarkedContentInfo getMarkedContentInfo() {
return mci;
}
} }

+ 6
- 1
src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java View File

import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;


import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.pdf.PDFAMode; import org.apache.fop.pdf.PDFAMode;


private void initialize() { private void initialize() {
PDFEncryptionParams params PDFEncryptionParams params
= (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS);
= (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS);
if (params != null) { if (params != null) {
this.encryptionParams = params; //overwrite if available this.encryptionParams = params; //overwrite if available
} }
if (s != null) { if (s != null) {
this.pdfAMode = PDFAMode.valueOf(s); this.pdfAMode = PDFAMode.valueOf(s);
} }
if (this.pdfAMode.isPDFA1LevelA()) {
//Enable accessibility if PDF/A-1a is enabled because it requires tagged PDF.
userAgent.getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE);
}
s = (String)userAgent.getRendererOptions().get(PDF_X_MODE); s = (String)userAgent.getRendererOptions().get(PDF_X_MODE);
if (s != null) { if (s != null) {
this.pdfXMode = PDFXMode.valueOf(s); this.pdfXMode = PDFXMode.valueOf(s);

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

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


import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOPException;
import org.apache.fop.area.Area; import org.apache.fop.area.Area;
import org.apache.fop.area.CTM; import org.apache.fop.area.CTM;
import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.txt.border.AbstractBorderElement; import org.apache.fop.render.txt.border.AbstractBorderElement;
import org.apache.fop.render.txt.border.BorderManager; import org.apache.fop.render.txt.border.BorderManager;
import org.apache.xmlgraphics.util.UnitConv;


/** /**
* Renderer that renders areas to plain text. * Renderer that renders areas to plain text.

+ 19
- 1
src/java/org/apache/fop/render/xml/XMLRenderer.java View File

import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;


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

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;


import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.QName;
import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContext;
import org.apache.fop.render.XMLHandler; import org.apache.fop.render.XMLHandler;
import org.apache.fop.util.ColorUtil; import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.DOM2SAX;


/** /**
* Renderer that renders areas to XML for debugging purposes. * Renderer that renders areas to XML for debugging purposes.
/** If not null, the XMLRenderer will mimic another renderer by using its font setup. */ /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */
protected Renderer mimic; protected Renderer mimic;


private int pageSequenceIndex;

/** /**
* Creates a new XML renderer. * Creates a new XML renderer.
*/ */
} }
transferForeignObjects(pageSequence); transferForeignObjects(pageSequence);
startElement("pageSequence", atts); startElement("pageSequence", atts);
if (this.getUserAgent().isAccessibilityEnabled()) {
String structureTreeElement = "structureTree";
startElement(structureTreeElement);
NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
for (int i = 0, n = nodes.getLength(); i < n; i++) {
Node node = nodes.item(i);
try {
new DOM2SAX(handler).writeFragment(node);
} catch (SAXException e) {
handleSAXException(e);
}
}
endElement(structureTreeElement);
}
handleExtensionAttachments(pageSequence.getExtensionAttachments()); handleExtensionAttachments(pageSequence.getExtensionAttachments());
LineArea seqTitle = pageSequence.getTitle(); LineArea seqTitle = pageSequence.getTitle();
if (seqTitle != null) { if (seqTitle != null) {

+ 9
- 1
src/java/org/apache/fop/util/DOM2SAX.java View File

import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;

import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler; import org.xml.sax.ext.LexicalHandler;
} }
} }


/**
* Writes the given fragment using the given ContentHandler.
* @param node DOM node
* @throws SAXException In case of a problem while writing XML
*/
public void writeFragment(Node node) throws SAXException {
writeNode(node);
}

/** /**
* Begin the scope of namespace prefix. Forward the event to the SAX handler * Begin the scope of namespace prefix. Forward the event to the SAX handler
* only if the prefix is unknown or it is mapped to a different URI. * only if the prefix is unknown or it is mapped to a different URI.

+ 160
- 0
src/java/org/apache/fop/util/TransformerDefaultHandler.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.util;

import javax.xml.transform.sax.TransformerHandler;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;
import org.xml.sax.helpers.AttributesImpl;

/**
* A DefaultHandler implementation that delegates all the method calls to a
* {@link TransformerHandler} instance.
*/
public class TransformerDefaultHandler extends DefaultHandler2 {

private TransformerHandler transformerHandler;

/**
* Creates a new instance delegating to the given TransformerHandler object.
*
* @param transformerHandler the object to which all the method calls will
* be delegated
*/
public TransformerDefaultHandler(TransformerHandler transformerHandler) {
this.transformerHandler = transformerHandler;
}

/**
* Returns the delegate TransformerHandler instance.
*
* @return the object to which all method calls are delegated
*/
public TransformerHandler getTransformerHandler() {
return transformerHandler;
}

/** {@inheritDoc} */
public void setDocumentLocator(Locator locator) {
transformerHandler.setDocumentLocator(locator);
}

/** {@inheritDoc} */
public void startDocument() throws SAXException {
transformerHandler.startDocument();
}

/** {@inheritDoc} */
public void endDocument() throws SAXException {
transformerHandler.endDocument();
}

/** {@inheritDoc} */
public void startPrefixMapping(String prefix, String uri) throws SAXException {
transformerHandler.startPrefixMapping(prefix, uri);
}

/** {@inheritDoc} */
public void endPrefixMapping(String string) throws SAXException {
transformerHandler.endPrefixMapping(string);
}

/** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attrs)
throws SAXException {
AttributesImpl ai = new AttributesImpl(attrs);
transformerHandler.startElement(uri, localName, qName, ai);
}

/** {@inheritDoc} */
public void endElement(String uri, String localName, String qName) throws SAXException {
transformerHandler.endElement(uri, localName, qName);
}

/** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException {
transformerHandler.characters(ch, start, length);
}

/** {@inheritDoc} */
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
transformerHandler.ignorableWhitespace(ch, start, length);
}

/** {@inheritDoc} */
public void processingInstruction(String target, String data) throws SAXException {
transformerHandler.processingInstruction(target, data);
}

/** {@inheritDoc} */
public void skippedEntity(String name) throws SAXException {
transformerHandler.skippedEntity(name);
}

/** {@inheritDoc} */
public void notationDecl(String name, String publicId, String systemId) throws SAXException {
transformerHandler.notationDecl(name, publicId, systemId);
}

/** {@inheritDoc} */
public void unparsedEntityDecl(String name, String publicId, String systemId,
String notationName) throws SAXException {
transformerHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
}

/** {@inheritDoc} */
public void startDTD(String name, String pid, String lid) throws SAXException {
transformerHandler.startDTD(name, pid, lid);
}

/** {@inheritDoc} */
public void endDTD() throws SAXException {
transformerHandler.endDTD();
}

/** {@inheritDoc} */
public void startEntity(String name) throws SAXException {
transformerHandler.startEntity(name);
}

/** {@inheritDoc} */
public void endEntity(String name) throws SAXException {
transformerHandler.endEntity(name);
}

/** {@inheritDoc} */
public void startCDATA() throws SAXException {
transformerHandler.startCDATA();
}

/** {@inheritDoc} */
public void endCDATA() throws SAXException {
transformerHandler.endCDATA();
}

/** {@inheritDoc} */
public void comment(char[] charArray, int start, int length) throws SAXException {
transformerHandler.comment(charArray, start, length);
}

}

+ 36
- 0
src/java/org/apache/fop/util/XMLUtil.java View File



import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.Locale;


import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
atts.addAttribute("", localName, localName, XMLUtil.CDATA, value); atts.addAttribute("", localName, localName, XMLUtil.CDATA, value);
} }


/**
* Converts a {@link Locale} instance to an RFC 3066 compliant language identifier.
* @param language the language
* @return the formatted language identifier
*/
public static String toRFC3066(Locale language) {
if (language == null || language.getLanguage().length() == 0) {
return null;
}
StringBuffer sb = new StringBuffer();
sb.append(language.getLanguage());
if (language.getCountry().length() > 0) {
sb.append('-');
sb.append(language.getCountry());
}
return sb.toString();
}

/**
* Converts an RFC 3066 compliant language identifier to a {@link Locale} instance.
* @param lang the language string
* @return the converted locale instance
*/
public static Locale convertRFC3066ToLocale(String lang) {
if (lang == null || lang.length() == 0) {
return null;
}
String[] parts = lang.split("-");
if (parts.length == 1) {
return new Locale(parts[0]);
} else {
return new Locale(parts[0], parts[1]);
}
}

} }

+ 3
- 2
src/sandbox/org/apache/fop/render/svg/SVGPainter.java View File

} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text)
throws IFException {

public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx,
String text) throws IFException {
try { try {
establish(MODE_TEXT); establish(MODE_TEXT);
AttributesImpl atts = new AttributesImpl(); AttributesImpl atts = new AttributesImpl();

+ 3
- 0
status.xml View File

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <release version="FOP Trunk" date="TBD">
<action context="Renderers" dev="JM,VH" type="add" fixes-bug="46705" due-to="Jost Klopfstein">
Added basic accessibility and Tagged PDF support.
</action>
<action context="Code" dev="JM" type="add"> <action context="Code" dev="JM" type="add">
Added support for encoding CMYK bitmap images (IOCA FS45) and TIFF images as embedded objects. Added support for encoding CMYK bitmap images (IOCA FS45) and TIFF images as embedded objects.
</action> </action>

+ 52
- 0
test/accessibility/README View File

his directory contains sample FO files for testing the accessibility features of
FOP.

To every FO file in this directory correspond two PDF files in the pdf/
sub-directory: one generated by the painter, one by the renderer. For example,
the text_1.fo file has been rendered into pdf/text_1_painter_orig.pdf and
pdf/text_1_renderer_orig.pdf. The configuration file config-painter.xconf (resp.
config-renderer.xconf) was used.

The PDF files have been checked with Adobe Acrobat Professional 9, using both
the full accessibility checker and the read-aloud feature. The checker reports
no error /and/ the entire document can be read aloud.


!! DO NOT MODIFY THOSE FILES, NEITHER THE FO NOR THE PDF !!


... Or at least, know what you are doing
If the FO files are modified, the resulting PDFs must be checked again, both
with the checker and the read-aloud feature. (Sometimes the checker reports no
problem yet part or all of the document cannot be read aloud.)

The purpose of this infrastructure is to be able to quickly re-test the
accessibility processing chain when any change has been made to it. The
configuration files disable the compression of the PDF streams, so it is
possible to compare a re-generated PDF with the original one by using a simple
diff tool. The files will not be identical because of the different creation
dates (and the ID key in the trailer), but apart from that there should be no
difference.

The rationale is that using a diff tool is much quicker and less tedious than
running Acrobat's accessibility checker and read-aloud feature every time.


To re-generate the PDF files using the painter:
../../fop -c config-painter.xconf text_1.fo pdf/text_1_painter.pdf
diff pdf/text_1_painter_orig.pdf pdf/text_1_painter.pdf
Or, going through the intermediate format:
../../fop -c config-painter.xconf text_1.fo -if application/pdf text_1_if.xml
../../fop -c config-painter.xconf -ifin text_1_if.xml pdf/text_1_painter.pdf
diff pdf/text_1_painter_orig.pdf pdf/text_1_painter.pdf

To re-generate the PDF files using the legacy renderer:
../../fop -c config-renderer.xconf text_1.fo pdf/text_1_renderer.pdf
diff pdf/text_1_renderer_orig.pdf pdf/text_1_renderer.pdf
Or, going through the intermediate format:
../../fop -c config-renderer.xconf text_1.fo -at application/pdf text_1_at.xml
../../fop -c config-renderer.xconf -atin text_1_at.xml pdf/text_1_renderer.pdf
diff pdf/text_1_renderer_orig.pdf pdf/text_1_renderer.pdf


$Id$

+ 34
- 0
test/accessibility/background-image_jpg_repeat.fo View File

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/bgimg72dpi.jpg"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 36
- 0
test/accessibility/background-image_jpg_single.fo View File

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/bgimg72dpi.jpg"
background-repeat="no-repeat" background-position-horizontal="50%"
background-position-vertical="50%"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 34
- 0
test/accessibility/background-image_png_repeat.fo View File

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/bgimg72dpi.png"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 36
- 0
test/accessibility/background-image_png_single.fo View File

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/fop-logo-color-24bit.png"
background-repeat="no-repeat" background-position-horizontal="50%"
background-position-vertical="50%"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 34
- 0
test/accessibility/background-image_svg_repeat.fo View File

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/rgb-circles.svg"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 36
- 0
test/accessibility/background-image_svg_single.fo View File

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/rgb-circles.svg"
background-repeat="no-repeat" background-position-horizontal="50%"
background-position-vertical="50%"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 205
- 0
test/accessibility/complete.fo View File

<?xml version="1.0" 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$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body column-count="2" margin-top="15pt"/>
<fo:region-before extent="12pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="8pt" text-align-last="justify">This is the page header<fo:leader/>Page
<fo:page-number/></fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-footnote-separator">
<fo:block><fo:leader leader-length="100pt" leader-pattern="rule"/></fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>(There’s another page sequence <fo:wrapper color="blue"><fo:basic-link
internal-destination="second">below</fo:basic-link></fo:wrapper>.)</fo:block>
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter<fo:footnote><fo:inline
baseline-shift="super" font-size="70%">1</fo:inline><fo:footnote-body><fo:block>See the
<fo:wrapper color="blue"><fo:basic-link
external-destination="http://xmlgraphics.apache.org/fop/">FOP
website</fo:basic-link></fo:wrapper> for more
information</fo:block></fo:footnote-body></fo:footnote>. FOP has a nice logo:
<fo:external-graphic src="../resources/images/fop-logo-color-24bit.png"
inline-progression-dimension.maximum="100%" content-width="scale-to-fit"
fox:alt-text="FOP Logo"/></fo:block>
<fo:table space-before="10pt" space-after="10pt" width="100%" table-layout="fixed">
<fo:table-header>
<fo:table-row>
<fo:table-cell border="2pt solid black" padding="2pt 2pt 0">
<fo:block>Header 1.1</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid black" padding="2pt 2pt 0">
<fo:block>Header 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 1.1</fo:block>
</fo:table-cell>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 2.1</fo:block>
</fo:table-cell>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application
that reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
<fo:block span="all" border-top="1pt solid black" border-bottom="1pt solid black"
padding-before="2pt" padding-after="2pt">This fo:block element spans all the columns of the
document. This is intended to test the abilities of the text-to-speech program.</fo:block>
<fo:block>And now we are back to normal content flowing in two columns. Let’s start a numbered
list:</fo:block>
<fo:list-block provisional-distance-between-starts="15pt" provisional-label-separation="0mm"
keep-with-previous="auto">
<fo:list-item keep-with-previous="always">
<fo:list-item-label end-indent="label-end()">
<fo:block>1.</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<fo:block>Line 1 of item 1</fo:block>
<fo:block>Line 2 of item 1</fo:block>
<fo:block>Line 3 of item 1</fo:block>
</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item keep-with-previous="always">
<fo:list-item-label end-indent="label-end()">
<fo:block>2.</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<fo:block>Line 1 of item 2</fo:block>
<fo:block>Line 2 of item 2</fo:block>
<fo:block>Line 3 of item 2</fo:block>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
<fo:block>And now we are going to see how a second page sequence is handled.</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="8pt" text-align-last="justify">This is the page header<fo:leader/>Page
<fo:page-number/></fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-footnote-separator">
<fo:block><fo:leader leader-length="100pt" leader-pattern="rule"/></fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block id="second">Apache FOP (Formatting Objects Processor) is a print formatter driven by
XSL formatting objects (XSL-FO) and an output independent formatter<fo:footnote><fo:inline
baseline-shift="super" font-size="70%">1</fo:inline><fo:footnote-body><fo:block>See the
<fo:wrapper color="blue"><fo:basic-link
external-destination="http://xmlgraphics.apache.org/fop/">FOP
website</fo:basic-link></fo:wrapper> for more
information</fo:block></fo:footnote-body></fo:footnote>. It is a Java application that
reads a formatting object (FO) tree and renders the resulting pages to a specified
output.</fo:block>
<fo:table space-before="10pt" space-after="10pt" width="100%" table-layout="fixed">
<fo:table-header>
<fo:table-row>
<fo:table-cell border="2pt solid black" padding="2pt 2pt 0">
<fo:block>Header 1.1</fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid black" padding="2pt 2pt 0">
<fo:block>Header 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 1.1</fo:block>
</fo:table-cell>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 2.1</fo:block>
</fo:table-cell>
<fo:table-cell border="1pt solid black" padding="2pt 2pt 0">
<fo:block>Cell 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block language="fr" country="FR">Apache FOP (Formatting Objects Processor) est une
application de mise en page de documents respectant le standard XSL-FO. À partir d’un
document au format XSL-FO, cette application écrite en Java effectue une mise en page et
renvoie un document prêt pour impression.</fo:block>
<fo:block span="all" border-top="1pt solid black" border-bottom="1pt solid black"
padding-before="2pt" padding-after="2pt">This fo:block element spans all the columns of the
document. This is intended to test the abilities of the text-to-speech program.</fo:block>
<fo:block>And now we are back to normal content flowing in two columns. Let’s start a numbered
list:</fo:block>
<fo:list-block provisional-distance-between-starts="15pt" provisional-label-separation="0mm"
keep-with-previous="auto">
<fo:list-item keep-with-previous="always">
<fo:list-item-label end-indent="label-end()">
<fo:block>1.</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<fo:block>Line 1 of item 1</fo:block>
<fo:block>Line 2 of item 1</fo:block>
<fo:block>Line 3 of item 1</fo:block>
</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item keep-with-previous="always">
<fo:list-item-label end-indent="label-end()">
<fo:block>2.</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<fo:block>Line 1 of item 2</fo:block>
<fo:block>Line 2 of item 2</fo:block>
<fo:block>Line 3 of item 2</fo:block>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
<fo:block>The end of the document has now been reached.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 23
- 0
test/accessibility/config-painter.xconf View File

<?xml version="1.0" encoding="UTF-8"?>
<fop version="1.0">
<accessibility>true</accessibility>
<source-resolution>144</source-resolution>
<use-cache>false</use-cache>
<font-base>../resources/fonts/</font-base>
<renderers>
<renderer mime="application/pdf">
<filterList>
<value>null</value>
</filterList>
<filterList type="image">
<value>flate</value>
<value>ascii-85</value>
</filterList>
<fonts>
<font embed-url="DejaVuLGCSerif.ttf">
<font-triplet name="DejaVu" style="normal" weight="normal"/>
</font>
</fonts>
</renderer>
</renderers>
</fop>

+ 24
- 0
test/accessibility/config-renderer.xconf View File

<?xml version="1.0" encoding="UTF-8"?>
<fop version="1.0">
<prefer-renderer>true</prefer-renderer>
<accessibility>true</accessibility>
<source-resolution>144</source-resolution>
<use-cache>false</use-cache>
<font-base>../resources/fonts/</font-base>
<renderers>
<renderer mime="application/pdf">
<filterList>
<value>null</value>
</filterList>
<filterList type="image">
<value>flate</value>
<value>ascii-85</value>
</filterList>
<fonts>
<font embed-url="DejaVuLGCSerif.ttf">
<font-triplet name="DejaVu" style="normal" weight="normal"/>
</font>
</fonts>
</renderer>
</renderers>
</fop>

+ 35
- 0
test/accessibility/image_jpg.fo View File

<?xml version="1.0" 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$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the JPEG format: <fo:external-graphic
src="../resources/images/cmyk.jpg"
inline-progression-dimension.maximum="100%" content-width="scale-to-fit"
fox:alt-text="CMYK colours"/>. Here is the end of the text.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 35
- 0
test/accessibility/image_png.fo View File

<?xml version="1.0" 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$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the PNG format: <fo:external-graphic
src="../resources/images/fop-logo-color-24bit.png"
inline-progression-dimension.maximum="100%" content-width="scale-to-fit"
fox:alt-text="FOP Logo"/>. Here is the end of the text.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 45
- 0
test/accessibility/image_svg.fo View File

<?xml version="1.0" 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$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the SVG format: <fo:external-graphic
src="../resources/images/circles.svg"
inline-progression-dimension.maximum="75pt" content-width="scale-to-fit"
fox:alt-text="Nice circles"/>. And here is the same image as an instream-foreign-object:
<fo:instream-foreign-object inline-progression-dimension.maximum="75pt"
content-width="scale-down-to-fit" fox:alt-text="The same nice circles">
<svg xmlns="http://www.w3.org/2000/svg" width="12cm" height="12cm">
<g style="fill-opacity:0.7; stroke:black; stroke-width:0.1cm;">
<circle cx="6cm" cy="2cm" r="100" style="fill:red;" transform="translate(0,50)" />
<circle cx="6cm" cy="2cm" r="100" style="fill:blue;" transform="translate(70,150)" />
<circle cx="6cm" cy="2cm" r="100" style="fill:green;" transform="translate(-70,150)"/>
</g>
</svg>
</fo:instream-foreign-object>.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 35
- 0
test/accessibility/image_wmf.fo View File

<?xml version="1.0" 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$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="320pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the WMF format: <fo:external-graphic
src="../resources/images/testChart.wmf"
inline-progression-dimension.maximum="100%" content-width="scale-to-fit"
fox:alt-text="Metafile Companion Test Chart"/> Here is the end of the text.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 0
- 0
test/accessibility/leader.fo View File


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

Loading…
Cancel
Save